• Fighting complexity in software development
    +2

    It's pretty close to free monad. You can check free monad recipe out. Also there's turtle program interpreter example.
    Someone please correct me if I'm wrong, but free monad adds another layer of abstraction on top of interpreter: when in interpreter you have an exit node in you initial instruction tree, free monad has an additional type with 1 node for instruction (without exit node) and 1 exit node.

  • Я растерял веру в разработку, выгорел, но меня спас культ инструмента
    0

    Во-первых, можно использовать все то же самое (но лучше этого не делать)
    Во-вторых, функции, особенно в F#, очень легко композируются.
    Если делать именно dependency injection, то для этого помогает partial application, т.е вы просто указываете в вашей функции аргументами все необходимые зависимости, а реальный инпут указываете в самом конце:


    let getUser getUserDtoFromDb mapUserDto userId =
        userId |> (getUserDtoFromDb >> mapUserDto) // пихаем айдишник в функцию
    //созданную на лету из наших двух с помощью оператора ">>"
    
    let getUserImpl = getUser MyRepo.getUser MyMapper.mapUser // передаем зависимости (2 параметра из 3 необходимых, и получаем функцию, которая принимает айдишник и возвращает юзера из базы

    Но гораздо лучше делать dependency rejection и луковую архитектуру. Функции все так же будут легко композироваться, но будут более гранулярными и легче тестироваться.

  • Как правильно работать с исключениями в DDD
    +1

    Я абсолютно согласен с вами касательно семантики исключений, goto и читабельности.
    Раз уж вы решили использовать монады Result & Maybe, и вас при этом беспокоит невысокая читаемость конструкций работы с ними, в силу особенностей языка C#, у меня возникает вопрос: рассматривали вы для себя возможность перехода на F#, и если да, то почему воздержались?


    Работать с монадами там гораздо проще, как и определить конструкцию Result (которая уже есть в стандартной библиотеке начиная с версии 4.1):


    type Result<'Ok, 'Error> =
          | Ok of 'Ok
          | Error of 'Error

    и благодаря Computation Expressions "зараженность" резалтами больше не выглядит страшно:


    let createUser userDto =
        result {
             let! validatedDto = validate userDto //в случае Error возвращается ошибка, в случае Ok исполняется дальше
             let! userId = create validatedDto
             return userId
        }

    то же самое с Maybe.


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


    На эту тему есть отличная книга Скотта Влашина

  • Проблемные личности среди разработчиков
    +5

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


    • Отказался перерабатывать нахаляву — плохо относится к компании.
    • Не хочет больше подтирать за одним и тем же сотрудником — нет эмпатии/соучастия
    • Требует законный отпуск, хотя просят не уходить — не может войти в положение, выслушать
    • Устал от бесконечных костылей, говорит, что время инкрементального рефакторинга давно упущено, теперь только выбросить и переписать, а продолжать так жить больше нельзя — истерит и закапывается в перфекционизм, не может предложить решение
    • Разработчик объясняет срыв сроков тем, что руководитель проекта постоянно меняет требования в последний момент — не может взять ответственность на себя

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

  • Проблемные личности среди разработчиков
    +2
    Нет, он перешел в стадию поддержки, я ушел на другой, а потом и вовсе сменил компанию.
  • Проблемные личности среди разработчиков
    +12
    Он действительно знает, как писать отличное программное обеспечение, и если ему дать достаточно времени, то сможет создать идеальную систему. Проблема в том, что он верит, что у него есть всё время в мире и полная свобода, хотя это далеко не так. Вместо того, чтобы найти компромисс, он сосредоточился на создании идеальной системы. Он считает, что это лучше для бизнеса.

    Вот тут тонкий момент. Большинство людей, управляющих ИТ проектами, на моем опыте с легким сердцем ставят клеймо идеалиста на любом разработчике, которому не насрать на долгосрочную перспективу и который не хочет делать одну и ту же работу 10 раз. У них постоянно "заказчик хочет это вчера" и хоть трава не расти, а когда ты начинаешь объяснять, что кроме краткосрочной выгоды нас ждут тяжелые долгосрочные лишения, ты сразу идеалист и не понимаешь, как делать бизнес по-взрослому.


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


    И они в свое время меня почти задавили числом, я был готов поверить. Но повезло, и я попал на проект, где "ежедневные коммиты" не были приоритетом. И все прошло как по учебнику: долгое планирование и компетентный архитектор обеспечили проект, где вообще не было форсмажоров. Внедрение нового разработчика в команду не было проблемой, равно как и его выход из команды.


    Видел также прямо противоположную ситуацию: некомпитентный техлид и по совместительству интерфейс для заказчика за 3 месяца написания проекта с нуля породил легаси-монстра, как в плане архитектуры, так и в плане стабильности работы, я никогда не видел подобного. И каждый день на этом проекте проходил с девизом выкатить новую фичу как можно скорее, потому что заказчик ждет.
    Самое смешное, что я случайно потом спалил, что этот техлид сам бежит впереди паровоза, и подгоняет кнутом, даже когда заказчик сказал, что понял риски и готов дать столько времени, сколько нужно.


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

  • Приверженцы статической и динамической типизаций никогда не поймут друг друга. И TypeScript им не поможет
    0

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


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


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

  • Приверженцы статической и динамической типизаций никогда не поймут друг друга. И TypeScript им не поможет
    0
    Это я к тому, что вероятно, неверно относить язык к тому или иному виду типизации

    Язык либо динамически типизирован, либо статически. Он не может "плавать" где-то посередине. В языке могут быть различные средства для того, чтобы что-то почерпнуть из другого мира, например dynamic в C#. Но от того, что в сишарпе есть dynamic он не стал динамически типизированным.
    Еще, например, в С# есть неявное приведение типов. Но оно работает, только если заранее описать, как оно должно работать, оно не работает для всего и всегда. Да и делается обычно это для каких-то совсем очевидных случаев, вроде int -> long.


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


    Как бы вы ответили на вопрос: какой язык лучше, со слабой статической типизацией, или сильной динамической?

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

  • Приверженцы статической и динамической типизаций никогда не поймут друг друга. И TypeScript им не поможет
    0
    Нет, не у всех, я видел контрпримеры, как живьем, так и просто очень качественный код чужих проектов. Большинство факапов, которые я видел, вообще можно было бы избежать, тупо следуя самым базовым принципам DDD. Да что там ДДД, достаточно было просто сделать нормальную слабосвязанную систему, правильно разграничив ответственности. Но нет, об этом думать нам слишком долго, нам поформошлепить надо побыстрее, пользователи уже 10 минут новых фич не получали.
  • Приверженцы статической и динамической типизаций никогда не поймут друг друга. И TypeScript им не поможет
    +2
    Если плохо понять природу проекта или плохо уметь проектировать, конечно же, получится все ровно так, как вы описываете. Сначала будет трата времени на бойлерплейт, потом на борьбу с ним и болезненное натягивание совы на глобус.
    Кстати, именно так и происходит, когда за архитектуру берется мидл, даже сообразительный — просто опыта не хватает.

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

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

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

    Отдельно добавлю, что во многих мейнстримных языках (C#, Java, Go etc.) система типов слабая, не хватает банальных типов-сумм, я уже молчу про HKT. Тем не менее, это уже лучше, чем ничего.
  • Приверженцы статической и динамической типизаций никогда не поймут друг друга. И TypeScript им не поможет
    0
    Объекты могут незначительно различаться, но при этом все равно быть успешно распарсены одной JS функцией

    придется обертывать в try/catch практически весь код, а не предположительно наиболее уязвимые участки кода

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

    Точность, достойная тру-разработчика. Просто восхитительно. Надеюсь, вас в жизни не допустят до написания кода систем, имеющих хоть какое-то отношение к человеческому здоровью/жизни.


    "Наши самолеты в целом более менее скорее летают, чем падают. Предположительно большинство из них долетит до места назначения, наиболее похожие на критически уязвимые места в коде мы с большой вероятностью обернули в try/catch".

  • Приверженцы статической и динамической типизаций никогда не поймут друг друга. И TypeScript им не поможет
    0

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


    Вы упускаете суть строгой статической типизации: она защищает от ошибок проектирования. Если система типов имеет еще и алгебраические типы данных, то при правильном проектировании она защищает от ошибок бизнес-логики. Это очень хорошо описано в книге Скотта Влашина "Domain Modeling Made Functional", настоятельно рекомендую.

  • Приверженцы статической и динамической типизаций никогда не поймут друг друга. И TypeScript им не поможет
    +2

    А для чего придуманы знаки препинания и заглавные буквы?


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

  • Приверженцы статической и динамической типизаций никогда не поймут друг друга. И TypeScript им не поможет
    +4

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


    Другое ее применение — там, где поток требований к программе быстро и непредсказуемо меняется, и расходы на статические описания элементов программы (никто не будет спорить, что это расходы?) себя не оправдывают. Пример — веб-разработка.

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


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

    Что такое универсальные приложения? Это когда и мессенджер, и календарь, и ядро ОС немношк?




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


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

  • Приверженцы статической и динамической типизаций никогда не поймут друг друга. И TypeScript им не поможет
    +5

    После многих споров на тему статика vs динамика, у меня создалось устойчивое впечатление, что разработчики делятся на 2 лагеря:


    • Те, кто предпочитают думать, прежде чем что-то делать, а именно построить математическую модель и потом ее имплементировать.
    • Те, кому ближе философия "че тут думать, прыгать надо", а именно набросать что-то, а потом по ходу разбираться.

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

  • Приверженцы статической и динамической типизаций никогда не поймут друг друга. И TypeScript им не поможет
    +4
    В описанном сценарии типизация не виновата никак вообще. Возможно, алгоритм херовый, возможно, у постановщика задачи в голове моча и он не знает, что требовать и как продукт будет развиваться, возможно, программист херово знает язык, возможно задача в принципе не решаема. Ни динамическая, ни статическая типизация к этому отношения не имеют.

    О каких издержках кстати речь? Что код тормозит? Или процесс разработки слишком долгий? Или памяти много потребляется?
  • Приверженцы статической и динамической типизаций никогда не поймут друг друга. И TypeScript им не поможет
    +10
    Есть сложные задачи, в которых нет однозначного алгоритма, а его еще надо найти. Писать такие на статических языках — ад.

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

  • F# меня испортил, или почему я больше не хочу писать на C#
    +2
    Это не детский сад, это доказанный факт. Вы можете, конечно, глаза закрыть и притвориться, что вы в домике, но реальность это не отменит.

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


    Я же уже показывал, как такой код транслируется почти без потерь по размеру. Поскольку объявлений типов там нет, а есть только логика, то перевод будет с оверхедом ~15% (можете сами перевести и проверить), из них больше половины — скобки, то есть указанный вами код на c# по факту записывается с эффективным оверхедом около ~5%, примерно 128 строк вместо 121 (если брать второй файл, например). Как видно, ни о каком "f# позволяет писать на порядок меньше кода" говорить нельзя, экономия в 7 строчек из 128 — это детский сад.

    Вы первый файл смотрели? Там ТОЛЬКО объявления типов. Кстати, у вас с каждым следующим комментом заявленный оверхед магически уменьшается. Сначала было 30% с учетом скобок и 15% без, потом 15% с учетом скобок и 5% без.
    Да, киньте в меня плз ссылкой, где вы показывали это, сорян, если я в танке сижу и пропустил.


    Мне не нравится заставлять/предлагать вам переписать на C# то, что у меня есть на F#, но я не вижу другого выхода, раз вы кидаетесь громкими утверждениями и с потолка берете 121 строку и 5%.
    Если таки возьметесь за переписывание этих двух файлов — давайте облегчим задачу: необязательно транслировать 1 в 1. Просто реализуйте ту же логику: классическая змейка + перки на атаку и скорость с кулдауном. Потом сравним надежность, лаконичность и читаемость.

  • F# меня испортил, или почему я больше не хочу писать на C#
    +3

    Рассуждения о том, что Value Equality не нужно на практике (почитайте что ли про DDD и Value Objects vs Entities) — это детский сад. Оно не нужно такой ценой, оторой достается на C#, но нахаляву этому будут рады все.


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


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

  • F# меня испортил, или почему я больше не хочу писать на C#
    +1
    Нет разницы. Смысл в том что это не относится к клиентскому коду.

    Есть разница, и я сразу написал, в чем она. Раз уж меряем код — давайте мерять честно.


    При желании можно добавить, поправив реализацию Match/With и добавив кодировку кейзов, например, параметрами генерика. В клиентский код добавится по паре строк на тип примерно, но это все по факту неинтересно.

    Довайте добавим, если мы хотим полный эквивалент.


    И точная оценка в 30% — это не чудесное совпадение

    Это не точная оценка, много чего опущено.


    Это уже тоже к делу не относится, речь же о переписывании конкретного кода.

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


    Конечно, если у вас весь код — это объявление кучи discriminated unions, то тут получится выгадать ~30%

    Там объявлено 2 юниона. Это 11 строк из 117, которые там есть. Если вы думаете, что приведенный пример это специально надроченный семпл, чтобы показать максимум лаконичности, вы глубоко заблуждаетесь.


    И мой поинт все еще остается в силе — в F# меньше кода (даже по вашим приуменшенным оценкам), и код надежней.


    Скоро в c# добавят сахарок для рекордов и нормальный паттерн-матчинг (и nullable типы нормальные) и, с-но, все, до свидания, основные преимущества f# будут покрыты.

    Nullable типы будут не нормальные. На уровне рефлекшна никакой разницы не будет между string * string?, так что это уже хуже, чем Option<'T>.
    Record types — посмотрим, добавят ли подобие with синтаксиса.


    f# просто не предоставляет какие-либо средства, которые могли бы серьезно помочь в сокращении кода. Ну нету там таких средств. discriminated unions можно проще объявлять, деконструкцию в паттернах быстрее делать и экономить за счет сложных дслей в computational expressions — список закончился.

    Вы даже тут уже сами себе противоречите. Хотите преуменьшить возможности F# изо всех сил, но даже у вас набрался список из 3 серьезных пунктов, хотя говорите, что средств нету. Клоунада.

  • F# меня испортил, или почему я больше не хочу писать на C#
    +4

    match & with это не библиотечные функции, это языковая конструкция, так же как и if/else или switch case в сишарпе. И работает этот матч не только с заданными типами, а вообще с чем угодно. Так что справедливо было либо переписать на if else / switch case либо указать реализацию ваших функций Match & With. Кстати, в них будет пусть и небольшой, но оверхед, но это мелочи.
    Exhaustive check не особо нужная фича? С чего бы? Это ворнинг нахаляву (а при warning as errors ошибка компиляции) вместо юнит теста. Нихера себе ненужная фича.


    Да, а еще у вас нет null safety.


    Кстати, будет ли работать ваш from-select, ведь эти методы возвращают не IEnumerable?


    В итоге даже в таком примитивном примере, где нет ни многопоточности, ни сложной смены состояний, ничего вообще интересного, мы получили больше строк кода (кстати, не забудьте либо переписать на if else / switch либо добавить реализацию функции Match+With), а решение менее надежное. Что и требовалось доказать.

  • F# меня испортил, или почему я больше не хочу писать на C#
    0

    Если ваш код на F# — трансляция из C# один в один, то да, краткости не выйдет. Но при правильном применении абстракций кол-во кода сокращается. Временами, за счет оверхеда — и аллокаций больше, и перфоманс может просесть. В общем, все признаки перехода на более высокий уровень абстракции.


    А то, что F# ничего кроме сахара не имеет — ну, называйте это как угодно. Сахар, кодогенерация — не важно. Кучу бойлерплейта убирает, и головной боли меньше. Скорость разработки растет, стабильность кода тоже. Что еще нужно?

  • F# меня испортил, или почему я больше не хочу писать на C#
    +3
    VS Code уже давно полноценная ide

    Все с вами ясно


    Спикеры на конфах, активисты сообщества в блогах и чатах, рассказывая про F#, показывают именно ionide. Видимо они не в курсе, что он дерьмово работает.

    Не перевирайте мои слова, я говорил про большие проекты. Еще он, например, не может прожевать проекты Xamarin. И спикеры, кстати, нередко говорят, что Ионид хорош только для пет проектов (потому его и используют для презентации новичкам — не надо ставить ничего тяжеловесного, чтобы попробовать).


    Там те же проблемы — периодически всё ломается и не работает. Сообщения об ошибках не пустые, да. Но от этого они не на много более информативные.

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


    Ваша с юзером Сзер риторика соответствует моим представлениям о типичном фанбое F# — хамоватом студенте неудачнике.

    Лол. Я не знаю, что должно происходить в жизни человека, чтоб он с маньячным упорством приходил под каждую статью про F# и рассказывал всем, как все вокруг неправы. Ну ладно на хабре, где статья может в несколько хабов попасть, но прийти в тематический телеграм-чат и там всем заливать — вы уверены, что в этой истории неудачники мы?


    Если кому-то кажется, что все вокруг идиоты, варианта два: либо он невероятный гений, либо он сам идиот.
    Ну, может быть, вы и правда гений. История нас рассудит.

  • F# меня испортил, или почему я больше не хочу писать на C#
    +1
    Кого и зачем вы пытаетесь обмануть? VS Code это текстовый редактор, а Ionide это лишь плагин к нему. И о боже мой он дерьмово работает на больших проектах, и временами выдает дурацкие ошибки.
    Где тут промышленный тулинг и IDE?

    Однако, вы ничего не сказали про Visual Studio & Rider. Когда вы уже успокоитесь и перестанете строчить свои поверхностные субъективные желчные комменты? Ведете себя так, словно F# материализовался и лично насрал вам в миску.
  • F# меня испортил, или почему я больше не хочу писать на C#
    0
    Потому что вы видите сопоставление имени поля и имени переменной, которую собираетесь туда присвоить. При нормальном нейминге шанс ошибиться ниже. Это не значит, что он нулевой, но он ниже
  • F# меня испортил, или почему я больше не хочу писать на C#
    0
    let name = "name"
    let email = "email"
    let has1 = true
    let has2 = false
    let emp1 = newEmployee id name email has1 has2
    let emp2 = newEmployee id email name has2 has1

    Оба варианта скомпилируются. Так вероятность ошибиться выше, чем при нормальной инициализации. Кроме того, на ревью ошибку заметить тоже тяжелее.

  • F# меня испортил, или почему я больше не хочу писать на C#
    0
    Ну вы сейчас явно выдумываете, первый вариант объективно лучше.

    Ну вы сейчас явно выдумываете, первый вариант объективно хуже.

  • F# меня испортил, или почему я больше не хочу писать на C#
    +2

    В первом варианте легко перепутать местами параметры одного типа, к тому же он хуже читается.
    Единственный бонус — карринг. Но вы сами постоянно пишете, что карринг не нужен.
    То есть с одной стороны, вы утверждаете, что F# код хреново читается, с другой стороны сами пишете менее читаемый код, чем можно было бы. Говорите, что фшарписты продают душу лишь бы кода поменьше писать, но сами этим грешите там, где это совсем не нужно.


    Может быть, дело не в языке?

  • F# меня испортил, или почему я больше не хочу писать на C#
    +3

    Ага, ведь на каждом языке/фреймворке стоит правдивый лейбл "Я принесу вашему бизнесу 273 доллара за 2 недели". C# занял свою нишу, на нем написана куча проектов и программистов на нем гораздо больше на рынке. Внедрение новой технологии это всегда риск, и каждый бизнес сам решает, насколько он охотно идет на это. Посмотрите на обилие легаси проектов с древними технологиями и ужасным кодом — для бизнеса было бы просто чудесно по щелчку пальцев превратить этот код в хороший: и фичи быстрее делаться будут, и багов будет меньше, и текучка кадров упадет, и басфактор тоже снизится. Но бросить все и написать с нуля — это риск и гарантированный простой продукта. Переписать все на новый язык с новой парадигмой — это еще больший риск. А потом же обязательно стоит учесть момент с количеством кадров — сейчас мы перепишем, а нанимать кого будем?


    В долгосрочной перспективе, конечно же, лучше писать на F# (на мой взгляд, по крайней мере). Но в долгосрочную перспективу не все умеют, а если и умеют, не всегда ее выбирают.

  • F# меня испортил, или почему я больше не хочу писать на C#
    +4
    Мне наставили минусов, поэтому я не могу отвечать. Учитывая идиотскую систему минусования, введённую идиотами, владеющими хабром, пожалуй, это будет мой последний сюда визит.

    Боже, как же мы без вас? Кто придет в статью про F# и расскажет, какое он дерьмо, кто придет на хабр и откроет нам глаза, что хабр сделан идиотами? Потеря.


    Но я вас понимаю, постоянно хейтить F# дело трудное и неблагодарное, даже с вашим опытом.

  • F# меня испортил, или почему я больше не хочу писать на C#
    +2
    Лень отвечать, но не лень приходить под каждую статью про F# и рассказывать, какой это дерьмовый и никому не нужный язык.

    Интересно, как вы себе представляете ссылку на реальный проект? Что кто-то откроет свои исходники, сохраняя при этом легаси, ради того, чтобы Паша с хабра успокоился?
  • F# меня испортил, или почему я больше не хочу писать на C#
    +3

    Когда мне говорят, например, что после перехода на F#


    • кол-во кода сократилось на 60%
    • производительность в таких-то сервисах упала на 4-7%
    • кол-во аллокаций выросло на 15%
    • время реализации новых фич упало с 1 месяца до 1-2 недель, да плюс кол-во багов уменьшилось


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



    Когда я читаю комментарии, подобные вашим, я вижу сплошную субъективщину и эмоции.


    • Библиотек у F# нет? Giraffe, Hopac, Rezoom.SQL, FsharpLu.Json Json/Xml/Csv type providers и так далее. С чего это они маргинальные? Если проект поддерживает 1-2 человека, это не значит, что он плох. Может быть, просто язык настолько хорош, что вам не нужна армия мейнтейнеров? А может быть, библиотека не так уж сложна? Или автор дьявольски умен?
    • Тулинг отвратительный? Это ложь. Тулинг хуже, чем у C#, но не настолько, чтобы скулить об этом под каждой статьей и уж тем более не настолько, чтобы заниматься промышленной разработкой было нерентабельно.
    • Все либы написаны под сишарп? Это ложь, ссылки выше.
    • F# в эти либы можно только сбоку воткнуть? С чего бы? F# умеет ООП не хуже C#, да и ООП вообще тут не при чем, используй себе и ОРМ, и автомаппер, и ASP.NET, если не хочешь жираф, суаве или сатурн. Код бизнес-логики это вообще не затрагивает.
      Сборка проектов маргинальными утилитами? Это вообще блин о чем? Проекты собираются и классическими средствами ровно так же, как и C#. К слову, на нашем C# проекте используется FAKE.
    • Функциональные структуры данных не такие эффективные? Да у нас тут преждевременный оптимизатор в треде. В C# коде чаще всего фигурируют IEnumerable<> & List<T>. Самая частая операция с ними — foreach. Давайте, расскажите мне, как форыч по листу в миллион раз эффективней форыча по связному списку.
      Далее, поиск по функциональной мапе медленнее, чем по хеш таблице, да. Только кто заметит эту разницу на словаре, в котором 10-20 элементов?
      А вот там, где действительно нужна высокая скорость работы, можно использовать императивные коллекции, никто не мешает это делать. Получается, в F# у вас есть выбор между функциональными и императивными коллекциями, а в C# нет. Ну, если не считать Collections.Immutable, который все ругают.
    • Неоправданный рост когнитивной нагрузки при чтении ФП кода? Это чистая субъективщина, не подкрепленная вообще ничем. Когнитивная нагрузка при чтении ваших бездоказательных утверждений для меня выше, чем при чтении качественного ФП кода.
    • ФП код невозможно дебажить? Хорошо, что я не знал этого, когда дебажил ФП код. Слава богу, приходится его дебажить гораздо реже, чем ООП, иначе невозможное пришлось бы творить слишком часто.
  • F# меня испортил, или почему я больше не хочу писать на C#
    0

    F# имеет аттрибут [<CLIMutable>]. Он позволяет мутацию, но не из вашего F# кода.

  • F# меня испортил, или почему я больше не хочу писать на C#
    0

    Ну вы же понимаете, что это непрактично для продакшна? А если мне нужно другое количество аргументов? А если это не Func, a Action?
    Сравните теперь с каррингом в F#, где он нативный, и делать не надо ничего вообще.


    let inline add x y z = x + y + z
    let add5 = add 5
    let add5then7 = add5 7
  • F# меня испортил, или почему я больше не хочу писать на C#
    +2

    Хорошо, пример с if/else неудачный, черт с ним.
    Меня тут несколько раз уже носом ткнули в это, вы не первый. Как насчет всего остального, что есть в статье?


    Далее. readonly? Хорошо, но кода надо написать все еще гораздо больше, чем в F#.
    И это важно, потому что это влияет на решение разработчика о том, как он будет писать код. Все предпочитают двигаться по пути наименьшего сопротивления, все хотят писать меньше кода для решения одной и той же задачи.
    У разработчика есть выбор:
    1) Написать обычную изменяемую структуру, которая всем понятна и является дефакто стандартным решением этой задачи, набрав X символов
    2) Написать неизменяемую структуру, набрав 3X символов, объяснять на код ревью, почему было принято такое странное решение, писать больше кода каждый раз, когда хочешь поменять 1-2 поля в ней, и, скорее всего, научить JsonConvert парсить ее, потому что дефолтного конструктора нет.


    Кто в здравом уме выберет второй вариант?
    Не забывайте, написать на C# неизменяемую структуру на принцип, чтобы доказать кому-то что-то, это совсем не то же самое, что писать так каждый день на работе.
    То же самое относится к вашему "учите матчасть". Так сделать можно, но никто так делать не будет.


    Что насчет неизменяемых коллекций в C#? Да, есть Collections.Immutable, но их все ругают за тормознутость, я ни в одном проекте не видел их использование.


    Кстати, Equality & Comparison все еще надо самостоятельно реализовывать.


    Покажите, пожалуйста, как выглядит каррирование на C#. Я честно не знаю.

  • F# меня испортил, или почему я больше не хочу писать на C#
    +3

    Мне больше всего понравился этот сайт.

  • F# меня испортил, или почему я больше не хочу писать на C#
    +1

    Портянки тарабарщины трудны в прочтении независимо от парадигмы. А так — в каждой парадигме свои устоявшиеся абстракции, и если у вас есть несколько лет опыта в ООП, но в ФП его гораздо меньше — не стоит удивляться, что когнитивная нагрузка для вас субъективно выше. Это вовсе не значит, что все воспринимают ФП так же, как вы.


    А вообще в вашем утверждении можно поменять "функциональной" на "оопэшной", и суть не изменится — субъективщина без аргументов.

  • F# меня испортил, или почему я больше не хочу писать на C#
    –2
    Вы добавляете логирование в свойства ДТО/моделей? А что вы предлагаете делать, когда мыльник пустой пытаются присвоить?
  • F# меня испортил, или почему я больше не хочу писать на C#
    +1

    Зачем жить с половиной слабореализованных фич, если можно получить полный набор?
    Кроме того, про DU в сишарпе вообще пока ничего не слышал. Expression-based он тоже вряд ли станет когда-нибудь, верно? Обе эти фичи сильно способствуют стабильности и самодокументируемости кода.

  • F# меня испортил, или почему я больше не хочу писать на C#
    +1

    Разные способы есть. Если email по бизнес логике обязателен, то, например, можно вернуть ошибку с помощью DU еще до создания этого экземпляра, но мне нравится вот такой подход:


    module Email =
        type EmailAddress =
            private
            | ValidEmail of string
            | InvalidEmail of string
    
        let ofString = function
            | "validEmail" -> ValidEmail "validEmail"
            | invalid -> InvalidEmail invalid 
    
        let (|ValidEmail|InvalidEmail|) = function
            | ValidEmail email -> ValidEmail email
            | InvalidEmail email -> InvalidEmail email
    
    open Email
    
    let invalid = Email.ofString "invalid"
    let valid = Email.ofString "validEmail"
    
    match invalid with
    | InvalidEmail invalid -> printfn "invalid was InvalidEmail %s" invalid
    | ValidEmail valid -> printfn "invalid was ValidEmail %s" valid
    
    match valid with
    | InvalidEmail invalid -> printfn "valid was InvalidEmail %s" invalid
    | ValidEmail valid -> printfn "valid was ValidEmail %s" valid

    Тут мы убрали возможность создавать мыльник напрямую, но оставили возможность матчить валиден ли он или нет.