Почему объектно-ориентированное программирование — это отстой

в 12:41, , рубрики: erlang, Erlang/OTP, ооп, перевод, переводы, метки: , ,

Когда я первый раз услышал об объектно-ориентированном программировании — сразу отнёсся к нему скептически. Честно говоря, даже не знаю, почему. Просто оно показалось мне каким-то неправильным. Но ООП очень быстро стало популярным (почему — я объясню ниже) и критика в его адрес превратилась в этакую «ругань в церкви». А объектно-ориентированность стала обязательной составляющей любого уважаемого языка программирования.

С ростом популярности Erlang часто стали задавать вопрос «— А Erlang — объектно-ориентированный?». Правильный ответ был бы «— Да что вы, нет!». Но мы не могли так заявлять в полный голос, поэтому пришлось выкручиваться. Мы придумали несколько достаточно нетривиальных ответов, которые бы представляли Erlang типа-объектно-ориентированным языком (для тех, кто больше всего тянет руку с этим вопросом), но при этом и не объектно-ориентированным для тех, кто на самом деле в теме.

Тут мне хотелось бы вспомнить тезисное выступление директора французского IBM на 7 конференции IEEE по логическому программированию. Он рассказал о том, что IBM добавило в Prolog достаточно много объектно-ориентированных расширений. На вопрос о причинах этого он ответил:

«— Наши покупатели хотели объектно-ориентированный Prolog, поэтому мы сделали объектно-ориентированный Prolog»

Помню, я думал «Как хорошо! Просто, никаких угрызений совести, никакого самоанализа, никаких метаний по поводу того, правильно ли так делать.»

Почему объектно-ориентированное программирование — это отстой

Мои ЛИЧНЫЕ возражения по теме ООП — это претензии к его основным положениям. Я выделю некоторые из этих положений и суть моих претензий.

Возражение №1. Структуры данных и функции не должны быть привязаны друг к другу

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

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

Структуры данных же просто существуют. Они не выполняют никаких действий. Они исключительно декларативны. «Понимание» структуры данных в разы проще «понимания» функции.

Функции представляются чёрными ящиками, трансформирующими входы в выходы. Если я понимаю вход и выход, то я могу понять и функцию (хотя это вовсе не означает то, что я смог бы эту функцию написать).

Функции обычно «понимаются» как части вычислительной системы, передающие данные из структуры данных типа T1 в структуру данных типа T2.

Поскольку функции и структуры данных — это совершенно разные виды животных, то решение содержать их в одной «клетке» фундаментально неверное.

Возражение №2. Всё должно быть объектом

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

-deftype day() = 1..31
-deftype month() = 1..12.
-deftype year() = int().
-deftype hour() = 1..24.
-deftype minute() = 1..60.
-deftype second() = 1..60.
-deftype abstime() = {abstime, year(), month(), day(), hour(), min(), sec()}.
-deftype hms() = {hms, hour(), min(), sec()}.
... 

Заметьте, что эти определения не принадлежат ни одному конкретному объекту. Они общеиспользуемы без каких-либо ограничений, поэтому такие структуры данных, представлющие «время» могут быть использованы любой функцией.

Кроме того, у них нет никаких связанных методов.

Возражение №3. В объектно-ориентированных языках определения типов размещаются повсеместно

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

Я приведу пример. Предположим, я хочу определить глобально видимый тип данных.

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

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

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

Возражение №4. У объектов есть скрытое состояние.

Состояние — это краеугольный камень всех проблем. В частности — необходимо избегать функций с сайд-эффектами.

В то время, когда состояние в языках программирования нежелательно, в реальном мире состояние доминирует. Мне интересно состояние моего банковского счёта, поэтому когда я кладу или снимаю с него деньги — я жду, что состояние счёта корректно обновится.

Что могут предложить языки программирования для работы с этим состоянием из реального мира?

  • Объектно-ориентированные языки программирования скажут «— Надо спрятать состояние от программиста». Состояния скрываются, доступ к ним можно получить только с помощью специальных функций;
  • Обычные языки программирования (C, Pascal) скажут, что видимость переменных состояния должна регулироваться правилами областей видимости языка;
  • Декларативные языки скажут, что состояния нет.

Глобальное состояние системы хранится во всех функциях и вытекает изо всех функций. Используются механизмы навроде монад (для функциональных языков) и DC-грамматик (для логических языков). Эти механизмы прячут состояние от программиста, позволяя ему программировать не принимая состояние во внимание, но при этом позволяя ему и получать доступ к состоянию, если в этом возникнет необходимость.

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

Почему ООП так популярно?
  • Причина 1 — все думают, что его легко изучить;
  • Причина 2 — все думают, что с его помощью можно повысить степень повторного использования кода;
  • Причина 3 — хайп вокруг ООП;
  • Причина 4 — оно создаёт Новую Индустрию Программирования.

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

Вот это — то, что реально движет объектно-ориентированным программированием.

От переводчика.
Оригинал: Joe Armstrong, взято отсюда.

Нашумевший в определённых археологическо-программистских кругах текст, написанный Joe Armstrong, автором Erlang. Дату написания текста достоверно установить не удалось, но, судя по косвенным данным, это было в начале 90х.

Автор: 80x86

  1. Георгий:

    Просто ты, чувак, не въехал в ООП… Или обидели тебя где-то…

* - обязательные к заполнению поля