Страницы

Поиск по вопросам

вторник, 31 декабря 2019 г.

Зависимости между слоями архитектуры

#архитектура


Читаю Чистая архитектура. Искусство разработки программного обеспечения и что-то
понять формулировку к картинке не могу...




  Круги на рис. 22.1 лишь схематически изображают основную идею: иногда
  вам может понадобиться больше четырех кругов. Фактически нет никакого
  правила, утверждающего, что кругов должно быть именно четыре. Но
  всегда действует правило зависимостей. Зависимости в исходном коде
  всегда должны быть направлены внутрь. По мере движения внутрь уровень
  абстракции и политик увеличивается. Самый внешний круг включает
  низкоуровневые конкретные детали. По мере приближения к центру
  программное обеспечение становится все более абстрактным и
  инкапсулирует все более высокоуровневые политики. Самый внутренний
  круг является самым обобщенным и находится на самом высоком уровне.


Разве все не с точностью наоборот и самый внешний слой является наиболее абстрактным
и чем ближе к центру тем менее абстрактно все становится? 
    


Ответы

Ответ 1



Мне кажется, на проблему надо посмотреть исторически. Есть шанс разобраться, почему Мартин называет абстрактное абстрактным. Понятие уровня или слоя оформилось в середине 80-х. Оно возникло из-за постепенного увеличения размера программ. Вначале программисты писали одну программу, потом стали разбивать её на функции, потом на модули, и, наконец, настало время, когда число модулей в программе перевалило за сотню. Естественным решениям стало группировать модули по глобальной ответственности. Часть из них отвечало за представление данных, часть за хранение, и часть за обработку. Такой способ управления сложностью мы называем трёхзвенной или трёхуровневой архитектурой. Одним из правил трёхзвенной архитектуры является чёткое направление зависимостей сверху вниз. Вверху уровень представления, он зависит от уровня предметной области (она же бизнес-логика), который в свою очередь зависит от уровня доступа к данным. Три уровня и между ними две стрелки — зависимости. Где в этой картинке абстракции, а где детали? Если присмотреться, то нигде. Понятие абстрактного типа данных хорошо формализовано. В объектно-ориентированных языках программирования ему соответствуют интерфейсы или абстрактные классы, чью реализацию мы можем написать. Реализация и является деталью. В классической трёхзвенной модели вполне можно обойтись без абстракций. Абстракции появляются, когда мы хотим изменить способ хранения. В идеальном случае нам было бы достаточно заменить один слой, слой доступа к данным. Но от него в трёхзвенной архитектуре зависят два верхних слоя, значит, придётся переписывать и их. Получается, если мы хотим перейти с MySQL на Postgres, или на MongoDB, нам придётся переписывать всё приложение. Накладно. Именно так возникает потребность в инверсии зависимостей. Мы говорим: да, наши объекты с уровня бизнес-логики где-то хранятся, но мы постараемся ограничиться минимальными знаниями о способе их хранения. Все наши ожидания, которые нужны на уровне бизнес-логики, мы оформим в виде интерфейса репозитория. Именно так в предметной области появляются интерфейсы, то есть те самые абстракции. Реализация этих интерфейсов остаётся на уровне доступа к данным. Теперь зависимость направлена от уровня доступа к данным и уровню бизнес-логики. Если нам потребуется изменить способ хранения, мы сделаем это безболезненно. У нас получается картинка, близкая к той, которую рисует Мартин. В центре находятся сущности и службы, которые имеют очень абстрактное представление о внешнем мире. Как показываются объекты пользователю? Как-то показываются. Как они хранятся? Как-то хранятся. Все представления о внешнем мире описаны в виде абстракций, то есть интерфейсов. Скажем, представления о хранении описаны в виде репозиториев. Снаружи на слой с абстракциями смотрят уровни с реализацией. Уровень представления знает про окна (или про HTTP-запросы) и умеет конвертировать сущности в формы или HTML. Уровень хранения знает про SQL и умеет конвертировать сущности в записи. Все ли классы на уровне предметной области абстрактны? Нет. То, что относится непосредственно к бизнес-логике, может быть описано конкретными классами. Но помимо них в слое есть абстракции, которые реализуются во внешних слоях. Если не все классы в центре абстрактны, почему весь уровень считается самым абстрактным? Потому что здесь абстракций больше всего. По мере продвижения наружу их количество убывает. Помимо прочего, классы из этого слоя живут в идеальном мире, окружённые сферическими конями в вакууме. Заказы состоят из Позиций, в которых указаны Товары и их Количество. Идеальный мир продаж. Снаружи этого мира живут авторизации, базы данных, транзакции, форматирование и другие важные вещи. Именно их Мартин и называет деталями реализации.

Ответ 2



Для того, чтобы понять эти абстрактные формулировки, нужно мыслить абстрактно :) Если читать эту формулировку то возникает вопрос, как же самый нижний уровень может быть абстрактным, когда на самом нижнем уровне находится конкретные и готовые классы моделей? Попробуем разобраться. Нижний уровень - самый абстрактный и независимый Весь смысл в том, что направленность зависимостей внутрь предполагает, что верхний уровень всегда что-то знает о нижнем, а нижний уровень ничего не знает о верхнем, в целом об этом часто говорится в книге. Модели (сущности, бизнес-объекты) сами по себе очень независимы в идеальной архитектуре, ведь говорится о том, что чем ниже уровень, тем сущности более абстрактны, но автор книги использует слово абстрактно не всегда в том понятии в котором вы привыкли его слышать программисты, автор не имеет ввиду что модели должны быть определены ключевым словом abstract или интерфейсом и на нижнем уровне не должно быть классов, ведь это абсурд. Подразумевается, что это абстрактные объекты нашей системы и они абстрактны тем, что у них нет знаний о том, кто и где их будет создавать, каким образом и куда их отправят и как их будут использовать. Предположим, в модели может быть метод получения какого-то значения (фио, адрес, телефон и т.д), с одним но, формат должен приходить извне, следовательно формат должно определить приложение, а модель об этом ничего не знает, в этом и есть пример абстрактности, что модель не всегда может знать о формате и тот кто ее использует вправе определить свой формат. Разберем пример на основе уровней Для начала стоит понять, что один уровень можно разбить на десяток уровней, а десяток уровней можно агрегировать в несколько и здесь все зависит от архитектора, как указано , кругов действительно может быть сколько угодно. Предположим, вы решили написать какую-то систему где есть пользователи, определяем сущность пользователя с помощью класса User, это наша доменная модель в которой мы будем содержать информацию о пользователе. Созданная нами сущность абстрактна, ведь мы не знаем где она будет использоваться и как. Например, нам доменном уровне нам не очень важно в каком алгоритме будет формироваться хэш пароля, пусть это определяют уровни выше. Далее, нам нужен уровень выше, который будет неким абстрактным адаптером (не с точки зрения паттернов проектирования) к хранилищу пользователей, поэтому мы определяем интерфейс UserRepository, содержащий описания методов для работы с хранилищем пользователей. Уровень довольно абстректен, ведь он не говорит как это нужно делать, но этот уровень чуть менее абстрактен и более зависимый относительно моделей, ведь он уже точно знает что он будет использовать модель User, определяет входные/выходные значения, но тут мы до сих пор не знаем, какое же будет хранилище? Файл, бд, api? Далее, на следующем уровне, нам уже нужна конкретная реализация этого абстрактного адаптера, поэтому мы создаем MySQLUserRepository, который уже знает о нижних двух уровнях, знает о том, как и где будет хранить и получать эти данные. С каждым уровнем, вы можете заметить, что он становится менее абстрактным и более зависимым от уровня ниже, на 3 уровне мы точно знаем что уже работаем с MySQL и какие команды мы посылаем.

Комментариев нет:

Отправить комментарий