ИТ развој

Refactor Your APIs for the Next Decade, Not Just Next Quarter

Рефакторирајте ги вашите API-ја за следната деценија, не само за следниот квартал

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

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

Почнете со договорот, не со контролерот

Контролерите често се највидливото место од кое треба да се почне, но ретко се вистинскиот центар на дизајнот. Тие треба да преведат надворешно барање во операција на апликацијата и да го преведат резултатот назад во стабилен одговор. Ако контролерите содржат деловни правила, ORM пребарувања, гранични случаи при авторизација и обликување на одговори, „едноставна“ промена на крајна точка станува ризична бидејќи секоја грижа е поврзана со секоја друга грижа.

Запишете што ветува API-то пред да ги менувате деталите на имплементацијата. Корисен договор одговара на неколку едноставни прашања: на кој ресурс се однесува, кои операции се поддржани, кои полиња ги контролира клиентот, кои полиња се враќаат и кои грешки се значајни за повикувачите?

На пример, рута ориентирана кон база на податоци како POST /order_items ги наведува потрошувачите да размислуваат во рамки на табела. Акција ориентирана кон задача можеби е подобро изразена како POST /orders/{id}/items, каде што услугата ги поседува проверките на залихи, правилата за цени и транзициите на состојби. URL-то не е важниот дел; границата е. Клиентите треба да побараат деловен исход, а не да оркестрираат внатрешна перзистенција.

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

Најбрзиот начин да создадете кршливо API е директно да сереализирате ORM модели. Делува ефикасно сè додека преименување на колона, промена во нормализацијата или нова внатрешна релација не стане јавен настан што ја нарушува компатибилноста. Шемите на базата на податоци ги оптимизираат складирањето и интегритетот. API шемите ги оптимизираат јасноста, компатибилноста и употребливоста за клиентите. Тие се преклопуваат, но не се ист дизајн.

Воведете експлицитни модели за барања и одговори, дури и во мала PHP услуга. Трансформер за одговори, ресурсна класа или наменски DTO го прави мапирањето видливо и проверливо. Исто така, му дава на тимот безбедно место да додаде однесување за компатибилност додека доменот се менува под него.

final class OrderResponse
{
    public static function fromOrder(Order $order): array
    {
        return [
            'id' => (string) $order->id,
            'status' => $order->status->value,
            'total' => [
                'amount' => $order->totalInCents,
                'currency' => $order->currency,
            ],
            'createdAt' => $order->createdAt->format(DATE_ATOM),
        ];
    }
}

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

Правете промени со додавање секогаш кога е можно

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

Верзионирањето може да помогне, но не е замена за дисциплинирана еволуција. Патека како /v2 дава јасна граница за навистина некомпатибилни договори. Таа создава и обврска за одржување: ако верзија еден остане достапна, ѝ требаат сопственост, тестови, документација и план за повлекување. Избегнувајте создавање нови главни верзии за козметички промени во одговорите што можеле да бидат направени со додавање.

Застарувањето бара оперативен план

Едно поле не е застарено само затоа што така пишува во тикет. На клиентите им треба замена, јасен пат за миграција, доволно известување и начин да ја идентификуваат нивната преостаната употреба. Ако API-то има автентикација, логовите и метриките треба да им овозможат на операторите да утврдат кои идентитети на клиенти сè уште повикуваат крајна точка или зависат од стар параметар. Без таа видливост, отстранувањето е нагаѓање.

  • Документирајте ги старото однесување и неговата замена заедно.
  • Вратете го заменското поле или крајна точка пред да најавите отстранување.
  • Следете ја употребата по клиент, рута и релевантна форма на барање.
  • Поставете датум за преглед наместо да го оставите застареното однесување на неодредено време.
  • Отстранете го кодот за компатибилност само откако доказите покажат дека е безбедно.

Ставете ги деловните правила зад апликациски услуги

Рефакторирањето за долговечност обично значи создавање појасни разграничувања. Контролерот не треба да одлучува како се одобрува нарачка; треба да повика апликациска услуга како ApproveOrder. Таа услуга ги координира авторизацијата, валидацијата, доменските правила, перзистенцијата и споредните ефекти. Потоа инфраструктурниот слој имплементира пристап до складишта, објавување во редици или надворешни HTTP повици зад интерфејси што одговараат на потребите на апликацијата.

Ова не е аргумент за сложени апстракции околу секоја класа. Тоа е аргумент за сместување на променливоста таму каде што ѝ е местото. Провајдерите за плаќање, пристапот до базата на податоци, посредниците за пораки и објектите за барања на рамката веројатно ќе се менуваат независно од вашите основни деловни правила. Чувајте ги нивните детали на рабовите.

Придобивката е практична. Доменско правило може да се тестира без подигање веб-сервер или базa на податоци во контејнер. Миграција на база на податоци може да се распореди без истовремено редефинирање на API одговорот. Нов асинхрон работен тек може да се воведе без клиентите да ги загадуваат барањата со детали од имплементацијата.

Дизајнирајте ги патеките на неуспех исто толку внимателно како патеките на успех

Клиентите го градат своето однесување околу грешките исто колку и околу успешните одговори. Предвидливо API разликува невалиден влез, ресурси што недостасуваат, забранети дејства, конфликти и привремени неуспеси. Не треба да пушта во јавноста stack trace-ови, SQL пораки или формати на исклучоци од рамката како случајни договори.

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

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

Рефакторирајте ја и патеката на испорака

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

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

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

Градете за разговорите што ќе ги води вашиот иден тим

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

Изданието во следниот квартал е важно. Но API-то стекнува доверба со години, преку мали промени што остануваат разбирливи и безбедни. Рефакторирајте кон таа доверба: заштитете го договорот, изолирајте ја имплементацијата, набљудувајте ја реалната употреба и нека секоја промена го остави системот полесен за развој отколку што сте го нашле.

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

Mihajlo

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