Занятный доклад Мартина (aka Uncle Bob, автор кучи книг по ООП, в т.ч. “Чистый код”) про то, как надо делить код на компоненты.

TLDR:

  1. Чем сложнее проект, тем больше вероятность, что он провалится.
  2. Coupling (связанность) — это плохо, O(n^2), с его возрастанием снижается продуктивность, найм новых людей не работает, т.к. они не знают всех нюансов “так исторически сложилось”, делают ошибки и все становится еще хуже.
  3. Минимально число однонаправленных связей = N-1, и это дерево. Но если добавить только 1 связь, получится цикл, и будет циклическая зависимость, и все может сломаться, как цепная реакция.
  4. Компонент — это бинарный модуль, который может быть задеплоен независимо — dll, exe, jar. Неймспейсы/пакеты — не компоненты, но могут им соответствовать. (Хотя лично я считаю, что ничего этому не мешает). Компоненты обязательно должны содержать классы (вроде умный чел, но слышал ли он, что есть программирование без классов?)
  5. Система компонентов, удобная для использования, неудобна для разработки и наоборот, она зависит от потребителей. На ранних стадиях она может быть удобной для разработки, на поздних — для пользователя.
  6. Три первых принципа находятся в противоречии друг с другом, надо искать баланс.
  7. Не надо упаковывать ни по фичам, ни по пакетам, потому что у разных компонентов разные причины для изменения.
  8. Множественное наследование не реализовали не для защиты пользователей, а потому что сложно написать компилятор, который его поддерживает:))

Собственно принципы:

  1. Release Equivalency Principle — есть процесс релиза с версиями. Самый маленький компонент — это самый маленький кусок кода, который вы хотите переиспользовать.
  2. Common Closure Principle — SRP для компонента. Новая фича должна затрагивать ровной один компонент. Т.е. классы, которые изменяются по одной причине, должны быть в одном компоненте. “Все классы для работы с БД должны быть в одном компоненте” (sic!).
  3. Component Reuse Principle — Первый компонент зависит от второго, во втором поменялась какая-то мелочь, и первый пришлось обновлять/он сломался, хотя он и не зависел от этой мелочи. Такого быть не должно: если можно использовать только часть компонента, то надо его выделять в отдельный.
  4. Acyclic Dependencies Principle — зависимости компонентов между собой не должны создавать цикла.
  5. Stable Dependencies Principle — лучше зависеть от того, что тяжело изменить. Забавная аналогия: есть “взрослые компоненты”, которые не зависят от других, но от которых зависят многие, и “детские”, которые “безответственны”, но зависят от многих. И более нестабильный компонент должен зависеть от менее нестабильного, иначе легкий для изменения компонент перестанет быть таковым.
  6. Stable Abstractions Principle — на верхних уровнях все должны быть максимально конкретны, на нижних, от которых все зависят — максимально абстрактны. Но это касается только тех компонентов, которые активно развиваются и не касается всяких библиотечных классов, от которых все зависят, но при этом они очень конкретны.

Я может чего-то не понимаю, но под все эти принципы идеально подходит is-even/left-pad, и я не думаю, что экосистема npm — это эталон. В целом вроде доклад “умный”, но 1, 4 и 5 — очевидны, 2 и 3 противоречивы, 6 так вообще с непонятными исключениями. Конкретных приемов, как все это подружить, Мартин, увы, не приводит, поэтому практическая польза не очень высокая, но как затравка для холивара — неплохая тема.