Coupling и Cohesion: два понятия, которые стоит понимать каждому разработчику
Sorry for my English! English is not my native language. One of the reasons to create this blog is to improve my English writing. So I will be highly obliged if you will help me with this. If you find a grammar error on this page, please select it with your mouse and press Ctrl+Enter.
Последнее время я довольно активно изучаю паттерны проектирования и архитектуру приложений. И чем больше в это погружаюсь, тем чаще встречаю два понятия, которые лежат где-то в основе практически всего — coupling и cohesion.
На первый взгляд они звучат довольно абстрактно, но на самом деле описывают очень практичные вещи: насколько части системы зависят друг от друга и насколько хорошо они подходят друг другу внутри одного модуля или класса.
Coupling — связанность
Coupling показывает, насколько сильно один компонент зависит от другого.
Например, если класс напрямую создаёт и использует конкретную реализацию:
class OrderService { public function pay(Order $order): void { $gateway = new StripePaymentGateway(); $gateway->charge($order->total()); } }
OrderService жёстко связан со StripePaymentGateway.
Если завтра понадобится PayPal, тестовый mock или другой способ оплаты, придётся менять сам OrderService.
Можно уменьшить связанность, например, используя интерфейс и dependency injection:
class OrderService { public function __construct( private PaymentGateway $gateway ) {} public function pay(Order $order): void { $this->gateway->charge($order->total()); } }
Теперь OrderService не знает, какой именно платёжный шлюз используется.
Это уже напрямую связано с SOLID, особенно с Dependency Inversion Principle.
Cohesion — связность внутри компонента
Если coupling отвечает на вопрос:
«Насколько сильно этот компонент зависит от других?»
то cohesion скорее отвечает:
«Насколько хорошо всё внутри этого компонента относится к одной задаче?»
Представим класс:
class UserService { public function register(): void {} public function sendEmail(): void {} public function generatePdf(): void {} public function resizeImage(): void {} }
Формально всё это может работать. Но у класса очень низкая cohesion — в нём собраны совершенно разные обязанности.
Гораздо лучше разделить их:
UserService
EmailService
PdfGenerator
ImageResizer
Каждый компонент занимается своей задачей.
И здесь мы снова приходим к Single Responsibility Principle из SOLID.
Как это связано с паттернами?
На самом деле многие паттерны проектирования можно рассматривать через призму coupling и cohesion.
Dependency Injection помогает уменьшить coupling.
Strategy позволяет заменить конкретную реализацию и тем самым уменьшить зависимость между компонентами.
Facade скрывает сложность подсистемы и уменьшает количество зависимостей клиента.
Mediator уменьшает количество прямых связей между объектами.
А такие идеи, как Single Responsibility, помогают создавать компоненты с высокой cohesion.
Получается довольно простая картина:
High Cohesion
+
Low Coupling
↓
более гибкая архитектура
Конечно, это не означает, что нужно стремиться вообще избавиться от всех зависимостей. Зависимости между компонентами неизбежны.
Вопрос в другом — насколько они сильные и насколько оправданные.
Зачем вообще это понимать?
Понимание coupling и cohesion помогает смотреть на код немного шире, чем просто:
«Работает ли этот метод?»
Можно начать задавать другие вопросы:
Почему изменение одного класса требует изменений ещё в пяти местах?
Почему этот класс знает слишком много о других компонентах?
Почему в одном классе собрано столько разных задач?
Насколько легко заменить конкретную реализацию?
Насколько просто протестировать этот компонент отдельно?
Именно такие вопросы постепенно переводят мышление от написания отдельных классов к проектированию системы.
Для меня это одна из причин, почему при изучении паттернов и архитектуры важно понимать не только сами паттерны, но и фундаментальные принципы, которые за ними стоят.
Low coupling + high cohesion — пожалуй, одна из самых полезных концепций, которую стоит держать в голове при проектировании PHP-приложений.

Add new comment