ФП и 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-методом.
Связанные темы
Ресурсы
- Лекция: SEtJ_HjV6Aw
- Mediator+Bridge: bTLKpZgED5I
- Беседа GRASP/SOLID/GoF: LJJpbFcmKQs