ФП и SOLID, GRASP, GoF

Принципы хорошей архитектуры (SOLID, GRASP, GoF-паттерны) не привязаны к ООП — это адаптация принципов под объектную парадигму. ФП-аналоги тех же принципов существуют. Не все паттерны переводимы 1:1.

ФП-принципы = переписанный SOLID

Если ты спроецируешь то, что обычно в JavaScript-среде рассказывается про функциональное программирование, окажется, что это принципы SOLID, переписанные и адаптированные под объектно-ориентированное.

SOLID ФП-аналог
Single Responsibility Одна функция — одна задача
Open/Closed HOF, partial application для расширения без изменения
Liskov Substitution Совместимость типов сигнатур функций
Interface Segregation Маленькие функции, не "fat utility classes"
Dependency Inversion Передача функций как параметров (callbacks, strategies)

ООПшники "апроприировали" паттерны

Мы видим книжки и видим ООПшников, которые кричат, что это только их. Они всё апроприировали и сказали, что мы придумали всё это дело. Наши все вот эти товарищи, банда четырёх.

GoF (банда четырёх) закрепила паттерны как ООП-концепцию, хотя многие из них существовали до ООП.

Книга устаревает в момент написания

Книжка становится статична и рассказывает о том, что думал человек на момент написания. Мы всегда ограничены тем языковым инструментом, на который мы опираемся.

Пример: книга Брагилевского про Haskell — Haskell за это время сильно изменился, идеи устарели.

Алан Кей и оригинальное ООП

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

Современное ООП с наследованием — не то, что задумывалось как ООП. Изолированные сообщения между объектами без shared state — это ближе к ФП и Erlang/Akka модели.

Аргумент функциональщиков

Очень долго утверждали функциональщики, что нам эти принципы не нужны. Почему? Потому что это подпорки для плохих языков программирования.

В хорошем функциональном языке, типа Haskell, программы сами по себе получаются хорошие. Есть монады, функции высшего порядка, и больше ничего не нужно.

Почему это полу-правда

Эти понятия появились в ООП потому, что это было требованием бизнеса — делать более хорошие, расширяемые, гибкие программы.

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

ООП → индустрия → требования к расширяемости → SOLID, GRASP.

ФП-архитектура существует

Саша Гранин ("Functional Design and Architecture") — попытка систематизировать архитектурный взгляд на ФП. Hexagonal architecture, Ports & Adapters также применимы к ФП.

Паттерны переосмыслены в ФП-стиле

GoF паттерн ФП-аналог
Strategy Передача функции
Command Замыкание с захваченными аргументами
Observer Callback / Subscribe / Stream
Iterator Generator / Iterable
Visitor pattern matching
Adapter wrapper-функция
Decorator HOF
Chain of Responsibility pipe / compose / middleware
Template Method HOF с hook-функциями
State Sum-тип + функции по варианту

Bridge как SRP на уровне иерархий

Bridge — это SRP, только на уровне иерархии классов. Мост — это связка двух деревьев, двух или более деревьев. Зацепление из семейств двух контрактов.

В ФП Bridge — это два contract type-а (например Renderer и Application) и функция-связка (Mount).

type Renderer = (nodes: Node) => Element | null;
type Mount = (render: Renderer, app: Application, opts?: Options) => void;

Mediator в ФП — message bus

Mediator паттерн = центральный объект, через который объекты общаются. В ФП — pub/sub шина или actor с send-методом.

Связанные темы

Ресурсы