Автор: Sergey Teplyakov

У лука есть слои, и у людоедов есть слои! Ты понял? - Шрек

Эта заметка навеяна выступлением Jimmy Bogard на 0redev под названием Solid Architecture in Slices not Layers, которую я всячески рекомендую.

Как и у людоеда, у любого современного приложения есть слои. Классической моделью является мордочка наверху, бизнес-логика по центру и базейка снизу. Такое разделение вполне уместно и определяется множеством причин.

Conways Law

Любой сложный проект требует вовлечения людей с разной специализацией и интересами. Кто-то пилит базы данных, кто-то лабает UI, а кто-то отвечает за логику. Такое разделение позволяет людям специализировать, а менеджеру масштабировать разработку: выделяя группы и подгруппы, отвечающие за отдельные куски.

Такой разделение еще сильнее выстраивает барьеры между слоями приложения, поскольку тут начинает во всей красе проявляться Conways Law, когда архитектура приложения начинает повторять структуру организации.

Повторное использование слоев

Реюз это наше все. Мечта с детства и все такое.

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

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

Проблема

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

Давайте посмотрим, как сейчас обычно пилят софт: команда разработчиков вытягивает очередной сторик из бэк-лога, бодро оценивает его в 22 попугая, выясняет приоритет у мудрого заказчика, и приступает к делу.

Если задача видна пользователю (а именно ради этих зануд мы клавиатуры и топчем), то это значит, что полученный функционал с гарантией в процентов 90% будет покрывать разные слои. Нужно добавить новую формочку? Ок, нужно сделать новую вьюху, потом вью-модельку (или контроллер, или презентер), добавить модельку, поменять что-то в слое доступа к данным, прикрутить новую табличку в базу и добавить туда вьюшку или хранимочку.

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

Так вот, помимо небольшого периода времени в начале проекта, основные задачи команды являются сквозными и затрагивают множество слоев приложения.

Давайте вспомним, как выглядит классическая архитектура:

clip_image001 clip_image002

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

А что предлагается? А предлагается сделать сэндвич: взять инфраструктуру снизу/сверху, а внутрь расположить компоненты, связанные по функциональности.

clip_image006

Важность такого разделения в сознании разработчика/архитектора важна тем, что она будет приводить к другим паттернам, другому расположению компонент и т.п. В этом случае, например, мы сразу же уйдем от паттерна Repository громадной штуки, отвечающей за доступ к данным. Вместо этого, мы возьмем что-то типа паттерна Specification или Query, когда каждый класс будут ответственен за выполнение одной задачи с точки зрения пользователя/бизнес-логики.

Это же позволит разместить все типы, связанные с определенным функционалом в месте. Например, в случае работы с входом пользователя в систему мы создадим папочку Login, в которой уже будут файлы разных уровней: LoginView.cs, LoginVm.cs, LoginQuery.cs, LoginModel.cs etc. При изменении требований компонента входа в систему, нам все равно придется поменять все те же вьюху, модель, вью-модельку и запрос, но в этом случае, все эти элементы уйдут находиться в одном месте.

Я тут осознанно не хочу вдаваться в технические подробности описанного подхода. Для этого можно посмотреть выступление Джимми, и глянуть на его библиотеку MediatR. Мой главный посыл здесь в том, чтобы мы не забывали, зачем мы крошим приложения на слои. Чтобы сделать нашу жизнь легче. Правда ведь? А что если текущее проекция не сильно упрощает нашу жизнь? Ну тогда стоит подумать о других способах физической декомпозиции, которые будут решать существующие проблемы.

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

Помогла статья? Оцените её!
0 из 5. Общее количество голосов - 0
 

You have no rights to post comments

Дмитрий Крикунов

Публикую статьи, обучающие курсы и новости по программированию: алгоритмам, языкам (С++, Java), параллельному программированию, паттернам и библиотекам (Qt, boost).