Перейти к основному содержимому

Связанность, глобалы и запахи модульности

Разработчику Архитектору

Связанность (coupling) и глобальные сущности — частые причины хрупкого кода. Теория cohesion/coupling — в конструировании ПО; здесь — симптомы в коде и направления исправления.

Опора — MAPPER: объект в коде не должен знать о половине системы, если в реальности у него одна ответственность.


Высокая связанность — что видно в diff

Запах (Фаулер)ПризнакНаправление
Shotgun SurgeryОдно изменение правит 10 файловСобрать логику в один модуль
Divergent ChangeОдин класс меняется по разным причинамРазделить по ответственности
Feature EnvyМетод больше читает чужие поляMove Method
Inappropriate IntimacyКлассы лезут во внутренности друг другаИнкапсуляция, фасад
Middle ManКласс только пересылает вызовыInline / убрать прослойку
Message Chainsa.getB().getC().getD()Закон Деметры, статья 1
God Object«Всезнайка» на тысячи строкРазбиение по поддоменам
SingletonГлобальная точка доступаDI, явная передача зависимости

Полный указатель — 13.


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

Singleton — не паттерн GoF «для красоты», а скрытая глобальная переменная. Тесты не изолированы; порядок инициализации непредсказуем; подмена реализации на мок болезненна.

// Плохо: скрытая зависимость
public class ReportService {
public void Run() {
var db = DatabaseSingleton.Instance;
}
}

// Лучше: зависимость явна
public class ReportService {
private readonly IDatabase _db;
public ReportService(IDatabase db) => _db = db;
}

Глобальные функции, статика, goto:

  • обернуть доступ к DateTime.Now, файловой системе, env в инъектируемый порт;
  • статические Utils с бизнес-логикой → экземплярные сервисы;
  • goto и необоснованные break — переписать структурированно.

Скрытые предположения

Превратить скрытые допущения в явные. Магическое 9999 как «нет значения», неявный часовой пояс, аргументы по умолчанию в середине списка — всё это ломает быстрый провал.

# Скрыто: -1 значит «нет id»
if user_id == -1: ...

# Явно
if user_id is MissingUserId: ...

Группы данных и примитивы

Если одни и те же пять параметров ходят вместе (street, city, zip…) — это группа данных (Data Clump). Реифицируйте в Address (статья 6).


UI и домен

Бизнес-правила не живут в обработчиках кнопок. Presentation вызывает use case; валидация email — в Email, а не в onClick.

См. слои в конструировании, чистую архитектуру.


Иерархии

Глубокое наследование, «йо-йо» иерархии, подклассы ради одного if — тема ООП. Правило: поведение важнее «is-a»; композиция часто честнее наследования.

Кратко:

  • не наследовать ради переиспользования кода;
  • пустые классы и заглушки — удалить или заполнить смыслом;
  • protected поля — последний resort.

На ревью

  1. Новый import из «соседнего» bounded context — зачем?
  2. Появился static с mutable state?
  3. Тест требует «сначала вызови Global.init()»?
  4. Изменение одного поля затронуло 5+ модулей — нужен рефакторинг границ.

Дальше: YAGNI и техдолг, тесты, справочник тем.


См. также

Другие статьи этого же раздела в боковом меню (как на странице "О разделе").