Галоўная / Артыкулы / Семь пытанняў, якія трэба адпаведзець пры прадзеўстве першай лініі статты

Семь пытанняў, якія трэба адпаведзець пры прадзеўстве першай лініі статты

Спісак пераконтролу перед запускам, який абаратвае рэальную проблему корыстніка, гарантіі завершэння, адпаведнае прыналежнасць правілаў, старыя даны, павторныя спробы і канкуранцію, можлівасць абзярнага стэручання і безпеку распраўкі.

2797 слоў

Спадзейшы спосаб працаваць эфектываў над новым замовленнем — адкрыць рэдагувальнік і пачаць ствараць: дадаць канец-тэп, столбец, компонент. Проблема тая, што першая рэалізацыя тыхамо адпавядае на кожны вопыт, якога ніхто не задаў, а гэтыя адпаведзі прыемліюць форму схэм, кантрактаў API і тэстаў, якія вельмі складна зменіць. У гэтым кяле расказваеца пра сем вопытаў, якія апытныя інжынеры разглядаюць пры пачатку напісання коду, пра тое, што выходзіць з-пад контролу, калі іх ігнараваць, а таксама пра тое, як стварыць справяны падход, каб гэта прышвартавало процес, а не спамячвало яго.

Чаму першая рэалізацыя мае такую важнасць

Калі прыходзіць запит, пачатак з коду робіць абстрактную задачу болейш конкрэтной і меншаею. Аднак адкрытыя пытанні не зникаюць. Хтось усё рава должен адначыць, хто ўладае правілам бізнесу, што означае „завершанне“ для багатоэтапной операцыі, і што будзе з дакументамі, створанымі да змены. Якщо ніхто не адначыць, код адначыць случайна.

Такая случайная адначыць рэдкая час зводзіцца толькі да аднаго месца. Форма першай версіі часта становіцца структурой таблы, форматам адпаведзі, спяльным функцыям, якіе імпортуе кожны, і модэлем стану, ад якога залежыць інтерфейс. Калі іншы код запускае яго, а даныя у працэйнай сіткі паслухаюць яму, змена курсу значыць міграціі, прыемнікі сумеснасці і коордынаваныя выпускі. Працаваць гадзіну над правымі пытаннямі з самага пачатку — гэта дешавае у порэванні.

Ззовні гэта можа выглядаць як ваганне: чытанне існуючых процэсаў работы, запытанні пра тое, чаго на самай справе прагне досягнуць корыстнік, пераканальванне, як паводзяцца старыя даны, обсужванне частковых неудач. На практыцы гэта той самы процес рашэння проблем, які код у будзь-якым случае павінен быў бы выкарыстоваць, толькі ён адбываецца тады, калі яшчэ недарога змяніць свою думку.

1. Аддзельнайце запрошаную функцыю ад падстаўнай проблемы

Часта запиты прыходзяць у вобразе рашэнняў: дадаць кнопку, фільтр, можлівасць экспорту, новы статус. Запит можа быць абсалютна разумным, але ён описвае тое, калі людзі уявляюць сабе стварэнне чаго-то, а не разчароўванне чы ўсуненне бізнесовых наследкав, якія стояць за гэтым.

Вярненне гэтай асновной патрабоўкі зменяе тое, што вы ствараеце. Патрабоўка экспорту у формате CSV можа выйсці ад менеджэраў, якія не можуць парабліковаць недзельныя паказнікі між аддэламі. Экспорт дапамагае, але таксама стварае павтаральную ручную работу з таблічными працэсамі, якую захаваныя атласы чы ўзначальваныя падсумкі моглі б абэцьна усунуць. Патрабоўка ўтварэння яшчо адной значэння статусу можа паказаць, што адна ячэйка вялікім чынам перанасцярожана і выступае адночасна за платеж, затверджэнне чы выполнення. Даданне гэтай значэння закрывае заявку, але робіць модэль дадзеных ўсё больш складнойю для розумення.

Нічога з гэтага не значыць, што трэба дапытвацца пра кожную маленькую патрабоўку чы ператвараць зміну ў адной лініі на роботу над продуктам. Мета — дазнацца достатнько пра ситуацыю пользователя, каб адмаўліцца, чы запроектаваная зміна даскледзе паляпшэння рэзультатаў. Зазвычай дапамагае калькі лаконічных запитанняў:

  • Хто сьогодні не можа завершыць свою работу?
  • Калі яны наразе выконваюць це вручную?
  • Якое рашэнне падтрымае гэтая новая інфармацыя?
  • Што становіцца можлівым, калі такая функцыя ўжо існуе?
  • Якшчы праісці праз гэты крок, інжынеры сама сабою оптымізуяць чыстае запитанне. Кнапка чыстая, компонент можна викорыстоўваць знову, API апрануты, але функцыя все рава разчароўвае, таму што яна рашае запит болей точна, чым проблему. Мета не ў тым, каб адкладзіць напісанне коду; мета — пераканацца, што код ёсць правыя адпаведзь.

    2. З’явіце, што значыць успех для всей операцыі

    Багато вакансыйяў называюць дзеянне, але не вказваюць, калі яно завершыцца. Падача заявкі, аправарэнне запису, копіюванне проекта чы сінхронізацыя дадзэнняў здаюцца простымі, пакуль не будзе калькі крокаў і адны з яных не пастане.

    Неабяжна процедура затверджэння, яка фіксуе змяну, запішвае рэкорд у журнал аудыту, выдае запаведанне і павярамоўляе прасібніка. Якшто запіс выйшаў успешны, а павярамоўленне — ні, чы магчыма сказаць, што затверджэння успелася? Якшо корыстнік пракуе знова, чы можа рэкорд быць затверджаны два разы? Якшо нельга запісаць ентрэю ў журнал аудыту, чы трэба скасаваць змяну статусу? Якшо запаведанне адкладзіцца, чы затверджэння ўжо завершана чы застаецца у процесе? Гэта не дробныя тэхнічныя деталі. Гэтыя пытанні визначаюць, чаго продукт обяцвае своім корыстнікам.

    Корыстны спосаб — прадумаць межы завершэння працы перад тым, як запісваць алгоритм роботы:

    • Эфекты, якія должны выйсці успешнымі чы незусім разам, таму што частковы рэзультат будзе недзейснаваным статусам, паўінацься ў адной транзакцыі.
  • Эфекты, якія ўзнакомны, але второсортныя, такія як пісьмо з прывітанням, не должны вяліць рашэнне пра тое, чы спраўна адбылася галоўная дзеянне. Часта яны належаць да фонавага задання з прабамамі паўтарэння і явным статусам "у паўходзе".
  • Тая ж запытка выступае і ў маленькіх функцыйнасцях. Калі хтось запускае экспорт, чы ён спраўна адбыўся як толькі стварылася файлавая структура і заданне было прийнята, чы пазней з’явіцца лінк? Калі інтэрфейс паказвае "Збержана", чы сервер падтвердзіў стойкасць даных, чы толькі змяніўся локальны стан?

    Якщо залішыць гэта нечыясным, кожны слой стварае свою сабэйную дэфініцыю. Інтэрфейс паказвае успех, хоць бэкенд усё ўжо працуе; адпаведны процес практыкуе спробу зноў, калі корыстнік вось ужо вырашыў, што ёй не паспела; а система монітарынгу фіксуе «здоровы» запит, нават якщо важлівы парадукт знік. Спачатку чыткая фіксацыя гарантый спрыяе спростэнню рэалізацыі, адтуды кожны крок мае чыстаю задачу. Гэта таксама формуе контракт адпаведнай вяскрасці: API, які вяртае значэнне "accepted", не аднацца з тым, які вяртае "done", і кліенты павінны знать, каторую вяскрасць яны атрымліваюць.

    3. Адначытае, кой слой неса адпаведальнасць за кожную рашэнне

    Функцыя можа даваць правильныя рэзультаты, але застаўцца небезпечной, якщо рашэнне знаходзіцца не там, дзе трэба. Тыповыя прыклады:

    • Фронтэнд скрывае кнопку ад корыстнікаў без дазволу, але API прыймае запит, калі ён надаецца безпосередна.
  • Кантролер пераканальвае пераход стану, але запланаваная задача вызывае базовую службу і адхіляе гэтыя пераканальванні.
  • Служба адхіляе толькі унікальныя даны, але скрыпт тэхнічнага адзначэння запісвае іх безпосередна ў таблыцу.
  • У кожным случае правіло існуе, але не кожны пат выконваецца чераз яго.

    Рашэння — знайсці шар, які мае достатню правоўую валядзьбу, каб кераваць гэтым правілам. Інтэрфейс можа відбіваць правыя для зручнасці выкарыстоўвання, але ён ніколі не являецца межой безпекі. Кантролер — гарна адзінка для пераканальвання формату HTTP-запытку, тады как бізнес-правілы зазвычай павінны знаходзіцца глыбэй, каб фонавыя задачы і внутршніі вызывальнікі мелі ідэнтычную працу. Пераканальванне унікальнасці на рэўэле аплікэйшну дае зрозумелыя паказанні пра адмоўкі, але толькі обмежэння базы дадзеных наспрамці захоўвае інварыянт, калі запісы вядуцца адночасна.

    Адміністрацыя стосуецца як дзеўалёта, так і правіл. Фільтры, якія павінны быць можлівымі да аднароджэння і застацца актуальнымі пасля апдэта, ўлучна падходзяць для URL. Тымчасовы ввод належыць форме. Права доступу і статус, які застаёцца, падаюць з сервера, і кліент не должен ствараць сваю сабе версію на аднойчыных прыпусках.

    Калі автарытет неясны, вы сталквачыцеся з проблемамі коордынацыі: падвойныя пераконтроўкі на розных рэвэлях, копіі таго ж значэння, якія павінны заставацца сінхроннымі, і змены, якія ператвараюцца ў пошук і замену. Апдэйт політыкі тады паўтараецца ў інтерфейсе, кантролеры, службах, працоўніках і кальколях, без гарантыі, што кожная копія яшчэ мае тое ж значэння. Кожная важлівая рашынка павінна маты адпаведнага власніка. Іншыя рэвэляў могу адображаць, кешаваць, выкананыць або перадаваць рэзультат, але не павінны яго перадзначаць. Гэта зменшвае як рызыкі для безпекі, так і витраты на адтрыманне, таму што всі знаюць, дзе знаходзіцца аднаковы істочнік даных.

    4. Адзначыце даны, якія вядомы ўжо

    Для жаданага модэлю пішуцца новыя коды. Аднак даны, якія викорыстоўваюцца у працэсе, таксама маюць следы кожнага паканальнага модэля.

    Зробіць полье обавязковым для заполнення лёгка для записаў, створаных пасля выпуску, але тыясячы старэйшых рядоў можаць не мець гэтага полья. Перадзялённая модель статуса можа добра описваць будучыя процесы роботы, але заставляе історычныя ряды застрэцца ў статусах, якія новы код больш не визнае. Новая обавязковая зв’язка можа вясці на ентыт, якога проста не існавало калі запісваліся старэйшыя ряды.

    Перад тым, як дадаць перакананне або змяніць схему, запытайце:

    • Можна лягкім спосабам мігруаваць існуючыя записы?
    • Чакі роўнасць патрэбны тымчасовы статус „невядома“?
    • Чы гэтае змена перапісвае історыю, чы толькі змянюе будучую працэздатнась?

    Справядлівасць — гэта важлівая слова. Заполненне кожнай прасвечкі падходячым стандартным значэнням можа задовольніць абавязак NOT NULL, пры тым як вводзіцца некоректныя даны. Якщо аддзеў, якім керуе стары запис, ніколи не быў зафіксаваны, його пазначэнне нынешнім аддзеўам спроствае запиты, але робіць історычныя звёсткі менш надзеямі. Інодзе чыстая схема мае месца для значэнняў на кшталт „не вядома“ або „спадчына“, адколі незнанне ёсць справжняй часткай працэўказу гэтага запису.

    Старыя форматы таксама існуюць паza базай дадзеных. Старэйшыя кліенты можа ўсё яшчэ надсылать пакеты даных у прыгожыя форматы, запланаваныя задачы можа залежаць ад значэнняў статусу, якія новы прабег хочаць адмаўліць, а звёсткі можа тлумачыць столбцы па правілах, якія зменіліся давно.

    Не трэба вечна падтрымліваць кожную колышню практыку, але рашэнне пра міграцыю павінна быць чыста і ясная. Дзеяныя данні можна безпечна трансфармаваць, дзеяныя выклікаюць неабходнасць ручнага адзорту, дзеяныя старыя кліенты заслуговуюць на період сумеснасці, а іншыя можна намеравана зняць з эксплуатацыі. Ігнараванне гэтага пытання не прыводзіць да його зникнення — яно з’яўляецца знову у вигляде розрозненых альтернатываў, столбцоў з можлівасцю пустых значэнняў, якіх ніхто не розумее, незусім успешных міграцый і проблем з падтрымкам пасля развярнення. Раннее прыняцце рашэння даўае камандзе адную цяплую транзыцыю заместо багацько локальных спадчынных падходаў.

    5. Праектаваць так, каб работа павтаралася і выклікала конкурэнцію

    У описах функцый зазвычай прыпускаецца, што є адны корыстнік, адна кліка і чыстая последовальнасць: запит прыходзіць раз, нічога іншаго за гэты час не трагвае за запис, а адпаведны адказ доходзіць да кліента. У рэальных умовах эксплуатацыі няма такіх гарантый.

    • Корыстнік клікае знову, таму што сторанцыя выглядае так, нібы застаяла.
  • Связь параболічнага тэлефона з’яўляецца перерванай пасля таго, як сервер завершыў роботу, але перш чым прыйшоў адпаведны рэспанс.
  • Чатар выдае тую ж самую паведамленне два разы.
  • Двое адміністратара затверджуюць той самы незаканчаны элемент за кальколькі секунд.
  • Запланаваная задача апдэйтуе запис, які корыстнік все ўсё пераглядае ў старэй версіи.
  • Пытанне, якое трэба задаць з самага пачатку, — гэта чы можна без апасцярожнасці выконваць даную операцыю колькарацо і чы можна яе выконваць паралельна. Якшо павторэнне не няшкодзіць, дадатковыя механізмы можуць не быць неабходнымі. Якшо павторэнне стварае другую оплата, запрасэнне, файл або броніраванне залягачаў, системе патрабуецца спосаб разпазнаваць, што кальколькі прабаўкаў являюць сабою адну логічную дзеянне.

    Інструментарыя включае ключы ідэмпотентнасці, унікальныя обмежэння, умовныя апдейты, столбцы версій для оптымістичнага блакання, транзакцыі і таблыцу ID обробленых паведамленняў. Выбор таго чы то іншага залежыць ад таго, дзе локалізаваны рызыкі. Тое, што ніколі не работае, — цэх «мы спачатку пераканаліся», нібы межа перакананням і запісю не могла працаваць жадны іншы процес.

    Багі, якія выступаюць у адночасных операцыях, ўзначальны таму, што кожна з іх на перагляд выглядае правільна. Недакладнасць бывае ў прыемі межа чытання і запісу: два запиты чытаюць аднаковы, правільны фотазапіс, кожны з іх праходзіць свае пераканання, а кожны фіксуе рэзультат, які мяў бы выйсці толькі раз. Набагато краща, калі база дадзеных адхіліць адну з двух суперасунковых операцыяў з видаваемым конфліктом, чым храніць два суперасунковыя факты, якія пазней каму-то даведзецца роз’ясняць вручную.

    6. Планаваце, як функцыя будзе сабе паслужыць у рэальных умовах

    У вашам комп’ютере є пункты абсарбірання, можласць павтарэння дзеяння і чыстая память праекту. У рэальных умовах команда можа атрымаць толькі паведамленне пра падтрымку, у яком сказана, што ўсё не запрацавало.

    Таму уявіце расследаванне прытаманнае напісанню коду. Якшо операцыя не выйшла, як можна будзе з’ясавіць, у калі кроку стала проблема? Можна лёгка адстэпаваць адзін запит праз разныя сервісы? Чы будуць логі паказваць, чы дзеяння было выканана адна чы трохі разоў? Можна розразліцаваць статусы „ніколі не пачалося“, „ведаецца“, „часткова завершана“ і „збілася“?

    Гэта не ўказванне лічыць усё фіксаваць. Неструктураваны воблака дадзенаў ускладняюць расследаванне, а не спрыяюць яму. Корыстная можлівасць абзярлення захопляе толькі столькі інфармацыі, сколькі трэба, каб перадаць ход адной важлівай операцыі:

    • ID запита або кореляцыі
    • ID рэсурсу і назва операцыі
    • Час трывання
  • Адзінство стану, якое адзейшылася
  • Нумар акцэнту
  • Катэгорыя стабільнага кашлу
  • Таксама трэба захаваць значэнне неудачы. Неудачны запит не павінен таямна ператварыцца ў порожняй список. Тайма-аут прадастоўніка не павінен ігнараваць тое, што удалёны бок мог ужо завершыць роботу. Блок для ловлення шырокіх кашлаў не павінен зводзіць усе прычыны да адной загальнай паведамленні перад тым, як гэта паведамленне дасягне межы логавання.

    Адночасова трэба думаць пра вяснаванне. Чы можна без апасцерагаў перазапускаць задачу, якая не выйшла? Чы можа падтрымкі з’ясаваць текущы стан аперэйшу без ручнага запытвання калькюляцый? Чы можа корыстнік без апасцерагаў спробаваць зноў, і чы можа хтось дастаць ягоўму точныя вядомасі пра рэзультат?

    Функцыі з незрозумелым падчыненням стаюць дорогімі як толькі выйшоў проблема, а дадатковая наладка логавання часта запаздывае, таму што неабходны контекст існаваў толькі пад час выканання операцыі. Праектаванне доказоў з самага пачатку робіць іх частынай функцыі, а не твардым патчам пасля інцыденту.

    7. Адначыткі, як падтвердзіце, што змяна ў безпэчы

    Калі тэсты пішуцца пасля коду, яны часта відпаваюць яго ныявнай структуре. Якщо існуе дапаможны элемент, тэст пераканаецца, што ён быў вызваны; якщо існуе альтернатыва, тэст ёю скорытаецца; якщо існуе макет рэпазітарыя, тэст паўтарыць, што макет вернуў тое, што яму было сказана. Такія тэсты праходзяць, але мало чаго падтверджуюць.

    Рашэнне па прыемліванні доказа спачатку частаюць адкрываюць слабасі дыяграмы. Якщо аперацыя павінна быць ідэмпатным, тады тэст павінен яе запускать калькі разоў. Якщо адночасныя затверджэння адной записі павінны быць немагчымы, тады тэсту патрэбны справжнія конкуруючыя апдэйты. Якщо „не знайдзена“ і „паразіл“ — гэта разныя рынкты, тады кантракт павінен дазволіць бачыць оба. Якщо правілу паўнаважнае дабэйн-база, ніякі мокаваны тэст на елементарным рывені не можа паказаць, што яно дыяўэт.

    Гэта не значыць, што кожная функцыя патрэбна супермасіўная серыя тэстаў „з канца ў канец“. Выберыце рывень тэстаў на адной засадзе таго, які рывень фактычна паўнаважнае гарантію:

    • Чыстую трансфармацыю можна працаваць як на елементарным рывені.
    • Кантракт API зазвычай выкалічвае тэст інтеграцыі.
    • Інварыянт, паўнаважнае дабэйн-базаю, павінен быць перакананы на рэальной дабэйн-базе.
  • Рызикавая міграцыя можа выклікваць патронаванне, поэтапную реалізацыю або наявнасць флага для функцыі з запланаваным часам ўсунення.
  • У той жа час трэба враштовваць пытанне адваротнасці. Якшо змяны пачынаюць працаваць некоректна, чы можна ўвыключыць іх або вярнуць старую версію, не выклікаючы втраты дадзеных, занесеных за гэты час? Чы будзе працаваць пярэдняя версія програмы пасля змены схемы, чы міграцыя выклікае неабходнасць паэтапнага розширэння і скорачэння функцый? Чаму бы не выпускнуць продукт для маленькай групы людзей, пакуль не всі перастануць ад него залежаць?

    Якщо проект важкая для тэставання або важкая для зворачэння, гэта частаючы сігнал таго, што адзін крок выконвае занадта много задач, або што для змены патрэбны меншыя проміжныя крокі. Абсалютная паўтаросць не ёсць метай, адколі у програмнага забезпечэння завжды є неяснасці. Некалькі хацець, каб критычныя гарантіі былі видны ў тэстах і паказніках, а каб небяспечныя выборы былі можна скасаваць, тады памылка становіцца урокам, а не перманентным накладкам.

    Падтрымка прапорцыйнасці пярэдней роботы

    Этыя запытаннія не ўтвараюць аргументу пра тое, што планаванне завжды краща за выконання. Чрэзмерны аналіз можа затрымаць простую работу і стварыць архітектуру для рызыкаў, якія ніколі не стануць рэальнасцю. Разумны спосаб – сфокусавацца толькі на рашэннях, якія будуць дорогі, якщо код іх выконае неправильна: все, што стосуецца захаваных дадзенняў, грошэй, прав, зовнішніх наследкав або публічных контрактаў. Змена копіі або внутрэшня рефакторка за стабільным інтэрфейсам рэдка калі выклікае патрэбу ў всім списку.

    У лёгкай форме чарт-списак можа быць включаны ў апісанне тыкета:

    • Аслівны проблема, ў адной фразе, і хто яго мае
    • Што значыць „выконана“ і якія наследкі є второснымі
    • Едынаві адпаведальны за кожная бізнес-правілле
    • План ўсага існуючага дадзенняў і старых кліентаў
    • Працэс пад час перапрыбутку і пад адночасным доступам
    • Што фіксуецца і як восстанавляюцца неудачы
  • Як будзе перакантравацца гарантія і як можна вернуцься да пачатковага стану
  • Заключныя заўважэнні

    Калі на гэтыя запытанні ёсць адпаведныя адказы, код зазвычай стае простым і зрозумелым. У модэлі стану менш немагчымых комбінацый, кожная правіла мае свое месца, база дадзеных контролюе незмянныя параметры, а адпаведныя рэспансы паведамляюць, чыргавае завершылася чы проста была прийнята, а тэсты нацэлены на гарантію, а не на текущую структуру функцый.

    Самэтле адпрацоўнікі, які стараюцца адказна, можу здацца медлівымі на пачатку виканання задачы, але працягваюць яе завершыць раней: яны не дазволяюць, каб неяснасцы продукту, старыя даны, адночасныя процесы і недагляданыя аспекты роботы таямна ператвараліся на стойкія тэхнічныя рашэнні. Правы момент, каб развязаць гэтыя проблемы, — гэта да таго часу, калі першая прыемная рэализацыя ўжо не павінна падвергнуцца вплыву адзіноў, тэстаў і рэальных даных. Апісанне функцыі рэдка калі ёст трудныя частка; справжняя сложнасць — у выборы таго, што яна можа значыць.

    Спадневаная літэратура

  • Проектаванне бэкенд-сістэмы на адказах: ад скарычвальніка URL да е-камерцыі — падход, які спачатку фокусуецца на трэбаваннях, для праектавання бэкенд-сістэм на Node.js: калі трэба дадзіць балансэры навантажэння, Redis, реплікі, кяухі і ліміты частоты, а такса кожнага з іх.