Являются ли небольшие объемы функционального программирования понятными для не-FP людей? [закрыто]

43

Кейс : я работаю в компании, пишу приложение на Python, которое обрабатывает много данных в массивах. На данный момент я являюсь единственным разработчиком этой программы, но, вероятно, она будет использоваться / изменяться / расширяться в будущем (1-3 года) другим программистом, в данный момент мне неизвестным. Я, вероятно, не буду там напрямую помогать, но, возможно, окажу некоторую поддержку по электронной почте, если у меня будет время.

Итак, как разработчик, который изучил функциональное программирование (Haskell), я склонен решать, например, фильтрацию следующим образом:

filtered = filter(lambda item: included(item.time, dur), measures)

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

Вопрос : сегодня нормально писать такой код?

  • Как разработчик, который не написал / изучил FP, реагирует на такой код?
  • Это читабельно?
  • Изменяемые?
  • Должен ли я написать документацию, как объяснить ребенку, что делает строка?

     # Filter out the items from measures for which included(item.time, dur) != True

Я спросил моего босса, и он просто сказал: «FP - это чёрная магия, но если она работает и является наиболее эффективным решением, то можно использовать её».

Каково ваше мнение по этому поводу? Как не-FP программист, как вы реагируете на код? Является ли код "googable", чтобы вы могли понять, что он делает? Я хотел бы получить отзыв об этом.

kd35a
источник
14
На мой взгляд, многие современные языки допускают некоторую степень функционального программирования и использования, которое становится все более распространенным. Лично я бы сказал, пойти на это (по крайней мере, для относительно простых задач фильтрации / отображения).
Йоахим Зауэр
Я не могу дать вам незатронутый ответ, потому что мне нравится FP. Было бы неплохо добавить комментарий, если он выходит за рамки простого.
Бруно Шеппер
3
Ваш комментарий может быть понятнее; Фильтр включает в себя элементы, для которых тест имеет значение True, поэтому ваш комментарий может выглядеть следующим образом: # Select the item's from measures for which included(item.time, dur) == Trueизбегание двойного отрицания всегда улучшает понимание.
Мартин Питерс
6
Рассматривали ли вы вместо этого использование списочных представлений? Их часто считают более «питоническими», чем карта / фильтр.
phant0m
2
@MatjazMuhic Ну, это прекрасно ...;)
kd35a

Ответы:

50

Это читабельно?

Для меня: да, но я пришел к выводу, что сообщество Python часто считает списочные выражения более чистым решением, чем использование map()/ filter().

Фактически, GvR даже рассматривал возможность отказа от этих функций вообще.

Учти это:

filtered = [item for item in measures if included(item.time, dur)]

Кроме того, преимущество заключается в том, что понимание списка всегда возвращает список. map()а filter()с другой стороны вернет итератор в Python 3.

Примечание. Если вы хотите использовать вместо этого итератор, его просто заменить []на ():

filtered = (item for item in measures if included(item.time, dur))

Честно говоря, я вижу мало причин для использования map()или filter()в Python.

Это модифицируемо?

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

def is_included(item):
    return included(item.time, dur)
filtered = filter(is_included, measures)
filtered = [item for item in measures if is_included(item)]

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

Как разработчик, который не написал / изучил FP, реагирует на такой код?

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

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

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

phant0m
источник
5
Возможно, стоит также упомянуть выражения генератора , которые работают так же, как и списки, но возвращают генераторы вместо списков, как mapи filterв Python 3.
Джеймс
@James: Отличная идея, я добавил их в свой пост. Благодарность!
phant0m
2
Я обычно привожу reduceконтрпример к тому, что вы всегда можете использовать аргумент для понимания списка , поскольку его относительно сложно заменить reduceвстроенным генератором или списком.
Кодзиро
4
+1 за то, что вы отметили предпочтительный язык рассматриваемого языка. ИМХО согласованность имеет огромное значение, и использование языка таким образом, как значительная часть «говорящих», может обеспечить большую ремонтопригодность, чем даже комментарии иногда.
Джошуа Дрейк
4
+1 за «Он ищет документацию по Python и знает, как она работает через пять минут. В противном случае он не должен программировать на Python».
Бьярке Фрейнд-Хансен
25

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

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

Код перед рефакторингом:

var categorizedProducts = new Dictionary<string, List<Product>>();

// Get only enabled products, filtering the disabled ones, and group them by categories.
foreach (var product in this.Data.Products)
{
    if (product.IsEnabled)
    {
        if (!categorizedProducts.ContainsKey(product.Category))
        {
            // The category is missing. Create one.
            categorizedProducts.Add(product.Category, new List<Product>());
        }

        categorizedProducts[product.Category].Add(product);
    }
}

// Walk through the categories.
foreach (var productsInCategory in categorizedProducts)
{
    var minimumPrice = double.MaxValue;
    var maximumPrice = double.MinValue;

    // Walk through the products in a category to search for the maximum and minimum prices.
    foreach (var product in productsInCategory.Value)
    {
        if (product.Price < minimumPrice)
        {
            minimumPrice = product.Price;
        }

        if (product.Price > maximumPrice)
        {
            maximumPrice = product.Price;
        }
    }

    yield return new PricesPerCategory(category: productsInCategory.Key, minimum: minimumPrice, maximum: maximumPrice);
}

Тот же код после рефакторинга с использованием FP:

return this.Data.Products
    .Where(product => product.IsEnabled)
    .GroupBy(product => product.Category)
    .Select(productsInCategory => new PricesPerCategory(
              category: productsInCategory.Key, 
              minimum:  productsInCategory.Value.Min(product => product.Price), 
              maximum:  productsInCategory.Value.Max(product => product.Price))
    );

Это заставляет меня думать, что:

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

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

Арсений Мурзенко
источник
8
+1, если FP не делает ваш код более читабельным для всех , вы делаете это неправильно.
Дьёрдь Андрасек
7
Я могу видеть, как в одиночку кто-то, никогда не видевший FP раньше, мог считать первый фрагмент более читаемым поверх второго. Но что если мы умножим это на 100? Чтение 100 коротких сжатого почти на английском , как предложения описывающего , что против тысяч линий водопровода , как код. Огромный объем кода, каким бы знакомым он ни был, должен быть настолько подавляющим, что знакомство уже не такая большая победа. В какой-то момент кому-то должно быть легче освоиться с элементами FP, а затем прочитать несколько строк по сравнению с чтением тысяч строк знакомого кода.
Esailija
7
Больше всего меня беспокоит то, что мы довольны тем, что разработчикам приемлемо не изучать функциональный стиль. Преимущества были доказаны много раз, парадигма поддерживается основными языками. Если у людей нет способности понимать функциональные приемы, их следует учить или самим учить, даже если они не собираются их использовать. Я ненавижу XSLT с пылкой страстью, но это не помешало мне изучить его как профессионала.
Sprague
2
@MainMa Ваша точка зрения полностью верна, я должен был быть более конкретным. Я имею в виду, что разработчик на любом данном языке должен эффективно использовать возможности этих языков. Например, использование «функционального стиля» в C # (использование программирования в стиле фильтра / отображения / уменьшения или передачи / возврата функций) не является чем-то новым, и поэтому я думаю, что любой разработчик C #, который не способен читать такие операторы, должен обновить свои навыки ... наверное, очень быстро. Я, конечно, думаю, что каждый разработчик должен немного изучить Haskell, но только по академическим соображениям. Это другое дело.
Sprague
2
@Sprague: я понял вашу точку зрения и согласен с ней. Просто вряд ли можно ожидать, например, что программисты на C # начнут использовать парадигмы из FP, когда слишком многие из этих программистов даже не используют дженерики. Пока не будет так много неквалифицированных программистов, планка нашей профессии будет низкой, тем более что большинство людей без технического образования вообще не понимают, что такое разработка.
Арсений Мурзенко
20

Я не программист FP, и недавно я должен был изменить код моего коллеги в JavaScript. Был Http-запрос с обратным вызовом, который очень напоминал включенное вами утверждение. Я должен сказать, что мне потребовалось некоторое время (например, полчаса), чтобы все это выяснить (в целом код был не очень большим).

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

Учитывая, что я работаю около 1,5 лет, я думаю, что большинство программистов смогут понять и изменить такой код, поскольку я это сделал.

Кроме того, как сказал в своем комментарии Йоахим Зауэр, во многих языках часто встречаются фрагменты FP, например C # (indexOf, например). Так много не-FP программистов имеют дело с этим довольно часто, и фрагмент кода, который вы включили, не является чем-то ужасным или непонятным.

superM
источник
1
Спасибо за ваш комментарий! Это дало мне больше информации о другой перспективе. Легко стать слепым дома, и тогда вы не знаете, как это выглядело, когда вы не знали FP :)
kd35a
1
@ kd35a, пожалуйста. К счастью, я могу быть объективным здесь))
superM
1
+1 за указание, что многие языки теперь содержат элементы FP.
Джошуа Дрейк
LINQ является основным примером FP ​​в C #
Конрад Моравский
3

Я бы сказал определенно да!

Существует много аспектов функционального программирования, и использование функций высшего порядка, как в вашем примере, является лишь одним из них.

Например, я считаю, что написание чистых функций чрезвычайно важно для любого программного обеспечения, написанного на любом языке (где под «чистым» я подразумеваю отсутствие побочных эффектов), потому что:

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

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

Оба эти метода отлично работают в Python и других языках, которые обычно не классифицируются как функциональные. Они часто даже поддерживаются самим языком (то есть finalпеременными в Java). Таким образом, будущие программисты по обслуживанию не столкнутся с огромным барьером для понимания кода.


источник
2

У нас было то же самое обсуждение компании, в которой я работал в прошлом году.

Дискуссия касалась «магического кода», и нужно ли его поощрять или нет. Если взглянуть на это немного больше, то казалось, что у людей совершенно разные взгляды на то, что на самом деле было «магическим кодом». Те, кто поднял обсуждение, в основном имели в виду, что выражения (в PHP), которые использовали функциональный стиль, были «магическим кодом», тогда как разработчики, которые происходили из других языков, которые использовали больше стиля FP в своем коде, похоже, думали, что магический код был скорее когда вы сделали динамическое включение файлов через имена файлов и так далее.

Мы никогда не пришли к какому-либо хорошему заключению по этому поводу, более того, люди думают, что код, который выглядит незнакомым, «магический» или трудно читаемый. Так стоит ли избегать кода, который кажется незнакомым другим пользователям? Я думаю, что это зависит от того, где это используется. Я бы воздержался от использования выражений в стиле fp (динамическое включение файлов и т. Д.) В основном методе (или важных центральных частях приложений), где данные должны передаваться в туннеле понятным и простым для чтения, интуитивно понятным способом. С другой стороны, я не думаю, что нужно бояться выдвигать конверт, другие разработчики, вероятно, быстро изучат FP, если столкнутся с кодом FP ​​и, возможно, найдут хороший внутренний ресурс для консультаций по этим вопросам.

TL; DR: Избегайте высокоуровневой центральной части приложений (которые необходимо прочитать для обзора функциональности приложения). В противном случае используйте это.

Кристофер Кек
источник
Хороший момент в том, чтобы не использовать его в коде более высокого уровня!
kd35a
Я всегда думал, что не хватает формализма и очень много возможностей для определения методов программирования в различных типах блоков (таких как статические методы, публичные методы, конструкторы и т. Д.). Хороший ответ ... это заставляет меня вернуться к некоторым из этих мыслей.
Sprague
2

Сообщество C ++ недавно также получило лямбду, и я считаю, что у них примерно такой же вопрос. Ответ не может быть тем же, хотя. С ++ эквивалент будет:

std::copy_if(measures.begin(), measures.end(), inserter(filter),
  [dur](Item i) { return included(i, dur) } );

Сейчас std::copyэто не ново, и _ifварианты тоже не новы, но лямбда есть. Тем не менее, он довольно четко определен в контексте: durон захвачен и, следовательно, является постоянным, Item iизменяется в цикле, и один returnоператор выполняет всю работу.

Это выглядит приемлемым для многих разработчиков C ++. Я не пробовал мнения о лямбдах более высокого порядка, и я бы ожидал гораздо меньшего принятия.

MSalters
источник
Интересно отметить, что могут быть разные ответы в зависимости от того, на каком языке он находится. Вероятно, это связано с постом @Christopher Käck о том, что PHP-кодерам было больше проблем с такими вещами, чем Python-кодерам.
kd35a
0

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

Если да, вы, вероятно, хорошо идти. Если нет, вы должны сделать это более понятным.

Может ли ваш коллега быть глупым и не понимать чего-то, что должно быть очевидным? Да, но вы всегда должны программировать в соответствии с KISS.

Может быть, ваш код более эффективен / красив / элегантен, чем более простой и защищенный от идиотов подход? Тогда вам нужно спросить себя: нужно ли мне это делать? Опять же, если ответ отрицательный, не делайте этого!

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

Арнаб Датта
источник
не стесняйтесь объяснить причину понижения голосов
Датта