Jak psát robustní aplikace pokaždé pomocí „Čisté architektury“

Jako vývojáři nemůžeme zabránit tomu, abychom v našich systémech používali externí knihovny a rámce. Ruce komunity vytvářejí úžasné nástroje a jejich používání je pouze přirozené. Všechno však má nevýhodu.

Nedbalé týmy a jednotlivci se mohou dostat do nebezpečné situace strukturováním svých systémů podle nástrojů, které používají. Obchodní pravidla se mísí s podrobnostmi o implementaci. To může mít za následek křehký systém, který lze těžko rozšiřovat a udržovat. Jaká by měla být rychlá změna v GUI, nakonec se změní na lov chyb, který bude trvat hodiny. Ale nemusí to tak být.

Softwarová architektura navrhuje modely a pravidla pro určování struktur (jako jsou třídy, rozhraní a struktury) v systému a jejich vzájemného vztahu. Tato pravidla podporují opětovné použití a oddělení obav z těchto prvků. To usnadňuje změnu podrobností implementace, jako je DBMS nebo knihovna front-end. Refaktory a opravy chyb mají vliv na co nejmenší části systému. A přidávání nových funkcí se stává hračkou.

V tomto článku vysvětlím model architektury navržený v roce 2012 Robertem C. Martinem, strýcem Bobem. Je autorem klasiky jako Clean Code a The Clean Coder. V říjnu letošního roku uvede na trh další knihu Clean Architecture.

Model má stejný název jako kniha a je postaven na jednoduchých konceptech:

Rozdělte složení systému do vrstev s odlišnými a dobře definovanými rolemi. A omezte vztahy mezi entitami v různých vrstvách. Rozdělení aplikace do vrstev není nic nového. Ale vybral jsem si tento přístup, protože to byl ten, který byl nejjednodušší pochopit a provést. A díky tomu je testování případů použití mrtvé jednoduché.

Musíme se jen ujistit, že Interactors fungují správně, a že je dobré jít. Nedělejte si starosti, pokud se vám slovo „Interactors“ zdálo být cizí, brzy se o nich dozvíme.

Zevnitř ven prozkoumáme každou z vrstev o něco dále. Použijeme ukázkovou aplikaci, která je nám dobře známa: čítače. Porozumět tomu není čas, takže se můžeme soustředit na téma tohoto článku.

Zde najdete ukázku aplikace a ukázky kódu budou v TypeScript. Některé níže uvedené kódy používají React a Redux. Některé znalosti o těchto řešeních mohou pomoci při jejich porozumění. Přesto jsou koncepce čisté architektury mnohem univerzálnější. Budete to schopni porozumět i bez předchozí znalosti uvedených nástrojů.

Subjekty

Entity jsou v diagramu jako Enterprise Business Rules. Účetní jednotky zahrnují obchodní pravidla, která jsou pro společnost univerzální. Představují entity, které jsou základní pro oblast její činnosti. Jsou to komponenty s nejvyšší úrovní abstrakce.

V našem vzorku čítačů je velmi zřejmá entita: samotný čítač.

Případy užití

Případy použití jsou označeny jako obchodní pravidla aplikace. Představují každý případ použití jedné aplikace. Každý prvek této vrstvy poskytuje rozhraní k vnější vrstvě a působí jako rozbočovač, který komunikuje s ostatními částmi systému. Jsou odpovědné za kompletní provedení případů použití a běžně se nazývají Interactors.

V našem vzorku máme případ použití pro zvyšování nebo snižování našeho čítače:

Všimněte si, že tovární funkce pro ChangeCounterInteractor obdrží parametr typu CounterGateway. Budeme diskutovat o existenci tohoto typu bude později v článku. Můžeme však říci, že mezi případy použití a další vrstvou stojí brány.

Adaptéry rozhraní

Tato vrstva se skládá z hranice mezi obchodními pravidly systému a nástroji, které umožňují interakci s vnějším světem, jako jsou databáze a grafická rozhraní. Prvky v této vrstvě fungují jako zprostředkovatelé, přijímají data z jedné vrstvy a předávají ji dopředu druhé, přičemž data upravují podle potřeby.

V našem vzorku máme několik adaptérů rozhraní. Jedním z nich je komponenta React, která představuje počítadlo a jeho ovládací prvky pro zvyšování a snižování:

Komponenta nepoužívá k zobrazení své hodnoty instanci Counter, ale místo toho instanci CounterViewData. Provedli jsme tuto změnu, abychom oddělili prezentaci logiky od obchodních dat. Příkladem je logika výstavy čítače založená na režimu zobrazení (římské nebo hinduistické arabské číslice). Níže je implementace CounterViewData:

Dalším příkladem adaptéru rozhraní je implementace Redux naší aplikace. Uvnitř této vrstvy by také žily moduly odpovědné za požadavky na server a použití místního úložiště.

Rámce a ovladače

Nástroje, které váš systém používá ke komunikaci s vnějším světem, tvoří vnější vrstvu. V této vrstvě obvykle nepíšeme kód, který zahrnuje knihovny jako React / Redux, API prohlížeče atd.

Pravidlo závislosti

Toto rozdělení do vrstev má dva hlavní cíle. Jednou z nich je vyjasnit povinnosti jednotlivých částí systému. Druhým je zajistit, aby každý z nich plnil své role co nejvíce nezávisle na sobě. Aby k tomu došlo, existuje pravidlo, které stanoví, jak by prvky měly na sobě záviset:

Prvek nesmí záviset na žádném prvku, který patří do vrstvy mimo jeho vlastní.

Například prvek ve vrstvě Použít případy nemůže mít žádné znalosti o žádné třídě nebo modulu související s grafickým uživatelským rozhraním nebo vytrvalostí dat. Stejně tak entita nemůže vědět, které případy použití ji využívají.

Toto pravidlo mohlo vyvolat otázky ve vaší hlavě. Vezměte si například případ použití. Spouští se v důsledku interakce uživatele s uživatelským rozhraním. Jeho provedení zahrnuje aktualizaci v nějakém trvalém datovém úložišti, jako je databáze. Jak může Interactor provádět příslušná volání do aktualizačních rutin, aniž by závisel na adaptéru rozhraní, který je zodpovědný za perzistenci dat?

Odpověď spočívá v prvku, který jsme zmínili dříve: Brány. Zodpovídají za vytvoření rozhraní potřebného pro použití v případech použití. Po vytvoření tohoto rozhraní je na adaptérech rozhraní, aby splnily svou stranu smlouvy, jak je znázorněno na obrázku výše. Níže máme rozhraní CounterGateway a konkrétní implementaci pomocí Reduxu:

Možná to nebudete potřebovat

Tato vzorová aplikace byla samozřejmě pro aplikaci čítače přírůstků / úbytků poněkud komplikovaná. A rád bych objasnil, že toto všechno nepotřebujete pro malý projekt nebo prototyp. Ale věřte mi, jak se vaše aplikace zvětšuje, budete chtít maximalizovat opakovatelnost a udržovatelnost. Díky dobré softwarové architektuře jsou projekty odolné vůči plynutí času.

Dobře ... Tak co?

V tomto článku jsme objevili přístup k oddělení entit našich systémů. Díky tomu je snazší udržovat a rozšiřovat. Například pro vytvoření stejné aplikace pomocí Vue.js bychom museli přepsat pouze součásti CounterPage a CounterWidget. Zdrojový kód vzorové aplikace je v odkazu níže:

Tento příběh jsem přeložil do portugalštiny! Je k dispozici zde.

Jaké výhody a nevýhody vidíte v tomto přístupu? Už jste použili něco podobného ve výrobě? Podělte se o své zkušenosti v odpovědích. Pokud se vám článek líbí, tleskejte za mě!