Prestanite loviti značajke, počnite projektirati za prilagodljivost
Rad na značajkama ima zavodljiv ritam. Stigne zahtjev, stvori se tiket, otvori se grana i novi endpoint ili zaslon počinje poprimati oblik. Isporuka se čini produktivnom jer je vidljiva. Ipak, mnogi pozadinski sustavi ne postaju teški zato što im nedostaju značajke. Postaju teški zato što se svaka nova značajka mora boriti s arhitekturom koja joj je prethodila.
Prilagodljivost je svojstvo koje sustavu omogućuje da primi promjenu, a da svako izdanje ne pretvori u rizično iskapanje. To nije apstraktan ideal rezerviran za velike organizacije. Važna je već prvi put kada se promijeni pružatelj plaćanja, klijentu treba malo drukčiji API odgovor, izvještaj počne prekoračivati vrijeme izvršavanja ili „jednostavno” polje baze podataka postane tri polja s različitim pravilima.
Cilj nije predvidjeti svaki budući zahtjev. Cilj je sljedeću razumnu promjenu učiniti dovoljno jeftinom da se može kvalitetno riješiti.
Značajke rješavaju današnji zahtjev; arhitektura oblikuje sutrašnje mogućnosti
Značajka odgovara na konkretno pitanje: mogu li korisnici izvoziti račune, zakazati obavijest ili pretraživati proizvode po kategoriji? Arhitektura odgovara na šire pitanje: kada se ti zahtjevi razviju, kamo promjena pripada, na što još može utjecati i koliko je sigurno tim može isporučiti?
Ta razlika mijenja odluke o implementaciji. Kontroler koji validira ulaz, upitima dohvaća nekoliko tablica, poziva API treće strane, oblikuje odgovor i šalje e-poštu može brzo isporučiti značajku. Također stvara jedno mjesto na kojem se nakupljaju nepovezane odgovornosti. Sljedeći programer mora razumjeti sve njih prije nego što može promijeniti bilo koju od njih.
Umjesto toga, težite granicama koje odražavaju smislenе odgovornosti. U PHP aplikaciji to može značiti zadržavanje HTTP aspekata u kontrolerima, poslovnih odluka u aplikacijskim servisima ili klasama usmjerenima na domenu, perzistencije iza repozitorija ili objekata upita gdje je to korisno te vanjskih integracija iza namjenskih klijenata.
Nemojte to pretvoriti u ritual stvaranja sučelja za svaku klasu. Poanta nije maksimalna apstrakcija. Poanta je izolirati promjenjivost: dijelove koji će se najvjerojatnije mijenjati neovisno.
Pronađite spojeve na kojima je promjena najvjerojatnija
Neke su ovisnosti inherentno nestabilne. Vanjski API-ji, kanali isporuke, pravila određivanja cijena, upiti za izvještavanje i formati uvoza podataka obično se mijenjaju češće od temeljnih koncepata poput narudžbe ili računa. Oni su dobri kandidati za eksplicitne spojeve.
Razmotrite isporuku obavijesti. Ako poslovni kod posvuda izravno poziva biblioteku za e-poštu, kasnije dodavanje SMS-a ili reda čekanja postaje opsežan refaktor. Mali ugovor na razini aplikacije daje mehanizmu isporuke svoje mjesto bez pretvaranja da svaki mogući kanal već postoji.
interface NotificationSender
{
public function send(Notification $notification): void;
}
final class OrderShippedService
{
public function __construct(
private NotificationSender $notifications
) {
}
public function notifyCustomer(Order $order): void
{
$this->notifications->send(
Notification::orderShipped($order)
);
}
}
Korisna granica nije samo sučelje. Ona je u tome što logika isporuke narudžbe sada ovisi o namjeri obavještavanja, a ne o određenom transportu. Implementacija e-pošte može se zamijeniti, staviti u red čekanja, ponovno pokušati ili dopuniti bez ponovnog pisanja poslovne odluke.
Koristite konfiguraciju za varijacije, a ne za skrivenu logiku
Konfiguracija je još jedan čest izvor slučajne složenosti. Varijable okruženja izvrsne su za vrijednosti specifične za implementaciju, poput vjerodajnica baze podataka, naziva hostova i krajnjih točaka servisa. Loša su zamjena za poslovna pravila.
Ako značajka ovisi o nekoliko kombinacija zastavica, varijabli okruženja i uvjetnih grana, sustav može biti konfigurabilan, ali ne i razumljiv. Trajne poslovne odluke stavite u kod s testovima. Konfiguraciju tijekom izvođenja održavajte uskom, eksplicitnom i validiranom pri pokretanju.
Dizajnirajte API-je za razvoj, a ne samo za prvog korisnika
API odgovor je ugovor, bilo da ga koristi mobilna aplikacija, drugi servis ili partner. Najbrži način za stvaranje budućih poteškoća jest izložiti sadržaje oblikovane prema bazi podataka i dopustiti korisnicima da se oslanjaju na svako polje.
Dajte prednost reprezentacijama usmjerenima na resurse koje izražavaju ono što korisnici trebaju. Kada je moguće, dodajte polja kompatibilno, izbjegavajte mijenjanje značenja ili tipa postojećih polja i budite promišljeni prije uklanjanja bilo čega. Kada je prijelomna promjena nužna, omogućite put migracije umjesto da tiho promijenite ponašanje pod postojećom rutom.
Odgovori o pogreškama zaslužuju istu disciplinu. Stabilna struktura pomaže korisnicima izgraditi predvidljivo rukovanje:
{
"error": {
"code": "validation_failed",
"message": "One or more fields are invalid.",
"fields": {
"email": ["Enter a valid email address."]
}
}
}
Točna shema manje je važna od dosljednosti. Klijent ne bi trebao trebati prilagođenu logiku raščlanjivanja za svaki endpoint niti zaključivati operativne pojedinosti iz poruka iznimki.
Neka baza podataka štiti istinu
Aplikacijski kod izražava namjeru, ali baza podataka konačni je autoritet nad pohranjenim podacima. Ograničenja nisu samo obrambeni detalji; ona pretpostavke čine provedivima kroz web zahtjeve, radnike, skripte i buduće putanje koda.
Koristite strane ključeve ondje gdje ih podatkovni model zahtijeva, jedinstvena ograničenja za stvarna pravila jedinstvenosti i transakcije za promjene koje moraju zajedno uspjeti ili pasti. Indeksirajte na temelju upita koje sustav stvarno izvršava, posebno filtriranja, spajanja i sortiranja na putanjama s velikim prometom.
Prilagodljivost također znači planirati promjene sheme kao implementacije, a ne kao izolirane migracije. Dodavanje nullable stupca obično je lakše uvesti nego odmah posvuda zahtijevati novu vrijednost. Za veći prijelaz upotrijebite slijed proširenja i kontrakcije:
- Dodajte novu strukturu u obliku kompatibilnom sa starijom verzijom.
- Isporučite kod koji može čitati i stare i nove reprezentacije.
- Popunite podatke u kontroliranim skupinama.
- Prebacite pisanja i čitanja nakon što se dokaže nova putanja.
- Uklonite staru strukturu tek kada više nije potrebna.
Ovaj pristup zahtijeva malo više promišljanja unaprijed, ali izbjegava prisiljavanje koda i podataka da se mijenjaju usklađeno tijekom jednog izdanja visokog rizika.
Neka operativno ponašanje bude dio dizajna
Servis nije prilagodljiv ako radi samo na prijenosnom računalu programera. Docker može pomoći da pretpostavke o izvođenju postanu eksplicitne: PHP ekstenzije, paketi operativnog sustava, konfiguracija web poslužitelja i pokretanje procesa postaju artefakti s verzijama. No spremnik nije automatski sustav spreman za produkciju.
Održavajte slike usmjerenima, omogućite konfiguraciju kroz okruženje i učinite ponašanje zdravlja i neuspjeha vidljivim. Ako je rad asinkron, definirajte što se događa kada zadatak ne uspije: pravila ponovnog pokušaja, idempotentnost, zapisivanje i put za intervenciju. Ponovni pokušaj bez idempotentnosti može privremeni mrežni kvar pretvoriti u dvostruke e-poruke, dvostruka terećenja ili dvostruke zapise.
Performanse slijede isto načelo. Počnite mjerenjem, zatim riješite ograničavajuće usko grlo. ORM upit koji učitava povezane zapise unutar petlje može biti ispravan, ali skup; željno učitavanje, ciljani join ili upit izrađen za određenu svrhu mogu biti pravi odgovor. Predmemoriranje može pomoći, ali uvodi odluke o poništavanju i dosljednosti. Tretirajte ga kao promišljen arhitektonski kompromis, a ne refleks.
Odaberite dosadnu jasnoću umjesto spekulativne fleksibilnosti
Prilagodljivi sustavi nisu oni s najviše obrazaca. To su oni u kojima programeri mogu prepoznati vlasništvo, testirati važno ponašanje, razumjeti načine neuspjeha i s pouzdanjem provoditi male promjene.
- Održavajte module kohezivnima oko poslovne sposobnosti.
- Učinite vanjske ovisnosti eksplicitnima i zamjenjivima ondje gdje promjenjivost to opravdava.
- Štitite invarijante podataka u bazi podataka kao i u aplikacijskom kodu.
- Isporučujte promjene sheme i API-ja kroz kompatibilne prijelaze.
- Izmjerite performanse prije dodavanja složenosti.
- Ostavite kod lakšim za snalaženje nego što ste ga zatekli.
Sljedeća značajka uvijek će stići. Trajna inženjerska odluka jest hoće li postati još jedna iznimka ugrađena u krhku putanju ili upravljiva promjena u sustavu dizajniranom za kretanje. Prestanite tretirati arhitekturu kao posao koji počinje nakon što su značajke dovršene. U zdravom pozadinskom sustavu arhitektura je način na koji značajke i dalje ostaju moguće.