Як разрабатаванне фронтэнду эвалюяўся ад стылювання да масштабавання систем
Інжыніярство фронтэнду развілася ад HTML і CSS да компанентаў React, кэшавання, інструментаў для манорепа і можлівасцяў абзірнасці. Чым зменілася кожны ўзлёт і чаму гэта адбылася.
Крыніцы: I Thought Frontend Was Colors and Fonts. Then I Shipped to a Million Users.
Інструменты развіліся, але наш спосаб мышлення развіўся ёща болей.
Якшо запытаць каго-небудзь, што значыць розрабатка фронтэнду, вы зазвычай чуеце тую ж адпаведзь: HTML, CSS, JavaScript. Кольоры, шрыфты, зображэння, макет.
Это правільная пачатковая точка. Але гэта не там, дзе заканчываецца історыя.
Тое, што спачатку было стварэнням веб-сторанак, перацвела ў інжынерную розрабатку цэлых систем, якія павінны заставацца шырокаспектнымі, правильнымі та працоўнастымі, калі тыясячы людзей адночасова з імі взаімаюцца.
Інструменты развіліся па гэтам шляху. Але ўсё болей змініўся набор пытанняў, якія мы научыліся ставіць сабе.
Ось цэлы шлях развіцця.
1. Усё пачалося з HTML, CSS і JavaScript
Ранні веб залічваў усё простым.
HTML адпавядаў за структуру. CSS — за візуальную прыемнасць. JavaScript дадаў адночаснае взаінавядзенне.
Заведамцо місіі можна было выразыць ў адной фразе:
Стварыць сторанку, якая выглядае гарна і правільна працуе.
Большасць сторанак была статычная. Серверы давалі цэлы HTML, прыглядачы яго атрыбутавалі, і сам прыглядач практычна не меў ніякай логіки.
З часам сторанкі пачалі браць на сябе больш адпаведальнасці. Формы пачалі перакантраваць введзенныя данні пад час, калі корыстувальнікі ўводзілі іх. Контэнт аднаўляўся без павного перзагрузкі сторанакі.
JavaScript продавжваў браць на сябе больш завадзяў, і ніколі не перадаваў іх назад.
- З сторанак на прыкладнікі
Веб-сайты ператварыліся на прыкладнікі. Гэта значыла дынамічныя інтарфейсы, вызовы API, формы з калькама шагоў, процесы аутэнтыкацыі і данні, якія заставаліся ў прыглядачы между адной інтеракцыяй і іншай.
Гэта змена адкрыла проблему, яку старыя тэхнікі не былі прызначаны рашаць.
Калі вы безпасэчна маніпулюеце DOM, видны экран стае вашым едынственным источнікам правды. Адна единица дадзейнаў можа існаваць у зменны, ўнутры вузла DOM і ў адпаведзі з сервера. Нічога не гарантуе, што гэтыя тры элементы застануцца супараднаванымі.
Як толькі вы апцэнаваеце адны з іх і забываете пра іншыя, вы патрапляеце ў ситуацію, калі баг проявляецца толькі пасля апэкты конкретнай последовальнасці клікаў.
Патрэбны быў спосаб прызначыць какім должна быць візуальная частка і пераказаць задачу выконання фактычных операцый над DOM іншаму элементу.
3. React: мысленне па компонентах
Праўы прорыв React не быў у яго синтаксі. Ён заклёваны ў ментальныя модэлі, якія стояць за ўсім гэтым.
UI = f(state)
Вы описваеце візуальную частку для пэўнага стану, а фреймворк вырашае, якія самыя мінімальныя змены DOM неабходны, каб досягнуць гэтага стану.
У зяместо тага element.appendChild(...) вы пісваеце тое, што трэба ўтварыць.
Базовая елементарабочая единіца перайшла з цэлага старонкі на компанент. Думайце пра адзін кранк, картку з інформацыяй пра тавар, дыалоговое вікно або адзін крок у процэсе платежа. Кожны з іх мае свой сабэйт, свой стыль і свою працэздатнась.
Ось што даў такі падход:
Можлівась перызнаўання. Створыце компанент адназнач, а потым выкарыстоўваеце яго ў дзесятках месцаў.
Локальная логіка. Вы можете зрозумець адзін компанент, не чытаючы всю прыкладку.
Можлівась тэставання. Падаеце ў яго параметры, пераканаліваецеся на выходны рэзультат, браузер не патрэбен.
Можлівась складання. Маленькія компаненты саедынаюцца, ствараючы большыя.
Цэнтральны вопыць змяніўся з "Як мне стварыць гэтую сторанку?" на "Калікі элементы складаюць гэты прыемлак?"
4. Next.js: ад UI да архітектуры
Чыста кліентская версія React мела свае наследкі.
Браузер спачатку завантажае порожнюю HTML-шэлку. Потым ён завантажае значны пакет JavaScript. Пасля чаго выконвае гэты пакет. Толькі пасля всьго гэтага корыстнік бачыць які-небудзь контэнт.
Гэта нормальна на моцным ноутбуку. Але на тэлефоне середньяго класу з слабым сігналам цэль значыць, што трэба колькі секунд стаяць пры порожнім экране. А пошуковыя роботы можа ўзагалі не знайсці нічы паслужальнага для індексавання.
Фреймворкі, такія як Next.js, даваюць разработчыкам кантроль над дзе і калі насправды генеруецца HTML.
SSG. Адрасаванне адбываецца пад час стварэння, а статычны файл выдаецца з CDN. Цэя опцыя ўсё ж самая быстрая, хоць кантэнт застаецца незмянным да наступнага стварэння.
ISR. Кантэнт застаецца статычным, але перзгенеруецца на фоне пасля вяліканутага часовага перыяду. Вы атрымліваеце швальнасць статычнага формата, пры чым кантэнт застаецца досыта свежым.
SSR. Адрасаванне адбываецца на сервере для кожнага запиту. Кантэнт завжды ў актуальным стане, але сервер кожны раз выконвае новую роботу.
CSR. Адрасаванне адбываецца выключна ў браузеры. Цэе падходягае для экранаў, якія захаваны пасля аблогавання, дзе індэксаванне не мае значэння.
Ключовая ідея: вы выбіраеце для кожнага маршруту окрема, а не для всія прыкладненняя разам.
Старонка маркетынгу выгадвае ад SSG. Старонка продукту выгадвае ад ISR. Панель керування выгадвае ад CSR.
І самэ час прыходзіць на выручку гідратацыя. Сервер адправляе HTML, а потым кліент зноў запускае дрэво компанентаў, каб наладзіць обрабнікі запуска ўпадакоў. Візуальна сторанка выглядае готовай, хоць на самае працоўная ён не ўсё яшчэ.
React Server Components і стрімінг існуюць галоўная метаю — запыніць гэты прыем. HTML адправляецца як толькі становіцца доступным, а для частак сторанки, якія ніколі не мелі быць інтерактывнымі, адправляецца менш JavaScript.
На гэтым этапе робота над фронтэндам перестае быць проста „шаром UI“. Рашэнняя ў паводзе стратэгіі атрыбутаў, маршрутацыі і кэшавання стаюць архітектурнымі рашэнняямі, і саме інжынеры фронтэнду іх прыймаюць.
5. Потым прыйшла масштабавання
Стварэнне прыкладнення — гэта адна з вызваў. Стварэнне прыкладнення, яке служыць мільйонам корыстувачаў, — гэта зусім іншая вызва.
Пытанняя, якія вы ставляеце, пачынаюць змініцца:
Што павінна быць, калі API, які працюе пасля іншага, сповольняе роботу, а не проста падае?
Як шасць разлучных команд можа адаваць код у той самы базовы код, не перасланяючыся адзіна з іншай?
Як можна запусціць змяну толькі для 1% корыстувачаў і вернуць яе за мінуту, якщо ўсё пайдzie не так?
Як працюе дапыт на трывалага тры гады Android-тэлефоне, які знаходзіцца там, дзе вы яго ніколі не тэставалі?
Калькі з вчорашніх запускаў є прычыной сьогоднішняго росту колькасці памылак?
Это запитанні на рэвэльнацыяй системы. Яны проста выяўляюцца ўнутрь браузера.
6. Скорасць — гэта не проста дапаможны элемент, гэта базовая адзьменнасць
Элегантны інтерфейс, які трэба шасць секунд, каб ён быў атрыбутаваны, можа расслівачвацца як несправны. Корыстувачы відчуваюць затрымку, прычому ўсё ўжо не можаць точна апісаць, у чым проблэма.
Сэрвісаванне качання ў сучасны час базуецца на памерэннях, а не на інтуіцыі. Core Web Vitals даюць командам спяльную мову для абмавінання пра швальнасць.
LCP (Largest Contentful Paint) пазначае момент, калі главны контэнт становіцца видным. Стараюцца, каб час быў меней 2,5 секунды.
INP (Interaction to Next Paint) паказвае, насколькі швабро інтэрфейс реагуе, калі хтось нажымае на елемент. Цялевая значэнне — меней 200 мілісекунд.
CLS (Cumulative Layout Shift) мерыць, насколькі элементы перасуваюцца пад час стабілізаціі сторанкі. Цялевая значэнне — меней 0,1.
Кожная тэхніка оптымізацыі адпавядае аднаму з гэтых памераў.
Раздзелэнне коду і яго павольна загрузка. Надаюць толькі той JavaScript, які насправды патрэбен для текущага маршруту, а не весь пакет прыкладнення. Це павышае як LCP, так і INP.
Настройка адаптавання зображэнняў. Ўжыце сучасныя форматы, правільна задаюце ўжоў, і завжды паказвайце шырыню та высоту з самага пачатку, каб ніч гэта не спраўлялася. Гэта дапамагае пакращыць показанні LCP та CLS.
Разумнае выкарыстоўванне шрыфтав. Заранее завантажваюце іх, прымаюце параметр font-display: swap, і скорачваеце набір симвалаў да таго, які насправды выкарыстоўваецца. Гэта спрыяе пакращанню CLS.
Распространэнне через CDN. Аддача байтав з сервера, які знаходзится геаграфічна бліжэй да корыстувальніка, паказвае позытыўны эфект для майже всіх показнікаў адразу.
Утриманне важкіх задач паza галоўным потокам. У браузере є адні потак, які адпавядае за адрасаванне та вашы скрыпты. Задача, якая відбываецца 300 мілісекунд, замаражоўвае кожны клік пры тым жа періядзе. Самэ гэта і є прычыной паўстання перадоў INP.
Основны прынцып, сказаны проста:
Даюць максымальна якасць выкарыстоўваючы як магчыма меншыя рэсурсы.
Адна парада: налагоджвайце на аднойчы знятых паказанні, а не на прыпущэннях. Чысла, зялёнутые з ноутбука разработчыка ў лабараторных умовах, часта не падпадаюць пад тое, што перасічныя корыстувальнікі адчуваюць у рэальных умовах, і саме даны з рэальных умоў відбіваюць рэальнасць.
7. Кэшаванне: утримайцеся ад паўторнага вычыслення таго, што вже рашана
Калі наплоў зростае, стварэнне той самай адпаведзі раз за разам стае марнатрацэйным. Кэшаванне існуе ў тым, каб не платіць гэтыя затраты два разы за ідэнтычную роботу.
Кожны запит праходзіць через калькі слоёў, і кожны з іх ёсць можлівасцю скорачыць роботу.
Browser → CDN → Application / ISR → Redis → Database
Чым ближэй адпаведзь выдаецца з месца, якое знаходзіцца ближэй да корыстувальніка, тым яна ўжо дешавей і быстрэй.
Адзінакова, чым ближэй да корыстніка знаходзіцца кешаваныя данні, тады цяжэй стае вернуцца назад, якщо ў іх ёсць памылкі.
Гэтыя труднасці ўскладнююць усю практыку кешавання.
Што паўінна быць у кеше? Данныя, якія є стабільнымі, дзельніцямі межы корыстнікаў і якія каштуюць много ресурсоў на стварэнне. Ніколі не трэба кешаваць данні, спецыфічныя для конкрэтнага корыстніка, як толькі ключ кеша не врачоўвае індывідуальныя характэрыстыкі корыстніка.
Як давго яны павінны застаўцца? Короткі тым павернення ў недзейнасць є бяспечней, але даўае меншы эфект. Дзягучы тым дапамагае быстрэй, але падвышае рызык.
Як яго ачысціць? Серед вароўнасцей — тым павернення ў недзейнасць на адповідны час (TTL), ачысцэнне па змаганні падзеяў (працюе пасля публікацыі) або хэшаванне імен файлаў на адповіднасць з ўместам, так што ачысцэнне стае непатрэбным.
Што выходзіць, калі пошук не ўдаецца? Якщо трымач, які шырока аднаўляецца, выйшае з ласкаў, а большая частка запытанняяў адразу ж падае на сервер, цэльваецца ситуацыя панікі. Чырабецца ад гэтага можна за дапамогою механізма блакавання або падачай застарэлай версіі, пакуль адзін запытанне займаецца яе апавежэнням.
Шаблон, які варта запамятаць, — stale-while-revalidate. Негайна падача версіі з кэшу, тыха яе апавежэнне на фоне і ўжо следующы візітар атрымлівае апцэнаваны контент. Карыстальнікі бачаюць высокую швалерасць, а вы захоўваеце правільнасць з незначныя запазджэнням.
Зважайце на тое, што насправды коштае памылка ў гэтым аспекте. Зламаны кэш не толькі спамячвае роботу — ён таксама можа паказаць некоректную цэну, неправільнае імя або чужыя даны.
Кэшаванне выглядае як тэхніка паўтарной працы, але на самай справе ёсьць рашэнням пра правільнасць.
8. Структураванне для росту
Калі кальколька каманд працуе ў аднай базе коду, спосаб её арганізацыі стае настолькі ж важны, як і швальнасць её роботы.
Межы між модулямі. Адначытае, што будзе доступна для публікі, што застанэцца внутршнім, і якія залежнасці дазволены.
Контракты для API. З атрыбутамі типу і версіямі, каб змены на бэкенде не спанулі процес стварэння, а не жывой сайт.
Дзе знаходзіцца стан. Стан сервера, стан URL і локальны стан кліента — гэта абсалютна разлічныя категорыі. Большасць багоў, звязаных з станам, выходзіць з таго, што адну категорыю спрыяжаюць з іншай.
Ізоляцыя неудач. Межы абэктаў кешаюць, каб адны несправны элемент не знехадзіў усю стораніцу.
Вывод змян. Флагі функцый, развертанне прыкладоў і можлівасць мгновеннага вярнэння.
Падчуванне зменшыцца з простага запуску функцыі да пераканання, што гэтая функцыя не будзе ускладнюваць кожныя будучыя змены.
9. Аднаўлены код у манорепа
Калі калькі прыложэнняяў павязаныя з тым самым заголовкам, тым самымі элементамі дизайна і тым самымі засобамі аутэнтыфікацыі, копіюванне і вярстанне коду стае нээфектываў.
Манорепа дазволяе командам дзеліцца компонентамі UI, системамі дизайна, функцыямі-прыборкамі, настройкамі і адзначэннямі типаў — ўсё гэта знаходзіцца ў аднам канонічным источніку правды, пры чым змены прабываюць атомічна ў всіх пакетах.
Аднак дзеленне коду таксама мае свою цэну. Кожны аднаўлены пакет стае залежнасцю, а кожная залежнасць фактычна ўособлівае чатырэння: апдэйт адной каманды можа затрымаць выпуск іншай каманды.
Практычны цэль — павторнае выкарыстоўванне без строгай з’яеднанасці.
Прыткая падчынна: дзеліцеся элементамі, які рэдкая змінююцца і маюць адно значэнне незалежна ад таго, дзе яны викорыстоўваюцца — такімі, як токены дизайна, компонент Кнопка або вызначэння типаў.
Утримайцеся ад дзеліцяння чым-небудзь, што ўключае спецыфічную логіку бізнесу адной з каманд. Дуплікацыя коду часта є дышэўней, чым выбіраць неправильную спольную абстракцыю.
Мікро-фронтэнды развіваюць гэю ідею далей, дазволяючы камандам самастоятельна выпускать продукты, але цэе супакоўваеся з адныя большой складнасцю пад час выканання і дуплікацыяй залежнасцэў. Такі компроміс можа быць розумным для вялікай організацыі з чысткімі межамі між камандамі. За межамі такога контексту гэта рэдкая вырашае проблемы.
10. Следзіце за системай у працэўным режыме
У вялікых масштабах фразы на кшталт "гэта працуе на маймашыне" або "гэта працавала нормальна ў стадійнай среды" вялікая толькі значэння.
На самай працо вам патрэбна можлівасць бачыць, як працюе програма ў рэальных умовах, на справжніх прыстроях, у рэальны час.
Адстаўленне паканянь у поўнасці супрацоўвае з заванесенымі карточкамі выхаднага коду, таму трэйс краху вядзе да вашага справжнега выхаднага коду, а не да спроставанага і зміненага варыянта.
Спостерэнне за рэальнымі корыстувачамі дазволяе збираць даныя пра Core Web Vitals ад справжніх корыстувачаў, разбіваючы іх па прыстроях, краінах і якосці з’ўязку.
Структураваная логгірацыя прыўязана да ID запиту, які можна пераследаваць ад браузера да кожнай з сервісаў у спадней частыне.
Апавешчэння, прыўязаныя да конкретных сімптамаў. Павядомляйце людзей, калі паўнасць паканянь або затрымкі перасягаюць заданы ліміт, а не проста калі спрацоўнасць CPU сервера расте.
Стежыце за выпускамі. Атрымайце атрыбут к кожнай памылцы, які паказвае конкрэтны выпуск, який яе створыў, тады на адпаведзенне на запитанне «Што змянілася?» пайдзе калексы секундаў, а не гады.
Запытанні, на якія ўможлівае адпаведзець такая наладка:
Дзе самэ гэта выклікае памылкі у корыстнікаў? Кой API-званак паслабляе якасць работы? Кой маршрут ўповільнены і для якога сегмента корыстнікаў? Чы не пагоршыў найнявэжэйшы выпуск ситуацыю па асоўна з пярэднім станам?
Код фронтэнда раней быў найважчым часткам стака для адзірвання. Але тепер гэта не павінна быць так.