Sådan skrives robuste apps hver gang ved hjælp af "Den rene arkitektur"

Som udviklere kan vi ikke forhindre at bruge eksterne biblioteker og rammer i vores systemer. Fællesskabets hænder bygger vidunderlige værktøjer, og at bruge dem er kun naturligt. Dog har alt en ulempe.

Skødesløse hold og enkeltpersoner kan komme i en farlig situation ved at strukturere deres systemer omkring de værktøjer, de bruger. Forretningsregler blandes med implementeringsdetaljer. Dette kan resultere i et sprødt system, der er svært at udvide og vedligeholde. Hvad der skulle være en hurtig ændring i GUI, ender med at blive en bugjagt, der varer i timer. Men det behøver ikke være sådan.

Software Arkitektur foreslår modeller og regler til bestemmelse af strukturer (som klasser, grænseflader og strukturer) i et system, og hvordan de forholder sig til hinanden. Disse regler fremmer genanvendelighed og adskillelse af bekymring for disse elementer. Dette gør det nemt at ændre implementeringsdetaljer såsom DBMS eller front-end bibliotek. Refaktorer og fejlrettelser påvirker så små dele af systemet som muligt. Og tilføjelse af nye funktioner bliver en leg.

I denne artikel vil jeg forklare en arkitekturmodel foreslået i 2012 af Robert C. Martin, onkel Bob. Han er forfatter til klassikere som Clean Code og The Clean Coder. I oktober i år lancerer han endnu en bog, Ren arkitektur.

Modellen har samme navn som bogen, og den er bygget på enkle koncepter:

Opdel systemets sammensætning i lag med forskellige og veldefinerede roller. Og begræns forholdet mellem enheder i forskellige lag. Der er ikke noget nyt i at opdele din ansøgning i lag. Men jeg valgte denne tilgang, da det var den, der var den enkleste at forstå og udføre. Og det gør test af brugssager døde enkle.

Vi er bare nødt til at sikre, at interaktorerne fungerer korrekt, og at vi er gode til at gå. Bare rolig, hvis ordet "Interaktorer" syntes fremmed for dig, vi vil lære om dem snart.

Fra indefra og ud skal vi udforske hvert af lagene lidt længere. Vi bruger en eksempelapplikation, der er ganske velkendt for os: tællere. Det tager ikke tid at forstå, så vi kan fokusere på denne artikels emne.

Du kan finde en demo af appen her, og kodeeksemplerne findes i TypeScript. Nogle af kodestikkene nedenfor bruger React og Redux. Noget viden om disse løsninger kan hjælpe med at forstå dem. Alligevel er Clean Architectures koncepter meget mere universelle. Du vil være i stand til at forstå det selv uden forudgående kendskab til de nævnte værktøjer.

Enheder

Enheder er i diagrammet som Enterprise Business regler. Enheder inkluderer forretningsregler, der er universelle for en virksomhed. De repræsenterer enheder, der er grundlæggende for dets driftsområde. Det er komponenterne med det højeste abstraktionsniveau.

I vores tællereksempel er der en meget indlysende enhed: Selve tælleren.

Brug sager

Brugssager påpeges som forretningsregler for anvendelse. De repræsenterer hvert af brugssagerne for en enkelt applikation. Hvert element i dette lag giver en grænseflade til det ydre lag og fungerer som et hub, der kommunikerer med andre dele af systemet. De er ansvarlige for den komplette udførelse af brugssager og kaldes ofte interaktorer.

I vores stikprøve har vi en brugssag til at øge eller nedbringe vores tæller:

Bemærk, at fabriksfunktionen til ChangeCounterInteractor modtager en parameter af typen CounterGateway. Vi vil diskutere eksistensen af ​​denne type vil senere i artiklen. Men vi kan sige, at Gateways er det, der står mellem Use Cases og det næste lag.

Interfaceadaptere

Dette lag består af grænsen mellem systemets forretningsregler og de værktøjer, der giver det mulighed for at interagere med den eksterne verden, som databaser og grafiske grænseflader. Elementer i dette lag fungerer som mæglere, modtager data fra det ene lag og videresender dem videre til det andet og tilpasser dataene efter behov.

I vores eksempel har vi flere interfaceadaptere. En af dem er React-komponenten, der præsenterer tælleren og dens kontroller for tilvækst og dekrement:

Bemærk, at komponenten ikke bruger en Counter-instans til at præsentere dens værdi, men en forekomst af CounterViewData i stedet. Vi har foretaget denne ændring for at afkoble præsentationslogikken fra forretningsdata. Et eksempel på dette er logikken i udstillingen af ​​tælleren baseret på visningsmodus (romerske eller hindu-arabiske tal). En implementering af CounterViewData følger nedenfor:

Et andet eksempel på en interfaceadapter ville være vores applikations Redux-implementering. Moduler, der er ansvarlige for anmodninger til en server og brugen af ​​lokal opbevaring, leveres også inde i dette lag.

Rammer og drivere

De værktøjer, dit system bruger til at kommunikere med den eksterne verden, udgør det yderste lag. Vi skriver normalt ikke kode i dette lag, der inkluderer biblioteker som React / Redux, browser APIs osv.

Afhængighedsreglen

Denne opdeling i lag har to hovedmål. En af dem er at klarlægge ansvaret for hver del af systemet. Den anden er at sikre sig, at hver af dem udfylder deres roller så uafhængigt af hinanden som muligt. For at dette kan ske, er der en regel, der angiver, hvordan elementerne skal afhænge af hinanden:

Et element må ikke afhænge af noget element, der hører til et lag uden for dets eget.

F.eks. Kan et element i laget Brug af tilfælde ikke have nogen viden om nogen klasse eller modul relateret til GUI eller datapersistens. Ligeledes kan en enhed ikke vide, hvilke Use Cases der bruger den.

Denne regel kan have rejst spørgsmål i dit hoved. Tag f.eks. En brugssag. Det udløses som resultat af brugerinteraktion med brugergrænsefladen. Dens udførelse involverer opdateringen i noget vedvarende datalagring, såsom en database. Hvordan kan interaktoren foretage de relevante opkald til opdateringsrutinerne uden at afhænge af en grænsefladeadapter, der er ansvarlig for dataudholdenhed?

Svaret ligger i et element, som vi har nævnt før: Gateways. De er ansvarlige for at etablere den grænseflade, der er brug for af Use Cases til at udføre deres job. Når de har etableret denne grænseflade, er det op til interfaceadaptere at opfylde deres side af kontrakten, som vist i diagrammet ovenfor. Vi har CounterGateway-interface og en konkret implementering ved hjælp af Redux nedenfor:

Du har muligvis ikke brug for det

Naturligvis var denne prøveansøgning noget for kompliceret til en apprement til stigning / reduktion. Og jeg vil gerne gøre det klart, at du ikke har brug for alt dette til et lille projekt eller prototype. Men tro mig, når din ansøgning bliver større, vil du maksimere genanvendelighed og vedligeholdelighed. God softwarearkitektur gør projekter modstandsdygtige over for tiden.

Okay ... Så hvad?

Med denne artikel opdagede vi en tilgang til at afkoble vores systemers enheder. Dette gør dem lettere at vedligeholde og udvide. For at opbygge den samme applikation ved hjælp af Vue.js, ville vi f.eks. Kun omskrive CounterPage- og CounterWidget-komponenter. Kildekoden for prøven er i nedenstående link:

Denne historie blev oversat til portugisisk af mig! Det er tilgængeligt her.

Hvilke fordele og ulemper ser du ved denne tilgang? Har du brugt noget lignende i produktionen? Del dine oplevelser i svarene. Hvis du kan lide artiklen, så klap for mig!