Инженерная практика Инженерная практика: анатомия системы и карта трека
0%

Инженерная практика: анатомия системы и карта трека

Инженерная практика: анатомия системы и карта трека

Есть два способа узнать, как устроена разработка. Первый — выучить по отдельности браузер, базу данных, Docker, Git и десяток фреймворков. Второй — понять, как из этого собирается одна работающая система, и уже потом углубляться туда, где болит. Первый способ даёт человека, который знает много слов и не может довести фичу до продакшена. Второй даёт инженера.

Этот трек — про второй способ. Он не заменяет специализированные треки портала: по базам данных на портале двадцать глав, по фронтенду восемнадцать, по DevOps восемнадцать, по Git четырнадцать. Он делает то, чего не делает ни один из них: показывает стыки. Как клиент договаривается с сервером. Почему решение о хранилище тянет за собой решение о масштабировании. Почему «нам нужны микросервисы» — это чаще всего вопрос про организацию команды, а не про технологию. Что происходит с кодом между моментом, когда вы нажали git push, и моментом, когда его увидел пользователь.

Дальше — сквозной разбор анатомии системы, карта ответственности между треками портала и описание того, как читать этот трек.


1. Один клик: сквозной путь через всю систему

Начнём с конкретного. Пользователь нажимает «Оплатить» в интернет-магазине. Между нажатием и надписью «Заказ принят» проходит 400 миллисекунд, и за это время изменение пробегает через все слои, которым посвящены главы этого трека.

В этой картинке спрятано почти всё содержание трека.

  • Клиент валидирует форму, но его валидации никто не верит: он работает на чужом устройстве, в чужой сети, и его код можно переписать в консоли браузера. Об этом — «Клиентская сторона».
  • Сервер принимает запрос, проходит по цепочке промежуточных обработчиков и решает, что считать истиной. Об устройстве этого пути, моделях конкурентности и таймаутах — «Серверная сторона».
  • Хранилище обеспечивает атомарность: либо заказ создан и остаток списан, либо ничего. О том, как выбирать хранилище и как не выстрелить себе в ногу ORM-ом, — «Слой данных».
  • Контракт между клиентом и сервером — идемпотентный ключ, код ответа, формат ошибки, правила ретрая. Об этом — «Интеграция».
  • Форма системы — то, что здесь показано как «сервис + очередь + воркер», могло быть одним процессом или пятнадцатью. Об осознанном выборе формы — «Архитектурные шаблоны на практике».

Всё это — только правая половина картины: то, как система работает. Есть вторая половина — то, как она появляется и меняется: контроль версий, окружение, сборка, ворота качества, конвейер, конфигурация. Ей посвящены главы 06–11.


2. Три контура обратной связи

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

Инженер отличается от «человека, который пишет код» тем, что видит все три контура сразу и понимает цену задержки в каждом. Тест, который идёт сорок минут, ломает первый контур. Ручной выкат по инструкции в вики ломает второй. Отсутствие внятных логов ломает третий — и тогда починка одного бага занимает не полчаса, а два дня.

Практическое следствие, к которому мы будем возвращаться: любое инженерное улучшение можно оценить вопросом «на сколько это сокращает петлю обратной связи и за какие деньги». Это работает и для линтера, и для микросервисов. Метрики DORA — по сути измерение второго и третьего контуров; о них подробно в «CI/CD» и в треке Project Management.


3. Анатомия: кто за что отвечает

Слово «слой» перегружено, поэтому договоримся о значениях сразу — эта путаница стоит командам недель споров.

Термин Что это Пример
Слой (layer) логическое разделение кода по ответственности представление / прикладная логика / доступ к данным
Ярус (tier) физическое разделение по узлам развёртывания браузер / сервер приложений / сервер БД
Сервис единица независимого развёртывания orders, billing, search
Модуль единица логической связности внутри кодовой базы пакет, namespace, bounded context

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

Общая карта ответственности:


4. Где на портале лежит глубина

Это, пожалуй, самая полезная таблица трека. Если вам нужно разобраться в теме до дна, идти надо не сюда, а в специализированный трек. Этот трек объясняет, зачем тема нужна и как она стыкуется с остальными; специализированный — как она устроена внутри.

Тема Что даёт этот трек Куда идти за глубиной
Браузер, HTML/CSS/JS, React роль клиента, границы ответственности frontend
Мобильные приложения клиент как класс задач mobile
Сети, HTTP, TLS, DNS путь запроса на уровне приложения networking
Базы данных выбор хранилища, ORM, миграции databases
Стили API контракт и его эволюция architecture-patterns / API
Архитектурные шаблоны карта форм и процедура выбора architecture-patterns
Паттерны проектирования отличие от архитектурных design-patterns
Моделирование предметной области границы модулей DDD
Git зачем VCS и как встроен в процесс git
Редакторы и IDE критерии выбора окружения editors
Тестирование место тестов в потоке testing
Принципы и чистый код связь принципов с практикой principles
CI/CD, контейнеры, облака анатомия конвейера devops
Производительность поиск узкого места performance
Распределённые системы что ломается при разделении distributed-systems
Надёжность, SLO, инциденты взгляд прикладного инженера SRE
Безопасность приложений секреты и стыки security
Платформа и DX окружение как продукт platform-engineering
Роли, процессы, карьера контекст вокруг инженера sdlc-and-career

Полная карта всех треков и рекомендованный порядок прохождения — в дорожной карте.


5. Четыре решения, которые дороже всего менять

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

1. Модель данных. Схема переживает код. Приложение можно переписать за квартал, а неудачно спроектированную структуру данных с миллионами строк придётся мигрировать годами, с обратной совместимостью на каждом шаге. Отсюда правило: думать о модели дольше, чем о фреймворке.

2. Граница между сервисами. Проведённая по неверному месту граница превращается в распределённый монолит: сервисы формально отдельные, но любое изменение требует согласованного релиза трёх из них. Граница должна совпадать с границей изменения, а та — почти всегда с границей команды и домена (закон Конвея).

3. Контракт, отданный наружу. Внутреннюю функцию можно переименовать за пять минут. Публичный API, которым пользуются чужие клиенты, живёт годами и умирает медленно, через deprecation и sunset-заголовки.

4. Способ хранения состояния. Решение «состояние живёт в памяти процесса» кажется безобидным ровно до момента, когда понадобился второй экземпляр приложения.

Обратите внимание на нижнюю часть графика: споры о форматировании и логгере занимают непропорционально много времени команд именно потому, что в них легко участвовать. Правильный ответ — автоматизировать и забыть; об этом в главе «Качество в потоке».


6. Правило по умолчанию: начинайте с простого

У трека есть сквозная позиция, и её честнее заявить сразу.

Монолит по умолчанию. Не потому, что микросервисы плохи, а потому, что разделение покупается операционной сложностью: сеть между вызовами, распределённые данные, сквозная трассировка, отдельные конвейеры, дежурства. Эти расходы оправданы, когда есть настоящая сила, толкающая к разделению — независимый релизный цикл, радикально разный профиль нагрузки, организационная граница. Мода такой силой не является. Подробный разбор с критериями — в главах 05 и 12.

Скучные технологии. У команды есть ограниченный бюджет на новизну. Каждая незнакомая технология тратит его — и когда в три часа ночи падает прод, знакомая PostgreSQL стоит дороже модного хранилища. Эта мысль хорошо сформулирована в эссе Дэна Маккинли «Choose Boring Technology» (https://mcfunley.com/choose-boring-technology).

Сначала измерить, потом чинить. Интуиция инженера о том, где узкое место, ошибается чаще, чем угадывает. Правило распространяется и на производительность, и на качество, и на процесс. См. «Масштабирование» и performance / измерение.

Обратимость важнее правильности. Решение, которое можно откатить за десять минут, можно принять быстро. Решение, которое нельзя откатить, требует обсуждения и записи. Отсюда популярность фича-флагов, канареечных выкатов и ADR.


7. Как устроен трек

Четырнадцать глав делятся на три блока. Первый — как система устроена, второй — как она создаётся и меняется, третий — как она живёт.

Блок I — как система устроена.

  1. Клиентская сторона — недоверенная среда, толстый и тонкий клиент, что можно и что нельзя класть на клиент, состояние на клиенте.
  2. Серверная сторона — жизненный цикл запроса, модели конкурентности, stateless, таймауты и пределы ресурсов.
  3. Слой данных — что даёт СУБД, как выбирать хранилище, пул соединений, ORM и N+1, миграции схемы.
  4. Интеграция — контракт, стили API, ошибки, ретраи и идемпотентность, эволюция без поломки клиентов.
  5. Архитектурные шаблоны на практике — слои и ярусы, каналы и фильтры, клиент-сервер, MVC, событийная архитектура, микросервисы; процедура выбора и ADR.

Блок II — как система создаётся.

  1. Контроль версий — зачем VCS, распределённая модель, снимки вместо патчей, хороший коммит, ветвление как решение о процессе.
  2. Рабочее окружение — воспроизводимый локальный стенд, версии рантайма, docker compose, IDE и отладка, инструменты проектирования.
  3. Сборка и зависимости — манифест и lock-файл, SemVer, транзитивные зависимости, воспроизводимая сборка, артефакты и кэш.
  4. Качество в потоке — лестница автоматических ворот, линтеры и типы, тесты в CI, покрытие, флаки-тесты, ревью.
  5. CI/CD — граница между integration, delivery и deployment, анатомия конвейера, фича-флаги, стратегии выката, метрики DORA.

Блок III — как система живёт.

  1. Конфигурация и окружения — одна сборка и пять окружений, иерархия источников конфигурации, секреты и их ротация, дрейф.
  2. Масштабирование — куб масштабирования, поиск узкого места, эволюция от MVP до распределённой системы и обратно.
  3. Эксплуатация и эволюция — наблюдаемость, инциденты, постмортемы, техдолг, легаси и удушающая смоковница.

8. Три маршрута чтения

Трек рассчитан на последовательное чтение, но не обязан читаться так.

Если вы junior и хотите увидеть картину целиком — читайте подряд, 00 → 13. Главы намеренно не требуют предварительного знания конкретных технологий: там, где нужна база, стоит ссылка на трек intro.

Если вы уже пишете код, но не понимаете, что происходит после git push — начните с блока II: 06 → 07 → 08 → 09 → 10, затем 11. Это самая частая дыра у людей, пришедших из учебных проектов: код писать умеют, довести до пользователя — нет.

Если вы проектируете новую систему или разбираете старую — 05 → 03 → 04 → 12 → 13. Это маршрут про форму системы, её данные, её стыки и её будущее.


9. Что считать результатом

Проверка усвоения — не «знаю термины», а «могу ответить на вопросы».

  • Куда я положу эту логику: на клиент или на сервер, и почему?
  • Что произойдёт с этим запросом, если база ответит за 30 секунд вместо 30 миллисекунд?
  • Какое хранилище подходит под эту форму запросов и этот объём?
  • Что случится с клиентами, если я перееименую поле в ответе API?
  • Сколько экземпляров моего приложения можно запустить прямо сейчас, ничего не меняя?
  • Через сколько минут после коммита я узнаю, что сломал сборку?
  • Что именно я увижу в логах и метриках, когда это упадёт в три часа ночи?
  • Что я откачу первым действием, если выкат оказался плохим?

Если на все восемь есть внятный ответ — трек сделал свою работу.


Мини-итог

Разработка — это не набор технологий, а три контура обратной связи вокруг одной системы: контур кода, контур поставки и контур эксплуатации. Клиент отвечает за удобство, сервер — за истину, хранилище — за долговечность, контракт — за возможность меняться независимо. Форма системы (монолит, сервисы, события) — это решение о стоимости изменения, а не о современности. Всё остальное в этом треке — детали того, как эти утверждения работают на практике.

Источники

  • Len Bass, Paul Clements, Rick Kazman. Software Architecture in Practice, 4th ed. — каноническая схема разбора шаблонов «контекст / задача / решение».
  • Martin Fowler. Patterns of Enterprise Application Architecturehttps://martinfowler.com/eaaCatalog/
  • Nicole Forsgren, Jez Humble, Gene Kim. Accelerate — эмпирическая связь инженерных практик с результатами бизнеса.
  • Dan McKinley. Choose Boring Technology — https://mcfunley.com/choose-boring-technology
  • Martin Fowler. Bliki — https://martinfowler.com/bliki/ (короткие статьи по большинству тем этого трека).

Что дальше

Начнём с той части системы, которую видит пользователь, и с главного правила стыка: клиент отвечает за отклик, сервер — за истину.

Клиентская сторона: что происходит на стороне пользователя

Нашли неточность? Выделите фрагмент текста — рядом появится жучок.

Нужен разбор именно вашей ситуации?

Статья описывает общий случай. Если у вас частный — можно разобрать его отдельно, платно. А если не хватает целого материала, предложите тему: её оплачивают вскладчину, и она выходит открытой для всех.

Доска запросов