Надвор од boilerplate: Архитектирање API за одржлива еволуција на backend-от
Бекендот ретко станува тежок затоа што една одлука била непромислена. Почесто, станува тежок затоа што многу разумни кратенки тивко се зацврстуваат во архитектура: контролерот директно комуницира со базата на податоци, крајната точка враќа што и да произведе ORM, Docker контејнерот носи продукциска конфигурација, а „привременото“ правило за интеграција станува дел од јавен договор.
Затоа одржливата работа на бекенд не е главно замена на стара рамка или додавање повеќе сервиси. Станува збор за создавање доволно структура за системот да може да се менува без секоја промена да изгледа како хируршка интервенција. API-јата се најважната граница во тој напор. Тие поврзуваат клиенти, бази на податоци, редици, системи од трети страни и идни верзии на производот. Третирајте ги како архитектура, а не како инсталација.
Почнете со договори, не со контролери
API договорот треба да опишува на што потрошувачите можат да се потпрат, независно од тоа како апликацијата моментално ги складира податоците. Ред во база на податоци е детал од имплементацијата. HTTP одговорот е ветување.
Разгледајте крајна точка за клиент. Враќањето необработен модел е практично, но изложува имиња на колони, nullable полиња, временски ознаки и релации што подоцна можеби ќе треба да се променат. Мапер за одговор создава мал, но вреден слој на независност.
final class CustomerResponse
{
public static function from(Customer $customer): array
{
return [
'id' => $customer->id,
'name' => $customer->fullName(),
'email' => $customer->emailAddress(),
];
}
}
Ова не е формалност сама по себе. На тимот му дава намерно место за справување со преименувања, пресметани вредности, правила за приватност и повратна компатибилност. Базата на податоци може да еволуира, додека надворешниот договор останува стабилен.
Истиот принцип важи и за влезот. Валидирајте ги податоците од барањето на работ, а потоа преведете ги во команда или објект на ниво на апликацијата. Не дозволувајте товарот на барањето неконтролирано да поминува низ контролери, сервиси и код за перзистенција.
Вградете ја промената во API-то
Верзионирањето често се дискутира како избор на URL: /v1 или заглавие. URL-то е помалку важно од дисциплината што стои зад него. Верзијата треба да претставува поддржан договор, а не изговор да се дуплира целата апликација секогаш кога ќе се промени едно поле.
Кога е можно, претпочитајте дополнителни промени. Додавањето опционално поле во одговорот обично е полесно за потрошувачите отколку преименување поле или менување на неговото значење. Кога е неопходна промена што ја нарушува компатибилноста, направете ја транзицијата експлицитна:
- Прецизно документирајте го стариот и новиот договор.
- Одржувајте ги двете патеки функционални во договорен период за миграција.
- Следете ја употребата, така што повлекувањето ќе се темели на докази, а не на надеж.
- Отстранете го стариот договор само откако сопственоста на потрошувачите и комуникацијата се јасни.
Одговорите за грешки ја заслужуваат истата грижа како и успешните одговори. Клиентот не треба да мора да анализира HTML страница за грешка, да извлекува значење од нејасна порака или да погодува дали повторното обидување е безбедно. Воспоставете конзистентна структура со код читлив за машина, порака читлива за човек и детали на ниво на поле кога валидацијата не успее.
{
"error": {
"code": "validation_failed",
"message": "The request contains invalid fields.",
"fields": {
"email": ["Must be a valid email address."]
}
}
}
Конзистентноста ја намалува сложеноста за клиентите и ја прави оперативната поддршка далеку помалку двосмислена.
Држете ги деловните правила надвор од транспортот и складирањето
Контролерите треба да ги координираат HTTP аспектите: автентикација, валидација, статус на одговорот и серијализација. Репозиториумите треба да се справуваат со аспектите на перзистенцијата. Ниту едните ниту другите не треба да станат дом на деловната политика.
Практичен среден слој е апликациски сервис или класа за случај на употреба. Таа изразува дејство на јазикот на доменот: креирај нарачка, откажи претплата, одобри поврат на средства. Таа класа може да повикува репозиториуми, да објавува настан или да повикува адаптер за плаќање без API контролерот да биде одговорен за секој детал.
Ова раздвојување се исплаќа кога истата операција подоцна мора да се изврши од worker за редици, задача од командна линија или друго API. Исто така ги прави тестовите пофокусирани. Тест за случај на употреба може да ги провери правилата без конструирање HTTP барање или поврзување со вистинска база на податоци.
Одржливоста не е отсуство на код. Таа е присуство на граници што ја прават следната промена разбирлива.
Нека базата на податоци го спроведува она што е важно
Валидацијата во апликацијата е корисна, но не е замена за ограничувања во базата на податоци. Две истовремени барања можат да ја поминат проверката за единственост на ниво на апликација пред кое било од нив да запише. Уникатниот индекс е конечниот авторитет. Странските клучеви, check ограничувањата каде што се поддржани, соодветната nullability и индексите за реални обрасци на пребарување го штитат системот во услови што само апликацискиот код не може целосно да ги контролира.
Промените во шемата исто така имаат потреба од стратегија за еволуција. Избегнувајте распоредувања што бараат апликацискиот код и промените на шемата да станат видливи во точно истиот момент. Побезбеден образец е прошири, мигрирај, стесни:
- Додадете компатибилен елемент на шемата, како нова nullable колона или табела.
- Распоредете код што може да работи и со старите и со новите претставувања.
- Пополнете ги податоците наназад во контролирани серии ако е потребно.
- Префрлете ги читањата и запишувањата на новото претставување.
- Отстранете ја старата патека само откако повеќе не се користи.
Овој пристап е побавен од една деструктивна миграција, но е многу попростувачки при враќање назад, делумно распоредување и оперативни изненадувања.
Користете Docker за средините да бидат едноставни
Контејнерите се корисни кога го намалуваат разидувањето меѓу средините, а не кога го прикриваат. PHP сликата на апликацијата треба да ги содржи runtime-от и кодот што ѝ се потребни; конфигурацијата како акредитиви, надворешни URL-адреси и знаменца специфични за средината треба да се доставува при извршување. Чувајте ги зависностите за локален развој експлицитни, вклучувајќи ги базата на податоци, кешот и сервисите за редици што апликацијата навистина ги користи.
Добриот работен тек со контејнери, исто така, разликува грижи при градење и при извршување. Изградете непроменлива слика еднаш, а потоа промовирајте ја истата слика низ средини со различна конфигурација. Ако продукцијата бара повторно градење затоа што се променила вредност на конфигурацијата, моделот на испорака носи премногу знаење за средината во артефактот.
Проверките на здравје треба да проверуваат значајна подготвеност, а не само дали постои процес. PHP процесот може да е активен додека поврзувањето со базата на податоци, миграциите или потребните зависности се недостапни. Во исто време, избегнувајте секоја здравствена крајна точка да извршува скапи далечински проверки; изберете проверки што одговараат на намената на платформата за распоредување.
Мерете пред да оптимизирате
Работата на перформанси почнува со прашање: каде всушност се троши времето? Бавните одговори може да доаѓаат од неиндексирано барање, прекумерна серијализација, далечинска зависност, повторени промашувања во кешот или заостанување во редица. „Оптимизирањето на PHP“ пред да се идентификува тесното грло често е само прераспоредување на сложеноста.
За крајни точки со голем товар од базата на податоци, проверете ги бројот на барања и плановите на барањата, а потоа намалете ја непотребната работа. Вообичаени подобрувања вклучуваат избирање само на потребните колони, избегнување случајни барања по запис, додавање индекс што одговара на реален филтер или join и страницирање на ограничени колекции. Кеширањето може да помогне, но додава одлуки за инвалидирање и конзистентност. Кеширајте стабилни податоци што се скапи за пресметување со јасна стратегија за сопственост и истекување; не го користете за да прикриете суштински неефикасен образец за пристап.
Градете системи што можат мирно да се менуваат
Најдобрата бекенд архитектура ретко е најразработената. Таа е онаа чии договори се јасни, чиј интегритет на податоците има вистинско спроведување, чии чекори на распоредување толерираат промени и чии одлуки за перформанси се информирани од набљудување.
Надвор од котли и шаблонски код, одржливото инженерство е навика на зачувување опции. Секоја експлицитна граница, компатибилна миграција, предвидлив одговор за грешка и мерлива операција ја прави следната функционалност помалку ризична. Така бекендот расте без да стане нешто што тимот се плаши да го допре.