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

Что такое парадигма программирования?

Парадигмы программирования — это способ классификации различных языков программирования на основе их характеристик. (Некоторые парадигмы в основном учитывают модели исполнения языка, такие как, например, авторизация побочных эффектов). Другие больше ориентируются на способ организации кода или на синтаксис, используемый для кодирования. Существует очень большое количество различных парадигм, но наиболее известными из них являются декларативное программирование и императивное программирование. Некоторые языки поддерживают только одну парадигму, например Haskell для функционального программирования. С другой стороны, другие могут поддерживать более одного, например Python или C++. Мы более подробно рассмотрим, как работает декларативное программирование.

Парадигмы функционального программирования

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

Чистая функция — это функция, удовлетворяющая двум следующим условиям:

  • Результат функции зависит только от аргументов, а не от внешнего контекста.
  • Функция не имеет краевых эффектов/побочных эффектов

Пример

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

Преимущества и недостатки

Преимущества

В функциональном программировании так называемые «чистые» функции — это функции, которые никаким образом не изменяют состояние программы. Выходные данные зависят только от входных данных (как функции в математике), поэтому их легче понять. Чистые функции принимают аргументы один раз и выдают неизменяемый результат для каждого из них. Поэтому они не дают скрытых результатов. Они используют неизменяемые значения, что упрощает отладку и тестирование. В дополнение к созданию неизменяемых результатов функциональное программирование поддерживает концепцию ленивых вычислений, когда значение оценивается и сохраняется только тогда, когда это необходимо. Поскольку чистые функции тратят только входные значения, не только проще выполнять функции параллельно, но и легче создавать рекурсивные функции. Такие выражения, как map, reduce или filter, просты и лаконичны.

Недостатки

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

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

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

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

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

Императивные парадигмы программирования

Парадигмы императивного программирования. Императивное программирование — это метод программирования, описывающий последовательность операций для изменения текущего состояния программы.

Императивный код объясняет, как что-то делать (содержит логику, циклы, условия и т. д.).

пример

Если рассматривать программу пошагово:

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

В конце выполнения endArray будет равно [2,4,6].

Преимущества и недостатки

Преимущества

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

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

Недостатки

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

При изменении кода, например, для добавления функций или оптимизации, высок риск ошибок.

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

Сравнение

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

Читать этот код очень просто: сначала filter извлекает только те части формы, которые являются обязательными. Во второй раз map позволяет нам получить только название каждой части и reduce структуру. Затем мы получаем результат в 3 шага.

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

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

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

Но как насчет производительности? Чтобы ответить на этот вопрос, мы собираемся сравнить эти два решения с помощью инструмента jsben.ch.

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

Результат этого теста следующий:

Функциональное программирование почти в два раза мощнее императивного решения.

В случае с нашей формой вы можете перейти по этой ссылке

После бенчмаркинга этих решений мы получаем следующий результат:

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

Однако оба подхода можно смешивать с последним решением:

Список уже сокращен, с императивным условием.

Когда мы сравним эти 3 решения, мы увидим, что смешанное решение является наиболее эффективным.

Вывод

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

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

Источники