Аккуратный код
Аккуратный код
Связность — мера, которая показывает, насколько чётко методы внутри класса сфокусированы на решении его основной задачи. Слово «связность» — это перевод английского слова 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. Это был совет об управлении разработкой. Хотите больше знать о планировании спринтов, управлении продуктом или о настройке инфраструктуры? Присылайте вопросы.