Насколько завершёнными должны быть классы в OOП (анти-принцип YAGNI)?

01 Ноября 2022 (ред)

YAGNI («You aren't gonna need it»; с англ. — «Вам это не понадобится») — процесс и принцип проектирования ПО, при котором в качестве основной цели и/или ценности декларируется отказ от избыточной функциональности, — то есть отказ добавления функциональности, в которой нет непосредственной надобности.

С этим утверждением из Википедии довольно сложно спорить. Но любая программа не имеет своего завершения и постоянно изменяется и обновляется, если это не так, то, скорее всего ей никто не пользуется. Поэтому "непосредственная" надобность может быть разной - в рамках коммита, релиза, месяца, года и тд.

Допустим, разработчику, слишком сильно ориентирующемуся на YAGNI, поставлена задача подключить новую базу данных к проекту. Он делает класс-обёртку, но в итоге все удивлены — нет ни одного публичного метода, чтобы пользоваться этим модулем. Но, возражает программист, модулем же никто ещё не пользуется, поэтому все методы приватные. При этом ему не известно, будут ли добавлять только данные или получать или и то и другое или расширять класс наследованием. Ситуация специально показана абсурдной, ведь все ждали от него что-то типа CRUD(создание, чтение, модификация, удаление), но непосредственной необходимости в этих методах нет. А он ожидал, что в первой же задаче на добавление данных - будет добавлен метод добавляющий их, на удаление - удаляющий и тд. Последнее выглядит логичным, но противоречит другой концепции OOП - принципу на букву "O" (open-closed principle) из SOLID. А конкретнее - его второй части, где частые изменения не приветствуются.

«Программные сущности (классы, модули, функции и т. п.) должны быть открыты для расширения, но закрыты для изменения»

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

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

Более правильное прочтение совета YAGNI будет как раз запрет на добавление лишних возможностей модулю, вероятность использования в дальнейшем которых очень мала. Нужно ли добавлять методы, на использование которых пока ничто ещё не указывает? Если вы хотите сделать модуль самодостаточным, но не универсальным, это будет рационально. А вот универсальным вы его можете сделать, если это публичный фреймворк или библиотека, не привязанная к конкретному проекту, вариантов использования которой более чем достаточно.

Для ответа вы можете авторизоваться


Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.