ООП — объектно-ориентированное программирование

Часть вторая

ООП — объектно-ориентированное программирование

По моему опыту, самая серьёзная проблема ООП заключается в том, что оно мотивирует игнорировать архитектуру модели данных и применять бестолковый паттерн сохранения всего в объекты, обещающие некие расплывчатые преимущества. Если это подходит для класса, то это отправляется в класс.

Вместо построения хорошей архитектуры данных внимание разработчика смещено в сторону изобретения «хороших» классов, взаимосвязей между ними, таксономий, иерархий наследования и так далее. Это не просто бесполезное занятие. В глубине своей оно очень вредно.

При проектировании архитектуры данных в явном виде результатом обычно является минимальный необходимый набор структур данных, обслуживающих цель нашего ПО. Если мыслить в категориях абстрактных классов и объектов, то грандиозность и сложность абстракций сверху ничем не ограничивается.

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

А небезызвестный Линус Торвальдс часто критиковал ООП и С++ в частности, упоминая, в том числе отсутствие ограничений. Речь о том, что большое количество инструментов и методов позволяет добиваться функционально одинаковых реализаций множеством различных способов. Это можно было бы считать преимуществом, но появляется риск ошибок, обнаружить которые очень сложно. Наследование объектов может привести к тому, что баг «вылезет» в неожиданном месте, далеко от исходной неточности в описании «родителя».

Недостатки ООП

Проблема обезьяны и банана

Представьте, что вы настраиваете новое приложение и думаете, как создать новый класс. И тут вы вспоминаете о прекрасном маленьком классе, который создали для другого проекта. Этот класс идеально подошёл бы и сейчас.

Никаких проблем! Вы можете повторно использовать класс из старого проекта. Но есть один нюанс: этот класс может быть подклассом другого класса. Потому вам нужно будет добавить и родительский класс. Затем вы поймете, что родительский класс зависит от других классов. В результате вы должны добавлять кучу кода.

Вот известная цитата создателя Erlang, Джо Армстронга:

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

Этим все сказано. Да, возможность повторно использовать классы — едва ли не основное преимущество объектно-ориентированного программирования. Но не стоит использовать его всегда: иногда лучше написать новый класс.

Проблема хрупкого базового класса

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

ООП мотивирует писать спагетти-код

Хотя ООП помогает объединять модули и разделять логику, оно также создаёт собственные проблемы. Часто у нас получается огромная цепочка наследования и ссылок. Когда что‑то одно нужно изменить, десятки других элементов ломаются. Эта проблема возникает из самой природы ООП. Оно спроектировано так, чтобы определять то, что выполняет доступ к нашим данным. Это значит, что чаще всего мы волнуемся о разъединении, сохранении принципа DRY, абстракции и так далее. Из‑за этого в результате возникает множество слоёв и ссылок просто для того, чтобы не нарушить принципы ООП, например, для управления доступом.

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

Это хорошо, потому что мы можем менять внутреннее устройство, не позволяя никому узнавать об этом. Но в то же время это портит ситуацию, потому что внешний мир ожидает, что от таких методов будет поступать конкретное множество данных.

22
3 комментария

Это точно проблема ООП, или проблема злоупотреблением наследования, когда можно применять композицию?

3
Ответить

ООП действительно непростой инструмент, но эта статья - какой-то один сплошной поток неструктурированного сознания.
Автору стоило бы для начала почитать какой-то концептуальный труд по ООП (например Бертрана Мэйера с его "Объектно-ориентированное конструирование программных систем"), а не забивать себе голову попурри из цитат людей, чей бэкграунд бесконечно далёк от тех областей, где ООП используют по понятным (но видимо не автору) причинам.
Большая проблема с ООП в том, что многие пытаются применять его начитавшись бестолковых статей в интернете. И эта - одна из них.

2
Ответить

Замените в статье ООП на ФП/ПП/PHP/jQuery/JavaScript/Python/React и получите контента на год вперед.

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

2
Ответить