Я хочу заметить: речь пойдет не о лямбда выражениях в Java/Python, а о более продвинутом ФП, типа Haskell или Scala с cats/scalaz.
Итак, я утверждаю, что:
- ФП далеко не везде применимо.
- Приносит головную боль при интеграции с готовыми решениями.
- Тратить время на ФП не всегда разумно.
Разберем эти пункты более подробно и оценим масштаб трагедии.
1. ФП далеко не везде применимо
Это кажется удивительным, но далеко не все это понимают. Более того, такие языки, как С, очень далеки от своего заката. Гораздо дальше, чем Haskell или Scala. Взгляните на любой игровой движок. С вероятностью 90%, большая его часть написана на С. Взгляните в прошивку любого бытового устройства в своей квартире. Скорее всего, это снова С! Операционные системы? Конечно, С.
Почему же так происходит? Дело в том, что все вышеперечисленное работает напрямую с железом. Железо не знает никаких функций высшего порядка. Железо — это набор регистров (что уже является изменяемым состоянием), прерываний (опять же, которые изменяют состояние) и команд, которые переносят нули и единицы из одной ячейки в другую.
Конечно, можно воспользоваться абстракцией и забыть про все эти железные штуки. Но во-первых, это не всегда разумно. Если наша программа достаточно простая, то нет смысла закрываться какими-то слоями абстракции. Во-вторых, часто в таких программах скорость работы ставится на одну из ключевых позиций. Поэтому дополнительные затраты на “объяснение” железу ФП полностью погубит пользу вашей разработки. ФП здесь проявить себя не может.
2. Приносит головную боль при интеграции с готовыми решениями
В каждом уважающем себя языке программирования есть большое количество готовых решений. В С# — это, например, Entity Framework и .Net. В Java — это Hibernate и Spring. И почти каждый фреймворк нацелен на работу в привычном нам ООП стиле. Почти всегда эти решения имеют изменяемые состояния и совершенно не пригодны для работы с чистым ФП.
Любой прожженный функциональный программист скажет, что надо выкинуть эти решения и работать без них. Окей. Давайте просто для справки прикинем, что мы потеряем от такого решения:
- Почти всегда такие решения приводят к boilerplate коду.
- Мы теряем огромный пласт функционала. Конечно, мы можем взять готовую библиотеку для работы в функциональной парадигме. Но почти всегда такое решение гораздо менее популярно, а значит не может предложить и половины всех возможностей популярных решений.
- Готовые продукты, которые используют такое решение, надо будет почти полностью рефакторить.
- Мы теряем хорошо протестированное и отлично детерминированное решение. Вместо этого мы идем в сторону неизвестности. Есть ли в популярных решениях проблемы? Конечно! Но о них, как правило, уже все давно известно. В нашем новом подходе такого точно не будет.
На самом деле список можно продолжать еще долго. На мой взгляд, совокупность потерь делает ФП, как минимум, не везде и не всегда пригодным.
3. Тратить время на ФП не всегда разумно
Что удивляет не менее, часто программисты не видят, что стоит за кодом. Не всегда язык программирования и парадигма определяет качество продукта. На бэке все идет к контейнеризации. Уже почти не важно на чем вы пишете: Python, Java, Scala. Код на любом из этих языков можно обернуть в образ и поставлять контейнером.
В таком мире не столь важно, что внутри контейнера, если оно отвечает всем поставленным требованиям. Здесь более важно, как организована система целиком. Возникает вопрос: вы действительно уверены, что ваше время стоит вкладывать в изучение ФП с его теорией категорий? Возможно стоит вложиться в развитие общей архитектуры системы. К тому же, найти людей без знания ФП, которые готовы предоставить вам такие контейнеры, гораздо легче.
Представьте себе такую ситуацию. Вы сидите ночами и изучаете всю теорию. Вы смотрите ролики на YouTube, читаете книги, вникаете в математические выкладки. Со временем вы уже можете построить небольшое приложение, но еще не все понятно. Вы начинаете практиковаться дальше: берете более продвинутые книги, ходите на митапы, ведете с коллегами разговоры о высоком. Но вот появился реальный проект. С вашими знаниями вы попадаете на лидирующую роль в этом проекте. Жизнь удалась! И вот вы написали просто идеальный сервис. Остается всего одна проблема. Что с ним делать дальше? Как настроить процесс автоматизации? Как настроить “умную” балансировку? Как другим сервисом найти ваш? На эти вопросы ответа у вас может просто не быть! Вы еще уверены, что ФП вам так необходимо?
Выводы
На самом деле, я отношусь к ФП крайне положительно. Все, что я хочу сказать: это инструмент, который подходит далеко не всегда и везде. На мой взгляд, инженер не должен мыслить категориями нравится/не нравится. Вместо этого должны быть максимально объективные причины для использования того или иного решения.
Прежде чем изучать/внедрять функциональную парадигму, следует задаться как минимум тремя вопросами: возможность применения в своей профессиональной области, на сколько дорого это может сказаться при интеграции с готовыми решениями и окупятся ли потраченные время и ресурсы. Если у вас не возникает панической атаки ни от одного из этих вопросов, то можно брать на вооружение.
Спасибо за внимание!
Комментарии (40)
SkylineIT
04.10.2018 12:57+2Скоро людей, которые пишут на C++/C#/Java, вообще не останется.
Эммм… Сильное заявление.
Писал 2 года на Scala в Spark'e. Писал, писал, всё здорово. Начал менять работу после слов: «Зачем нам один дорогой Scala разработчик, если можно взять 2-3 Java разработчиков и научить работать со Spark?».
Смотрел конференцию когда-то давно (наверное в 2017 году) Евгения Борисова на JPoint, где как раз таки наоборот говорят о закате Scala.lyrix Автор
04.10.2018 15:26Все верно. Следующие два предложения после цитаты как раз об этом и говорят.
compilator
04.10.2018 17:03Тоже слышал про закат Скалы, где-то в конце 2015. Но судя по тому что скоро выйдет 3-я версия, помоему с ней всё хорошо.
ROKarpov
04.10.2018 17:27+1Скоро людей, которые пишут на C++/C#/Java, вообще не останется. Так ли это? Не думаю
sshikov
04.10.2018 20:22У меня вокруг по большей части Spark разработчики. Большая часть из них пишет на Java. Но при этом, насколько я знаю, ни для кого не составляет особого труда между делом наваять сотню-другую строк в Spark Shell, который есть scala в чистом виде.
- не понимаю тех, кто разделяет эти понятия. Разработчик — он либо разработчик, либо не.
- с выходом Java 8 произошел сильный сдвиг в применимости ФП в Java. На сегодня они скорее сближаются, чем отдаляются.
- 2017 это очень давно по меркам развития языков. Все уже тогда ждали scala 3, и сейчас ждут. То что там обещано — выглядит хорошо. И это будет вероятно упрощение.
aamonster
04.10.2018 15:03+1«Возникает вопрос: вы действительно уверены, что ваше время стоит вкладывать в изучение ФП с его теорией категорий?»
Именно на этот вопрос — ответ однозначно положительный. Лично я не готов пока переходить на ФП (хм… в основном потому, что никто особо и не предлагает — так бы было неплохо сменить парадигму для освежения мозгов), но его понимание помогает лучше писать и на нынешних императивных языках. Не говоря уж о том, что это лично мне просто интересно (возможно, в силу полученного образования или из-за чтения в детстве развлекательных книжек по математике типа Гарднера/Ллойда/Дьюдени).
nehaev
04.10.2018 15:24+1Я тоже люблю ФП и тоже считаю, что он не везде применим. Но агрументация, приведенная в статье, кажется мне крайне слабой.
ФП далеко не везде применимо — и это "далеко не везде" в итоге сводится к программированию железа. Но вот если что и есть "далеко не везде", так это программирование железа на низком уровне. Большинство популярных языков программирования (Java, C#, Python, JavaScript и т.п.) отделены от железа виртуальными машинами и интерпретаторами и вполне себе высокоуровневые для использования ФП.
Приносит головную боль при интеграции с готовыми решениями — это да, но прогресс не стоит на месте. В той же скале множество задач можно решить без использования джава-фреймворков. Ну и да, если бы люди всегда предпочитали "старые-добрые" EJB всему "новому и непонятному", то Spring никогда не стал бы "хорошо протестированным и отлично детерминированным решением".
Тратить время на ФП не всегда разумно — здесь все сводится к абсурдному тезису, что кроме кода есть еще архитектура. Кроме кода есть еще много чего, но если мы все-таки говорим про именно код, изучение ФП еще как имеет смысл.
lyrix Автор
04.10.2018 15:391) Железо — это один из случаев, когда вы не можете пользоваться ФП. Это факт.
2) Готовые решения — второй случай когда вы не всегда можете пользоваться ФП. Это факт.
3) Предположим ФП позволяет писать идеальные программы. Все, что я хочу сказать — это будет не столь важно со слабой архитурой. Если выбирать между кодом и архитектурой, то выбор должен падать на второе. Это же тоже понятно?
Таким образом, я показал, что, во-первых, есть низкоуровневый слой, где ФП мало применим. Во-вторых, есть моменты и на более высоких уровнях, в которых ФП себя хорошо не проявит. Вы же согласны с этим? Почему тогда это не соответствует теме статьи? Приведите свои аргументы. Мне правда интересно.
nehaev
04.10.2018 16:17Если выбирать между кодом и архитектурой, то выбор должен падать на второе. Это же тоже понятно?
Перед кем может стоять такой выбор?
Вы же согласны с этим? Почему тогда это не соответствует теме статьи?
Я согласен с введением и заключением, но приведенная аргументация меня не убеждает, поскольку каждый тезис можно опровергнуть, используя ту же логику.
Приведите свои аргументы. Мне правда интересно.
Аргументы против ФП? Даже не знаю. Я всегда использую ФП по умолчанию и отступаю от него только при наличии веских причин это сделать, причем происходит это настолько редко, что с трудом поддается какому-то обобщению.
lyrix Автор
04.10.2018 17:24+1Я согласен с введением и заключением, но приведенная аргументация меня не убеждает, поскольку каждый тезис можно опровергнуть, используя ту же логику.
Приведите пример использования той же логики в утвержднии, что ФП мало применимо на низком уровне и плохо сочетается с большинством готовых решений на многих языках. Я не совсем понимаю, что здесь противоречивого.
Аргументы против ФП?
Вообще не понял к чему вы это написали. Мы вроде обсуждали ограничения ФП, а не отказ от него…
Даже не знаю. Я всегда использую ФП по умолчанию и отступаю от него только при наличии веских причин это сделать, причем происходит это настолько редко, что с трудом поддается какому-то обобщению.
Вы согласны с введением и заключением, но не можете объяснить почему?
nehaev
04.10.2018 19:19+1Хм… То есть вы действительно не понимаете разницу между "ФП мало применимо на низком уровне" и "ФП далеко не везде применимо"? С первым мало кто будет спорить, но сводить второе к первому — весьма смелое преувеличение.
Про "головную боль при интеграции с готовыми решениями", опять-таки неверно для скалы, которую вы приводите в пример. И в целом аргументация не учитывает прогресс в софтостроении, "старое" не всегда значит "хорошее".
Про "выбор между архитектурой и кодом" — просто абсурд.
И естественно я согласен с вещами типа "инженер не должен мыслить категориями нравится/не нравится", это вроде достаточно очевидно. Каких еще объяснений вы от меня хотите?
sshikov
04.10.2018 20:15Тот уровнень, где реально нужно «железо», на сегодня лежит сильно ниже мобильного телефона. Так что для телефона это все уже не верно. Вон как хорошо туда котлин-то зашел.
И как показывает жизнь, он отодвигается все дальше и дальше. Так что это практически не аргумент.
Neftedollar
04.10.2018 22:46Контрпример — вполне себе пример глубокого проникновения ФП в "программирование железа". Да, это не читсяй ФП язык, но уж ФП там побольше чем во многих мейнстримовых языках.
evocatus
05.10.2018 15:37А на самом низком уровне — языки описания аппаратуры SystemVerilog и VHDL — ОЧЕНЬ похожи на функциональное программирование. И я бы хотел увидеть функциональные языки, которые бы транслировались в HDL.
muhaa
04.10.2018 15:50+1Рассмотренные в статье доводы слишком очевидны. Но допустим, основная проблема проекта — реализовать множество сложных переплетающихся друг с другом алгоритмов и функций и не утонуть в этом всем. Тогда вопрос: достаточно объектного, или принципиально лучше будет с ФП?
У одного физика видел интересное наблюдение: «Математики любят упорядочивать свои аргументы порой до степени полной непостижимости для непосвящённых». Когда я пытаюсь писать в функциональном стиле, у меня ощущение, что я занимаюсь чем-то похожим. Возможно с опытом это прошло бы.
eugene_bb
04.10.2018 17:00+3Можно еще один пункт рассмотреть:
Сейчас в функциональное программирование приходят в основном опытные разработчики и качество их работы выше среднего, не зависимо от того работают они в ФП или ООП стиле.
Если ФП станет майнстримом и подтянутся остальные, то скорее всего они найдут способы удивить тех, кто утверждает что ФП само по себе делает код в среднем качественнее.evocatus
05.10.2018 15:42Кстати, интересно посмотреть на работы тех студентов, которые начинали изучать программирование на LISP на курсе «The Structure and Interpretation of Computer Programs» в MIT с Hal Abelson и Jerald Sussman.
time2rfc
04.10.2018 17:24+2Очень интересная заметка, спасибо автору за публицкаю своих мыслей.
Недавно выходила на хабре статья со статистикой по зарплатам и она утверждала что медиана и максимальная зп у Scala программистов выше чем у Java программистов.
Как профессиональный Scala программист я полностью согласен с автором.
develop7
04.10.2018 18:53+1я бы на месте автора напротив всемерно приближал торжество функциональщины, чтобы в будущем делать состояние за пару лет поддержки императивщины (как современные укротители Кобола)
prefrontalCortex
04.10.2018 20:15Почему же так происходит? Дело в том, что все вышеперечисленное работает напрямую с железом. Железо не знает никаких функций высшего порядка.
Интересно, что вы скажете на тот факт, что иногда вполне себе функциональный (ну ладно, мультипарадигменный) Common Lisp позволяет писать оптимизированный высокопроизводительный код, вполне себе работающий с низкоуровневыми примитивами железа (SSE) и обгоняющий по производительности аналогичный код на C++?
lyrix Автор
05.10.2018 17:52Простите, причем тут С++? Обычно код для операционок, высопроизводительных движков и микроконтроллеров пишут на приемущественно на c, asm. Ни разу не видел прошивку на лиспе. Возможно я слишком молод для такого.
Не могли бы вы назвать игровой движок или какой-нибудь военный/космический проект с микроконтроллером на лиспе? Мне действительно интересно стало. Не особо представляю как там происходит жёсткий контроль управления памятью.
sshikov
04.10.2018 20:26Хотел бы я поглядеть, где автор в Spring нашел изменяемые состояния, которые мешают работать с ФП. На мой взгляд — это фигня какая-то, ничем не подтвержденная.
Vitter
04.10.2018 21:10Всё по отдельности «не везде применимо». Поскольку нет универсально-удобных инструментов для любых случаев.
Что касается «готовых решений» — ну, если вы фреймоврк под Java вы попытаетесь подключить к Haskell, то результат будет точно такой же как и подключение к PHP или JavaScript.
Для ФП языков создаются свои фреймворки, которые удобны для использования
kagetoki
05.10.2018 06:50Сумбур какой-то.
Уже почти не важно на чем вы пишете: Python, Java, Scala. Код на любом из этих языков можно обернуть в образ и поставлять контейнером.
С одной стороны вы говорите, что не важно на чем писать, с другой стороны говорите, что ФП может быть помехой. Если вы уже используете JVM или .net, вся экосистема вам уже доступна, все фреймворки и библиотеки к вашим услугам. Разница только в сложности поддержки кода, и для многих задач ФП обеспечит более легкий в поддержке код, особенно если речь идет про потоковую обработку данных и/или конкарренси.
В С# — это, например, Entity Framework и .Net. В Java — это Hibernate и Spring. И почти каждый фреймворк нацелен на работу в привычном нам ООП стиле. Почти всегда эти решения имеют изменяемые состояния и совершенно не пригодны для работы с чистым ФП.
То, что, например, EF работает с мутацией наших моделей, все еще не означает, что мы не можем его использовать из F#. Популярное решение — impure/pure/impure sandwich. Сделайте модели, которые будет мутировать EF, они все равно даже в ООП обычно сразу мапятся в другие модели, и наш собственный код их никак не мутирует. Собственно, конкретно в F# вы можете использовать рекорды с аттрибутом
[<CLIMutable>]
, который позволит десериализацию, но ваш код мутировать эти объекты не сможет.
вы действительно уверены, что ваше время стоит вкладывать в изучение ФП с его теорией категорий? Возможно стоит вложиться в развитие общей архитектуры системы.
Представьте себе, теория категорий в ФП тесно связана с построением архитектуры.
Остается всего одна проблема. Что с ним делать дальше? Как настроить процесс автоматизации? Как настроить “умную” балансировку? Как другим сервисом найти ваш? На эти вопросы ответа у вас может просто не быть!
Я не понял, как это связано с тем, на каком языке написан сервис. С момента, как вы его захостили и выставили публичный апи, всему остальному миру плевать, на чем внутри написан сервис, он использует его как черный ящик со стандартным протоколом коммуникации. Проблемы балансировки и service discovery тоже непонятно какое отношение имеют к парадигме программирования. Если уж на то пошло, есть Azure, который предоставляет автоскейлинг, например, для Azure Functions. И можно писать AF хоть на С#, хоть на F#, хоть на JS, не побоюсь этого слова.
Что касается вывода — да, любой инструмент хорош для подходящей задачи, спасибо. Но ничего нового вы нам тут не сказали.
vmm86
05.10.2018 09:38Сегодня все больше людей переходят на функциональную парадигму. Скоро людей, которые пишут на C++/C#/Java, вообще не останется. Так ли это?
Вы знаете, со временем телевидение перевернет жизнь всего человечества.
Ничего не будет: ни кино, ни театра, ни книг, ни газет — одно сплошное телевидение.
staticlab
nehaev
Чтобы сделать этот аргумент автора еще более абсурдным, можно переделать так:
lyrix Автор
Можно почти любое утверждение довести до абсурда подобным образом. Чем вы и воспользовались. В статье просто говорится о переоценке подхода к написанию программ. Больше это не монолит, а отдельный изолированный блок.
nehaev
Вполне возможно. Но из этого никак не следует, что тем кто пишет код этих микросервисов теперь не обязательно изучать парадигмы программирования.
lyrix Автор
Вы снова передёргиваете. Я не говорил о том, что не надо изучать парадигмы. Я просто хотел сказать, что вы должны понимать зачем вам это. Я же почти так и написал в заключении. Разве нет?
Не поверите сколько есть людей, которые все ещё пишут на Java 5, J2EE Легаси проекты и не планируют менять что-то. Мне кажется, что в таком случае следует выбирать в изучении и применении что-то отличное от Haskell. Не согласны?
nehaev
Ну если для вас текущий проект на Java 5 — это что-то вроде рабства, на всю жизнь — то да, не имеет смысл тратить силы на то, что выходит за его рамки. Но обычно все-таки люди изучают то, что им интересно, и потом находят занятие в соответствие со своими знаниями и интересами.