Надвор од кодот: Архитектирање софтвер што ВИ не може само да го копира
ВИ може за неколку секунди да создаде контролер, миграција, Dockerfile и тест со уверлив изглед. Тоа менува колку брзо тимовите можат да генерираат код. Не ја отстранува потешката работа: да се одлучи што треба да значи кодот кога ќе пристигнат вистински корисници, несовршени податоци, прекини и идни промени.
Софтверот што вреди да се изгради ретко се издвојува поради паметна синтакса. Се издвојува поради одлуките околу синтаксата: каде живее деловното правило, кои неуспеси се прифатливи, како се развиваат податоците, што ветува API и како системот останува разбирлив шест месеци по првото издание.
Тоа се деловите што ВИ не може едноставно да ги копира од промпт. Тие бараат архитектура обликувана од контекстот.
Кодот е моментална состојба; архитектурата е збир на одлуки
Генерирана функција може да изгледа исправно, а притоа тивко да ги нарушува границите на системот. Разгледајте крајна точка што создава нарачка. Директната имплементација може да го валидира влезот, да внесе редови, да наплати преку давател на плаќања и да испрати е-пошта во едно барање.
Работи во демо со среќна патека. Во продукција, трансакцијата во базата на податоци може да успее додека барањето за плаќање истекува. Повторувањето на HTTP-барањето може двапати да му наплати на клиентот. Испраќањето е-пошта пред трансакцијата да се потврди може да извести некого за нарачка што не постои.
Архитектонското прашање не е „можеме ли да ја напишеме оваа крајна точка?“ Туку: „што мора да остане точно ако кој било поединечен чекор не успее?“
Поиздржлив дизајн ги раздвојува одговорностите. Зачувајте ја нарачката и outbox-настанот во една трансакција во базата на податоци. Обработете го настанот асинхроно. Направете ја операцијата за плаќање идемпотентна со стабилен клуч изведен од нарачката. Запишете го нејзиниот исход пред да активирате последователни ефекти.
DB::transaction(function () use ($command) {
$order = Order::create([
'customer_id' => $command->customerId,
'status' => 'pending_payment',
'total_cents' => $command->totalCents,
]);
OutboxEvent::create([
'type' => 'order.payment_requested',
'payload' => ['order_id' => $order->id],
]);
});
Ова не е архитектура заради самата архитектура. Тоа е намерен одговор на неуспех, дуплирање и опоравување. ВИ може да помогне во изработката на деловите, но тимот сепак мора да ги избере гаранциите што му се потребни.
Направете ги границите видливи
Многу backend-апликации стануваат тешки не затоа што се големи, туку затоа што секој слој знае премногу. Контролерите директно повикуваат ORM-модели. Моделите содржат логика за валидација, авторизација, цени и е-пошта. Позадинските задачи ги повторуваат правилата од веб-барањата. Тогаш мала промена бара погодување која копија од правилото е меродавна.
Корисна граница е онаа што штити концепт кој веројатно ќе се промени. На пример, политиката за попусти не треба да биде расфрлана низ контролери, задачи за наплата и SQL-прашања. Дајте ѝ јасно место зад интерфејс или апликациска услуга.
final class PriceOrder
{
public function __construct(
private DiscountPolicy $discounts,
private TaxCalculator $taxes,
) {}
public function calculate(Cart $cart, Customer $customer): Price
{
$subtotal = $cart->subtotal();
$discount = $this->discounts->for($cart, $customer);
$tax = $this->taxes->for($cart, $customer, $subtotal - $discount);
return new Price($subtotal, $discount, $tax);
}
}
Целта не е секоја апликација да се присили во разработени слоеви. За мала внатрешна алатка можеби е подобар едноставен, директен код. Поентата е да се препознае каде променливите правила, надворешните зависности и важните инваријанти заслужуваат јасна точка на раздвојување.
Дизајнирајте API-ја за двосмисленост, не само за успех
API-договорот е ветување дадено под притисок. Клиентите ќе повторуваат барања, ќе испраќаат застарени податоци, ќе изоставуваат незадолжителни полиња и ќе зависат од случајно однесување ако тоа остане достапно доволно долго.
Затоа добриот API-дизајн дефинира повеќе од успешен одговор. Тој дефинира идентитет, валидација, конкурентност и грешки. Ако клиентот може безбедно да повтори барање за создавање, документирајте или имплементирајте идемпотентност. Ако ажурирањето може да ја презапише измената на друг корисник, користете поле за верзија, условно барање или друга експлицитна стратегија за конкурентност.
- Користете стабилни идентификатори на ресурси наместо, каде што е можно, да изложувате случајни детали од базата на податоци.
- Враќајте грешки во конзистентна форма што клиентите можат сигурно да ја анализираат.
- Валидирајте на влезната граница, но наметнете критични инваријанти и во доменот или базата на податоци.
- Третирајте ги пагинацијата, сортирањето и филтрирањето како дел од договорот, а не како дополнителна мисла.
- Верзионирајте намерно кога го менувате значењето, а не само затоа што крајната точка изгледа стара.
Ограничувањата во базата на податоци се особено вредни тука. Валидацијата во апликацијата ја подобрува повратната информација; уникатните индекси, надворешните клучеви и проверките ја штитат вистината кога друг процес, скрипта или иден кодов пат ќе ја заобиколи таа валидација.
Моделирањето податоци е дизајн на производ во забавена снимка
Изборите за шемата имаат долг век. Колона наречена status изгледа безопасно сè додека не треба да претставува причини за откажување, состојба на плаќање, состојба на исполнување и историски премини. JSON-блокот изгледа флексибилен сè додека не станат важни известувањето, индексирањето и правилата за интегритет.
Моделирајте ги прашањата на кои бизнисот мора да одговори. Ако адресата за испорака на нарачката мора да остане историски точна откако клиентот ќе го уреди својот профил, направете нејзина снимка во нарачката. Ако се вклучени пари, зачувувајте цели помали единици и валута заедно, наместо да се потпирате на вредности со подвижна запирка. Ако бришењето има правни или оперативни последици, дефинирајте го однесувањето за задржување и враќање пред да додадете лежерна колона deleted_at.
Ниту еден од овие избори не е универзално точен. Нивната вредност доаѓа од тоа што компромисот се прави експлицитен додека промената сè уште е евтина.
Оперативната едноставност е функционалност
Docker може да ги направи развојните средини повторливи, но контејнерот не е оперативна стратегија. Продукцискиот софтвер има потреба од набљудливо однесување: структурирани логови, значајни проверки на здравјето, метрики што одразуваат работа со влијание врз корисниците и предупредувања поврзани со услови што можат да се преземат.
Претпочитајте распоредување за кое може разумно да се размислува. Конфигурацијата треба да доаѓа од околината или од управуван механизам за тајни, никогаш од слика во која се вградени акредитиви. Миграциите на базата на податоци треба да бидат компатибилни и со старата и со новата верзија на апликацијата за време на пуштањето. Позадинските работници треба чисто да се исклучуваат за распоредувањето да не напушти задача на половина пат.
Перформансите го следат истиот принцип. Почнете со мерење и со патеката на барањето што корисниците навистина ја чувствуваат. Додајте го соодветниот индекс откако ќе го испитате образецот на прашањето. Кеширајте податоци со експлицитна приказна за поништување или истекување. Ставете во редица работа што не мора да го блокира одговорот. Избегнувајте побрз бенчмарк да го третирате како доказ дека системот е побезбеден или полесен за ракување.
Користете ВИ како потпора, не како архитект
ВИ е одлична во намалување на триењето: објаснување непознат код, изработка на нацрти за тестови, предлагање рефакторирања, преведување меѓу рамки и создавање прва верзија на повторлива интеграциска работа. Нејзиниот излез станува вреден кога развивачот ги обезбедува ограничувањата што таа не може да ги заклучи.
Пред да прифатите генериран код, поставете неколку прашања на ниво на сениор: Што се случува при повторување? Кои премини на состојби се дозволени? Дали оваа операција е атомска? Може ли две барања да се натпреваруваат? Како се забележува неуспехот? Која претпоставка за зависност или шема е скриена тука? Може ли друг развивач да ја објасни оваа одлука без да ја реконструира од деталите на имплементацијата?
Трајната предност не е да се пишува повеќе код од сите други. Таа е да се градат системи чии важни одлуки остануваат јасни, чии неуспеси се преживливи и чија следна промена има безбедно место каде да се смести. Тоа е работата надвор од кодот — и токму таму инженерското расудување останува незаменливо.