От переводчика
Это вольный перевод статьи о том, почему люди боятся функциональных языков, присутствует ирония и юмор, для тех кто может и любит читать на английском оригинал здесь.
Про автора
Я разработчик и архитектор британской не софтверной компании. Имею 20 летний опыт в различных областях от высоко-уровневых UX/HCI до низко-уровневых реализаций баз данных.
Несмотря на то что я использую C# в своей повседневной работе, я писал промышленный код на многих языках, мои любимые Smalltalk, Python и совсем недавно F# (поэтому я и создал этот сайт).
Разглагольствования по поводу того чего я не понимаю
Вам надоела вся эта шумиха вокруг функциональных языков? Мне тоже! Я выскажу по этому поводу несколько причин почему разумные люди, такие как мы с вами, должны держаться подальше от этого.
Немного поясню: когда я говорю «статически типизированный функциональный язык программирования», я подразумеваю языки, которые поддерживают вывод типов по-умолчанию и прочее. На практике это означает Haskell и семейство языков ML (включая OCaml и F#).
Причина 1. Я не хочу следовать последним тенденциям
Как и большинство программистов я консервативен и не люблю изучать новые вещи. Собственно поэтому я выбрал карьеру в IT.
Я не поддаюсь массовым увлечениям просто потому, что все «крутые парни» делают это, сначала я жду пока вещь дозреет, и я смогу увидеть кое-какие перспективы.
Для меня, функциональное программирование существует ещё слишком малое время, чтобы убедить меня, что оно здесь всерьёз и надолго.
Да я полагаю, что некоторые педанты будут утверждать, что ML и Haskell существуют почти столько же сколько старые фавориты Java и PHP, но я услышал про Haskell совсем недавно, так что этот аргумент совсем неубедительный.
Посмотрим ка на новичка в этой семье: F#. Господи, да ему всего лишь 7 лет! Конечно, это может быть достаточное время для геолога, но в эпоху интернета, 7 лет — это просто мгновение ока.
Таким образом, я определённо был бы осторожным и подождал несколько десятилетий, чтобы посмотреть либо функциональное программирование останется, либо не оправдает надежд.
Причина 2. Мне платят за строки кода
Я не знаю как вы, но чем больше строк кода я написал, тем более продуктивным я себя чувствую. Если я смогу наштамповать 500 строк в день, то работа сделана хорошо. Мои коммиты большие и мой босс может видеть, что я был занят делом.
Но когда я сравниваю код написанный на функциональном языке с хорошим олдскульным 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-х строк. А теперь представьте разницу, если это умножить на размер проекта.
Если бы я использовал это, моя производительность бы резко упала. Извините, но я не могу себе этого позволить.
Причина 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 мой любимый язык.
Вот сигнатура функции какого-то 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>>
.Конечно, компилятор сделает проверку типов для вас и предупредит, если выявит несоответствие типов. Но зачем позволять компилятору делать эту работу если её могут сделать ваши мозги?
Хорошо я допускаю, что если вы используете generic'и, лямбды, функции которые возвращают функции и все эти новомодные штуки, тогда да, ваши определения типов действительно могут стать чрезмерно сложными и запутанными. И становится очень трудно ввести их правильно.
Но у меня есть лёгкое решение для этого — не используйте generic'и и не передавайте функции где попало, ваши сигнатуры станут намного проще.
Причина 5. Я люблю исправлять баги
Ничто не нравится мне так, как охота на мерзкие баги. Ну а если баг в продакшене, то это ещё лучше, ведь вы заодно станете героем, когда исправите его.
Но я прочитал, что в программах на статически типизированных функциональных языках гораздо сложнее допустить баг. Вот облом.
Причина 6. Я живу в отладчике
Кстати, об исправлении багов, я провожу значительную часть моего дня в отладчике, пошагово выполняя код. Да, я знаю, мне следует использовать юнит-тесты, но ведь проще сказать чем сделать? Ведь так?
В любом случае очевидно, что если ваш код на статически типизированном функциональном языке компилируется, то обычно он работает.
Я сказал, что вы должны потратить много времени чтобы привести типы в соответствие, но когда это сделано и код успешно компилируется, то нечего отлаживать. Ну и какое в этом удовольствие?
Эта причина приводит меня к следующей…
Причина 7. Я не хочу думать о каждой мелочи
Проверить типы, убедиться что всё в порядке, всё это звучит так утомительно для меня.
На самом деле, я слышал, что вы вынуждены думать обо всех возможных краевых случаях, и обо всех возможных ошибках вызванных неверными входными данными, и вообще о всём что может пойти не так. И вы должны сделать всё это в начале, вы не можете полениться и отложить всё это на потом.
Мне гораздо больше нравиться получить программу полностью (ну почти полностью) работающую по позитивному сценарию (где все возможные ошибки не учитываются), ну а уже потом исправлять баги по мере того как они появляются.
Причина 8. Я люблю проверять на null
Я очень добросовестно делаю проверки на null в каждом методе. Это даёт мне большое удовлетворение, я знаю, что в результате мой код полностью пуленепробиваемый.
void someMethod(SomeClass x)
{
if (x == null) { throw new NullArgumentException(); }
x.doSomething();
}
Ха-ха! Я просто пошутил. Конечно же, я не могу вставлять проверки на null везде, иначе бы я никогда не закончил ни один настоящий проект.
Кроме того, за свою практику я всего лишь раз сталкивался с серьёзной проблемой вызванной NullPointerException. И бизнес потерял не так уж много денег, в течении нескольких недель которые я потратил на поиск проблемы. Так что я не уверен, что это такое уж необходимое дело.
Причина 9. Я везде применяю шаблоны проектирования
Впервые я прочитал о шаблонах проектирования в книге Head First Design Patterns (на которую почему-то ссылаются как на «книгу Банды четырёх», но я не уверен почему), и с тех пор я всегда прилежно использовал их для решения любых проблем. Уверен, что мой код после этого выглядит серьёзно, «энтерпрайзно» и это впечатляет моего босса.
Но я не вижу никаких упоминаний о шаблонах в функциональном проектировании. Как я могу сделать что-нибудь полезное без использования Стратегии, Абстрактной Фабрики, Декоратора, Прокси и всего остального?
Возможно функциональные программисты не знают о шаблонах?
Причина 10. Слишком много математики
Вот код для вычисления суммы квадратов. Этот способ записи слишком сложно понять из-за всех этих странных символов.
ss=: +/ @: *:
Ой, извините! Я ошибся, это был код на J.
Но зато я слышал, что функциональные языки используют странные символы типа
<*>
и >>=
, или непонятные концепции типа «монад» и «функторов».Я не знаю почему функциональные программисты не смогли придерживаться уже известных мне вещей, таких очевидных как символы типа ++, != и лёгких концепций типа «наследование» и «полиморфизм».
Итог. Я не понимаю этого
Вы знаете, я не понимаю этого. Я не понимаю, чем функциональное программирование полезно.
Я очень хочу чтобы кто-нибудь просто показал мне настоящие преимущества на одной странице, вместо того чтобы заваливать меня информацией.
Обновление: Хорошо, сейчас я прочитал статью «все что вам нужно знать на одной странице». Но она очень короткая и простая для меня.
Всё таки я ищу что-то немного более глубокое, что-то с чём я мог бы продуктивно поработать.
И нет, не говорите мне, что мне следует прочитать руководства, поиграть с примерами и написать свой собственный код. Я просто хочу посмотреть, не делая всего этого.
Я не хочу менять своё мышление, просто для того чтобы изучить новую парадигму.
Комментариев нет:
Отправить комментарий