ИТ развој

Pragmatic PHP: Build APIs That Scale Without the Boilerplate

Прагматичен PHP: Изградете API-ја што се скалираат без шаблонскиот код

Скалирањето на API ретко е попречено од самиот PHP. Почесто, тоа е попречено од апликација што секое барање го претворила во долг синџир на скриена работа: вчитување премногу податоци, извршување пребарувања во циклуси, поврзување на HTTP-грижите со деловните правила и третирање на распоредувањето како посебен проблем за подоцна.

Прагматичниот PHP е за спротивставување на тоа постепено отстапување. Тоа не значи избегнување структура. Тоа значи избирање структура што се исплаќа сама по себе: јасни граници, предвидлив пристап до податоци, воочливи неуспеси и извршувачка околина што се однесува исто на лаптоп и во продукција.

Започнете со мала, експлицитна патека на барањето

API-крајната точка треба лесно да се следи од рутата до одговорот. Корисна основа е да се одделат транспортот, апликациската логика и инфраструктурата без да се создава класа за секоја линија код.

Контролерот треба да го валидира барањето и да го обликува одговорот. Сервис или акција треба да го изрази случајот на употреба. Репозиториум или објект за пребарување треба да ги поседува деталите за перзистенцијата. Ова спречува објектите специфични за рамката да навлезат во јадрото на апликацијата.

final class CreateOrderAction
{
    public function __construct(
        private OrderRepository $orders,
        private TransactionManager $transactions
    ) {
    }

    public function execute(CreateOrder $command): Order
    {
        return $this->transactions->run(function () use ($command) {
            $order = Order::create(
                customerId: $command->customerId,
                items: $command->items
            );

            $this->orders->save($order);

            return $order;
        });
    }
}

Ова не е архитектура заради самата архитектура. Акцијата ја прави работната единица очигледна. Им дава фокусирана цел на тестовите и го прави сопствеништвото над трансакцијата експлицитно. Контролерот може да ги претвори неуспесите при валидацијата во одговор за клиентот без да одлучува како се перзистираат нарачките.

Направете ја работата со базата на податоци видлива

Повеќето проблеми со перформансите на API се проблеми со базата на податоци маскирани како проблеми на апликацискиот слој. Брза крајна точка не е онаа што користи умна синтакса; туку онаа што од базата на податоци ги бара точните податоци во ограничен број операции.

Внимавајте на класичниот образец N+1. Преземањето страница со нарачки, а потоа вчитувањето клиент или ставки од нарачката за секоја нарачка, може да изгледа безопасно во локален развој. Под оптоварување, тоа станува мултипликатор на пребарувања. Користете нетрпеливо вчитување, спојувања или наменско пребарување за читање кога на одговорот му се потребни поврзани податоци.

Пагинацијата заслужува иста дисциплина. Пагинацијата со отстапување е позната, но големите отстапувања може да станат скапи и неконзистентни додека редовите се менуваат. Кога клиентите природно се движат напред низ стабилно подредување, пагинацијата со курсор често е подобар избор. Користете детерминистички клуч за сортирање, вклучете разрешувач на изедначувања како ID и кодирајте само состојба што му е потребна на следното барање.

  • Индексирајте ги колоните што се користат за филтрирање, спојување и подредување врз основа на реалните обрасци на пребарување.
  • Изберете ги само полињата што ѝ се потребни на крајната точка; избегнувајте стандардно да вчитувате цел запис.
  • Поставете разумни ограничувања за големината на страницата, за едно барање случајно да не стане масовен извоз.
  • Проверувајте ги плановите за пребарување кога пребарувањето ја менува формата или станува тесно грло во продукција.

Трансакциите треба да бидат кратки. Не држете трансакција на база на податоци отворена додека повикувате друга услуга, испраќате е-пошта или генерирате извештај. Прво перзистирајте ја промената на состојбата, а потоа предајте ја дополнителната работа преку сигурен механизам соодветен на гаранциите за испорака на системот.

Дизајнирајте API за промени, не само за првиот клиент

HTTP API-јата брзо стануваат договори. Доследноста е повредна од паметно име за крајна точка. Изберете конвенции за именување ресурси, товари на грешки, пагинација, временски ознаки и идентификатори, па применувајте ги насекаде.

Грешките при валидација треба да им помогнат на клиентите да го поправат барањето. Одговорите за конфликт треба да соопштат вистински конфликт на состојба, а не да прикриваат неочекуван исклучок. Грешките на серверот треба да се евидентираат со доволно контекст за барањето за да може да се истражат, додека клиентот добива безбедна, стабилна порака.

Идемпотентноста е важна секогаш кога клиентите може повторно да се обидат со запишувања. Мрежите откажуваат, балансерите на оптоварување истекуваат и корисниците двапати испраќаат формулари. За операција како создавање плаќање или обезбедување сметка, клучот за идемпотентност му овозможува на серверот да препознае повторено барање и да го врати резултатот од првичната операција наместо да ја изврши двапати. Чувајте го клучот со релевантниот идентитет на барањето и резултатот и дефинирајте колку долго останува валиден.

Верзионирањето треба да биде намерно, но не треба да биде првиот одговор на секоја промена. Додавајте опционални полиња кога клиентите можат безбедно да ги игнорираат. Воведете нова крајна точка кога семантиката навистина се разликува. Резервирајте нова верзија за промени што постојните клиенти не можат безбедно да ги интерпретираат.

Користете Docker за да ги отстраните изненадувањата од околината

Контејнерите се најкорисни кога ги намалуваат разликите меѓу развојот, тестирањето и распоредувањето. Сликата на PHP-апликацијата треба да ги содржи потребните PHP-екстензии, апликацискиот код и предвидлива команда за стартување. Конфигурацијата што се разликува по околина треба да доаѓа од променливи на околината или управувана конфигурација, а не од уредени слики.

FROM php:8.3-fpm-alpine

WORKDIR /app

COPY composer.json composer.lock ./
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
    && php composer-setup.php --install-dir=/usr/local/bin --filename=composer \
    && rm composer-setup.php \
    && composer install --no-dev --prefer-dist --no-interaction

COPY . .

CMD ["php-fpm"]

Точната стратегија за слики ќе варира според платформата за распоредување, но принципот останува: изградете еднаш, конфигурирајте при извршување и одржувајте ја сликата репродуцибилна. Во практика, на продукциските слики им требаат и корисник за извршување што не е root, соодветни дозволи за датотеки и процесен модел што одговара на веб-серверот или платформата пред PHP-FPM.

Кеширајте внимателно и мерете пред да славите

Кеширањето може да направи доброто API да биде поевтино и побрзо. Може и да направи збунувачко API потешко за дебагирање. Започнете со податоци што се скапи за пресметување, често се читаат и безбедно може да се послужат малку застарени. Дефинирајте ги клучот за кеш, истекувањето, патеката за поништување и однесувањето при неуспех пред да го додадете.

Кешот не треба да стане единственото место каде што барањето може да успее. Ако не е достапен, апликацијата треба или безбедно да се врати на изворот на вистината или јасно да откаже кога свежината е суштинска. Избегнувајте кеширање грешки освен ако таквото однесување е намерно и краткотрајно.

Мерете ја латентноста на крајните точки, стапките на грешки, времето на базата на податоци, длабочината на редицата каде што е релевантно и заситеноста на ресурсите. Дневниците треба да вклучуваат идентификатор на барање или корелација. Метриките ви кажуваат дека постои проблем; траги и структурирани дневници помагаат да се објасни која зависност или патека на код го предизвикала.

Одржувајте ја кодната база лесна за менување

Одржливоста е карактеристика за перформанси за тимовите. Малите методи, директните имиња и тестовите околу важното однесување го прават побезбедно подобрувањето на API месеци по првичната имплементација. Претпочитајте тестови што ги извршуваат реалните граници каде што веројатно ќе се појават неуспеси: валидација, авторизација, перзистенција, серијализација и интеграција со инфраструктурни адаптери.

Не бркајте апстракција пред повторувањето да открие стабилен концепт. Јасен објект за пребарување обично е подобар од генерички репозиториум што не може да го изрази пребарувањето што навистина ви е потребно. Фокусирана акција обично е подобра од разгранет сервис што поседува неповрзани работни текови.

Здодевната патека често е скалабилната

API-јата се скалираат кога нивното однесување е разбирливо под притисок. Одржувајте ги патеките на барањата експлицитни, ограничете ја работата со базата на податоци, направете ги повторните обиди безбедни, спакувајте ги зависностите за извршување предвидливо и набљудувајте го системот пред да го подесувате. PHP е целосно способен да опслужува захтевни системи кога придружниот инженеринг е дисциплиниран.

Целта не е кодна база што изгледа софистицирано на дијаграм. Тоа е систем што може да се менува, дебагира и управува со доверба. Тоа е видот на скалабилност што трае.

Портрет на автор на блогот

Mihajlo

Јас сум Михајло - развивач поттикнат од љубопитност, дисциплина и постојаната желба да создадам нешто значајно. Споделувам увиди, упатства и бесплатни услуги за да им помогнам на другите да ја поедностават својата работа и да растат во постојано развивачкиот свет на софтверот и вештачката интелигенција.