Введение
День добрый, господа хорошие. На данный момент я в IT уже порядка 15 лет. Большую часть времени я был разработчиком, и даже уход в ветку менеджмента скорее дал толчок к работе над личными пет-проектами, чем к отказу от разработки.
За эти 15 лет было интересно наблюдать за изменением трендов, особенно вне энтерпрайз разработки. Самое интересное — это наблюдать, как технологии и паттерны циклически развиваются.
Парадокс сложной эффективности
Сегодня я хочу обсудить «Парадокс сложной эффективности». Давайте начнём с наглядного примера в игровой индустрии. Как многие из нас знают, в онлайн-играх есть система адаптивного баланса. Например, если какая-то техника слишком хорошо проявляет себя в игре, её боевой рейтинг повышается, и она будет сталкиваться с более сильной техникой.
Но есть нюанс: техника может быть мощной и сложной в использовании. Если в команде есть игрок, который умеет ей пользоваться, команда выигрывает с вероятностью 99%. Все знают это и пытаются играть на ней, но большинство не понимает, как это делать правильно, из-за чего техника не растёт в рейтинге, и триггер адаптивного баланса не срабатывает. В итоге, техника имеет плохой баланс и не приносит пользы большинству. Вот и пример «Парадокса сложной эффективности».
Применение в IT
Как это относится к текущим реалиям софтверной разработки? Рассмотрим многопоточность и производительность. Когда я начинал заниматься разработкой, многопоточность была чем-то сложным и не прощающим ошибок. Те, кто умел эффективно её использовать, писали отличные приложения, остальные тратили кучу времени на исправление дедлоков и утечек памяти. Приложения были эффективными, но их разработка занимала много времени и была дорогой.
Создатели языков начали добавлять синтаксический сахар, чтобы упростить работу и уменьшить вероятность ошибок. Работал ли этот код в многопоточном режиме? Ну в целом да, так же быстро. Но есть нюанс. Сахара становилось всё больше, и «ну в целом да» работало относительно предыдущего сахара, а вот относительно начала скорее нет.
Помните чудесный и прекрасный MVC, разработанный Xerox в 1979 году? А N-Tier из 90-х годов и Onion Architecture начала 2000-х?
Эти технологии решали проблемы своего времени. Они предлагали инструментарий для решения проблем. Если кто-то скажет вам, что они простые – киньте в него камнем. С ростом проекта всегда становилось сложнее разделять слои, приходилось вспоминать паттерны и думать над организацией кода. Ожидаемо что очень много проектов начали скатываться в «спагетти-код» и иже с ним.
Что с этим делать? Правильно, давайте перейдём на новый уровень витка. Просто разрежем это на мелкие приложения и сделаем кучу микросервисов. И что мы слышим? Да, крики общественности такие как «Долой все эти MVC, N-Tier!», «Зачем мне многослойка для CRUD API, работающего с одним ресурсом?».
Хорошо, хотите микросервисы – получайте новый набор инструментов:
API Gateway, Saga, Circuit Breaker
Bounded Context, Decompose by Business Capability, Decompose by Subdomain
Consolidate by Ownership, Merge by Functionality, Aggregate by Usage
В своё время мне очень понравилась фраза Мартина Фаулера, которая в моих кругах общения почему-то не обрела популярности.
While I do accept that there are valid reasons to go for a distributed design for many systems, I do think distribution is a complexity booster. A coarser-grained API is more awkward than a fine-grained one. You need to decide what you are going to do about failure of remote calls, and the consequences to consistency and availability. Even if you minimize remote calls through your protocol design, you still have to think more about performance issues around them.
Заключение
Что мы получили в итоге:
Проекты, в которых количество микросервисов перевалило за тысячу штук.
Проекты, в которых чек за логирование и трейсы стоит больше, чем вся остальная инфраструктура.
Проекты, в которых Cold Start однопоточных FaaS решений дольше, чем время выполнения кода.
Что мы слышим в общественности? Всё довольно ожидаемо:
Да здравствуют монолиты!
Даёшь хардкорный Си!
Даёшь Rust!
Почему так происходит? Потому что мы выбираем технологию, в которой кто-то успешен. Когда не выходит, говорим, что она устарела и переходим к следующей успешной технологии. Это и есть циклический «Парадокс сложной эффективности». Как говорится в басне Крылова:
«Тьфу пропасть! — говорит она, — и тот дурак,
Кто слушает людских всех врак;
Всё про Очки лишь мне налгали;
А проку на-волос нет в них».
...
К несчастью, то ж бывает у людей:
Как ни полезна вещь, — цены не зная ей,
Невежда про неё свой толк все к худу клонит;
А ежели невежда познатней,
Так он её ещё и гонит.
Итак, когда вы собираетесь сказать, что какой-то инструмент плох, и готовы кричать об этом, может быть, вы его не к тому или не так прикладываете? =)
Дополнительные референсы:
Martin Fowler о микросервисах: martinfowler.com
Многослойная архитектура: Wikipedia
Луковая архитектура: Jeffrey Palermo's blog
История MVC: Wikipedia