At bevæge sig væk fra magi - eller: hvorfor jeg ikke længere vil bruge Laravel

Det er tid til en ændring i de værktøjer, jeg bruger. Og jeg fortæller dig hvorfor!

Først og fremmest vil jeg sikre mig, at du kender til mine intentioner. Jeg prøver ikke at kvæle om Laravel eller hvorfor andre rammer kan være bedre.

Denne artikel er meget subjektiv. Jeg giver dig mine tanker og prøver også at få dig til at genoverveje dine rammevalg. Og når du holder fast ved Laravel efter en ny vurdering, er det fint. Jeg har ikke til hensigt at konvertere folk væk fra Laravel til andre rammer eller sprog. Men det er vigtigt at se nærmere på og sørge for, at du ved, hvad du bruger, og hvorfor du bruger det.

Introduktion

Jeg har arbejdet med Laravel i omkring 2 år nu. Jeg nød altid, hvor let det var at centrifugere en applikation og komme i gang på få minutter. Det giver så mange nyttige værktøjer ud af kassen. Konsolkommandoerne understøtter dig i alle aspekter under kodning. De genererer klasser, stilladser til godkendelse og meget mere.

Men jo dybere du går og jo større projekterne bliver, jo mere kompliceret vil udviklingen med Laravel blive. Eller lad mig omformulere det: jo bedre andre værktøjer vil gøre jobbet. Jeg siger ikke engang, at det kun er Laravels skyld. Det skyldes også delvis, at PHP ikke er særlig godt designet.

Lad os nu starte!

Veltalende ORM

Hvis du allerede har arbejdet med Laravel, ved du helt sikkert om Eloquent. Det er ORM'en, der leveres med en standardinstallation. Den leveres med mange pæne funktioner. Men dets design gør din applikation unødvendigt kompleks og forhindrer IDE i at analysere din kode korrekt.

Dette skyldes dels det Active Record ORM- mønster, der bruges, og dels på grund af det faktum, at Eloquent vil redde udvikleren fra at skulle skrive mere kode. For at gøre det lader det udvikleren sætte meget ind i modellen, der ikke hører hjemme der.

Det lyder som gode intentioner, men jeg begyndte ikke at lide dette mere og mere.

Lad os se på et eksempel:

Den første ting du ser er, at der ikke er nogen egenskaber på modellen. Dette virker irrelevant, men for mig gør det en stor forskel. Alt indsprøjtes "magisk" i klassen ved at læse tabel metadata. Selvfølgelig forstår din IDE det ikke uden hjælp. Og du får ingen chance for at navngive dine ejendomme forskelligt fra dine kolonner.

Tjek nu omfangsmetoden. For Laravel-brugere er det ret klart, hvad det gør. Hvis du kalder denne metode, scopes den underliggende SQL-forespørgsel ved at tilføje den givne WHERE-klausul.

Du kan se, det er ikke statisk. Det vil betyde, at denne metode fungerer på et bestemt objekt i klassen. Men i dette tilfælde gør det det ikke . En rækkevidde kaldes på en forespørgselsbygger. Det har intet at gøre med selve modelobjektet. Jeg forklarer det, når du ser, hvordan du normalt kalder disse rækkevidde:

Du kalder en statisk metode, popular()som ingen nogensinde har defineret. Men da Laravel definerer en __call()og __callStatic()metode, bliver den håndteret gennem dem. Disse metoder videresender opkaldet til en forespørgselsbygger.

Dette er ikke kun noget, som din IDE ikke forstår. Det gør refactoring sværere, kan forvirre nye udviklere, og statisk analyse bliver også sværere.

Når du lægger sådanne metoder på din model, overtræder du desuden S for SOLID. Hvis du ikke er bekendt med det, er SOLID et akronym, der står for:

  • S Ingle ansvar Princip
  • O pen / Lukket princip
  • L iskov Substitutionsprincip
  • Jeg understreger segregeringsprincippet
  • D ependency Inversion Princip

Når du bruger Eloquent, har dine modeller flere ansvar. Det indeholder data fra din database, hvilket er, hvad modeller normalt gør, men det har også filtreringslogik, måske sortering og endnu mere i den. Du vil ikke have det.

Globale hjælpere

Laravel leveres med en hel række globale hjælpefunktioner. De virker meget praktiske, og ja, de er praktiske.

Du bliver bare nødt til at vide, at du ofrer din uafhængighed for den håndløshed, og dit globale navneområde bliver forurenet. Det fører sjældent til konflikter, men det bør foretrækkes at undgå det helt.

Lad os se på et par eksempler. Her er en liste over tre hjælpermetoder, som vi har, men ikke har brug for, da der er bedre alternativer:

  • app_path()- hvorfor? Hvis du har brug for stien til appen, skal du spørge app-objektet. Du får det ved at antyde typen.
  • app()- huh? Vi har ikke brug for denne metode. Vi kan indsprøjte appinstansen!
  • collect()- Dette skaber en ny forekomst af klassen Collection. Vi kan bare nye et objekt op af os selv.

Endnu et konkret eksempel:

Vi bruger Laravels globale request()hjælper til at hente POST-dataene og sætte dem i vores model som attributter.

I stedet for at bruge den globale hjælper, kunne vi skrive tip et Requestobjekt som en parameter i controller-metoden. Afsenderen i Laravel ved, hvordan man kan give os det nødvendige objekt. Det kalder vores metode med det, og vi behøver ikke at kalde en hjælper.

Og vi kan tage dette et skridt videre for at afkoble endnu mere. Laravel er PSR-7-kompatibel. Så i stedet for at skrive antydning til anmodningsobjektet, kan du også skrive tip ServerRequestInterface. Det giver dig mulighed for at erstatte hele rammen med alt, hvad der er PSR-7-kompatibelt. Alt i denne metode vil fortsætte med at arbejde. Dette ville mislykkes, hvis du stadig bruger hjælpemetoderne. Den nye ramme kommer ikke med hjælpemetoden, og du bliver derfor nødt til at omskrive den del af din kode.

Du skifter sjældent hele rammen, men der er mennesker, der gør det. Og selvom du måske aldrig skifter, er det stadig vigtigt for interoperabilitet. At være i stand til at indsprøjte afhængigheder og have en kortfattet dataflyt i stedet for at løse og anmode om afhængigheder og data udefra er vejen at gå. Det gør test, refactoring og næsten alt lettere, når du får fat i det.

Jeg var glad, da jeg læste, at med Laravel 5.8 fjernes streng- og array-hjælpere fra kernen og lægges i en separat pakke. Dette er et godt første skridt. Men dokumentationen skal begynde at modvirke brugen af alle hjælperfunktioner.

Facader

Argumenterne fra sidste del spiller også ind her. Facader synes at være et godt værktøj til hurtigt at få adgang til nogle metoder, der ikke rigtig er statiske. Men de binder dig ind i rammen igen. Du bruger dem til manuelt at løse afhængigheder i stedet for at instruere miljøet om at give dem.

Det samme gælder for kompleksiteten ved at føre alt gennem de magiske metoder.

Da vi talte om IDE-support, ved jeg, at nogle af jer måske leder mig til IDE-hjælperpakken fra barryvdh. Det behøver du ikke. Jeg kender allerede denne pakke. Men hvorfor er det endda nødvendigt? Fordi nogle designbeslutninger i Laravel bare ikke er gode. Der er rammer, hvor du ikke har brug for det. Tag f.eks. Symfony. Intet behov for IDE-hjælperfiler, fordi det er godt designet og implementeret.

I stedet for facader kunne vi bruge afhængighedsinjektion igen som vi gjorde i det foregående eksempel. Vi ville have et rigtigt objekt og kunne kalde rigtige metoder på det. Meget bedre.

Jeg vil endnu en gang give dig et eksempel:

Vi kunne let rydde op. Lad os bede Laravel om at indsprøjte a ResponseFactoryog sende os den aktuelle anmodning:

Vi har nu med succes fjernet brugen af ​​facader fra vores controller. Koden ser stadig ren og kompakt ud, hvis ikke endnu bedre end før. Og da vores controllere altid udvider den generelle Controllerklasse, kunne vi tage alt et skridt videre ved at flytte reaktionsfabrikken til den overordnede klasse. Vi har brug for det i alle andre controller klasser alligevel.

Jeg hørte, at nogle mennesker leverer "for mange konstruktorparametre" som et argument mod at injicere alt. Men det er jeg ikke enig i. Det skjuler kun afhængighederne og dermed kompleksiteten i første omgang. Hvis du ikke kan lide at have 10 til 20 argumenter i din konstruktør, har du ret.

Løsningen er dog ikke magisk. At have brug for så mange afhængigheder i en enkelt klasse betyder, at denne klasse sandsynligvis har for mange ansvarsområder. I stedet for at skjule denne kompleksitet, refaktorerer du den klasse. Opdel det i nye, og forbedr din applikationsarkitektur.

Sjov kendsgerning: der er et ægte designmønster kaldet ”facademønster”, introduceret i Gang of Fours bog. Men det har en helt anden betydning. Laravels facader er i det væsentlige statiske servicelokatorer . Navngivningen formidler bare ikke det. Samme navngivning af forskellige ting gør også diskussioner om arkitektur i projekter sværere, fordi den anden part måske forventer noget helt andet bag dette navn.

Konklusion

Lad os slutte. Jeg skriver muligvis snart en opfølgning på, hvilke teknologier jeg foretrækker at bruge i dag. Men for øjeblikket, lad mig opsummere det, vi har lært:

Laravels tilgang til at gøre alt så let som muligt er god. Men det er svært at komme sammen, når dine apps bliver mere avancerede. Jeg foretrækker fantastisk IDE-support, stærkere skrivning, rigtige objekter og god teknik. Jeg går måske endda tilbage til Laravel, når jeg vil skrive en mindre app.

Mange af mine punkter er ikke kun Laravels skyld. Jeg kunne bytte de dele, jeg ikke kan lide, for eksempel ORM. Men i stedet skifter jeg bare værktøjssættet, hvor standardindstillingerne passer bedre til mine behov. Jeg ser ikke noget formål i at bruge en ramme, hvor jeg skal bruge mere tid på at undgå fælder, det sætter til dårlig teknik, end at udvikle min app. Andre rammer og værktøjer leveres med bedre designede standardindstillinger og mindre magi.

Så indtil videre siger jeg farvel til Laravel.

Tak for din tid. Jeg vil sætte pris på en god diskussion i kommentarerne, og jeg er selvfølgelig åben for dine spørgsmål og forslag.

PS: Særlig tak til Marco Pivetta for korrekturlæsning og yderligere input!

Rediger 1. marts 2019:

Siden min artikel blev udgivet på Reddit, har jeg oprettet en Reddit-konto for at besvare et par kommentarer. Min konto er ikke den, artiklen blev sendt fra, men denne: //reddit.com/u/nschoellhorn

Rediger 13. marts, 2019:

Hvis du læser så langt, kan du lige så godt tjekke min Twitter-profil. Tak for din fortsatte interesse for dette emne! Jeg er altid åben for produktive diskussioner, så er du velkommen til at komme i kontakt, enten her eller på Twitter.