Kodeafhængigheder er djævelen.

"Forandring er den eneste konstante ..." - Heraclitus (filosof)

De værktøjer, biblioteker og rammer, vi bruger til at opbygge vores webapplikationer i dag, adskiller sig drastisk fra dem, vi brugte for kun få år siden.

Om få korte år fra nu vil de fleste af disse teknologier have ændret sig dramatisk igen. Alligevel gør mange af os disse til en central, uløselig del af vores apps.

Vi importerer, bruger og arver fra månedens smag-rammer, som om de alle vil være omkring og uændrede for evigt. Nå ... det er de ikke. Og det er et problem.

Efter mere end 20 års udvikling, design og arkitektur af webapplikationer er jeg blevet værdsat to vigtige sandheder:

  1. Eksterne afhængigheder udgør en stor trussel mod den langsigtede stabilitet og levedygtighed af enhver applikation.
  2. Det bliver stadig vanskeligere - om ikke umuligt - at opbygge nogen form for ikke-triviel app uden at udnytte eksterne afhængigheder.

Denne artikel handler om at forene disse to sandheder, så vores apps har størst chance for langvarig overlevelse.

Kaninhullet er meget dybt.

Hvis vi begynder at tænke på alle de ting, vores webapps afhænger af, er det let at tænke på et dusin eller flere, før vi overhovedet kommer til koden:

  • Strøm
  • Forbindelse
  • Firewall
  • DNS
  • Serverhardware (CPU, disk, ram, ...)
  • Køling
  • Virtualiseringsplatform
  • Containerplatform
  • Operativ system
  • Webserverplatform
  • App Server Platform
  • Webbrowser

Som udviklere er det godt at være opmærksom på disse ting, men der er ofte ikke meget, vi kan gøre ved dem. Så lad os ignorere dem for nu og kun tale om koden.

I kode er der tre slags afhængigheder:

1. Afhængigheder, vi kontrollerer

Dette er kode skrevet og ejet af os eller vores organisation.

2. Afhængigheder, som vi ikke kontrollerer

Dette er kode skrevet af en tredjepartsleverandør eller open source softwarefællesskab.

3. Afhængigheder, når de er fjernet

Dette er de kodeafhængigheder, vores tredjeparts kodeafhængigheder afhænger af. (Sig det tre gange hurtigt!)

Vi vil primært tale om afhængigheder, som vi ikke kontrollerer .

Afhængigheder, vi kontrollerer, og afhængigheder, når de først er fjernet, kan stadig forårsage hovedpine, men i tilfælde af afhængigheder, vi kontrollerer, skal vi være i stand til at gribe direkte ind og afbøde eventuelle problemer.

I tilfælde af afhængigheder, når de først er fjernet, kan vi normalt stole på, at en tredjepart tager sig af det for os, da de også er afhængige af disse.

Hvorfor kodeafhængighed fra tredjepart er god

En stor del af din webapplikation eksisterer for at løse almindelige problemer: godkendelse, autorisation, dataadgang, fejlhåndtering, navigation, logning, kryptering, visning af en liste over emner, validering af formindgange osv.

Uanset hvilken teknologiestak du bruger, er der en god chance for, at der findes fælles løsninger på disse problemer og er tilgængelige som biblioteker, som du nemt kan erhverve og plug-in på din codebase. At skrive noget af dette helt fra bunden er generelt spild af tid.

Du vil koncentrere dig om kode, der enten løser et usædvanligt problem eller løser et almindeligt problem på en usædvanlig måde. Det er det, der gør din applikation værdifuld: koden, der implementerer de forretningsregler, der er unikke for din app alene - den "hemmelige sauce".

Googles søgning og siderangeringsalgoritme, Facebooks tidslinjefiltrering, Netflix's "anbefales til dig" sektion og datakomprimeringsalgoritmer - koden bag alle disse funktioner er "hemmelig sauce".

Tredjepartskode - i form af biblioteker - giver dig mulighed for hurtigt at implementere disse kommodiserede funktioner i din app, så du kan holde fokus på din "hemmelige sauce".

Hvorfor kodeafhængighed fra tredjepart er dårlig

Se på enhver ikke-triviel webapp, der er bygget i de sidste par år, og du vil blive helt forbløffet over den mængde kode, der faktisk kommer fra et tredjepartsbibliotek. Hvad hvis et eller flere af disse tredjepartsbiblioteker ændrer sig drastisk eller forsvinder eller går i stykker?

Hvis det er open source, kan du måske rette det selv. Men hvor godt forstår du al koden i det bibliotek, du ikke ejer? En stor grund til, at du i første omgang bruger et bibliotek, er at få fordelene ved koden uden at skulle bekymre dig om alle detaljerne. Men nu sidder du fast. Du har helt bundet din formue til disse afhængigheder, som du ikke ejer og ikke kontrollerer.

Måske tror du, jeg overdriver eller taler ud fra et rent akademisk synspunkt. Lad mig forsikre dig - jeg har snesevis af eksempler på klienter, der fuldstændigt snooker sig ved at indlejre tredjepartskode for tæt i deres app. Her er blot et nylig eksempel ...

En tidligere klient af mig byggede deres app ved hjælp af en Backend-as-a-Service-udbyder, der ejes af Facebook, kaldet Parse. De brugte et JavaScript-klientbibliotek leveret af Parse til at forbruge Parse-tjenesten. I processen koblede de tæt alle deres kode - inklusive den "hemmelige sauce" -kode - til dette bibliotek.

Tre måneder efter min kundes oprindelige produktlancering - ligesom de begyndte at få en god trækkraft med rigtige betalende kunder - meddelte Parse, at den lukkede ned.

Nu i stedet for at fokusere på at gentage deres produkt og udvide deres kundebase, måtte min klient finde ud af, hvordan jeg enten kunne migrere til en selvhostet open source-version af Parse eller erstatte Parse helt.

Forstyrrelsen, som dette forårsagede for en ung, ny applikation, var så enorm, at min klient til sidst skrottede appen helt.

At balancere det gode og det dårlige

For flere år siden var min løsning til at overvinde risiciene, mens jeg bevarede fordelene ved tredjepartsbiblioteker, at pakke dem ind ved hjælp af adaptermønsteret.

I det væsentlige pakker du tredjepartskoden ind i en adapterklasse eller et modul, du har skrevet. Dette fungerer derefter for at udsætte funktionerne i tredjepartsbibliotekerne på en måde, som du kontrollerer.

Hvis du bruger dette mønster, hvis et tredjepartsbibliotek eller en ramme ændres eller forsvinder, er du kun nødt til at rette lidt adapterkode. Resten af ​​din app forbliver intakt.

Dette lyder godt på papir. Når du har selvstændige afhængigheder, der kun giver nogle få funktioner, vil dette gøre tricket. Men ting kan blive grimme hurtigt.

Kan du forestille dig at skulle pakke hele React-biblioteket (inklusive JSX), før du bruger noget af det? Hvad med indpakning af jQuery eller Angular eller Spring-rammen i Java? Dette bliver hurtigt et mareridt.

I disse dage anbefaler jeg en mere nuanceret tilgang ...

For hver afhængighed, du vil føje til din codebase, skal du evaluere det risikoniveau, det vil indføre ved at gange to faktorer:

  1. Sandsynligheden for, at afhængigheden ændres på en materiel måde.
  2. Mængden af ​​skade, som en væsentlig ændring af afhængigheden vil gøre for din ansøgning.

Et tredjepartsbibliotek eller en ramme er mindre tilbøjelige til at ændre sig, når nogle af eller alle følgende ting er rigtige:

  • Det har eksisteret i flere år og har haft flere store udgivelser.
  • Det er meget brugt af mange kommercielle applikationer.
  • Det har aktiv støtte fra en stor organisation - helst et firma eller en institution med husstandsnavne.

Et tredjepartsbibliotek eller en ramme vil skade din applikation mindre, når nogle af eller alle følgende ting er rigtige:

  • Det bruges kun af en lille del af din applikation, snarere end at blive brugt i hele.
  • Koden, der afhænger af den, er ikke en del af den “hemmelige sauce”, jeg talte om tidligere.
  • Fjernelse af det kræver minimale ændringer af din codebase.
  • Hele din applikation er meget lille og kan omskrives hurtigt. (Vær forsigtig med denne - det er sjældent rigtigt meget længe).

Jo mere risikabelt noget er, jo mere sandsynligt bør du være at pakke det ind eller undgå det helt.

Når det kommer til koden, der virkelig er central for værdiforslaget til din applikation - din "hemmelige sauce" - skal du være yderst beskyttende over for den. Gør denne kode så uafhængig som muligt. Hvis du absolut har brug for en afhængighed, skal du overveje at injicere den i stedet for direkte at henvise til den. Selv da skal du være forsigtig.

Nogle gange betyder det at sige "nej" til et tredjepartsbibliotek, som du synes er virkelig sejt, eller som du virkelig vil bruge af en eller anden grund. Vær stærk. Tro mig, det vil betale sig. Bare spørg alle de mennesker, der investerede meget i den allerførste udgivelse af Angular, eller min tidligere klient, der brugte Parse overalt. Det er ikke sjovt. Tro mig.

Apropos sjov, se på dette ...

Billedet ovenfor er afhængighedsgrafen for et program kaldet TinyTag Explorer.

At generere en afhængighedsgraf for dine eksisterende apps er en fantastisk måde at forstå det risikoniveau, der introduceres af dine afhængigheder. Jeg har sammensat en liste over gratis værktøjer til at generere grafer svarende til ovenstående på en række sprog, herunder JavaScript, C #, Java, PHP og Python. Du kan få det her.

Hjælp mig med at hjælpe andre

Jeg vil hjælpe så mange udviklere som muligt ved at dele min viden og erfaring med dem. Hjælp mig venligst ved at klikke på knappen ❤ anbefale (grønt hjerte) nedenfor.

Endelig glem ikke at få fat i din liste over gratis afhængighedsgrafgeneratorer her.