Архитектурные стили и антипаттерны; связанность и связность модулей¶
Об этом материале
Объём: четыре темы, ориентировочно неделя-полторы. Отчётность: отчёт, граф зависимостей проекта и архитектурный тест в репозитории. Требование: к каждому стилю и антипаттерну — пример из реального кода.
Материал для самостоятельной работы после лекции 2. Лекция дала два понятия — связность и зацепление — и критерий «модуль должно быть можно удалить». Здесь они превращаются в систематику: шкалы вместо ярлыков, каталог архитектурных стилей с ценой каждого, каталог антипаттернов и метрики, которыми зависимости можно измерить. Ориентировочно неделя-полторы.
Что входит в этот материал¶
- Связность и зацепление как шкалы, а не как ярлыки
- Стили архитектуры
- Антипаттерны
- Метрики и правила зависимостей
Что уже было в лекции¶
Сильная связность внутри модуля, слабое зацепление между модулями; определение архитектуры; критерий «модуль должно быть можно удалить»; MVC и MVVM. Дальше — систематика.
Как работать с этим документом¶
- Читайте не подряд, а по темам: у каждой есть вопрос, на который она отвечает.
- К каждому уровню связности и зацепления подберите свой пример из кода, который видели. Без примера уровень не изучен.
- К каждому стилю запишите одну строку: «решает X ценой Y».
- К каждому антипаттерну — случай из своей практики или из открытого репозитория.
- Инструменты: графы зависимостей сборок, SonarQube или NDepend для метрик, NetArchTest для правил как тестов.
Тема 1. Связность и зацепление как шкалы, а не как ярлыки¶
Обе характеристики имеют классификацию (Стивенс, Майерс, Константайн, 1974) — от худшей к лучшей.
Связность (cohesion), снизу вверх:
| Уровень | Что объединяет элементы модуля | Пример |
|---|---|---|
| Случайная | ничего | класс Utils, Helpers, Common |
| Логическая | похожая категория действий | InputHandler, обрабатывающий мышь, клавиатуру и файлы |
| Временная | выполняются в один момент | Startup, где инициализируется всё подряд |
| Процедурная | порядок выполнения | шаги, идущие подряд, но не связанные данными |
| Коммуникационная | работают с одними данными | отчёт, читающий и печатающий одну выборку |
| Последовательная | выход одного — вход другого | пайплайн обработки |
| Функциональная | решают одну задачу | PriceCalculator |
Зацепление (coupling), сверху вниз (от худшего):
| Уровень | Суть | Как выглядит |
|---|---|---|
| По содержимому | модуль лезет во внутренности другого | рефлексия по приватным полям |
| Общее | общая глобальная область | статические изменяемые данные, синглтоны |
| Внешнее | общий внешний формат/протокол | все модули читают один и тот же файл конфигурации |
| По управлению | один модуль управляет ветвлением в другом | булев параметр-флаг Process(bool isRefund) |
| По структуре данных | передаётся структура, нужна её часть | передаём весь Order ради Total |
| По данным | передаются ровно нужные значения | Calculate(decimal amount) |
Отдельно изучите connascence (Мейлир Пейдж-Джонс) — более современный и точный язык, чем «coupling»: связность по имени, типу, значению, позиции, алгоритму, времени выполнения, с двумя измерениями — сила и локальность. Хорошая практическая формулировка: чем сильнее форма связности, тем ближе должны находиться связанные элементы.
Тема 2. Стили архитектуры¶
Пройдите по каждому: какую проблему решает, чем платит, когда неуместен.
- Слоистая (layered). Классика: представление → приложение → домен → инфраструктура. Проблема: зависимость домена от инфраструктуры вниз по стеку.
- Луковая и Clean Architecture. Инверсия зависимостей на уровне слоёв: домен в центре и не зависит ни от чего, интерфейсы репозиториев объявлены в домене, реализации — снаружи.
- Порты и адаптеры (гексагональная). Та же идея в других терминах: ядро окружено портами, адаптеры подключают к нему БД, HTTP, очереди. Полезно понять, что onion/clean/hexagonal — это варианты одной мысли.
- Pipes and Filters. Обработка потоками; естественно ложится на LINQ,
IAsyncEnumerable, каналы Go, стримы Java. - Микроядро (plugin). Ядро + расширения; так устроены IDE, сборщики, браузерные движки.
- Событийно-ориентированная. Модули общаются событиями, зацепление минимально, но появляется трудность трассировки и порядка. Изучите разницу «событие как факт» и «событие как команда».
- CQRS и, отдельно, Event Sourcing — почему их часто путают и почему второе почти никогда не нужно там, где хватает первого.
- Монолит, модульный монолит, микросервисы. Обязательно прочитайте критику микросервисов и понятие распределённого монолита.
- MV*-семейство (MVC, MVP, MVVM, MVI/Redux) — уже разобрано в лекции 2, здесь только дополните MVI/однонаправленным потоком данных.
Для каждого стиля выпишите одну строку: «решает X ценой Y».
Тема 3. Антипаттерны¶
Архитектурные:
- Big Ball of Mud — отсутствие структуры как результат эволюции; самая распространённая «архитектура» в природе.
- Distributed Monolith — сервисы разделены физически, но связаны намертво: релиз только всем скопом.
- Anemic Domain Model — сущности без поведения плюс «сервисы», делающие всё; прямая связь с запахами Data Class и Feature Envy из лекции 2. Обязательно прочитайте статью Фаулера и контраргументы к ней: тема спорная, и знать обе стороны полезнее, чем занять сторону.
- God Object / God Class — на уровне класса и на уровне проекта.
- Golden Hammer — любимая технология как ответ на все задачи.
- Lava Flow — окаменевший мёртвый код, который боятся трогать.
- Vendor Lock-in и Inner-Platform Effect — самописная «платформа внутри платформы».
- Spaghetti / Ravioli / Lasagna — три способа испортить структуру: хаос, избыточное дробление, слишком много слоёв.
Управленческие и процессные (пригодятся не меньше): Analysis Paralysis, Design by Committee, Cargo Cult (соблюдение формы без понимания причины), Resume-Driven Development.
Задание при чтении: к каждому антипаттерну подобрать пример из собственного опыта или открытого репозитория. Без примера пункт не считается изученным.
Тема 4. Метрики и правила зависимостей¶
- Метрики Мартина: Ca, Ce, нестабильность I, абстрактность A, расстояние до главной последовательности D. Понять смысл: стабильные модули должны быть абстрактными, нестабильные — конкретными.
- Принципы связности пакетов: REP (переиспользование = релиз), CCP (вместе меняется — вместе лежит), CRP (не заставляй зависеть от лишнего).
- Принципы зацепления пакетов: ADP (без циклов), SDP (зависимость в сторону устойчивости), SAP (устойчивое должно быть абстрактным).
- Закон Деметры и его практические границы (почему LINQ-цепочки его формально нарушают и почему это нормально).
- Закон Конвея — структура системы повторяет структуру коммуникаций в организации; и «обратный манёвр Конвея» как способ этим управлять.
- Инструменты: NDepend, SonarQube, графы зависимостей сборок,
dotnet list package --include-transitive; тесты архитектуры (NetArchTest, ArchUnitNET) — превращение правил в проверяемые ограничения.
Вопросы для самопроверки¶
- Чем логическая связность отличается от функциональной? Приведите свой пример класса с логической связностью.
- Почему булев параметр в сигнатуре считается зацеплением по управлению и чем его заменить?
- Onion, Clean, Hexagonal — в чём они действительно различаются, а в чём это одно и то же?
- Как отличить микросервисы от распределённого монолита по одному признаку?
- Anemic Domain Model — всегда ли антипаттерн? Сформулируйте позицию и контраргумент.
- Что означает высокое
Iи низкоеAодновременно, и почему это плохо?
Практика¶
Взять открытый проект среднего размера (или свой) и построить граф зависимостей между модулями. Найти: цикл зависимостей; модуль с самой низкой связностью; место, где нарушен SDP. Написать отчёт на одну страницу с предложением, как это исправить — и добавить архитектурный тест, который зафиксирует исправленное правило.
Литература¶
- Р. Мартин. Чистая архитектура — принципы компонентов, метрики связности и зацепления, границы.
- М. Фаулер. Рефакторинг — запахи, из которых вырастают архитектурные дефекты.
- У. Браун и др. AntiPatterns — первоисточник термина.
- С. Браун. C4 model (c4model.com) — уровни описания архитектуры.
- Статьи о connascence (Мейлир Пейдж-Джонс) — более точный язык, чем «coupling».
Как я буду это проверять¶
Письменный отчёт: ответы на вопросы для самопроверки и вывод по практике, плюс код в репозитории. Критерий — не «сделано», а объяснено: почему выбран такой вариант, чем платим, что сломается при изменении требования. Формулировка «так принято» не засчитывается: принято кем и почему.