valóban moduláris kód létrehozása függőségek nélkül

a szoftver fejlesztése nagyszerű, de… azt hiszem, mindannyian egyetértünk abban, hogy kissé érzelmi hullámvasút lehet. Az elején minden nagyszerű. Új funkciókat ad hozzá egymás után napok, ha nem órák Alatt. Te vagy a tekercs!

gyors előre néhány hónap, és a fejlesztési sebesség csökken. Ez azért van, mert nem dolgozol olyan keményen, mint korábban? Nem igazán. Lépjünk előre még néhány hónapot, és a fejlesztési sebességed tovább csökken. A projekten való munka már nem szórakoztató, és húzássá vált.

rosszabb lesz. Elkezdi felfedezni több hibát az alkalmazásban. Gyakran egy hiba megoldása két újat hoz létre. Ezen a ponton elkezdheti énekelni:

99 apró hibák a kódban.99 kis bogár.Vegyél le egyet, foltozd körbe,

…127 apró hiba a kódban.

hogyan érzi magát most ezen a projekten? Ha olyan vagy, mint én, akkor valószínűleg elveszíti motivációját. Csak fájdalom az alkalmazás fejlesztése, mivel a meglévő kód minden változása kiszámíthatatlan következményekkel járhat.

ez a tapasztalat gyakori a szoftver világában, és megmagyarázhatja, miért akarja oly sok programozó eldobni a forráskódját, és mindent átírni.

a szoftverfejlesztés lassulásának okai az idő múlásával

Tehát mi az oka ennek a problémának?

a fő ok a növekvő komplexitás. Tapasztalataim szerint a legnagyobb mértékben hozzájárul az Általános komplexitáshoz az a tény, hogy a szoftverprojektek túlnyomó többségében minden összekapcsolódik. Az egyes osztályok függőségei miatt, ha megváltoztat egy kódot az osztályban, amely e-maileket küld, a felhasználók hirtelen nem tudnak regisztrálni. Miért is? Mivel a regisztrációs kód az e-maileket küldő kódtól függ. Most nem változtathat meg semmit hibák bevezetése nélkül. Egyszerűen nem lehet nyomon követni az összes függőséget.

tehát itt van; problémáink valódi oka a komplexitás növelése, amely a kódunk összes függőségéből származik.

Big Ball of sár and How to Reduce It

vicces dolog az, hogy ez a kérdés már évek óta ismert. Ez egy általános anti-minta, az úgynevezett ” nagy sárgömb.”Szinte minden olyan projektben láttam ezt a típusú architektúrát, amelyen az évek során több különböző vállalatnál dolgoztam.

tehát mi ez az anti-minta pontosan? Egyszerűen szólva, akkor kap egy nagy labdát a sár, ha minden elem egy függőség más elemekkel. Az alábbiakban látható a jól ismert nyílt forráskódú Apache Hadoop projekt függőségeinek grafikonja. Annak érdekében, hogy megjelenítse a nagy sár labdát (vagy inkább a nagy fonalgolyót), rajzoljon egy kört, és egyenletesen helyezze el a projekt osztályait. Csak húzzon egy vonalat az egymástól függő osztályok párjai között. Most láthatja a problémák forrását.

az Apache Hadoop nagy sárgömbjének vizualizációja, néhány tucat csomóponttal és több száz vonallal, amelyek összekötik őket egymással.

Apache Hadoop”big ball of sár”

megoldás moduláris kóddal

ezért feltettem magamnak egy kérdést: Lehetséges-e csökkenteni a komplexitást, és továbbra is szórakozni, mint a projekt elején? Az igazat megvallva, nem lehet kiküszöbölni az összes komplexitást. Ha új funkciókat szeretne hozzáadni, akkor mindig meg kell növelnie a kód összetettségét. Ennek ellenére a komplexitás mozgatható és elválasztható.

hogy más iparágak hogyan oldják meg ezt a problémát

Gondolj a gépiparra. Amikor egy kis mechanikus műhely gépeket készít, megvásárol egy sor szabványos elemet, létrehoz néhány egyedi elemet, és összerakja őket. Ezeket az alkatrészeket teljesen külön-külön készíthetik, és a végén mindent össze tudnak szerelni, csak néhány csípéssel. Hogy lehetséges ez? Tudják, hogy az egyes elemek hogyan illeszkednek egymáshoz az iparági szabványok, például a csavarok mérete és az olyan előzetes döntések alapján, mint a szerelési lyukak mérete és a köztük lévő távolság.

egy fizikai mechanizmus technikai diagramja és annak darabjai egymáshoz való illeszkedése. A darabokat a következő sorrendben számozzuk, de ez a sorrend balról jobbra megy 5, 3, 4, 1, 2.

a fenti szerelvény minden elemét külön vállalat biztosíthatja, amely semmilyen ismerettel nem rendelkezik a végtermékről vagy annak Egyéb darabjairól. Mindaddig, amíg minden moduláris elemet a specifikációk szerint gyártanak, a tervek szerint elkészítheti a végső eszközt.

megismételhetjük ezt a szoftveriparban?

persze tudunk! Az interfészek használatával és a vezérlési elv megfordításával; a legjobb az a tény, hogy ez a megközelítés bármilyen objektumorientált nyelven használható: Java, C#, Swift, TypeScript, JavaScript, PHP-a lista folytatódik. A módszer alkalmazásához nincs szükség díszes keretre. Csak be kell tartania néhány egyszerű szabályt, és fegyelmezettnek kell maradnia.

a kontroll inverziója a barátod

amikor először hallottam a kontroll inverziójáról, azonnal rájöttem, hogy találtam megoldást. Ez egy koncepció a meglévő függőségek felvételéről és az interfészek használatával történő megfordításáról. Az interfészek a módszerek egyszerű deklarációi. Nem nyújtanak konkrét megvalósítást. Ennek eredményeként, akkor lehet használni, mint egy megállapodás két elem között, hogyan kell csatlakoztatni őket. Ezeket fel lehet használni, mint egy moduláris csatlakozók, ha úgy tetszik. Amíg az egyik elem biztosítja az interfészt, a másik pedig az implementációt, addig együtt tudnak működni anélkül, hogy bármit is tudnának egymásról. Zseniális.

lássuk egy egyszerű példát, hogyan tudjuk szétválasztani a rendszerünket moduláris kód létrehozásához. Az alábbi diagramok egyszerű Java alkalmazásokként valósultak meg. Megtalálhatja őket ezen a GitHub adattáron.

probléma

tegyük fel, hogy van egy nagyon egyszerű alkalmazásunk, amely csak egy Main osztályból, három szolgáltatásból és egyetlen Util osztályból áll. Ezek az elemek többféleképpen függenek egymástól. Az alábbiakban egy megvalósítást láthat a” nagy sárgömb ” megközelítéssel. Az osztályok egyszerűen hívják egymást. Szorosan kapcsolódnak egymáshoz, és nem lehet egyszerűen kivenni egy elemet anélkül, hogy megérintene másokat. Az ezzel a stílussal létrehozott alkalmazások lehetővé teszik, hogy kezdetben gyorsan növekedjen. Úgy gondolom, hogy ez a stílus megfelelő a proof-of-concept projektekhez, mivel könnyedén játszhatsz a dolgokkal. Ennek ellenére nem megfelelő a gyártásra kész megoldásokhoz, mert még a karbantartás is veszélyes lehet, és bármilyen változtatás kiszámíthatatlan hibákat okozhat. Az alábbi ábra ezt a nagy iszapépítészeti labdát mutatja.

a fő az A, B és C szolgáltatásokat használja, amelyek mindegyike Util-t használ. A C szolgáltatás az a szolgáltatást is használja.

miért függőség injekció van minden rossz

a keresést egy jobb megközelítés, tudjuk használni a technikát hívott függőség injekció. Ez a módszer feltételezi, hogy minden összetevőt interfészeken keresztül kell használni. Olvastam azt állítja, hogy szétválasztja elemek, de ez tényleg, bár? Nem. Vessen egy pillantást az alábbi diagramra.

az előző architektúra, de függőségi injekcióval. Most a Main az A, B és C Interfészszolgáltatást használja, amelyeket a megfelelő szolgáltatások valósítanak meg. Az A és C szolgáltatások egyaránt használják a Service B interfészt és az Util interfészt, amelyet az Util valósít meg. A C szolgáltatás az a Interfészszolgáltatást is használja.

az egyetlen különbség a jelenlegi helyzet és a nagy sárgömb között az, hogy most ahelyett, hogy közvetlenül hívnánk az osztályokat, az interfészükön keresztül hívjuk őket. Ez kissé javítja az elemek elválasztását egymástól. Ha például újra szeretné használni a Service A – et egy másik projektben, akkor ezt úgy teheti meg, hogy eltávolítja magát a Service A – et, a Interface A – vel együtt, valamint a Interface Bés a Interface Util – et. Mint látható, a Service A még mindig más elemektől függ. Ennek eredményeként továbbra is problémákat tapasztalunk az egyik helyen a kód megváltoztatásával, a másikban pedig a viselkedés elrontásával. Továbbra is azt a problémát okozza, hogy ha módosítja a Service B és a Interface B értéket, akkor minden tőle függő elemet meg kell változtatnia. Ez a megközelítés nem old meg semmit; véleményem szerint csak egy réteg felületet ad az elemek tetejére. Soha ne adjon be semmilyen függőséget, hanem meg kell szabadulnia tőlük egyszer és mindenkorra. Éljen a függetlenség!

a megoldás moduláris Kód

a megközelítés azt hiszem, megoldja az összes fő fejfájás függőségek teszi, hogy nem használ függőségek egyáltalán. Létrehoz egy komponenst és annak hallgatóját. A hallgató egy egyszerű felület. Amikor egy metódust az aktuális elemen kívülről kell meghívnia, egyszerűen hozzá kell adnia egy metódust a hallgatóhoz, és helyette meg kell hívnia. Az elem csak fájlokat, hívási módszereket használhat a csomagjában, valamint a main framework vagy más használt könyvtárak által biztosított osztályokat használhatja. Az alábbiakban láthatja az elem architektúra használatára módosított alkalmazás diagramját.

az elem architektúra használatára módosított alkalmazás diagramja. A fő az Util-t és mindhárom szolgáltatást használja. Main is megvalósítja a hallgató minden szolgáltatás, amely által használt szolgáltatás. A hallgató és a szolgáltatás együtt tekinthető elemnek.

Felhívjuk figyelmét, hogy ebben az architektúrában csak a Main osztálynak van több függősége. Az összes elemet összekapcsolja, és magában foglalja az alkalmazás üzleti logikáját.

a szolgáltatások viszont teljesen független elemek. Most, akkor vegye ki minden szolgáltatás ki ezt az alkalmazást, és újra őket valahol máshol. Nem függnek semmi mástól. De várj, jobb lesz: soha többé nem kell módosítania ezeket a szolgáltatásokat, mindaddig, amíg nem változtatja meg a viselkedésüket. Amíg ezek a szolgálatok azt teszik, amit tenniük kell, érintetlenül hagyhatók az idők végezetéig. Ők lehet létrehozni egy profi szoftver mérnök, vagy egy első alkalommal kódoló veszélybe a legrosszabb spagetti kódot bárki valaha szakács goto nyilatkozatok keverve. Nem számít, mert logikájuk kapszulázott. Bármilyen szörnyű is lehet, soha nem fog kifolyni más osztályokba. Ez lehetőséget ad arra is, hogy a projektben végzett munkát több fejlesztő között Ossza meg, ahol minden fejlesztő önállóan dolgozhat a saját összetevőjén anélkül, hogy meg kellene szakítania egy másikat, vagy akár tudnia kellene más fejlesztők létezéséről.

végül még egyszer elkezdheti írni a független kódot, akárcsak az utolsó projekt elején.

Elemminta

határozzuk meg a szerkezeti elemmintát, hogy megismételhető módon tudjuk létrehozni.

az elem legegyszerűbb változata két dologból áll: A fő elem osztály és a hallgató. Ha egy elemet szeretne használni, akkor végre kell hajtania a hallgatót, és hívásokat kell kezdeményeznie a fő osztályba. Itt található a legegyszerűbb konfiguráció diagramja:

egyetlen elem diagramja és annak hallgatója egy alkalmazáson belül. Mint korábban, az alkalmazás az elemet használja, amely a hallgatóját használja, amelyet az alkalmazás valósít meg.

nyilvánvaló, hogy végül nagyobb összetettséget kell hozzáadnia az elemhez, de ezt könnyen megteheti. Csak győződjön meg arról, hogy egyik logikai osztály sem függ a projekt többi fájljától. Csak a fő keretrendszert, az importált könyvtárakat és más fájlokat használhatják ebben az elemben. Amikor olyan eszközfájlokról van szó, mint a képek, nézetek, hangok stb., azokat is be kell zárni az elemekbe, hogy a jövőben könnyen újrafelhasználhatók legyenek. Egyszerűen átmásolhatja a teljes mappát egy másik projektbe, és ott van!

az alábbiakban látható egy példa grafikon, amely egy fejlettebb elemet mutat. Figyeljük meg, hogy ez áll a nézet, hogy ez használ, és ez nem függ más alkalmazás fájlokat. Ha szeretne tudni egy egyszerű módszert a függőségek ellenőrzésére, nézze meg az Importálás részt. Vannak-e fájlok az aktuális elemen kívülről? Ha igen, akkor el kell távolítania ezeket a függőségeket úgy, hogy áthelyezi őket az elembe, vagy hozzáad egy megfelelő hívást a hallgatóhoz.

egy összetettebb elem egyszerű diagramja. Itt az "elem" szó tágabb értelemben hat részből áll: nézet; A, B és C logika; elem; és Elemfigyelő. Az utóbbi kettő és az alkalmazás közötti kapcsolat ugyanaz, mint korábban, de a belső elem az A és a C logikát is használja.a C logika az A és a B logikát használja. az a logika a B logikát és a View logikát használja.

vessünk egy pillantást egy egyszerű” Hello World ” példára is, amelyet Java-ban hoztak létre.

public class Main { interface ElementListener { void printOutput(String message); } static class Element { private ElementListener listener; public Element(ElementListener listener) { this.listener = listener; } public void sayHello() { String message = "Hello World of Elements!"; this.listener.printOutput(message); } } static class App { public App() { } public void start() { // Build listener ElementListener elementListener = message -> System.out.println(message); // Assemble element Element element = new Element(elementListener); element.sayHello(); } } public static void main(String args) { App app = new App(); app.start(); }}

kezdetben a ElementListener értéket definiáljuk a kimenet nyomtatásának módjának meghatározásához. Maga az elem az alábbiakban van meghatározva. A sayHellohívásakor az elemen egyszerűen kiírja az üzenetet a ElementListener használatával. Vegye figyelembe, hogy az elem teljesen független a printOutput módszer megvalósításától. Meg lehet nyomtatni a konzol, a fizikai nyomtató, vagy egy díszes UI. Az elem nem függ a megvalósítástól. Ennek az absztrakciónak köszönhetően ez az elem könnyen felhasználható különböző alkalmazásokban.

most nézd meg a fő App osztályt. Megvalósítja a hallgatót, és összeszereli az elemet a konkrét megvalósítással együtt. Most már elkezdhetjük használni.

ezt a példát JavaScript-ben is futtathatja itt

elem architektúra

vessünk egy pillantást az elemminta használatára egy nagyszabású alkalmazásban. Egy dolog megmutatni egy kis projektben-egy másik, hogy alkalmazzuk a való világra.

a szerkezet egy teljes verem webalkalmazás, hogy szeretem használni a következőképpen néz ki:

src├── client│ ├── app│ └── elements│ └── server ├── app └── elements

egy forráskód mappában kezdetben felosztottuk a kliens és a szerver fájlokat. Ez egy ésszerű dolog, mivel két különböző környezetben futnak: a böngészőben és a back-end szerveren.

ezután az egyes rétegekben lévő kódot az app és elements nevű mappákra osztjuk. Az Elements független komponenseket tartalmazó mappákból áll, míg az alkalmazásmappa az összes elemet összekapcsolja, és tárolja az összes üzleti logikát.

így az elemek újra felhasználhatók a különböző projektek között, miközben az alkalmazásspecifikus komplexitás egyetlen mappába van beágyazva, és gyakran egyszerű elemhívásokra redukálódik.

gyakorlati példa

abban a hitben, hogy a gyakorlat mindig trump elmélet, vessünk egy pillantást egy valós példa létre Node.js és TypeScript.

valós példa

ez egy nagyon egyszerű webes alkalmazás, amely a fejlettebb megoldások kiindulópontjaként használható. Ez nem követi az elem architektúra, valamint használ egy széles körben szerkezeti elem Minta.

a kiemelésekből láthatja, hogy a főoldalt elemként különböztették meg. Ez az oldal saját nézetet tartalmaz. Tehát, ha például újra szeretné használni, egyszerűen átmásolhatja az egész mappát, és egy másik projektbe dobhatja. Csak kössön össze mindent, és készen áll.

ez egy alapvető példa, amely bizonyítja, hogy már ma elkezdheti az elemek bevezetését a saját alkalmazásában. Elkezdhetjük megkülönböztetni a független komponenseket és elkülöníteni a logikájukat. Nem számít, mennyire rendetlen a kód, amelyen jelenleg dolgozik.

Gyorsabban Fejlődjön, Gyakrabban Használja Újra!

remélem, hogy ezzel az új eszközkészlettel könnyebben fejlesztheti a karbantarthatóbb kódot. Mielőtt belevágna az elemmintázat gyakorlati használatába, gyorsan összefoglaljuk az összes főbb pontot:

  • a szoftverekben sok probléma merül fel a több összetevő közötti függőség miatt.

  • ha egy helyen változtat, kiszámíthatatlan viselkedést vezethet be valahol máshol.

három közös építészeti megközelítés:

  • a nagy sárgömb. Nagyszerű a gyors fejlődéshez, de nem olyan nagy a stabil termelési célokra.

  • függőségi injekció. Ez egy félig sült megoldás, amelyet el kell kerülni.

  • elem architektúra. Ez a megoldás lehetővé teszi független komponensek létrehozását és más projektekben történő újrafelhasználását. Karbantartható és ragyogó a stabil gyártási kiadásokhoz.

az alapelem minta egy fő osztályból áll, amely rendelkezik az összes főbb módszerrel, valamint egy hallgatóval, amely egy egyszerű felület, amely lehetővé teszi a kommunikációt a külvilággal.

a teljes stack elem architektúra elérése érdekében először válassza el a front-end-et a back-end kódtól. Ezután mindegyikben létrehoz egy mappát egy alkalmazáshoz és elemekhez. Az elements mappa minden független elemből áll, míg az alkalmazás mappa mindent összeköt.

most már elkezdheti létrehozni és megosztani saját elemeit. Hosszú távon ez segít könnyen karbantartható termékek létrehozásában. Sok szerencsét, és hadd tudja, mit teremtett!

Továbbá, ha úgy találja magát idő előtt optimalizálja a kódot, olvassa el, hogyan lehet elkerülni az átok idő előtti optimalizálás fickó Toptaler Kevin Bloch.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.