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

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

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

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

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

Самая сложная часть этой темы, как заметил Меррик: Это одна из тех вещей, о которых вы догадываетесь, но не можете объяснить.

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

Давайте вернемся к первоначальному определению, над которым я высмеивал: «Императивное программирование - это« как »вы что-то делаете, а декларативное программирование больше похоже« что »вы делаете». На самом деле здесь спрятана НЕКОТОРАЯ хорошая информация. Давайте сначала рассмотрим достоинства этого определения, вырвав его из контекста программирования и посмотрев на пример из «реальной жизни».

Вы решаете, что потратили слишком много времени на споры о «Усталости от JavaScript» ™ и реактивном функциональном программировании, и ваш муж заслуживает приятного свидания. Вы решили пойти в Red Lobster, поскольку в последнее время много слушаете Бейонсе. 👑🐝. Вы приезжаете в Red Lobster, подходите к стойке регистрации и говорите…

Повелительный подход (КАК): я вижу, что таблица, расположенная под знаком Gone Fishin, пуста. Мы с мужем собираемся пойти туда и сесть.

Декларативный подход (ЧТО): Таблица на двоих, пожалуйста.

Императивный подход связан с тем, КАК вы на самом деле получите место. Вам нужно перечислить шаги, чтобы показать, КАК вы собираетесь получить стол. Декларативный подход больше касается того, ЧТО вы хотите - стола на двоих.

"Ok." - твой мозг

Больше метафор!

Я задам вам вопрос. Я хочу, чтобы вы подумали как об императивном, так и о декларативном ответе.

«Я принадлежу Wal-Mart. Как мне отсюда добраться до твоего дома? »

Повелительный ответ: выйдите из северного выхода с парковки и поверните налево. Двигайтесь по автомагистрали I-15 на юг, пока не дойдете до съезда с шоссе Bangerter. Сверните направо с выезда, как будто собираетесь в Ikea. Идите прямо и на первом светофоре поверните направо. Продолжайте движение на следующий светофор, затем поверните налево. Мой дом № 298.

Декларативный ответ: Мой адрес: 298 West Immutable Alley, Draper Utah 84020.

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

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

Декларативный ответ сотруднику Red Lobster предполагает, что сотрудник Red Lobster знает все необходимые шаги, чтобы заставить нас сесть за стол. Знание адреса предполагает, что у вас есть какой-то GPS, который знает, как добраться до вашего дома.

У автомобиля с автоматической коробкой передач есть своего рода слой абстракции над переключением передач.

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

Если это предложение имеет смысл, у вас все отлично!

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

Обязательные: C, C ++, Java
Декларативные: SQL, HTML
(Может быть) Смешивание: JavaScript, C #, Python

Подумайте о своем типичном примере SQL или HTML,

SELECT * FROM Users WHERE Country=’Mexico’;
<article>
  <header>
    <h1>Declarative Programming</h1>
    <p>Sprinkle Declarative in your verbiage to sound smart</p>
  </header>
</article>

Взглянув на оба примера, вы получите очень четкое представление о том, что происходит. Оба они декларативны. Их волнует, ЧТО вы хотите сделать, а не КАК вы этого хотите.

Вы описываете, чего пытаетесь достичь, но не инструктируете, как это сделать. Реализация выбора всех пользователей, проживающих в Мексике, была отвлечена от вас. Вас не волнует, как веб-браузер анализирует вашу статью и отображает ее на экране. Ваше ЧТО - это мексиканские пользователи и новый заголовок и абзац на вашем веб-сайте.

Все идет нормально. Давайте рассмотрим более практические примеры JavaScript.

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

  1. Напишите функцию с именем double, которая принимает массив чисел и возвращает новый массив после удвоения каждого элемента в этом массиве. двойной ([1,2,3]) - ›[2,4,6]
  2. Напишите функцию с именем add, которая принимает массив и возвращает результат сложения каждого элемента в массиве. добавить ([1,2,3]) - ›6
  3. Используя jQuery (или обычный JavaScript), добавьте обработчик события click к элементу с идентификатором «btn». При нажатии переключите (добавьте или удалите) «выделить», а также изменить текст на «Добавить выделение» или «Удалить выделение» в зависимости от текущего состояния элемента.

Давайте посмотрим на наиболее распространенные подходы к этим проблемам, которые также являются императивными подходами.

function double (arr) {
  let results = []
  for (let i = 0; i < arr.length; i++){
    results.push(arr[i] * 2)
  }
  return results
}

2.

function add (arr) {
  let result = 0
  for (let i = 0; i < arr.length; i++){
    result += arr[i]
  }
  return result
}

3.

$("#btn").click(function() {
  $(this).toggleClass("highlight")
  $(this).text() === 'Add Highlight'
    ? $(this).text('Remove Highlight')
    : $(this).text('Add Highlight')
})

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

  1. Наиболее очевидная общность заключается в том, что они описывают КАК что-то делать. В каждом примере мы либо явно перебираем массив, либо явно описываем шаги по реализации желаемой функциональности.
  2. Это может быть не так очевидно, если вы не привыкли мыслить «декларативно» или, точнее, «функционально». В каждом примере мы изменяем некоторую часть состояния (если вы не знакомы с термином «состояние», это, по сути, информация о чем-то, хранящемся в памяти, что должно звучать очень похоже на переменные). В первых двух примерах мы создаем переменную с именем результаты, а затем мы постоянно их модифицируем. В третьем примере у нас нет никаких переменных, но у нас все еще есть состояние, живущее в самой DOM - затем мы изменяем это состояние в DOM.
  3. Это немного субъективно, но для меня приведенный выше код не очень удобочитаем. Я не могу просто взглянуть на код и понять, что происходит. Мой мозг должен пройти через код так же, как это сделал бы интерпретатор, но с учетом контекста, в котором живет код (еще один негативный фактор изменяемых данных).

Ладно, хватит кода. Давайте теперь рассмотрим несколько декларативных примеров. Цель - исправить все проблемы сверху. Таким образом, каждый пример должен описывать, ЧТО происходит, не может изменять состояние и должен быть легко читаемым.

1.

function double (arr) {
  return arr.map((item) => item * 2)
}

2.

function add (arr) {
  return arr.reduce((prev, current) => prev + current, 0)
}

3.

<Btn 
  onToggleHighlight={this.handleToggleHighlight}
  highlight={this.state.highlight}> 
    {this.state.buttonText}
</Btn>

Намного лучше

Обратите внимание, что в первых двух примерах мы используем встроенные в JavaScript методы map и reduce. Это восходит к тому, о чем мы неоднократно говорили в этой статье, что большинство декларативных решений - это абстракция над некоторой императивной реализацией.

В каждом примере мы описываем ЧТО мы хотим, а не КАК (мы не знаем, КАК реализованы map и reduce, нам также все равно). Мы не изменяем ни одно состояние. Все мутации абстрагируются внутри map и reduce. Кроме того, он более читабелен (если вы, конечно, привыкнете к map и reduce).

А что насчет №3? Ну, я немного схитрил и использую React - но учтите, что все три обязательные ошибки все еще исправлены. Настоящая прелесть React в том, что вы можете создавать декларативные пользовательские интерфейсы. Глядя на наш компонент Btn, я могу легко понять, как будет выглядеть пользовательский интерфейс. Еще одно преимущество состоит в том, что вместо состояния, живущего в DOM, оно живет в самом компоненте React.

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

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

Одна вещь, в которой я не стал заходить слишком далеко, - это то, что функциональное программирование является подмножеством декларативного программирования. Если вы еще этого не сделали, я настоятельно рекомендую поближе познакомиться с методами функционального программирования на JavaScript. Начните с .map, .reduce, .filter и двигайтесь дальше.

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

С учетом всего вышесказанного, одна из моих любимых вещей - найти в Интернете определения, в которых создатель этого определения больше заботился о том, чтобы звучать умно, чем о предоставлении полезного, потребляемого определения. Императив против декларативного имеет ТАКОЕ много хороших примеров. Наслаждаться!

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

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

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

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

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

Первоначально опубликовано на tylermcginnis.com

Следите за новостями Тайлера МакГинниса в Twitter.