Mennesker har svært ved at se det store billede af et problem uden at bruge en masse tid og kræfter på det. Det sker især, når man arbejder med store og komplekse applikationer. Hvad er bivirkningerne af mine ændringer? Hvorfor påvirker denne linje her testene af en fjern del af kodebasen? Der findes ikke en perfekt eller komplet løsning, men Shopify har udviklet et værktøj, som sandsynligvis vil hjælpe dig og dit team.
Introduktion
For at kunne tale om Packwerker vi nødt til at introducere et par begreber først.
- Sammenhængskraft: henviser til målet for, hvor meget elementer i et modul eller en klasse hører sammen.
- Kobling: henviser til graden af afhængighed mellem moduler eller klasser.
- Grænser: refererer til barrierer mellem Kode. I dette tilfælde henviser en kodegrænse til forskellige områder inden for den samme kodebase.
- Modularisering: Processen med at opdele et softwaresystem i flere separate moduler, hvor hvert modul fungerer uafhængigt.
Problemer
Som vi ved, Ruby giver ikke en god løsning til at håndhæve kodegrænser. Vi kan specificere synligheden, men alle afhængigheder vil blive indlæst i det globale navnerum. I store eller monolitiske applikationer giver denne mangel på grænser følgende problemer.
- Lav samhørighed,
- Høj kobling,
- Spaghettikode.
I et forsøg på at modularisere Shopifys monolit og håndhæve grænser prøvede de forskellige løsninger uden at opnå de forventede resultater:
- Indstilling af private konstanter,
- Etablering af grænser gennem perler,
- Brug af test til at forhindre associationer på tværs af komponenter,
- Brug af Rubys modulationsperle,
- Oprettelse af mikrotjenester.
Med al den viden, de havde fra tidligere forsøg, besluttede de at skabe deres eget værktøj: Packwerk.
Packwerk
Hvad er Packwerk?
Packwerk er et statisk analyseværktøj, der bruges til at håndhæve grænser mellem grupper af Ruby filer kaldet pakker.
Hvad er en pakke?
A pakke er en mappe, der indeholder automatisk indlæst kode. Shopifys hold opfordrer til at bruge den bedste designpraksis, når man laver pakker.
- Vi bør pakke ting sammen, der har høj funktionalitet samhørighed,
- Pakkerne bør være relativt løst koblet til hinanden.
Typer af grænsetjek
Vi kan håndhæve grænser for privatliv og afhængighed, kontrollere overtrædelser af grænserne og cykliske afhængigheder.
Packwerk i praksis
Der er ikke én bestemt måde at strukturere eller omstrukturere din applikation på, når du opretter pakker. I denne artikel vil vi følge den tilgang, der foreslås af
Stephan Hagemann i Gradvis modularisering til Ruby on Rails.
Vælg et projekt
Du kan oprette en ny projekt eller vælg et af dine projekter. Jeg besluttede at bruge et open source-projekt, der hedder KodeTriage. Det er vigtigt at nævne, at vi har brug for en Rails 6-applikation, da Packwerk bruger Zeitwerk.
Initialiser Packwerk
Først skal vi tilføje gemmen til vores Gemfile på følgende måde perle 'packwerk'
og derefter køre bundt
i konsollen. Så er vi klar til at initialisere perlen ved at køre packwerk init
.
Derefter bemærker vi, at Packwerk genererede tre filer til os:
-
packwerk.yml
-
pakke.yml
-
bøjninger.yml
packwerk.yml er konfigurationsfilen for Packwerk hvor vi blandt andet definerer inkluderede og ekskluderede filer, viser indlæsningsstierne og definerer bøjningsfilen;
pakke.yml er en pakkes konfigurationsfil. I denne fil tilføjer vi konfigurationen for grænserne for vores pakke. Enhver mappe med package.yml vil blive genkendt som en pakke af Packwerk. Sådan er det, Packwerk skabte vores første
pakke, og vi kalder den rod pakke.
bøjninger.yml er der, hvor vi placerer vores egne bøjninger og akronymer, hvis vi bruger dem.
Du kan læse mere om filerne og deres konfiguration i
Packwerk.
Packwerk egenskaber
For at modularisering skal fungere, har vi brug for tre grundlæggende egenskaber: en navngiven beholder, dens indholdog eksplicit afhængigheder på andre containere. Så lad os definere disse egenskaber i Packwerk:
-
Navn: Navnet på en pakke er dens relative sti fra roden af
ansøgning.
-
Indhold: Når vi placerer en package.yml i en mappe, er alle filerne i mappen nu indholdet af pakken.
-
Afhængigheder: Vi kan definere afhængigheder af andre pakker ved at tilføje afhængighedsnøglen til pakke.yml.
En anden fil, der ikke er inkluderet som standard, men som anbefales, er README. Det er vigtigt at give oplysninger om brugen af pakken.
Slutningen på Episode I
Læs mere
GraphQL Ruby. Hvad med performance?
Skinner og andre transportmidler
Rails-udvikling med TMUX, Vim, Fzf + Ripgrep