ИТ развој

Stop Chasing Features, Start Architecting for Adaptability

Престанете да бркате функции, почнете да архитектуирате за приспособливост

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

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

Целта не е да се предвиди секое идно барање. Целта е следната разумна промена да биде доволно евтина за добро да се спроведе.

Функционалностите го решаваат денешното барање; архитектурата ги обликува утрешните опции

Функционалноста одговара на конкретно прашање: дали корисниците можат да извезуваат фактури, да закажуваат известување или да пребаруваат производи по категорија? Архитектурата одговара на пошироко прашање: кога тие барања ќе се развиваат, каде припаѓа промената, на што друго може да влијае и колку безбедно тимот може да ја распореди?

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

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

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

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

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

Разгледајте ја испораката на известувања. Ако деловниот код директно повикува библиотека за е-пошта насекаде, подоцнежното додавање SMS или редица станува обемно рефакторирање. Мал договор на ниво на апликација му дава место на механизмот за испорака, без да се преправа дека секој можен канал веќе постои.

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)
        );
    }
}

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

Користете конфигурација за варијации, не за скриена логика

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

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

Дизајнирајте API-ја за еволуција, не само за првиот потрошувач

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

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

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

{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "fields": {
      "email": ["Enter a valid email address."]
    }
  }
}

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

Оставете ја базата на податоци да ја заштити вистината

Апликацискиот код изразува намера, но базата на податоци е конечниот авторитет над складираните податоци. Ограничувањата не се само одбранбени детали; тие ги прават претпоставките применливи низ веб-барања, работници, скрипти и идни патеки на кодот.

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

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

  1. Додадете ја новата структура во форма компатибилна наназад.
  2. Распоредете код што може да ги чита и старите и новите претставувања.
  3. Пополнете ги податоците наназад во контролирани серии.
  4. Префрлете ги запишувањата и читањата откако ќе се потврди новата патека.
  5. Отстранете ја старата структура само откако повеќе нема да биде потребна.

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

Направете го оперативното однесување дел од дизајнот

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

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

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

Изберете јасност без изненадувања наместо шпекулативна флексибилност

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

  • Одржувајте ги модулите кохезивни околу деловна способност.
  • Направете ги надворешните зависности експлицитни и заменливи таму каде што нестабилноста го оправдува тоа.
  • Заштитете ги инваријантите на податоците во базата на податоци, како и во апликацискиот код.
  • Распоредувајте промени на шемата и API преку компатибилни транзиции.
  • Мерете ги перформансите пред да додадете сложеност.
  • Оставете го кодот полесен за навигација отколку што сте го нашле.

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

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

Mihajlo

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