Галоўная / Артыкулы / Семь скрытых предположений, из-за которых JavaScript терпит неудачу при реальном трафике

Семь скрытых предположений, из-за которых JavaScript терпит неудачу при реальном трафике

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

3164 слоў

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

Чаму локальная разработка ўскладнюе прыкметаванне

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

Процэс вырабаткі зменяе вхідныя даны, а не сама мова. Запісы былі створены пяцьма разнымі версіямі прыкладнага програмнага забезпечэння, і не всіяяныя аднообразна. Люди клікаюць два разы, таму што экран здавался застойным. Адпаведзіцы прыходзяць у іншай парадку, чым былі надслааны запиты. API трэціх сторон працуюць повольна, вяртаюць частковыя даны або выканаюць тайма-аут. Калькі экземпляраў адной і той жа службы апдэйтуе адныя і тыя ж рядкі ў однаковы момент. Поле, якія завжды запоўняліся локальна, паказваюцца як "", null, значэнне з перыяду, які быў скасаваны дваячоўга версіямі раней, або як строка, у якой мае быць число.

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

1. Значэнні не завжды маюць той тип, які выглядае.

У JavaScript значэнне можа перасягнуць калькі меж і ў кожной з іх абмовіць свой первачны тип. Чыслаўскі ідэнтыфікатор базы дадзенаў ператвараецца на строку, калі потрапляе ў URL. Поле з прапускам прыходзіць на сервер у вачынку "true" або "false". Пустые данні стаюць "", хоця сервер чакаў null. Часавы пазначкі ISO перадаюцца у вачынку звычайнага тексту і обрабляюцца як Date, проста таму, што выглядаюць так.

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

Прасілля да ператварэння дае адпаведзі, якія выглядаюць майже правильна

Серьзныяі багі — це тыя, калі JavaScript выконвае правдападобную перакладку заместо таго, каб выклікваць адказ пра бяг. "10" правільнаа параболіцуецца з цыфрамі за дапамою < і >, але "10" + 1 дае "101". Строка "false" считаецца істынай, таму флаг, які мяў бы выключыць адпаведную функцыю, можа яе выключыць. Пустая строка ў аднам хелперы считаецца "выкрадзенай", а ў іншам — легітым значэннем.

Нічага не зламваецца. Сістэмы пагінацыі прахоўвае неправільную сторанку, апынулася недзейная опцыя становіцца выбіраемай, а userId === record.ownerId тыха паспяшае з-за таго, што адна сторона — цыфра, а другая — строка. Команды потым латуюць кожны сімптам, які з’яўляецца, і кодбаза паступова накаплівае кальколька субтыльна разных правіла нормалізацыі.

Нормалізуйце раз, на межы

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

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

2. Адна кліканне не значыць адна выконання

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

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

Дзе дуплікаты насправды шкодзяць

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

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

Проектаванне запісаў, якія тольеруюць павтарэнне

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

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

Ключовая ідея закладаецца на тое, што прытрыманне часу або адпаведна на адказе памылкі не ўбеджаюць у тым, што аперацыя зазнала невядомага. Сервер мог ужо завершыць сваю роботу пасля таго, як кліент перастае чакаць. Павторны запуск без стабільнага ідэнтыфікатора аперацыі ператварае гэту невядомасць у дубліраўанне. Надзеяны система — гэта не тая, якая запобегае кожнаму павторнаму запуску; гэта тая, дзе павторны запуск не змінюе сэрцаўнага значэння аперацыі. Механізмы на стороне сервера падробна расказаны ў разумеўцы ключоў ідэмпотентнасі ў Node.js POST-канцэнтрах.

3. Код, які чакае, все ж можа выконваліцца паралельна

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

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

Конкурэнція «пераканацца, потым дзеяць» на сервере

Уявіце тэрмінал затверджэння, які завантажвае пункт у статусе «чакае» і потым ставіць яго ў статус «затверджаны». Два адміністраторы ачынаюць той самы экран і нажымаюць на кнопку затверджэння за кальколькі секундаў адзіны ад другога. Оба запытання чытаюць значэнне pending прытаму, як ніхто з іх не выкарыстоўвае функцыю апдэйта. Канечны статус можа выглядаць нормальна, але якщо дзеянне таксама выкарыстоўвае паведамлення або запісуе ентры для аудыту, гэтыя пахыбны эфекты вырабляюцца два разы.

Тая ж самая конкурэнція ў браузеры

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

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

Выбор механізма захавання

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

  • Умовная змена, напрыклад "set status to approved where status is pending", праз перакананне колькасці афектаваных рэядоў.
  • Оптымістычная канкурэнцыя з столумом версіі, які павінен адпаваць.
  • Транзакцыя базы дадзеных з адпаведным рэвэлем ізоляцыі.
  • Абмежэнне ўнікальнасці, якое змушвае другую практыку збіркі дадзеных неякша завершыцца.
  • Анулюванне запита або ідэнтыфікатор операцыі, який дазволяе толькі найсвежэйшым рэзультатам змінюваць спяльны стан.
  • Апасоўная думка заключаецца ў тым, што код, які чытае дадзеныя па порядку, значыць, што система будзе дзейсніцца па порядку. JavaScript можа зробіць адну функцыю вельмі простай у розумэнні, нават калі ў той жа час запускаецца множына ёё копій.

    4. Запиты не завершаюцца ў той порядак, у які былі запусканы

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

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

    Старыя рэспансы — это правильныя даны, але ў неправім часе

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

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

    Адначыце, хто ўладае рэзультатам

    Надзейны спосаб рашэння пачынаецца з правіла прыналежнасці. У багатых інтэрфейсах павінна перамогчы найняўэйшая запита, таму трэба альбо анулюваць старыя запиты, альбо пазначыць кожны з іх номерам у рэядку та адкінуць рэзультаты, якія больш не ў часе. Іншыя практыкі выкарыстоўваюць прыему «першый увайшоў — першы выйшоў» або незалежны статус для кожной операцыі. Тае ж правіло прыналежнасці павінна дапамагаць у керуванні статусам загрузкі та адказоў на падазры: абанаваны запит не павінен зняць індыкатор загрузкі для актыўнага запиту чы паказваць адказ на запыт, які ўжо заменіўся. Па деталям, прызначаным для React, адзірніце React search with clear state ownership.

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

    5. Малыя калекцыі не застаюцца малымі

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

    За дапамой тэстовых фіксатураў гэтыя дзеянні завершаюцца мгновенна, а код застаецца настолькі коракам, што яго алгарытмічны кашт застаецца непазначальным. У прыняцоўскай среде данні зрастаюць, не змянюючы візуальнага выгляду коду. find усередине map для двух колекцыяў по дзесять тысяч записаў означае прыбліжна сто мільйонаў параболенняў. includes усередине ціклу дадае ўжо адну лінейную перасканаванне на кожны элемент. Адчытнік, створанный для адной каманды, раптам запускаецца ў всій арганізацыі.

    Падаброўваеце структуру да шаблона адчынення

    Методы масів не ўтвараюць проблемы; проблема крыўчуе ў викорыстанні последовной структуры для паўтаральных пошукаваў за ключамі або пераканання ў наявнасці элемента. Створыце Map, ключамі якога будуць ідэнтыфікаторы, аднойчы, і тады кожны пошук у сярэжнем сярэбрзе будзе выконваны за сталячы час. Вярніцеся да Set, калі падымаецца пытанне «Чы гэты элемент ў колекцыі?». Часта кращай адпаведзю ёст тыяжэй з базой дадаў, так што не трэба завантажваць обе колекцыі ў памяць і спаўнаюць іх у коде прыкладнага програму.

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

    Памяць і канкурантнасць таксама зменяюцца

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

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

    6. Абсэнцыя дадзенаў — гэта не доказ таго, што нічога не адбылася

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

    Калі альтернатыўныя рашэнняя маскуюць проблемы

    Запыт дашборда не выконваецца, таму што база дадзеных не працюе; сервіс вяртае [], а інтэрфейс весела паведамляе "Знакі зберагання не знайдзены". Пашук праваў не выконваецца, опцыйная ланцоўка дае undefined, і код спрыяе гэтаму як звычнаму false. Неправільны адпаведзень вяртае undefined, які пазней ператвараецца на стандартны об’ект на трох роўнаў глыбей. Аплікацыя выглядае стабільной, таму што ніколи не зламваецца, але яна паведамляе корыстнікам тое, чаго на самай працэ не ведае.

    Гэтыя наследкі нельга заменіць адзін другам:

    • Запыт, які выканаўся і вярнуў нуль рэядоў, проты запыту, які так і не быў выкананы.
    • Аватар, які можа не існаваць, проты об’екта корыстніка, які не існуе.
    • Умышленая адмова аплікацыі праты перыяду безадраснасці сеті.

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

    Спачатку задаюцца правіла, а потым дадаецца захоўнай синтаксіс

    Ўзайце неабяжлівыя ланцюгаванні там, дзе значэнне практычна можа не існаваць. Ўзайце альтэрнатыўны варіант, калі система мае адпаведную замену. Калі вы ловіце паказанні, перакладзіце іх у стабільныя катэгорыі, такія як «не знайдзена», «забранае», «недоступнае» або «нэўярныя», але заставіце первычную прычыну і контэкст для логаў і манітарынгу. Грацыязны спад працэса должен заставіць аплікацыю застаўцца корыстной, заадно не выдаваючы хыбных даных; яна ніколі не должна ствараць вражання успеху, вярнучы правдопадобнае значэнне.

    7. Стан у памяці не дзеліцца межа аплікацыёй

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

    У працэйнай суперактывасці той самы код можа выконвалівацца ў калькольных процэсах, контейнерах, экземплярах без сервера або ў розных регіонах, і кожны з іх мае свою памяць:

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

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

    Дайте стацыі той масштаб, які ёй насправды трэба

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

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

    Продакшн ўсё жа адкрытый, а не хаотычны

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

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

    Галоўныя вывары

    • Аналізаваць і перакантраваць зовнішнія значэння аднойчы на межы, і падтрымліваць синхроннасць шыматоў працы і статычных тыпаў.
    • Спрыяваць кожнаму значным запісу як да чаго-то, што можа выконвацца больш ніж раз, і забезпечыць унікальнасць там, дзе зберагаюцца даны.
    • Памятаць, што await призупіняе адну вызов; ён не серыявае систему і не блакуе спільны стан.
    • Выбраць, які асінхронны рэзультат контролюе текущы стан, уключаючы паказчыкі завантажэння і адзінакоў.
    • Выбраць структуры даных і запыты па вобшчай колькасці, якая будзе у вас, а не па прыкладным фіксату, які вы тэставаеце.
    • Зберагаць „пусты“ і „неудачны“ як аднародныя рэзультаты да самага корыстніка і вашага манітарынгу.
    • Зберагаць стан у тым масштабе і трываласці, якія ёму практычна трэбаюць, і прыйміце, што будзь-які адзін процес можа зникнуць.

    Спадні матэрыялы