Какой самый популярный стиль организации кода вы встречали в корпоративных кодовых базах? Лично я чаще всего видел решение, подразумевающее группировку всех файлов по их типу. Таким образом, к примеру, в системе MVC все контроллеры, все сервисы, все репозитории, все POJO и так далее находятся вместе. Давайте назовем такое решение "стековым" стилем организации кода.
Это ужасный способ организации кода, и далее я объясню почему. Но сначала позвольте мне представить альтернативу.
Гораздо более удачный способ организации - группировка файлов по логической составляющей. Назовем это "смысловым" стилем организации кода. Идея состоит в том, чтобы держать вместе все файлы и классы, связанные с одной концепцией. Ставя смысловую составляющую на первое место, мы оптимизируем организацию кода для человеческого понимания (компиляторам все равно, куда вы помещаете какой файл). Обращая внимание в первую очередь на то, за какую часть проекта отвечает конкретный код, разработчики приходят к более разумному пониманию фактических границ системы.
Теперь давайте разберемся, почему я считаю, что смысловая модель лучше, чем модель стека.
Неправильная абстракция
Люди не читают код по назначению файлов и классов. Никто никогда не говорит: "покажите мне весь API проекта" или "продемонстрируйте мне все запросы, отправляемые решением". Люди читают код, полагаясь на его смысл и роль. Как в системе управления гостиницами, например, люди отдельно думают о номерах, гостях, ценах и так далее.
Поскольку стековый стиль организован по типу кода, трудно понять логическую модель системы. Мы не можем понять основные составляющие проекта и отношения между ними. Для этого приходится копать на один уровень глубже. Для человека, впервые читающего код, это является огромным источником неприятностей.
В нашем примере с управлением гостиницей, организованном смысловым стилем, весь код, связанный с гостями (независимо от технического назначения), помещён в один пакет, весь код, связанный с номерами, - в другой и так далее. Каждый из этих пакетов может иметь свою собственную внутреннюю организацию в стиле "стека" или просто несколько классов на одном уровне. Это позволяет легко найти все, что связано, скажем, с гостями, в одном месте.
Нарушения связи
Многие разработчики считают, что "стековая" организация все же выигрывает, отделяя разные слои кода друг от друга. Чтобы найти необходимые классы или файлы на любом уровне проекта, нужно просто перейти к слою, содержащему эти уровни. Это, безусловно, способствует разделению слоев друг от друга.
Проблема этого аргумента в том, что он фокусируется на разделении, но полностью игнорирует потребность в связи между определёнными структурами. Допуская, что все файлы и классы определённого типа в такой системе расположены вместе, справедливо ли будет сказать, что их взаимная связь, как структур одинакового назначения, но разного смысла, нас устраивает? Положено ли все же, к примеру, контроллерам, находиться отдельно от своих классов и репозиториев? Можем ли мы позволить, скажем, всем репозиториям быть сильно зависимыми друг от друга, но отделенными от уровня сервисов? Очевидный ответ - НЕТ! Такой код стал бы хрестоматийным куском г*вна. Рефакторинг такой системы на более мелкие решения был бы абсолютным кошмаром, потому что вам пришлось бы отделить друг от друга все классы на каждом уровне стека. Это убивает основную цель использования стиля MVC.
Стиль "смысла" способствует установлению связей между различными узлами проекта, связанными исключительно областью применения. Это также облегчает будущий рефакторинг, поскольку логические границы более ясны, чем в стиле "стека". В добавок, как я уже сказал, внутри этих логических границ нам ничего не мешает при необходимости устроить "стековую" организацию и наслаждаться разделением структур разного назначения.
Трудно менять
Чтобы внести какие-либо значимые изменения в кодовую базу, организованную в "стековом" стиле, например добавить новое поле к структуре и модернизировать ее API, разработчик должен прошерстить несколько пакетов и изменить каждый из них. Это создает бессмысленную когнитивную нагрузку, поскольку разработчику приходится модифицировать множество "вещей", а не одну логическую вещь.
В "смысловом" стиле, если вы что-то меняете, вы вносите изменения только в пределах одной логической границы. Это облегчает внесение изменений, поскольку, меняя только один объект, мы работаем только в очень небольшой части кодовой базы.
Ограничивает выбор дизайна
Поскольку код организован из соображений функциональности, он ограничивает возможности людей подходить к дизайну системы. Например, поскольку логика предметной области должна относиться к "сервисам", разработчики противятся использованию правильно разделённых конструкций и запихивают все в сервисы, создавая тем самым кошмарные классы длиной в тысячи строк.
"Смысловой" же способ не ограничен определённым набором функциональных понятий, внутри которых будет организован код. Используя его, разработчик может создавать неограниченное количество смысловых групп файлов и классов, создавая наиболее приемлемую для конкретного проекта дизайн-модель.
Способы
Автор: Айдар