Мы любим говорить о техническом долге. Это монстр под нашей кроватью, виновник медленных спринтов и разочарованных разработчиков. «Нам нужно провести рефакторинг», — кричим мы. «Базовое кодовое хранилище — беспорядок!» — протестуем мы на ретроспективах. Но вот неудобная правда, которую никто на вашем последнем совещании по архитектуре не хотел услышать: иногда настоящий виновник — это не быстрые исправления и короткие пути. Иногда всё наоборот — мы создали нечто слишком хорошее для того, что на самом деле нужно было сделать.
Чрезмерная инженерия — злой близнец технического долга, за исключением того, что этот близнец приходит на корпоративную вечеринку в дорогом костюме, впечатляет всех модными словечками и тихо разрушает вашу скорость, пока все аплодируют.
Парадокс, о котором никто не говорит
Позвольте мне описать ситуацию. Вы находитесь на третьей неделе нового проекта. Требования кажутся простыми: создать пользовательскую панель. Простые вещи. Но потом что-то происходит. Может быть, вы только что прочитали статью о событийно-ориентированной архитектуре. Может быть, вы в восторге от нового фреймворка, о котором все говорят. Может быть, в прошлом вы обожглись на проблеме масштабируемости и решили никогда больше не допускать этого.
Прежде чем вы это осознаете, вы разработали решение, которое имело бы смысл для продукта, обслуживающего миллионы пользователей. За исключением того, что вы обслуживаете 50 бета-пользователей, которые просто хотят видеть свои данные.
Вот жестокая ирония: то, что выглядит как надёжная инженерия, часто становится тем же бременем, которое создаёт неустранимый унаследованный код. Оба варианта замедляют вас. Оба разочаровывают вашу команду. Оба усложняют эволюцию вашего продукта. Единственная разница в том, что с унаследованным кодом, по крайней мере, есть оправдание — кто-то создал его быстро в 2015 году. С чрезмерно спроектированным кодом вы сами выбрали это.
Чрезмерная инженерия не ощущается как принятие технического долга. Это ощущается как противоположность. Это ощущается ответственным. Профессиональным. Как будто вы строите «правильно». И именно поэтому это так опасно. Вы создаёте долг, чувствуя себя при этом добродетельно.
Почему мы попадаем в эту ловушку
Прежде чем мы сможем что-то исправить, нам нужно понять, почему умные люди — включая вас, вероятно — продолжают совершать эту ошибку.
Разрыв MVP
Наиболее распространённая причина — слишком раннее или слишком агрессивное отказ от философии минимально жизнеспособного продукта. MVP должен быть скучным. Он должен решать одну проблему, делать это хорошо и ждать обратной связи от пользователей. Но человеческая природа — и особенно природа разработчиков — восстаёт против скуки.
Для менее опытных команд соблазн почти неотразим: «Пока мы создаём это, давайте также добавим эти три другие функции». «Схема базы данных должна поддерживать этот будущий вариант использования». «Давайте сделаем так, чтобы это работало с этой другой системой, с которой мы возможно интегрируемся позже». Каждое решение имеет смысл по отдельности. Вместе они создают налог на сложность, который ваш текущий продукт не должен платить.
Ловушка опыта
Вот что вам не говорят в программистских bootcamp: опыт может работать против вас. Разработчики с многолетним опытом борьбы со масштабируемыми катастрофами становятся чрезмерно осторожными. Вы видели, что происходит, когда вы не планируете рост. Поэтому вы перепланируете. Вы строите крепость до того, как кто-либо попытается её атаковать.
Проблема? Большинство атак так и не происходит. И крепость, которую вы построили, становится лабиринтом, замедляющим вашу собственную команду.
Соблазнение технологиями
Мы работаем в отрасли, одержимой блестящими новинками. Каждая конференция продаёт вам последний фреймворк. Каждая страница трендов GitHub шепчет: «Вы могли бы использовать это…» И использование этого ощущается как инновация. Как будто вы не застряли в унаследованном мире.
Технический термин — «убивать муравья из базуки» — использование сложных решений, когда подойдут простые. Вам не нужен сложный потоковый платформа для системы флагов функций. Вам не нужна распределённая трассировка инфраструктуры, когда у вашего монолифа всего 10 API-интерфейсов.
Изолированные знания
Когда информация живёт в голове одного человека, команда компенсирует это, создавая защитную сложность. Вы добавляете уровни, потому что боитесь что-либо менять. Вы создаёте абстракции поверх абстракций, потому что не до конца понимаете существующие. Без общих знаний в команде более простые решения кажутся рискованными. Поэтому вы предпочитаете чрезмерную инженерию.
Реальная стоимость чрезмерной инженерии
Давайте поговорим о конкретном влиянии, потому что это не теоретический вопрос. Чрезмерная инженерия создаёт ощутимый, измеримый ущерб.
Разработка превращается в археологию
Сильно перепроектированный кодовый базис требует значительного времени только для понимания. У вас есть три уровня абстракции между HTTP-запросом и бизнес-логикой. У вас есть пользовательская событийная структура, которая делает то, что мог бы сделать простой обратный вызов. Разработчики тратят половину спринта на расшифровку запутанных реализаций вместо создания функций.
Новые члены команды? Они потеряны на несколько недель. Вы не можете просто прочитать код — вам нужен кто-то, кто объяснит грандиозное архитектурное видение. Это не инженерное совершенство. Это тюрьма знаний.
Сложность нарастает
Вот что меня убивает в чрезмерной инженерии: она создаёт больше технического долга, а не меньше. Замораживая архитектуру в чрезмерно жёсткие конструкции, вы теряете гибкость, которую, как вам казалось, вы приобрели. Масштабируемость, которая казалась важной во время планирования, может не поддержать даже базовые бизнес-потребности, как только они изменятся.
Вы строили для горизонтального масштабирования, но ваша реальная узкое место находится в обработке платежей. Вы создали архитектуру микросервисов для модульности, но зависимости между сервисами создают худшую связь, чем оригинальный монолит. Вы оптимизировали то, что на самом деле не было проблемой.
Инновации останавливаются
Когда большая часть времени разработки уходит на преодоление сложности, инновации останавливаются. Новые функции занимают в три раза больше времени для реализации. Исправления ошибок требуют археологических экспедиций по кодовому базису. Ваш продукт стагнирует, пока ваша команда выгорает.
Расходы взлетают
Это ударяет по бизнесу: чрезмерная инженерия увеличивает расходы на разработку и обслуживание без соответствующего увеличения ценности. Ваша инфраструктура становится сложнее, поэтому ваша оперативная команда растёт. Ваш код сложнее поддерживать, поэтому ваша скорость разработки падает. Вы тратите больше, чтобы получить меньше.
Прагматизм: золотая середина
Так каков ответ? Не «просто сделайте это просто» — это другая крайность, ведущая к другому виду катастрофы. Не «строить на будущее» — мы установили, что это ловушка.
Ответ — прагматизм. И прагматизм сложнее, чем любая крайность.
и ломитесь напролом"] -->|последствия| B["Спираль технического долга"] C["Чрезмерная инженерия
и планирование всего"] -->|последствия| D["Паралич сложности"] E["Прагматизм:
намеренные
решения"] -->|приводит к| F["Устойчивая
скорость"] style E fill:#90EE90 style F fill:#90EE90
Прагматизм означает задавать сложные вопросы перед реализацией:
Действительно ли это критически важно для успеха продукта прямо сейчас? Не «может быть полезно когда-нибудь». Не «мы должны предусмотреть будущее». Прямо сейчас, на этом этапе продукта, решает ли это проблему, которая имеет значение? Если ответ что-то меньшее, чем «абсолютно да», не делайте этого.
Какое самое простое решение решает эту проблему? Не «простое» в ленивом смысле. Но «простое» в смысле ясности, поддерживаемости и минимального количества движущихся частей. Можете ли вы решить это с помощью одного сервиса вместо трёх? Можете ли вы использовать таблицу Postgres вместо распределённой очереди?
Каков наш явный компромисс? Каждое решение, направленное на избежание сложности, имеет свою цену в виде скорости. Каждое решение, принимающее сложность, имеет свою цену в виде будущего обслуживания. Искусство заключается в том, чтобы знать, какую цену вы должны заплатить прямо сейчас. Может быть, вы принимаете некоторый беспорядочный код сегодня, чтобы успеть к рыночному сроку. Может быть, вы инвестируете в чистую архитектуру, потому что знаете, что это основа на следующие пять лет.
Формулируйте свои технические решения в бизнес-терминах: время безотказной работы (не стройте распределённые системы, если они вам не нужны). Скорость (простые архитектуры позволяют двигаться быстрее). Функции (не тратьте инженерные ресурсы на инфраструктуру, которая не открывает новые возможности).
Практические шаги, чтобы оставаться на земле
1. Ввести безжалостный обзор кода
Обзоры кода нужны не только для исправления ошибок. Они ваш предохранитель от чрезмерной инженерии. Когда кто-то предлагает новую абстракцию, новый сервис или новый фреймворк, заставьте их его обосновать.
Спросите: «Какую проблему это решает?» «Что произойдёт, если мы сделаем это более простым способом?» «Кто ещё понимает этот подход?»
Хорошие рецензенты кода — это архитектурные терапевты. Они помогают людям отделить подлинные инженерные потребности от архитектуры, ориентированной на резюме.
**2. Ежекварта
