Pull to refresh
31
0
Антон Куранов @Throwable

Пользователь

Send message

По-идее так и нужно делать, но уж больно смахивает на обычный конструктор. Когда полей немного проще всех запихать в конструктор (или несколько перегруженных), объявив опциональные значения как @Nullable, и вообще не заморачиваться ни с какими билдерами. Я вообще все поля делаю public final, чтобы еще и геттеры убрать. Вот в Immutables у билдеров есть очень полезная фича — это клонирование объекта с изменениями.

Просто чтобы понять суть многих проблем, посмотрите обсуждения, которые велись в блоге Kotlin, когда он еще был на этапе дизайна. Там тоже предлагали многообещающие нововведения, от большинства которых впоследствии пришлось отказаться, например от функции с множественным результатом. Некоторые из них все же были реализованы, но совсем в другом виде.

С присваиванием все просто — доступ к полю приоритетнее, и тогда ничего из уже написанного не сломается. И даже хрен с ним уж с присваиванием — пусть так и оставят setXXX(). Главная задача пропертей — это добавить сахорочку и уменьшить бойлерплейт на этапе определения объекта. Потому как более чем в 99% случаем все ваши геттеры-сеттеры — это тупо автогенерация доступа к полю. Для всех остальных случаев оставить обычный фолбэк в геттеры-сеттеры.


Сейчас для создания одного! свойства в Java приходится писать его имя 7-12 раз, его тип 3 раза, 2-3 раза повторяющийся джавадок и в общей сложности используя 19+ слов. Это есть настоящий идиотизм.


Кроме того, я устал от классов и хочу, чтобы все было интерфейсом, и чтобы проперти можно было описывать и там.

А вот классификация и типизация вполне себе присуща ежедневным рассуждениям, даже когда вы обсуждаете поход в магазин и покупку каких-то яблок и каких-то стейков, например.

Как правило в этом случае задача стоит достаточно конкретно и для ее решения хватает системы типов, предоставляемой типичным ООП-языком. Делал я как-то движок для покера, и подумал, что как раз тут пригодилась бы система типов для вычисления комбинаций. Оказывается, есть реализация на Хаскеле. Принцип более-менее понятен. Однако не могу сказать, что представленная модель сильно напоминает человеческое описание правил игры, а также, что сходный функционал на Java сильно в чем-то уступает.


Не понял, почему?

Может это вы оказались хорошим специалистов на фоне остальных, может задача была специфическая и ее эффективнее было решать на Хаскеле, может еще куча причин было. Я не слышал success stories от массового применения Хаскеля в компаниях, почему бы, если он настолько удешевляет разработку?


Почему в одной транзакции не может быть произвольного набора действий?

Для примера возьмем абстрактный регистр X и какие-нибудь два вычисления, изменяющие его значения: X := f1(X) и X := f2(X). Не важно какая реализация у X — STM, файл или строка в базе данных. Есть всего два варианта реализации транзакции:


  1. Все чтения X будут выдавать одно и то же значение, которое было на момент начала транзакции, а все изменения X будут видны уже после транзакции.
  2. Все последовательные изменения X будут видны в той же транзакции.

И оба способа плохие. В первом случае мы сразу получаем проблему "lost update". Во втором случае логика полагается на последовательное применение операций. Но поскольку в нашей функциональной программе последовательность чтений и записей не определена (или определена неявно), то это будет вести к трудноотловимым ошибкам.

Основной недостаток паттерна Builder — это то, что в отличие от конструктора, он синтаксически никак не учитывает обязательные поля, и позволяет вызвать build() до того, как все необходимые значения будут установлены. При этом даже в рантайме проверка может как делаться, так и не делаться. И для этого нет хорошего решения. Поэтому паттерн Builder полезен лишь когда у нас все поля опциональные.

п15. Чтоб можно было грабить корованы.


Очень наивные утверждения, ломающие обратную совместимость, либо рудиментарные, либо вообще не реализуемые ввиду возникающих побочных проблем. Из здравого я бы отметил только п.3 — properties. Легко реализуемо и сразу убирает огромное количество бойлерплейта.

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

Сущности — это лишь компоновка общего стейта, которая может отличаться для различных парадигм. Не важно чем он представлен — записями, объектами, переменными, таблицами в базе. Весь стейт мутирует всегда предсказуемо при последовательном применении операций, что отвечает интуитивной концепции времени. В каждый момент у нас есть стабильный snapshot всей нашей вселенной. Когда речь заходит о паралельном программировании, и нарушается sequential consistency, то все-равно так или иначе всю задачу стремятся свести к последовательному выполнению, изолируя области данных (например стек) и используя уже избитые примитивы синхронизации.
Да, ООП далеко не самая лучшая парадигма, и большинство фреймворков предлагает обычное процедурное программирование даже в ООП-языках, разделяя stateful и stateless объекты.


Всякие вещи на подобии взаимодействия с базами данных отделяются и отчищаются, смысл в том, что бы контролировать побочные эффекты, хаскель поощряет использование чистых функций

Как я уже писал выше, это предполагает определенную компоновку бизнес логики: т.е. мы отделяем все чистое и вычислимое от всего грязного и "эффектного". Хорошо, если у нас более-менее однородная задача, и она вся легко перекомпонуется — все эффекты, например, можно свалить вконец операции. Но это не всегда подходит для сложных бизнес-задач, которые состоят из множества других атомарных модулей, каждый из которых содержит как вычисление, так и действие.

Основной смысл в разделении эффектов и возможность выразить пусть и императивную предметную область максимально типобезопасно.

Я очень даже за типы и ненавижу безтиповые языки. Однако ни одна из современных областей знаний, кроме математики, на сегодня не оперирует терминами теории категорий и гомотопической теории типов. Поэтому если внезапно удастся создать Теорию Всего (и описать ее на Хаскеле), скорей всего она так и останется теорией, ибо пользоваться ей будет бесконечно сложно.
Между прочим сам алгоритм на императивном даже безтиповом языке программирования — это тоже вариант описания предметной области. И далеко не факт, что описание при помощи системы типов будет проще и понятнее самой императивной программы. Как указал один из респондентов, система типов может быть бойлерплейтом.


Я просто делаю за три месяца то, что соседняя команда обещала сделать за 9, и у меня всё готово

Ну вот это нифига не показатель. Показателем будет, например, когда весь стек компании (или большое число разнотипных задач) переписали на Хаскель, и стоимость проекта/сроки сдачи уменьшились на столько-то.


Ну будет часть бизнес-логики жить в какой-нибудь монаде типа STM, тоже мне проблема. Зато, опыт показывает, значимая часть всё ещё будет чистой, хорошо тестируемой, композируемой и так далее.

Все данные в STM не запихаешь, а чтобы база стала STM, нужен как минимум serializable уровень изоляции. Кроме того, чтобы обеспечить чистоту, вам придется отделить все чтения от всех записей, а такая компоновка не всегда соответствует задаче — все-таки в каждом из бизнес-модулей выполняются сразу как чтения, так и записи.

Т.н. "вычисление" не может достать что-то из БД или не может вызвать системную функцию? И функции внутри функциональной композиции не могут иметь "действия"?
Да, я имел ввиду именно негарантированный и вообще неявный порядок вычисления, когда вы делаете сложную композицию из функций, которые внутри содержат некие действия с общим стейтом. И я так думаю, это именно те случаи, которые имел ввиду Игорь Шевнин в своей фразе.

Игорь Шевнин: Ленивая модель вычислений обычно помогает, но когда порядок вызова функций важен, может быть трудно разобраться, что происходит.

Когда порядок функций важен (например когда надо приготовить файл или написать в базу), вы должны въявную это указывать при помощи IO/do, что как бы и есть императивное программирование. Другое дело, что ваш Хаскель таки на ура разрешает сайд-эффекты, а далеко не каждый разработчик сможет их увидеть. И в один прекрасный момент вместо (INSERT-UPDATE) выполняется (UPDATE-INSERT), вызывая очередную головную боль.


Игорь Шевнин: Но благодаря краткости и строгости Haskell подходит почти для любых задач.
Doctor_Ryner: Зачастую сложные конструкции Haskell позволяют создавать очень короткие решения, которые еще и оказываются очень гибкими и модульными.

Короткие не значит понятные. Был такой write-only язык Perl, там тоже были короткие однострочники, в которых сам автор уже через неделю нифига не шарил.


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

В ООП мире моделируется система сущностей, наиболее приближенная к реальному миру, а также ее эволюция во времени. В ФП моделируются абстрактные преобразования над исходными данными. Но тем не менее на определенном этапе любое ФП всегда скатывается в императивное программирование, например, когда нужно осуществить системные вызовы в определенной последовательности, и именно здесь начинаются настоящие сайд-эффекты. Без этого никак.


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

В том-то и дело. С одной стороны, мы хотим дать исчерпывающее описание предметной области на этапе декларации, чтобы компилятор отловил как можно больше и т.д. С другой стороны, а так ли это необходимо, и стоит ли платить за это ценой простоты и понятности кода, когда проще поставить в коде пару assert-ов или ручных приведений типов? Если учесть, что большинство сегодня вообще пишет без типов (JS, Python) и как-то худо-бедно справляется. Когда вы объясните клиенту, как моноиды и полугруппы связаны с его прибылью, тогда и поговорим за мощную систему типов.


Под андроид на Haskell будет скорее всего трудно писать, в этом случае лучше Java. А вот сервера писать на Haskell почти также удобно как и на Java.

Уже смущает слово "почти". Как только прикрутите к серверу базу данных, так у вас появится мутабельный стейт, и вся девственная чистота функций будет варварски сломана. Поэтому код потребует императивного последовательного применения изменений стейта, что не сильно будет отличаться от кода на Java + фреймворк.


Масло в огонь подливает то, что язык накладывает кучу «ограничений», не позволяет или сильно затрудняет кучу вещей, которые не вписываются в функциональную концепцию.

Ну да, это как всегда задачи виноваты, что не подходят под такой прекрасный язык.


Джон Доу: Чтобы первый элементарный проект хотя бы просто скомпилировался, ушло почти два месяца курения учебников, мануалов и туториалов по вечерам.

Прям мытарства какие-то с религиозным оттенком. На Ноде, РубиРейлсе или Спрингбуте через 5 минут уже все запустится, и работать будет не хуже. С таким же успехом можно программировать на брейнфаке и гордиться этим. Концептуальненько! Любой же нуб хочет сразу видеть что-то работающее, а уже потом разбираться с этим. На два месяца терпения ни у никого не хватит.


Денис Мирзоев: Да. Мне кажется высокомерность связана с тем, что они очень любят свой язык и расстроены его недооценённостью.

Высокомерность говорит о том, что в большинстве случаев ЧСВ — это единственная мотивация почему эти люди изучили Хаскель. Компенсируют что-то.


Вобщем, набор противоречащих мнений и отзывов. Поэтому стоит делать из Хаскеля очередного карго-культа, а из хаскелистов богов-гуру. В конце-концов, каждый мочит как он хочет.

Так что про гравитационное поле достаточно.

Как это достаточно? Именно гравитация забесплатно поднимет в стратосферу шарик с гелием, с которого уже можно будет запустить что-нибудь небольшое на реактивной тяге. Топливная экономия в 10км.


4.4. А зачем вообще таскать энергию ракету себя с собой?

4.4.6. Из пушки на Луну. Классика!

Объект Date включает в себя toString(), toLocaleString() и их методы расширения. Но пользы от них мало, поскольку они используются, в основном, для возвращения строк на основе местного часового пояса, причём возвращаемые значения зависят от браузера и ОС.

Браузер и ОС как раз используют базу IANA, а Date.toLocaleString() позволяет указать timezone в формате IANA (а соответственно представить время в любой TZ). Так что метод очень даже полезный.


Moment — отработанная JavaScript-библиотека, почти ставшая стандартом.

В Java была JodaTime, которая тоже таскала с собой свой tzdata. И основной недостаток — это когда меняется tzdata (иногда правительство устраивает такой геморрой своим гражданам), приходится следить за всеми обновлениями и каждый раз выпускать новую версию софта. Тогда как системный tzdata приходит клиенту автоматически с обновлениями ОС.

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

То, что стало можно передать функцию в качестве параметра — это еще не ФП, а лишь элементы ФП. Да, многие языки переняли некоторые идеи ФП для удобства использования в определенных операциях, но при этом весь основной дизайн приложения остается в ООП и императивной парадигме. В частности, упомянутый filter/map/fold используется теперь как инструмент работы с коллекциями, и на нем в большинстве случаев и заканчивается весь перенятый ФП. И это нормально, когда в языки портируют наиболее интересные идеи, использование которых будет оправдано в определенных кейсах. Но ФП далеко не серебряная пуля, как заявляет автор и другие приверженцы, и сильно усложняет дизайн приложения например там, где появляется мутабельный стейт (например база данных — здесь ФП наполняется императивными хаками ввиде IO/do), или там, где необходимо моделирование сущностей/свойств и их отношений.


Вам видится, что ФП не популярно? Мне пока видится ровно наоборот, как и тенденции.

Если следовать всем тенденциям, то и блокчейн непременно должен быть в каждом пылесосе и утюге. :) О причинах непопулярности pure-ФП языков сказал предыдущий оратор в треде.

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


Скала — это именно академический язык, помойка, в которую Одерски жадно набросал все, что только можно из других языков программирования в надежде, что это привлечет рыбех всевозможного калибра. Во времена застоя джавы он начал сильно форсить скалу как улучшенную джаву (потом, правда диаметрально поменял свое мнение, говоря, что скала — это совершенно другой язык), и на этот крючок попалось много компаний и разрабов (в т.ч. и я). Основным профитом заявлялась возможность при помощи системы типов писать DSL-и для предметной области. Но что-то как-то не сильно взлетело. Язык оказался сложным, громоздким, медленным в компиляции, трудночитаемым, не таким интероперабельным с Java, а также проблемным в совместимости с собственными версиями. Код зачастую превращался в мультипарадигменное месиво, которое было сложно контролировать (причем парадокс: те, кто только осваивал скалу писали лучший код, чем те, кто уже что-то на ней умел). Early-adopters вцелом оставались недовольными и зачастую переписывали свой стек обратно на Java. А тут еще Java 8 с лямбдами подоспела, что вызвало массовый обратный отток разрабов. Те же, кого не устраивала Java уже активно смотрели в сторону Котлина, который ехидно заявлял, что не ставит целью соперничать со скалой. В конце-концов, Одерски понял свою ошибку, но время уже было упущено.


Фактически единственной областью, где скала зарекомендовала себя — это потоковая обработка данных, и то во-многом благодаря сложившимся обстоятельствам в виде Akka. Чувствуя долгожданный профит, Одерски с друзьями запиливает Typesafe (ныне Lightbend), куда сваливает все необходимое для законченного решения.


Ну и как бы что Spark? У него есть удобоваримый Java-интерфейс. Да, написан на скале. С таким же успехом он мог бы быть написан на Java/Kotlin/Groovy.

Я тоже думал легенда, но вот нет. Американские и некоторые европейские банки до сих пор используют процессинг на коболе, и вроде как менять не собираются. У нас в компании в банковском департаменте до сих пор сидят коболисты и что-то делают. Рынок, конечно, ограниченный, но время от времени всплывают предложения для кобола.

Хорошо, я вас понял. Зайдем с другой стороны. Ответьте тогда на вопрос, почему на сегодняшний день при всех своих очевидных преимуществах ФП-языки так не популярны? Более того, за всю историю они никогда не были особо популярными? И тенденция к их популяризации в будущем тоже не радует. О них внезапно всмопнили десять лет назад, когда понадобилось масштабировать параллельные вычисления. Какой вы можете назвать общеизвестный проект, который написан на вашем любимом Хаскеле? У какого ФП-языка экосистема хотя бы приблизилась к объему C/C++/Java/JS? И какие будут соображения о причинах этого? Можете даже выбрать:


  • ФП сложны для понимания. Большинство людей обходится более простыми и понятными методами.
  • ФП не обучают в ВУЗах. На рынке мало специалистов по ФП, а соответственно возрастают риски и стоимость проекта.
  • ФП эффективны в решении определенного круга задач, но не подходят в качестве универсального инструмента.
  • ФП не подходят для больших проектов и не совместимы с используемыми там методологиями.
  • На ФП плохо моделировать предметную область, например сущности и отношения.
Обычно люди разговаривают и объясняют задачи на языке вообще не предназначенном для программирования, часто смешивая императивное "как" и декларативное "что".

Как раз человеку очень хорошо понятна последовательности действий, которая интуитивно связана с концепцей времени. И на этом языке можно вести диалог с заказчиком: сходи туда, получи такие-то данные, вызови этот интерфейс, затем вычисли то, и сохрани там и т.д… Фраза "копать от забора и до обеда" понятна любому солдату, тогда на ФП это будет бред вроде: "для обеда смотри: забор? копай метр, иначе смотри предыдущий метр и копай метр".


Был уже как-то язык, который был "близок к бизнесу", COBOL назывался, и что в итоге?

До сих пор индустриальный стандарт в банковской системе, а специалисты по нему наиболее высокооплачиваемые. Но не суть.


"Математичность" же синтаксиса — это реализация вполне разумного стремления сделать код читаемее человеческой речи, которая плохо структурированна, не имеет ни операционной, ни денотационной семантики и вообще слабо подходит для описания вычислений.

То есть вас не смущают в Scala идентификаторы, составленные из символов !\$%&/|, которые к тому же могут оказаться вообще всем чем угодно. То есть любой человек, взглянув на код "a! b" без детального анализа контекста сразу же поймет, что это эквивалентно a.sendMessage(b), только гораздо лаконичнее и математичнее. Императивные языки используют минимальный набор простых и понятных управляющих статичных конструкций (в минимуме — условие и цикл), в то время в функциональном языке вся логика — это композиция вычислений, к тому же динамически связанная.


Но фичи, знаете ли, вводятся не затем, чтобы сделать что-то сложнее и элитарнее.

Этим и отличаются академические языки от промышленных. В академических (таких как Хаскель или Скала) фичи вводятся просто чтобы было, например на основе чьей-то научной работы. Затем некоторые из них мигрируют в той или иной форме в промышленные, и только когда доказана их полезность.


В общем-то все эти претензии вместе взятые выглядят как "это не императивное программирование

Точно также можно сказать в ответ, "я выучил ФП, и теперь все, кто его не умеет или не хочет — говно".
Мои претензии — это не стоит рекламировать ФП как универсальную парадигму для всего (впрочем как и любую другугю). Количество задач там, где ее применение оправдано, достаточно ограниченно (посмотрите: сейчас это в основном потоковая обработка данных и распределенные вычисления). Для остальных задач проще и дешевле использовать традиционный подход.

Почему НЕ стоит использовать функциональное программирование (в бизнес-приложениях)?


  • менталитет людей не поменять, зачастую описание (и понимание) задачи приводится императивно ввиде линейного бизнес-процесса или алгоритма
  • многие ФП-языки не типизированные со всеми вытекающими проблемами
  • устаревший и непривычный синтаксис (и понятия) более близкий к математике, нежели к бизнесу
  • система типов базируется на сложных для понимания абстрактных понятиях
  • невозможность привычного дебага
  • отсутствие стейта и сложность мониторинга
  • параллельный мир: сложно интегрировать с уже существующими не ФП-технологиями (коих чуть менее, чем все), особенно там, где появляется state или IO и функции перестают быть чистыми.

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

Хочется добавить, что часто публикуемый однострочник для рекурсивного удаления файлов неверен и зачастую может выдавать java.nio.file.NoSuchFileException:


Files.walk(rootPath)
    .sorted(Comparator.reverseOrder())
    .forEach(p -> {
        try { Files.delete(p); }
        catch(IOException e) { /* ... */ }
      });

Information

Rating
Does not participate
Location
Madrid, Испания
Registered
Activity