Связность — мера, которая показывает, насколько чётко методы внутри класса сфокусированы на решении его основной задачи. Слово «связность» — это перевод английского слова cohesion. К сожалению, перевод не очень удачный, поэтому в разговорной речи программисты часто употребляют понятие «связность» в значении «зацепление», а «зацепление» не употребляют вовсе. Чтобы дальше не путаться с терминами, давайте сформулируем правило:

В хорошей архитектуре каждый класс не зависит от соседей и сфокусирован на решении только одной задачи

Давайте представим, что «Почтальон» из прошлого совета решил журналировать всю исходящую корреспонденцию. Чтобы такой журнал был полезным в расследовании инцидентов, в нём нужно хранить не только текст письма, но и идентификатор сущности, которая отправила письмо, к примеру номер заказа. Решим задачу «в лоб», при этом не забывая, что почту в нашем приложении отправляет не только «Заказ», но и «Догонятель»:

class Mailman:
  def __init__(self, customer, sender):
    self.customer = customer
    self.sender = sender
​
  def deliver(self, subject, message):
    ...
    self.log(subject, message)
​
  def log(self, subject, message):
    sender_name = 'Unknown'
​
    if self.sender.__class__.__name__ == 'Order':
      sender_name = f'Order #{self.sender.id}'
​
​    elif self.sender.__class__.__name__ == 'Chaser':
      sender_name = f'Chaser for Order #{self.sender.order.id}'
​
    LogEntry.objects.create(sender_name=sender_name, subject=subject, message=message)

Смотрите, как раздулся метод для журналирования, — вместо того, чтобы просто записать строчку в журнал, он вынужден залезать внутрь класса, который его вызвал. АПИ «Почтальона» потеряло в удобстве — теперь, когда в приложении появится новый класс, которому нужна почта (к примеру, восстановитель паролей), он не сможет отсылать письма, пока «Почтальон» не узнает, как представлять его в журналах.

У нас получилась слабая связность и сильное зацепление. Википедия

Давайте избавимся от зацепления и добавим связности — пусть все классы, которые пользуются «Почтальоном», сами показывают, как их зовут. Возьмём стандартный для Питона и Джанго метод перевода объекта в строку:

class Order:
  ...
  def __str__(self):
    return f'Order {self.pk}'
​
class Chaser:
  ...
  def __str__(self):
    return f'Chaser for {self.order}'
​
class Mailman:
  ...    ​
  def log(self, subject, message):
    LogEntry.objects.create(sender_name=str(self.sender), subject=subject, message=message)

На уровне архитектуры «Почтальон» больше не лезет внутрь своих потребителей. Теперь, если разработчик нового класса не будет знать, как на проекте принято вести журнал писем, ничего страшного не случится — в Питоне у каждого класса уже определён метод __str__, который даёт достаточно информации для расследования инцидентов.

Теперь — хорошо: сильная связность и слабое зацепление. Википедия

P. S. Это был совет об управлении разработкой. Хотите больше знать о планировании спринтов, управлении продуктом или о настройке инфраструктуры? Присылайте вопросы.

Управление проектомВеб‑разработка
Отправить
Поделиться
Запинить

Рекомендуем другие советы