SOLID: Low Coupling против читабельности

в 12:16, , рубрики: readability, solid, архитектура, структура программы, читабельность кода
Про применение термина Low Coupling

С переводом терминов Low Coupling и High Cohession есть путаница. Чтобы её избежать - я буду применять эти термины без перевода.

Кратко

  • SOLID улучшает coupling, но ухудшает читабельность

  • Для большинства проектов читабельность важнее связности

  • В начале разработки проекта делайте упор на читабельность и ясность

Как выглядит SOLID система

Давайте воссоздадим небольшой кусочек программы, который будет максимально приближен к SOLID. Этот пример я взял из курса Роберта Мартина по архитектуре (программиста, который и собрал вместе принципы SOLID).

Вот с такого минимального набора классов мы начинаем. Контроллер работает с http. Он достаёт данные из запроса, создаёт типизированную DTO и передаёт её в UseCase. Последний является точкой входа в ту часть приложения, которая не знает про http.

SOLID: Low Coupling против читабельности - 1

Давайте применим к этой структуре все принципы SOLID. На выходе мы получим вот это:

SOLID: Low Coupling против читабельности - 2

Что здесь происходит? Рассказываю. Controller использует UseCaseFactory, чтобы создать UseCaseActivator. Потом он использует RequestBuilder, чтобы заполнить RequestDTO. Так как DTO находится на стороне UseCase'а - UseCaseActivator принимает не её, а вырожденный интерфейс Request (интерфейс маркер). Который попадая в UseCase downcast'ится к RequestDTO. И вот UseCase начинает свою работу.

Я не буду разбирать, почему структура именно такая, и как она соотносится с принципами SOLID. Если хотите, то посмотрите это в оригинальном курсе (Clean Coders: Clean Code - эпизоды 7, 14 и 18. Есть на торрентах).

Будьте уверены, что увидев эту структуру у себя на проекте, вы подумаете, что это шутка по типу FizzBuzzEnterprise. Но нет. Это 100% SOLID структура от человека, который собирал и представил миру SOLID принципы.

Здесь я хочу донести одну мысль. Система, полностью построенная по SOLID, обладает отвратительной читабельностью. Это не значит, что принципы SOLID не работают. Если вы в 20 человек пишете desktop приложение на Java, которое можно расширять с помощью jar файлов - без SOLID можете даже не начинать. У меня есть опыт работы с командой, которая решила положиться на структуру фреймворка, а не на SOLID, когда писала свой монолит. Каждые несколько недель мы посылаем им bug report'ы, потому что на их стороне сломалось что-то, что ранее работало. Моя мысль лишь в том, что SOLID ухудшает читабельность. И про это написана вся эта статья.

Какую цель преследует SOLID

Роберт Мартин считает, что главным свойством архитектуры является "возможность откладывать принятие решений как можно дольше". В пример приводится его проект (Fitnesse), в котором они откладывали реализацию реляционной базы данных. А к концу разработки поняли, что лучшим вариантом будет хранение данных в обычной файловой системе. Откладывание решения о внедрении реляционной СУБД позволило им найти более производительный вариант хранения без потери в функциональности. Принципы SOLID работают в том же направлении. Они позволяют откладывать решения, а так же создавать структуру, в которой старые решения не будут изменяться под влиянием новых.

Так же одним из частых обоснований при объяснении принципов SOLID является возможность не перекомпилировать части приложения. Например при изменении компонента, связанного с базой данных, вам не нужно перекомпилировать компоненты предметной области, так как зависимости между ними инвертированы (БД зависит от domain, а не наоборот).

А теперь представьте, то вы разрабатываете web-приложение. В качестве языка вы выбрали PHP. В качестве framework'а - Laravel. И у вас точно будет MySQL или Postgress.

Ваш язык - интерпретируемый. Значит проблемы перекомпиляции у вас нет. SOLID и Clean Architecture говорят вам, что вы должны абстрагироваться от framework'а и СУБД. А значит вы не сможете использовать возможности фреймворка из классов бизнес-логики. А так же не сможете делать SQL запросы из UseCase'ов. Для всего этого вам понадобятся абстракции и инверсия зависимостей.

Вы защитили себя от изменений СУБД, framework'а и перекомпиляции. Но ни первое ни второе скорее всего никогда не изменится. А интерпретируемый язык решает все проблемы, связанные с перекомпиляцией. Вы получили в 3 раза больше файлов. При этом решив несуществующие на вашем проекте проблемы.

Так получилось, потому что SOLID нацелен на low coupling. Проблемы, которые он решает, появляются на больших и сложных проектах (>100'000 строк кода, а бизнес логика имеет много инвариантов). И в них он безусловно полезен. Но если ваш проект проще и меньше, есть много других, более полезных принципов архитектуры.

Свойства программной системы

Я предлагаю отслеживать у программ 3 показателя:

  • Low Coupling - как разные компоненты системы влияют друг на друга. Если при изменении в одном модуле вам приходится так же вносить изменения в большое кол-во других модулей, то у вашей системы high coupling. Каждое изменение требует больше времени, и может сломать те места, которые концептуально не связаны с изменённым кодом;

  • Читабельность - насколько легко программисту понять, что делает программа. Хорошие абстракции, унификация терминов и простой поток передачи управления делают программу простой для понимания. Программисту не приходится прыгать из файла в файл. Он точно знает, в какой файл пойти, чтобы исправить какое-то поведение. А читая код строка за строкой он будет понимать, в каком состоянии сейчас находится система, и как та или иная команда это состояние меняет;

  • Производительность - насколько быстро ваша программа работает и как мало памяти она использует. Чем быстрее работает приложение и чем меньше памяти она использует - тем лучше.

Улучшая один показатель мы непременно ухудшим 2 других. Это можно отобразить на следующей схеме:

SOLID: Low Coupling против читабельности - 3

Ваша программа будет точкой на этой схеме. Она может находиться в углу с производительностью, если вы делаете высоконагруженное приложение. Может находится справа, между читабельностью и low coupling, если вы делаете обычный CRUD. Может быть строго вверху в low coupling, если это большой модульный монолит.

SOLID: Low Coupling против читабельности - 4

На такой схеме легко понять, что делают с программой принципы SOLID. Они утягивают её от производительности и читабельности в сторону low coupling. Про это был большой спор между Робертом Мартином и Кейси Муратори (да, они спорили в markdown файлах на github, что вы им сделаете).

Я считаю важным запомнить эту закономерность. SOLID улучшает low coupling, но ухудшает читабельность и производительность. Не во всех приложениях нужен low coupling. А значит при их разработке не имеет смысла ухудшать остальные два показателя и сильно заострять своё внимание на следованию принципам SOLID.

С чего начинается читабельность

Предположим вы проанализировали своё приложение, и поняли, что читабельность для него важнее, чем low coupling. На каких принципах вам основывать свою архитектуру? С чего начать?

Готовые абстракции. В вашей сфере уже есть готовые паттерны для решения задач. Начните с их использования. Возьмите те, что предлагает ваш фреймворк. Вставляйте их названия в имена файлов. Например в web-разработке устоявшимися абстракциями будут: страницы, контроллеры, репозитории, запросы, ответы и т.п.

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

Транзакционный сценарий. Организуйте свою программу на основе транзакций. Это функции, которые либо выполняются полностью и изменяют состояние системы, либо не завершаются и, как следствие, не должны изменять состояние. Такая функциональность есть в реляционных СУБД. Перенесите эту идею в свой код.

Подробнее про читабельность и организацию кода вокруг неё вы можете узнать из книг:

  • "Изучаем DDD - предметно ориентированное проектирование" - Влад Хоносов

  • "Код, который умещается в голове" - Марк Симан

Заключение

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

Но чем дольше я работал над этими приложениями, тем чаще я стал замечать, что их low coupling начинает нас путать. У нас была большая фора по low coupling, которая заставляла нас прыгать от файла к файлу больше, чем было нужно. И тогда я пришёл к осознанию того, о чем написал в этой статье. Я перешёл от верхней точки треугольника "low coupling" немного ближе к читабельности. И очень доволен своим выбором.

Надеюсь я смог помочь и вам. Напишите в комментариях, что вы думаете про SOLID и про предмет обсуждения. Это моя первая статья на Habr. Я написал её за одну ночь, и решил стразу выложить, чтобы она не пылилась на моём диске, как много других недописанных мною статей. Если статья хорошо зайдет - буду писать еще. У меня много идей, которыми я хочу поделиться.

Автор: MrShnaider

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js