Как правила линтинга влияют на архитектуру приложения

от автора

В eslint есть одно простое, но мощное правило, которое поможет вам в поддержании архитектуры приложения.

import/no-restricted-paths позволяет указать зону, по которой запрещено импортировать определенные пути:

"zones": [{   "target": ["./moduleA"],   "from": ["./moduleB"],   "message": 'Модуль A не может импортировать модуль B', }]

Импорт модуля B в модуль A вызовет ошибку в IDE:

ESLint: Unexpected path "/moduleB" imported in restricted zone.  Модуль A не может импортировать модуль B(import/no-restricted-paths)

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

Далее рассмотрим, как одна простая настройка eslint-правила поможет при проектировании, разработке или рефакторинге сложных систем.

Влияние импортов на архитектуру

В любой архитектуре есть модули, которые взаимодействуют друг с другом.

Каждый такой модуль строится в первую очередь на принципе единственной ответственности (The Single Responsibility Principle или SRP) — “модуль должен иметь одну и только одну причину для изменения”. 

Правильные связи между этими модулями —  один из важных аспектов построения масштабируемой архитектуры и развития проекта. Когда мы импортируем один модуль в другой, мы создаем между ними связь, следовательно, импорт = связь.

Как часто вы сталкиваетесь с архитектурными спорами в проекте?
Бывает ли, что неудачные архитектурные решения пролезают в проект даже после код-ревью? Знаете ли вы, насколько связаны модули в вашем приложении?

Ответы на эти вопросы зависят от процессов, структуры вашего отдела, наличия в команде архитектора или людей, которые следят за архитектурой и т.п.

В целом, кажется, всё сводится к человеческому фактору. А человеческий фактор нужно автоматизировать.

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

Рассмотрим следующий пример. Стрелками на картинке обозначены импорты/связи между модулями

Пример некорректного использования импортов
Пример некорректного использования импортов

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

Так как же это автоматизировать?

rules: {   'import/no-restricted-paths': ['error', {     "basePath": rootPath,     "zones": [{       "target": ["./lib/ui-kit/*"],       "from": ["./backend/rest-api"],       "message": 'Пакет ui-kit не может содержать импорт из rest-api',     }],   }], }

Не правда ли, очень дешево написать пару строчек конфига и решить потенциальные проблемы архитектуры?

Заключение

Проектирование модуля, в котором соблюдается Single Responsibility Principle упрощает дальнейшие изменения и поддержку, так как это освобождает команду от распутывания сложных взаимосвязей между различными сущностями. Также несвязанные модули снижают риск возникновения проблем в других местах при изменениях.

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

Итого  import/no-restricted-paths:

  • Помогает контролировать связанность модулей.

  • Упрощает рефакторинг модуля.
    Можно зафиксировать связи модуля и начать его доработку.

  • Улучшает процесс.Можно построить назначение ревьюеров на изменение конфига, построить схему связей в приложении. Тогда о критично важных изменениях в проекте будет знать вся команда.

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

А какие неожиданные решения архитектурных проблем встречали вы?


ссылка на оригинал статьи https://habr.com/ru/company/okko/blog/716042/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *