Найти тему
Дед Мазай на Котлине

Качество кода ч.5

Код-ревью...
Код-ревью...

Части 1, 2, 3, 4

12. Сервис-классы содержат 1 публичный метод с параметрами или без

Это правило предлагает делать вот так:

class DoSomeThing {
suspend fun execute() { ... }
private suspend fun do1() { ... }
...
private suspend fun doN() { ... }
}

Вместо того, чтобы делать вот так:

class Worker {
suspend fun do1() { ... }
...
suspend fun doN() { ... }
}

Т.е. класс может иметь сколько угодно приватных методов и только 1 публичный.

Почему:

Чем меньше открытого API у вашего класса, тем меньше у этого класса ответственности (согласно SOLID она должна быть вообще одна), тем меньше на этот класс будет завязано других классов, тем проще вам и тем, кто придёт после вас будет поддерживать и изменять этот класс.

Если же нарушать это правило и, тем более, делать перекрёстные вызовы между публичными методами одного класса, то в скором времени вы почувствуете всю "прелесть" кода-лапши, не дающего вам вносить в код изменения "лёгким движением руки".

13. Название сервис-класса отражает его поведение (что он должен делать)

Я заметил, что 99,99% разработчиков перестают понимать приложение, если в названии класса-репозитория отсутствет постфикс "*Repository". Например, такие классы как: UserReopsitory, OrderRepository и т.п. ни у кого не вызывают вопросов. Все сразу понимают, что это, зачем и где их использовать.

Если же назвать эти же классы Users, Orders и т.п., то сразу посыпятся жалобы: непривычно, непонятно, каждый раз приходится лезть внутрь, чтобы посмотреть, что это и т.д.

И это понятно: если есть постфикс "*Repository", то сразу становится понятно, что этот класс делает: предоставляет остальному коду API для доступа к базе данных. Если нет такого постфикса, то понять назначение класса по его названию правктически невозможно.

Точно такое же правило необходимо применять и к сервис-классам, с той лишь разницей, что простое добавление постфикса "*Service" к имени класса не решает проблему понимания его назначения. Например, такие названия как UserService, OrderService не говрят нам ничего, кроме того, что это класс-прокладка между контроллером и репозиторием.

Если мы вспомним предыдущее правило (1 класс == 1 публичный метод), то станет очевидным, что для улучшения читаемости кода нам нужно давать сервис -классам названия, отражающие суть того, что эти классы делают. Например: CreateUser, UpdateOrder, ValidateCreateUserRequest, ValidateUpdateOrderRequest и т.д.

При этом нам становится неважно название единственного публичного метода такого класса. И мы можем сделать его одинаково нейтральным для всех классов - execute() (с параметрами или без).

Теперь наши сервис-классы не только соблюдают принцип единственной ответственности, слабо вязаны, но и способны одним своим названием говорить нам о своей ответственности - т.е. кратно повышают читаемость кода.

В качестве отступления: кто-нибудь вообще видит разницу между "связанностью" и "зацеплённостью"? Или это очередной карго-культ - называть разные явления словами-синонимами или одинаковые являения - разными словами, чтобы сразу ставить неофитов на свои места: вы ничего не понимаете в программировании, поэтому несите деньги, мы вам сейчас всё "объясним". ))