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

Декларативное и императивное программирование

Или насколько неверным было мое представление о React

Feb 11, 2018 · 4 min read

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

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

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

Согласно этой и этой информации:

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

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

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

Хорошо, вот метафора.

Декларативное программирование — это как попросить вашего друга нарисовать пейзаж. Тебе все равно, как он рисует, это зависит от него.

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

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

Ладно, ладно, вот несколько примеров кода. У нас есть кнопка, которая меняет цвет при нажатии. Я начну с императивного примера:

И пример нашего декларатвного React:

Возможно, различия незначительны. У нас по-прежнему есть логика, которая говорит: если красный, значит синий, но есть одна огромная разница. Пример c React никогда не затрагивает элемент. Он просто объявляет, что элемент должен отображаться с учетом нашего текущего состояния (далее — state). Он фактически не манипулирует самим DOM.

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

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

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

Чего следует избегать

Я либо допустил, либо позволил допустить все эти ошибки в коде, над которым работал. Это всего лишь советы.

Источник

Декларативное программирование в web-е

Что же такое декларативное программирование? Википедия подскажет нам:

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

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

Простая форма

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

В данном случае, на сервере у нас будет некий endpoint, который будет обрабатывать запросы от этой формы. Сразу небольшая оговорка — речь идет о RESTful сервисе, т.е. форма в данном случае обрабатывается JS приложением. Давайте попробуем ее описать:

Swagger (Open API standard)

Такое описание отлично подходит для тестировщика из вашей команды, но вряд ли легко поддается автоматизации. А с этим нам поможет Swagger — инструмент для разработки и тестирования API. Swagger основан на JSON-schema (о нем мы еще поговорим ниже), открытом стандарте описания JSON объектов.

Декларация

Если взять за основу предложенный выше список и “перевести” его в Swagger формат, то мы получим нечто подобное:

NOTE: для этого необходимо разместить файлы Swagger UI на одном домене с вашим бекендом или разрешить на вышеупомянутом крос-доменные запросы. Шпаргалка по CORS.

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


http://petstore.swagger.io/#/user/createUsersWithArrayInput

Поддержка в IDE

Чтобы сделать работу со swagger файлом еще более приятной, можно установить плагин для вашей любимой IDE:

Мне не удалось найти плагина для NetBeans, хотя я почти уверен что он есть. Если вы знаете, где его взять — буду признателен за ссылку.

Генерация

Чтобы не превращать поддержку Swagger файла в отдельную монотонную и нудную задачу, можно использовать генератор Swagger JSON файла на основе вашего исходного кода. Таким образом мы убиваем сразу нескольких «зайцев»:

Пример аннотации Swagger php

Пример команды для генерации JSON файла:

Подытожим: использовав Swagger мы задекларировали, как будет работать наш enpoint для внешнего мира.

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

Для валидации и очистки данных в декларативной манере отлично подходит нативная функция filter_var_array :

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

А вот и наша схема:

Пример php кода для валидации:

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

А теперь провалидируем полученный запрос:

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

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

В последнем примере мы подключаем еще целый ворох более мелких XSD. Как вы видите, описание сложных объектов может включать как сложные составные типы, так и более простые, базовые. Дабы полностью раскрыть тему, рассмотри пример одного из простых составных типов:

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

Обработка ошибок LibXML

Я думаю что я не единственный, кого не устроила бы ошибка “Invalid XML provided”, особенно если речь идет например об инструментах для отладки и тестирования. А посему, давайте немного расширим информацию об ошибках в документе. В итоге мы хотим получить внятное сообщение для дальнейших действий и номер строки, содержащей ошибку.

Тестирование

Как мы уже говорили, в случае использования Swagger, мануальное тестирование можно проводить прямо в браузере в Swagger UI. А дабы автоматизировать тестирование валидации, можно написать 2 очень простых теста. Для написания юнит тестов будем использовать phpUnit. Код приведу только для XML, но такой же подход отлично портируется и на JSON:

Проверка отсутствия ошибок на валидных XML/JSON

Проверка присутствия ожидаемой ошибки для невалидных XML/JSON

На этом у меня все. Приятной вам декларации!

Источник

Мышление в стиле Ramda: Декларативное программирование

Данный пост является четвёртой частью серии о функциональном програмировании под названием «Мышление в стиле Ramda».

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

Когда мы начинаем писать маленькие функциональные строительные блоки и объединять их, мы обнаруживаем, что нам необходимо написать множество функций, которые будут оборачивать операторы JavaScript, такие как арифметика, сравнение, логика и управление потоком. Это может показаться утомительным, но мы находимся за спиной Ramda.

Но сначала, небольшое введение.

Императивность vs Декларативность

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

Другое подобное разделение заключается в императивном програмировании против декларативного.

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

Один из классических декларативных языков — это Prolog. В Prolog програма состоит из набора фактов и набора правил вывода. Вы начинаете программу, задавая вопрос, и набор правил вывода Prolog’а использует факты и правила для ответа на ваш вопрос.

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

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

Декларативные заменители

Поскольку мы программируем на JavaScript, императивном языке, это нормально — использовать стандартные императивные конструкции при написании «нормального» JavaScript кода.

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

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

Арифметика

Во второй части мы реализовали серию арифметических трансформаций для демонстрации конвеера:

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

Мы можем использовать add(1) и subtract(1) для увеличения и уменьшения, но так как эти две операции такие распространённые, Ramda предоставляет inc и dec вместо них.

Так что мы можем ещё немного упростить наш конвеер:

Сравнение

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

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

Обратите внимание, что эти функции, как кажется, принимают свои аргументы в нормальном порядке (первый аргумент больше второго?). Это имеет смысл, когда мы используем их в изоляции, но может сбивать с толку при объединении функций. Эти функции нарушают принцип «данные идут последними», так что нам нужно быть осторожными, когда мы используем их в наших конвеерах и подобных им ситуациях. И именно здесь flip и заполнитель (__) могут принести пользу.

В дополнение к equals есть ещё identical для определения, являются ли два значения ссылками на то же пространство в памяти.

Логика

В основном, || используется для получения значений по умолчанию. К примеру, мы можем написать что-нибудь вроде этого:

Это распространённая идиома, и чаще всего работающая, но полагающаяся на JavaScript логику определения «ложности». Что если 0 является валидным параметром? Так как 0 является ложным значением, мы получим значение линии равное 80.

Условия

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

ifElse

Как мы упомянули выше, функции сравнения не работают подобно функциям объединения, так что здесь нам нужно начать использовать заполнитель ( __ ). Мы также можем применить lte вместо этого:

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

Константы

Функции-константы весьма полезны в ситуациях, подобных этой. Как вы можете предположить, Ramda предоставляет нам сокращение. В данном случае, сокращение называется always.

Ramda также предоставляет T и F в качестве дальнейших сокращений для always(true) и always(false)

Тождественность

Вторая ветвь сравнения ( a => a ) — это другой типичный паттерн в функциональном программировании. Это известно как «тождественность» (не знаю точного перевода термина «identity function», просто выберу этот — прим. пер.). То есть, это функция, которая просто возвращает тот аргумент, который она получила.

Как вы уже можете ожидать, Ramda предоставляет нам функцию identity:

«when» и «unless»

Если, как в нашем случае, вторая ветвь является тождественностью, мы можем использовать when вместо ifElse :

Мне не понадобилось использовать cond в моём коде с Ramda, но я писал подобный код на Lisp много лет назад, так что cond чувствуется старым другом.

Заключение

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

Далее

Это распространённый паттерн, и вновь Ramda предоставляем нам инструменты для того чтобы привести всё это к более чистому виду. Следующий пост, «Бесточечная нотация» рассматривает способы, позволяющие упростить функции, следующие подобному паттерну.

Источник

Чем отличается императивное программирование от декларативного

Предыстория

Не так давно я была в активном поиске работы и просматривала кучу сайтов с вакансиями/проектами. На некоторых из них «проходные» вопросы можно посмотреть еще до подачи отклика.

Большинство было вполне обычными, типа «сколько лет вы пользуетесь фреймворком Х?», но один мне показался интересным (я даже туда откликнулась, но #меняневзяли).

Это собственно и был вопрос из заголовка. И я решила разобраться. А лучший способ понять — это, как известно, объяснить. Так что добро пожаловать под кат.

В чем же отличия?

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

Императивный стиль

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

Это что ни на есть декларативный стиль, но при этом с примесью императивного.

Декларативный стиль

Такой стиль, в котором вы описываете, какой именно результат вам нужен.

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

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

Пример на JS

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

Наверное, правильно называть один стиль «более декларативным», а другой — «более императивным».

Источник

Декларативный подход к программированию

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

Что такое декларативное программирование:

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

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

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

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

Подходы к декларативному программированию:

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

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

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

Другая группа языков, классифицируемых как декларативные языки, — это предметно-ориентированный язык программирования или языки для решения конкретной проблемы.

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

Вывод:

В этой статье вы прочитали что такое декларативный подход к программированию и всё остальное с этим связанное.

Источник

Понравилась статья? Поделиться с друзьями:

Не пропустите наши новые статьи:

  • Что такое дек в программировании
  • Что такое деинсталляция программы
  • Что такое деинсталляция программного
  • Что такое деинсталляция программного обеспечения
  • Что такое деинсталляция программного обеспечения определение

  • Операционные системы и программное обеспечение
    0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest
    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии