Все практики хорошей архитектуры базируются на идее того, что требования будут меняться - и именно чтобы облегчить последующую поддержку - мы добавляем абстракции, паттерны, следуем SOLID-у и вот это вот все. Это, кстати, делает проектирование ПО очень сильно отличающимся от других видов разработки. Например, при проектировании моста никому в голову не придет на середине строительства превращать подвесной мост в разводной - а при разработке ПО считается, что проектировать надо так чтобы в любой момент любой слой можно было заменить безболезненно - переходя от реляционной БД к документно-ориентированной и обратно.
Беда в том, что спроектировать систему и угадать - какие именно будут изменения - а значит какие именно абстракции нужны - практически невозможно - а значит все эти абстракции оказываются избыточными - и в тоже время отказ от абстракций делает код трудно поддерживаемым. В шахматах такая ситуация - когда любой ход только ухудшает ситуацию - называется цугцвангом.
Представим себе молодого или не очень разработчика с несложной задачей - написать сервис который что-то получает по http, как-то элементарно меняет и отдает это в кафку (ETL-сервис). Если использовать высокоуровневые фреймворки - то код который все это выполняет уместится в 10 строк (не считая конфига). Но наш разработчик знает что должен быть слой контроллеров и слой сервисов. Далее, он задумывается - “что если завтра надо будет слать не в кафку в еще куда-то” - и делает абстрактный сендер с реализацией кафка сендер. А что если слать надо будет в разные топики - в зависимости от тела запроса? И он делает абстрактный тополоджиРесолвер с единственной реализацией - конкретным топиком. И, кстати, делает абстрактный бодиКонвертер - вдруг завтра поменяется формат передаваемых данных, абстрактный же мессаджКонвертр - вдруг завтра надо будет слать сообщения в другом формате.. Наконец. добавляет абстракцию фильтров, обработчиков ошибок отправки, обработчиков успешной отправки, слой репозитария (с пустой реализацией)… и гордо выставляет это на прод. Проходит полгода - приходит молодой сотрудник которому он передает код. И молодой сотрудник видит семь абстрактных классов и две абстрактные фабрики - с пустыми реализациями. И у него возникает сложнопреодалимое желание запихнуть в жопу предшественнику всю банду четырех - вместе с Мартинами (Фаулером и Робином) в придачу.
Но возможна и другая ситуация - первый разработчик не заморачивается абстракциями - а фигачит все в контроллере - один метод на который мапится POST-запрос - в нем и преобразование данных и отправка в кафку. Но - проходит месяц и его просят добавить фильтр, слать не только в кафку но и писать в базу, при ошибке отправлять емэйл - в итоге он по чуть-чуть “дописывает” свой код - превращая его в макарону. Проходит пол года - он передает код другому сотруднику - тот видит макаронину кода и исполняется желанием запихнуть в жопу предшественнику всю банду четырех…
Есть еще вариант найти “почти готовое решение” для задачи - типа апач кэмела, спринг интегрешенала или кафкаконнекта - в которых “все работает из коробки” и задачку “переслать POST-запрос в кафку” можно сделать вообще без кода . Но пройдет пол года, сервис передадут другому человеку, его потребуется доработать - что потребует уже чуть более глубокое знание этих фреймворков - и поддерживающий будет думать - какого хрена здесь этот фреймворк вместо того чтобы самому написать 30 строк тривиального кода - разбирайся теперь с ним, да еще и обновляй до последней версии… Я успел побывать во всех ролях - и передавал код-макаронину, и передавал равиоли-код с кучей абстракцией. И брал в поддержку код с безумным количеством слоев и брал в поддержку код с методами на 7000 строк делающими все что можно.
Очень редко но бывало и так что абстракция прям “подошла” когда для запуска сервиса с новыми требованиями хватило лишь добавить новую реализацию - но, увы, это редкость. Вывод из этого только один - принять как должное, что предугадать в каком направлении будет меняться проект - практически не реально. И если “не угадали” - не испытывать комплекс самозванца. Относиться к “гибкой архитектуре” и “бест практикс” с уважением - но без фанатизма - не ленясь разбивать код по слоям и сервисам - но только тогда когда это действительно нужно - а не городя фасад абстрактных генераторов в трех строчках кода.


Судя по тенденциям с работой и зарплатами, думать и ломать голову над архитектурой = облегчать работодателю замену тебя на более дешевого вкатыша, т.е. плохая практика :)