- PVSM.RU - https://www.pvsm.ru -

Десять причин не использовать статически типизированный функциональный язык программирования

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

Про автора

Я разработчик и архитектор британской не софтверной компании. Имею 20 летний опыт в различных областях от высоко-уровневых UX/HCI до низко-уровневых реализаций баз данных.
Несмотря на то что я использую C# в своей повседневной работе, я писал промышленный код на многих языках, мои любимые Smalltalk, Python и совсем недавно F# (поэтому я и создал этот сайт [2]).

Разглагольствования по поводу того чего я не понимаю

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

Немного поясню: когда я говорю «статически типизированный функциональный язык программирования», я подразумеваю языки, которые поддерживают вывод типов по-умолчанию и прочее. На практике это означает Haskell и семейство языком ML (включая OCaml и F#).

Причина 1. Я не хочу следовать последним тенденциям

Как и большинство программистов я консервативен и не люблю изучать новые вещи. Собственно поэтому я выбрал карьеру в IT.
Я не поддаюсь массовым увлечениям просто потому, что все «крутые парни» делают это, сначала я жду пока вещь дозреет, и я смогу увидеть кое-какие перспективы.
Для меня, функциональное программирование существует ещё слишком малое время, чтобы убедить меня, что оно здесь всерьёз и надолго.
Да я полагаю, что некоторые педанты будут утверждать, что ML [3]и Haskell [4]существуют почти столько же сколько старые фавориты Java и PHP, но я услышал про Haskell совсем недавно, так что этот аргумент совсем неубедительный.

Посмотрим ка на новичка в этой семье: F# [5]. Господи, да ему всего лишь 7 лет! Конечно, это достаточное время для геолога, но в эпоху интернета, 7 лет — это просто мгновение ока.
Таким образом, я определённо был бы осторожным и подождал несколько десятилетий, чтобы посмотреть либо функциональное программирование останется, либо не оправдает надежд.

Причина 2. Мне платят за строки кода

Я не знаю как вы, но чем больше строк кода я написал, тем более продуктивным я себя чувствую. Если я смогу наштамповать 500 строк в день, то работа сделана хорошо. Мои коммиты большие и мой босс может видеть, что я был занят делом.
Но когда я сравниваю код [6] написанный на функциональном языке с хорошим олдскульным C-подобным языком, то я вижу так мало кода что меня это пугает.
Просто посмотрите что я имею ввиду, вот код написанный на привычном языке:

public static class SumOfSquaresHelper
{
   public static int Square(int i)
   {
      return i * i;
   }

   public static int SumOfSquares(int n)
   {
      int sum = 0;
      for (int i = 1; i <= n; i++)
      {
         sum += Square(i);
      }
      return sum;
   }
}

а теперь сравните с этим:

let square x = x * x
let sumOfSquares n = [1..n] |> List.map square |> List.sum

17 строк против только 2-х строк. А теперь представьте разницу [7], если это умножить на размер проекта.
Если бы я использовал это, моя производительность бы резко упала. Извините, но я не могу себе этого позволить.

Причина 3. Я люблю фигурные скобки

И ещё одна вещь. Что происходит со всеми этими языками, которые избавились от фигурных скобок? Как они могут называться настоящими языками программирования?
Я покажу вам, что я имею ввиду. Вот пример кода с привычными фигурными скобками.

public class Squarer
{
    public int Square(int input)
    {
        var result = input * input;
        return result;
    }

    public void PrintSquare(int input)
    {
        var result = this.Square(input);
        Console.WriteLine("Input={0}. Result={1}", input, result);
    }
}

А вот похожий код, только без фигурных скобок.

type Squarer() =  

    let Square input = 
        let result = input * input
        result

    let PrintSquare input = 
        let result = Square input
        printf "Input=%i. Result=%i" input result

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

Причина 4. Я люблю видеть явные типы

Сторонники функциональных языков утверждают, что вывод типов делает код чище, не давая вам всё время загромождать его определениями типов.
Вообще-то, между прочим, я хочу видеть объявления типов. Я чувствую себя неловко, если не знаю точный тип каждого параметра. Вот почему Java [8]мой любимый язык.
Вот сигнатура функции какого-то ML-подобного кода. Определения типов не требуются, и всё выводится автоматически.

let GroupBy source keySelector = 
    ... 

А вот сигнатура функции для похожего кода на C#, с явными определениями типов.

public IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(
    IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector
    )
    ...

Может быть я и в меньшинстве, но вторая версия мне нравиться гораздо больше. Для меня важно знать, что функция вернёт тип IEnumerable<IGrouping<TKey, TSource>>.

Конечно, компилятор сделает проверку типов для вас и предупредит, если выявит несоответствие типов. Но зачем позволять компилятору делать эту работу если её могут сделать ваши мозги [9]?
Хорошо я допускаю, что если вы используете generic'и, лямбды, функции которые возвращают функции и все эти новомодные штуки, тогда да, ваши определения типов действительно могут стать чрезмерно сложными и запутанными. И становится очень трудно ввести их правильно.
Но у меня есть лёгкое решение для этого — не используйте generic'и и не передавайте функции где попало, ваши сигнатуры станут намного проще.

Причина 5. Я люблю исправлять баги

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

Причина 6. Я живу в отладчике

Кстати, об исправлении багов, я провожу значительную часть моего дня в отладчике, пошагово выполняя код. Да, я знаю, мне следует использовать юнит-тесты, но ведь проще сказать чем сделать? Ведь так?
В любом случае очевидно, что если ваш код на статически типизированном функциональном языке компилируется, то обычно он работает [11].
Я сказал, что вы должны потратить много времени чтобы привести типы в соответствие, но когда это сделано и код успешно компилируется, то нечего отлаживать. Ну и какое в этом удовольствие?
Эта причина приводит меня к следующей…

Причина 7. Я не хочу думать о каждой мелочи

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

Причина 8. Я люблю проверять на null

Я очень добросовестно делаю проверки на null [12]в каждом методе. Это даёт мне большое удовлетворение, я знаю, что в результате мой код полностью пуленепробиваемый.

void someMethod(SomeClass x)
{
    if (x == null) { throw new NullArgumentException(); }

    x.doSomething();
}

Ха-ха! Я просто пошутил. Конечно же, я не могу вставлять проверки на null везде, иначе бы я никогда не закончил ни один настоящий проект.
Кроме того, за свою практику я всего лишь раз сталкивался с серьёзной проблемой вызванной NullPointerException. И бизнес потерял не так уж много денег, в течении нескольких недель которые я потратил на поиск проблемы. Так что я не уверен, что это такое уж необходимое дело [13].

Причина 9. Я везде применяю шаблоны проектирования

Впервые я прочитал о шаблонах проектирования в книге Head First Design Patterns [14] (на которую почему-то ссылаются как на «книгу Банды четырёх», но я не уверен почему), и с тех пор я всегда прилежно использовал их для решения любых проблем. Уверен, что мой код после этого выглядит серьёзно, «энтерпрайзно» и это впечатляет моего босса.
Но я не вижу никаких упоминаний о шаблонах в функциональном проектировании. Как я могу сделать что-нибудь полезное без использования Стратегии, Абстрактной Фабрики, Декоратора, Прокси и всего остального?
Возможно функциональные программисты не знают о шаблонах?

Причина 10. Слишком много математики

Вот код для вычисления суммы квадратов. Этот способ записи слишком сложно понять из-за всех этих странных символов.

ss=: +/ @: *:

Ой, извините! Я ошибся, это был код на J [15].
Но зато я слышал, что функциональные языки используют странные символы типа <*> и >>=, или непонятные концепции типа «монад» и «функторов».
Я не знаю почему функциональные программисты не смогли придерживаться уже известным мне вещей, таких очевидных как символы типа ++, != и лёгких концепций типа «наследование» и «полиморфизм».

Итог. Я не понимаю этого

Вы знаете, я не понимаю этого. Я не понимаю, чем функциональное программирование полезно.
Я очень хочу чтобы кто-нибудь просто показал мне настоящие преимущества на одной странице [16], вместо того чтобы заваливать меня информацией.
Обновление: Хорошо, сейчас я прочитал статью «все что вам нужно знать на одной странице». Но она очень короткая и простая для меня.
Всё таки я ищу что-то немного более глубокое, что-то [17] с чём я мог бы [18] продуктивно поработать [19].
И нет, не говорите мне, что мне следует прочитать руководства [20], поиграть с примерами [21] и написать свой собственный код. Я просто хочу посмотреть, не делая всего этого.
Я не хочу менять своё мышление [22], просто для того чтобы изучить новую парадигму.

Комментарии автора к статье

Для тех, у кого проблемы с юмором: эту статью не нужно воспринимать всерьёз.

Для тех, кто думает, что я преувеличиваю или троллю. Всё в этой статье основано на том, что я прочитал или лично услышал от других людей (лишь с небольшим преувеличением). Я просто сделал явным то, что было неявным в их реакции.

Так же поясню, я не пытаюсь быть снобом или гнобить тех, кто предпочитает не использовать функциональное программирование. Люди могут использовать те инструменты, которые им нравятся. И есть множество хороших причин не использовать функциональные языки, те же причины которые привёл я, с этим не связаны. Я сталкиваюсь с подобными защитными и нерациональными «аргументами» всё время, и их не стоит воспринимать всерьёз.

Некоторые предпосылки по каждому пункту:

Причина 1: «мода». Не могу сказать сколько раз я это слышал. Пожалуйста почитайте немного о истории computer science. «Я консервативен и не люблю изучать новые вещи. Собственно поэтому я выбрал карьеру в IT.» Я думал это должно быть смешно. Ну ладно.

Причина 2: «оплата за строки кода». Никто не говорил этого прямо, но если вы посмотрите на любое обсуждение, скажем, Python vs Java, некоторым людям определённо комфортней писать длинный и скучный код.

Причина 3: «фигурные скобочки». Речь не о фигурных скобках как таковых. Многие люди утверждают, что отсутствие фигурных скобок делает код нечитаемым, и вообще они к ним привязаны [23]. Вот комментарий к этой самой статье [24], который показывает мою точку зрения.

Причина 4: «я люблю явные типы». Основано на реальных комментариях

Причина 5: «я люблю исправлять баги» и причина 6: «я живу в отладчике». Опять же никто не говорил этого напрямую, но слабое понимание инструментов статического анализа кода говорит об этом. Людей сложно заставить писать даже юнит-тесты. Я думаю, что прерывистое подкрепление [25] играет неявную роль в этом поведении.

Причина 7: «я не хочу думать о каждой мелочи». Никто из нас этого не делает. Вот почему мы должны использовать инструменты, которые не позволяют нам быть ленивыми. Иначе всё может закончиться для вас как одна из историй с The Daily WTF [26].

Причина 8: «я люблю проверять на null». Почитайте любые дискуссии по поводу полезности опциональных типов [27] и вскоре вы найдёте людей говорящих что проверка на null это не проблема.

Причина 9: «шаблоны проектирования везде». Почти дословно. Увы.

Причина 10: «слишком много математики». Ещё одна распространённая причина, и в какой-то мере я согласен (посмотрите мою просьбу на этом сайте [28]). Но нравится вам это или нет теоретическая часть computer science очень важна. SQL [29]основан на теории. Лямбды [30]основаны на теории. Алгоритмы для множеств, графов [31], шифрования [32]и всё остальное тоже основано на теории. Количество математиков [33]сделавших вклад [34]в computer science [35] огромно.

Для практического использования SQL, для манипуляции с множествами, вы не обязаны глубоко знать математику. По сути, «математика» которую вы должны изучить для функционального программирования не намного сложнее, чем принципы SOLID в ООП. Просто это разные вещи.

Итог. Я знаю, что изучение функционального программирования это сложно, и это требует некоторых изменений в том, как вы думаете о коде. Вот почему я сделал этот сайт [2], чтобы помочь тем, кому любопытно и кто хочет учиться.

А если вы не хотите изучать что-то новое, что ж, это тоже хорошо.

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

Автор: DarkCoder

Источник [37]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/news/41199

Ссылки в тексте:

[1] оригинал здесь: http://fsharpforfunandprofit.com/posts/ten-reasons-not-to-use-a-functional-programming-language/

[2] этот сайт: http://fsharpforfunandprofit.com/

[3] ML : http://en.wikipedia.org/wiki/ML_(programming_language)

[4] Haskell : http://en.wikipedia.org/wiki/Haskell_(programming_language)

[5] F#: http://fsharp.org/

[6] сравниваю код: http://fsharpforfunandprofit.com/posts/fvsc-sum-of-squares/

[7] представьте разницу: http://www.simontylercousins.net/journal/2013/2/22/does-the-language-you-choose-make-a-difference.html

[8] Java : http://steve-yegge.blogspot.co.uk/2006/03/execution-in-kingdom-of-nouns.html

[9] мозги: http://www.braintools.ru

[10] я прочитал: http://www.simontylercousins.net/journal/2013/3/7/why-bugs-dont-like-f.html

[11] то обычно он работает: http://www.haskell.org/haskellwiki/Why_Haskell_just_works

[12] проверки на null : http://stackoverflow.com/questions/7585493/null-parameter-checking-in-c-sharp

[13] необходимое дело: http://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare

[14] книге Head First Design Patterns: http://www.amazon.com/First-Design-Patterns-Elisabeth-Freeman/dp/0596007124

[15] код на J: http://en.wikipedia.org/wiki/J_(programming_language)

[16] настоящие преимущества на одной странице: http://fsharpforfunandprofit.com/why-use-fsharp/

[17] что-то: http://fsharpforfunandprofit.com/posts/designing-for-correctness/

[18] мог бы: http://fsharpforfunandprofit.com/series/designing-with-types.html

[19] поработать: http://fsharpforfunandprofit.com/posts/computation-expressions-intro/

[20] руководства: http://learnyouahaskell.com/

[21] поиграть с примерами: http://www.tryfsharp.org/Learn

[22] своё мышление: http://dave.fayr.am/posts/2011-08-19-lets-go-shopping.html

[23] они к ним привязаны: https://news.ycombinator.com/item?id=1877508

[24] комментарий к этой самой статье: http://www.reddit.com/r/programming/comments/1canx9/ten_reasons_not_to_use_a_statically_typed/c9enp88

[25] прерывистое подкрепление: https://en.wikipedia.org/wiki/Reinforcement#Intermittent_reinforcements

[26] The Daily WTF: http://en.wikipedia.org/wiki/The_Daily_WTF

[27] опциональных типов: http://en.wikipedia.org/wiki/Option_type

[28] мою просьбу на этом сайте: http://fsharpforfunandprofit.com/about/#banned

[29] SQL : http://en.wikipedia.org/wiki/Relational_algebra

[30] Лямбды : http://en.wikipedia.org/wiki/Lambda_calculus

[31] графов: http://en.wikipedia.org/wiki/Graph_traversal

[32] шифрования : http://en.wikipedia.org/wiki/Integer_factorization

[33] математиков : http://en.wikipedia.org/wiki/John_von_Neumann

[34] вклад : http://en.wikipedia.org/wiki/Claude_Shannon

[35] computer science: http://en.wikipedia.org/wiki/Alan_Turing

[36] этот парень: http://en.wikipedia.org/wiki/Green_Eggs_and_Ham

[37] Источник: http://habrahabr.ru/post/190492/