Больше 10 лет продолжается мое осознаное знакомство с Ocaml и около 18 лет знаком (на уровне любителя) с лиспом. Пожалуй, сейчас можно разрешить себе сказать публично: я считаю ООП лишним в большинстве задач. И сейчас объясню почему.
Любое проектирование системы начинается на декларативном языке интерфейсов. В терминах этого языка проектирования мы декларируем (описываем) задачу, наш проект. И только потом, на языке реализации, мы рассуждаем о терминах языка интерфейса.
В парадигме ООП на этом языке интерфейса удобно описывать устройство мира, прямо как пишут в книжках: вот это класс всех объектов, а эти имеют радиус, и они круги. А вот эти имеют два радиуса, потому что эллипсы. А радиус — тоже класс объектов, «положительное число». То есть в рамках этой парадигмы мы описываем родословную объектов, кто и какие какие характеристики (гены) имеет. Дальше, имея вот эту изданную и закоммиченную энциклопедию видов, на языке реализации начинается императивное написание инструкций того, чего же мы собственно хотим от объектов этого мира. Пишем инструкции для Listener интерфейса, который будет слать Events в ферму Worker’ов, создаваемых на Factory. Потом мы пишем инструкции для Listerner что делать в случае, если Worker посреди выполнения инструкции «построить дом» по какой-то причине скончался, не достроив последний этаж.
В парадигме функционального программирования в терминах языка интерфейса мы описываем конечную цель проекта («самый последний знак числа Пи», «веб-страница с кусом валют»), а также способы её достижения. Если мы можем доказать существование хотя бы одного способа достижения цели (некого преобразования одного типа в целевой) — значит мы можем выполнить проект. В свою очередь, исходные типы этого способа — это такие же подцели, которые точно так же либо имеют доказательства, либо нет. В моем простом примере, существование результата (типа данных) «самый последний знак числа Пи» очевидно не имеет доказательств (решений), потому что нельзя привести ни одного типа функций, который бы приближал нас к ней.
Таким образом, в функциональной парадигме уже на этапе проектирования мы описываем цели и граф путей её достижения. Мне кажется это более естественным способом проектирования.
И здесь такая индукция: реализация функции (описание конкретного способа преобразования из типа A в тип B) тоже есть цель, которую точно так же необходимо вывести, путем построения минимального достаточного графа способов получения B из A. То есть, язык реализации функции в некотором смысле становится языком, о терминах которого будут рассуждать уже в свою очередь при написании функций подцелей этой функции.
В мире ООП есть тенденция к переходу от способа рассуждения в декларациях вида «метод m совместим с объектами класса B» к декларациям вида «метод m ждет любой объект со свойствами P₁ + P₂». Ничего не хочу сказать, но вообще-то это чистая функциональщина :-)
У ООП есть своя отличная ниша. Это не те системы, где необходимо вычислить результат или сделать серию преобразований данных, а системы, где основной целью является описание объектов и их взаимодействия — без гарантий интерпретации кода в некий ожидаемый результат. Игрушки, интерфейсы.