Ну да, эти методологии часто сосуществуют вместе, но батл это битва крайностей 🥊
Так что всё таки
Фабрики и наследование или монады и функторы? Мьютбл или иммьютбл ? Java или Haskell ?
Объектно-ориентированное программирование
или
Функциональное программирование
Публичный пост
8 июня 2020
984
за «Объектно-ориентированное программирование»
за «Функциональное программирование»
Окей, не всегда. Я не про идиоматичный haskell-код, а про применение принципов ФП к повседневной разработке:
Эти вещи делают поток выполнения более понятным, за кодом проще следить. Микросервисы вот стараются строить по тем же принципам по тем же причинам.
Поэтому многие мейнстрим-языки сейчас внедряют элементы, которые раньше были только во всяких хаскелях: pattern matching, монады (привет, async/await!), рекорды.
Если раньше corutine, lambda, map, reduce, filter был уделом функциональных языков, то сейчас это втащили даже в джаву. И чем дальше тем больше будет функциональщины в языках.
Причина проста, закон мура уже не работает. Просто посмотрите на процессоры, тот же Ryzen хвастается 128 потоками исполнения, на что UltraSPARC T1 смотрит скептически. Да 15 лет назад был такой же SPARC. Стоил только как SPARC :) Но если мы возьмем прирост производительности ядра, то... современный CPU не далеко ущел от CPU 5 летней давности. Разница в производительности не радикальная.
А чем больше у нас потоков исполнения тем больше нам использовать хочется использовать все. ООП не имеет примитивов и подходов из коробки позволяющих это делать. А ФП может умеет и практикует. Более того позволяет делать это естественным образом, так что не сводит с ума того кто программирует и позволяет писать более компактный код. Минус же такого кода, нужно въезжать в концепцию и практиковать регуляно.
Обратная сторона микроинстансы. Там тоже ФП позволяет в рамках одного потока исполнения делать больше и лучше.
Был момент, когда каждая третья статья в интернете говорила о том, что эра ООП прошла, и в светлом будущем человечество будет писать функциональный код.
Ну и как бывает, хайп кончился, и все кто попробовал хаскель и пр. молодцы, а кто нет, вроде бы все ещё не стали невостребованными специалистами, кек.
Да, говорили они, "в некоторых сферах функциональный код намного лучше, да и вообще в нем нельзя сделать багов", но мы то с вами знаем :))
Одна из основных идей ООП это сокрытие данных. Это может быть удобно для абстракции, но очень неудобно, когда нужно обеспечивать одновременный доступ. Отсюда и появляются блокировки, дедлоки и race conditions.
ФП с неизменяемостью по умолчанию и данными на виду позволяет параллелить вычисления очень естественно. Часто это даже может сделать компилятор.
...конечно, выше, чем у процедурного, но ниже, чем у ФП. Это позволяет как минимум значительно удешевить разработку.
Процитирую своего коллегу: "Как-то я кодил на Scala, и из-за количества закрывающих скобочек код выглядит так, будто кто-то от души поугорал".
Говорят, человек не может за раз удержать в голове более ~7 элементов. То есть, цепочка вызовов функций, по-хорошему, не должна превышать это число — код становится трудным для понимания. Добавьте сюда человеческую лень и склонность мозга всячески экономить энергию, и это число сократится ещё на пару пунктов.
Часто от приверженцев ФП можно слышать аргумент а-ля "ты просто туповат(а) для ФП". Да, простите, я не bigdata-ml-highload-faang-engineer, но далеко не во всех областях это нужно.
В конце концов, чем проще программа для понимания, тем проще её отлаживать, а следовательно, качество ПО будет расти. Поэтому лучше пусть код будет написан максимально "для тупых".
Я за функциональные языки с динамической типизацией (Racket, Clojure) или императивные со статической, которые не имеют механизма наследования, а только композиции (Go). Разработчики не имеют достаточно контекста, чтобы пользоваться ООП и функциональными языками со строгой статической типизацией корректно. Попытки все типизировать и определить границы взаимодействия обычно не имеют смысла в большей части проектов, особенно на ранней стадии. Вам повезло, если у вас легко формализуемая область или вы знаете ваш домен настолько, чтобы попытаться использовать ООП или ML-подобное ФП.
И даже во дворе
ФП и его элементы отлично работает в отдельных областях приложения, но в других превращается в write-only code. Современные практики берут в себя лучшее из обоих миров; но в целом в любой непонятной ситуации лучше начинать с ООП.
А если серьезно, я вижу это все так: на самом деле, деление на парадигмы должно умереть как рудимент. Парадигмы существуют ни для чего, кроме как ссорить людей и плодить карго культы. Ни одна из них не акцентирует внимание на том, что действительно важно.
Есть такая штука как "three layer cake". "Трехслойный пирог" - ИМХО единственно верная высокоуровневая архитектура приложений. Все остальные методики - порты-адаптеры, чистая архитектура, луковка, гексагональная - либо неявно повторяют трехслойный пирог используя другую терминологию, либо провальны.
Статья написана по Хаскелю, но потенциально, на самом деле, идея применима абсолютно для любого стека. И на мой субъективный взгляд, послесловие этого поста поясняет очень иллюстративно, что есть где и зачем.