Bring klarhed til din monolit med afgrænsede sammenhænge

tjek videoen af denne tale fra Eliksirconf 2017 nedenfor

monolitiske applikationer er gode, når du begynder at opbygge din virksomhed, men som tiden skrider frem, bliver de vanskelige at vedligeholde. Disse kodebaser, når de vokser, bliver let Store kugler af mudder.

Indiana Jones Rock

når man bygger store applikationer i rammer som skinner, begynder de meget convention-over-configuration designprincipper, der gjorde skinner sådan en glæde at bruge, at komme i vejen, når applikationen vokser i omfang. Du kan også opleve de samme smerter, hvis:

  • Refactoring er vanskelig og kedelig, fordi metoder og klasser afhænger af for mange andre klasser
  • du har en stadigt voksende liste over forretningsobjekter, der er vanskelige at holde i dit hoved. Faktisk synes ingen at være i stand til at forstå systemet som en sammenhængende helhed
  • ændring af kode i et område af koden fører til uventede og utilsigtede bivirkninger på andre områder af koden, fordi det er nemt at ringe til globale tjenester og objekter

i vores sidste chat sammen diskuterede vi at udvikle et allestedsnærværende sprog sammen med forretningseksperterne og dit udviklingsteam for at hjælpe dit team med at arbejde tættere sammen. I dag vil vi bygge videre på det ved at introducere nye Domain-Driven Design (DDD) værktøjer. Derefter introducerer vi en ny mappestruktur til dine Rails-apps og forbereder dem på en fremtid, hvor din applikation er mindre koblet og mere sammenhængende. Lad os komme i gang!

lad os tale domæner

et nøgleprincip i DDD er, at det program, du bygger, nøje skal afspejle (business) domænet for den organisation, der bygger det. Derfor er vi nødt til at lave nogle lektier for at forstå forretningsområdet for dit program.

et domæne er, hvad virksomheden gør, og konteksten for, hvordan den gør det.

lad os se vores DeLorean eksempel fra det tidligere indlæg. I det markedsføres virksomheden som Uber til tidsrejser. Således er dets ” domæne “(“hvad det gør”) tidsrejse Ridesharing. Også inkluderet i domænet er “hvordan” af hvordan det gør det – ved at samarbejde chauffører, der ejer tidsrejsende DeLorean-køretøjer med passagerer, der ønsker at foretage tidsrejser.

for at få flere nuancer i forretningsdomænet introducerer DDD et andet koncept, kaldet underdomænet:

et underdomæne repræsenterer de mindre grupper eller enheder i virksomheden, der samarbejder i det daglige for at nå virksomhedens mål.

Delorean er opdelt i flere hold i virksomheden. Lad os se på to af dem, og se, hvad de er ansvarlige for:

Trip Platform team Finance Operations team
Mission Design og støtte de systemer, der rute ture og forbinde chauffører til passagerer Administrer de systemer, der involverer finansielle institutioner og kreditkort processorer
ansvarsområder
  • Forbind passagerer til chauffører
  • rute chaufføren til deres næste destination
  • Underret passagerer om ankommende chauffører
  • Underret chauffører om nye passagerer
  • Procesudbetalinger til chauffører
  • vedligehold hele systemet transaktionshistorik til revision
  • Byg finansielle rapporter
  • behandle kreditkortgebyrer til passagerer

hver af disse to grupper animerer et forretningsansvar eller underdomæne. Lad os nævne dem Ridesharing erfaring og e-handel, henholdsvis.

nu har vi en generel illustration af virksomheden og to af dens enheder, der hjælper den med at fungere i det daglige. Domænet og underdomænet er måder at modellere problemområdet i din virksomhed – og hvordan det fungerer for at udføre disse roller. Chancerne er, at din virksomheds org-diagram nøje afspejler underdomænerne i din virksomhed. I den virkelige verden kan afgrænsningerne være mindre klare-hold kan være ansvarlige for flere overlappende underdomæner.

lad os udfylde dette diagram med et par flere underdomæner i DeLorean-forretningen:

  • kundesupport underdomæne: løsning af kundesupport billetter kommer ind via e-mail
  • Marketing underdomæne: håndtering af marketing e-mail-kampagner og marketingkuponkoder
  • identitet underdomæne: hvordan systemet sporer hver bruger og hans / hendes identificerende oplysninger

afgrænsede sammenhænge i løsningsrummet

dette diagram foran os afspejler nu virksomhedens forretningsmål, opdelt i logiske enheder, der (forhåbentlig) når sine mål i den virkelige verden. Nu skal vi overlejre de programmer, der opnår disse mål over dette diagram. Disse systemer beskrives som afgrænsede sammenhænge:

en afgrænset kontekst er et system, der opfylder virksomhedens mål i den virkelige verden.

ethvert af vores programmelsystemer (som f.eks. en internettjeneste eller en internetapp), der fungerer som konkrete tilfælde i den virkelige verden, betragtes som afgrænsede sammenhænge.

teknisk set er den afgrænsede kontekst i DDD-speak en specifik grænse inden for dit domæne, som din ordliste fra dit allestedsnærværende sprog kun kan anvende – ideen er, at forskellige underdomæner kan have konkurrerende eller modstridende definitioner af udtryk. Dette indlæg vil ikke uddybe de sproglige nuancer i den afgrænsede kontekst. For yderligere læsning, se Martin fuglers forklaring på afgrænsede sammenhænge.

nu sker det så, at i Delorean implementeres alle disse underdomæner i et system – en stor kugle af Mudderskinner monolit. Vi tegner en blå boks omkring underdomænerne, hvis funktioner implementeres af programmellet. I dette tilfælde starter vi med vores førnævnte Rails monolith:

da det er monolitten, gør det stort set alt – og så her spiser det alle de andre underdomæner i diagrammet.

lad os ikke glemme – vi har et par andre programmer, vi ikke har modelleret her. Hvad med alle de gode tredjepartsintegrationer, som virksomheden bruger? Det er også programmelsystemer. Vi tegner dem som blå kasser.

forresten – det, vi har tegnet her, er et kontekstkort – et diagram, der blander forretningsmål og konkrete implementeringer af programmelsystemer. Det er nyttigt til at vurdere lag af landet af dine programmel systemer og visualisere afhængigheder mellem teams.

nu er dette rimeligt og rent, men vi lever i den virkelige verden, og virkelige verdensprogrammer kommer sjældent ud og ser konsistente og sammenhængende ud. Hvis du har bygget din Rails-app efter dens konventioner uden for boksen, mangler din app internt de grupperinger, der er nødvendige for at visualisere din app i dens bestanddele. I virkeligheden ser DeLorean-kodebasen noget mere ud som dette:

pointen er – Rails håndhæver ikke nogen organisatoriske begrænsninger på vores programmelsystemer – hvilket betyder, at logiske forretningsenheder (vores underdomæner), der antyder afkoblede grænseflader – ikke materialiseres i koden, hvilket fører til forvirring og stigende kompleksitet efterhånden som årene går.

den store ide: Organiser Rails-kode i moduler efter forretningsunderdomæne

selvom dine Ruby-klasser i din ansøgning sandsynligvis bor i det globale navneområde, kan de let plukkes i moduler. Vores mål er at skabe logiske grupper af domænekode, der kan isoleres i selvstændige komponenter.

faktisk er et af målene med Domænedrevne Designs at have en en-til-en-kortlægning fra et underdomæne til en afgrænset kontekst.

OK, hvad betyder det? Lad os komme ind på nogle anbefalinger sammen med eksempler.

Inverter mappestrukturer i en flad domæneorienteret gruppering

du kan huske, at følgende Rails-konventioner fører os til mappehierarkier, der grupperer klasser efter roller:

lad os flytte alt ud til en ny mappestruktur: lad os gruppere som funktionalitet efter domæne, i stedet. Vi starter med en første variation, som jeg kalder en flad domæneorienteret gruppering.

modulere klasser

Næste, du ønsker at modulere klasserne fra, hvad de var før. Da Driverklassen falder ind under Ridesharing-domænet, tilføjer vi det til et Ridesharing-modul:

du vil gøre dette for hver klasse, du flytter ind i app/domains flad mappestruktur.

Reference associated models by full class name

derudover skal du ændre dine ActiveRecord-modelforeninger for at henvise til klassen ved dens fulde, modulerede sti:

hold controllere opdaterede om, hvor de kan finde deres nyligt modulerede visninger

du skal også indsætte denne lille smule for at lade ruter fra controlleren vide, hvor de skal kigge efter visningerne:

her er den seje ting: du behøver ikke at flytte al din kode på en gang. Du kan vælge et lille domæne i din ansøgning, det mest modne område af din kode eller det område, som du har den bedste forståelse omkring, og begynde at flytte sine bekymringer til en enkelt domænemappe, alt sammen mens du forlader eksisterende kode i ro, indtil den er klar til at flytte.

nu har vi lavet nogle små skridt til at opnå arkitektonisk klarhed i vores ansøgning. Hvis vi ser nu, har vores modulære mappestrukturer hjulpet os med at gruppere vores kode som sådan:

Under hætten kan vores app se mere sådan ud:

hvad fungerer godt med denne tilgang?

  1. der er mindre støj i hver filmappe – ved at gruppere som filer efter domænespecificitet finder vi et naturligt organisatorisk punkt
  2. de enheder, der forbliver i hver domænemappe, er meget sammenhængende-de har sandsynligvis naturligt en tendens til at kommunikere med hinanden og vises naturligt med hinanden
  3. enheder, der ikke hører sammen, er nu adskilt (løsere koblet)
  4. hvis du har hold, der arbejder langs underdomæneansvar, disse ingeniører kan nu arbejde på en mere strømlinet, isoleret måde. Løsere kobling giver disse hold mulighed for at foretage ændringer med tillid til, at de ikke vil introducere regressioner eller flette konflikter tilbage til kodebasen
  5. scenen er nu sat i det lange løb for at begynde at flytte hver af disse domænemapper til en uafhængig programmeltjeneste (mere om det i et fremtidigt blogindlæg)

hvis du vil have yderligere vejledning i denne mappestruktur, har jeg udviklet en prøveapp, der udviser denne domæneorienterede mappestruktur: http://github.com/andrewhao/delorean. Tag et kig og lad mig vide, hvad du synes.

Hvad har vi lært?

i vores tid sammen lærte vi om domænedrevne designkoncepter omkring domæner og underdomæner. Vi lærte at visualisere vores programmelsystemer som afgrænsede sammenhænge på et kontekstkort, der viste os de områder af systemet, der hører sammen som sammenhængende dele.

slutter på en praktisk note, vi illustreret, hvordan Rails filer og mapper kunne “inverteret” og reimagined som domæne-første grupperinger.

i mit næste indlæg fortsætter vi vores diskussion i et kommende blogindlæg om, hvordan vi yderligere kan afkoble vores domæneorienterede Rails-kode med domænehændelser og til sidst komme ind i mikroservices land.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.