Использование логических операторов Javascript && и ||

Этот пост о том, как я обрабатывал данные JSON из вызовов веб-API, почему выбранный мной подход был «дурным вкусом» и что я сделал, чтобы это исправить.

Предпосылки

  • Вы знакомы с базовым Javascript (т. Е. Знаете циклы, if-thens и т. Д.).

Например, вам будет хорошо, если вы выполнили (или можете выполнить) базовые задания JavaScript в Free Code Camp от Куинси Ларсона (ссылка)

  • У вас есть поверхностные знания о веб-API. (т.е. вы знаете, для чего они используются). Вы немного знаете о реляционной базе данных и SQL.

Это не означает, что вы действительно использовали их в своем коде (хотя это было бы неплохо).

  • Вы НЕ опытный программист. Вам будет скучно :-)

Преамбула (также известная как почему этот пост?)

Вдохновением для этого поста послужила наводящая на размышления и популярная (2,1 тыс. Рекомендаций и их количество) статья о хорошем вкусе кодирования. Брайан использовал пример, приведенный Линусом Торвальдсом (вы знаете того парня, который в одиночку написал ядро ​​одной из самых надежных, эффективных и элегантных операционных систем в мире и раздал его бесплатно ) в интервью, чтобы рассказать о передовых методах разработки программного обеспечения. Хотя я призываю всех прочитать эту статью, мой пост о том, чем я закончил после прочтения его статьи.

Я начинающий программист-хобби, самоучка. А мой партнер (как в коде, так и в жизни), обученный устаревшей CS, говорит, что я немного кодовый придурок. Сначала я кодирую, а потом думаю (об алгоритме и прочем). Я кодирую для своего удовольствия (то есть пока не ради денег). Как только я получаю работающее и протестированное приложение, я развертываю его и никогда не оглядываюсь назад (ну, я слушаю жалобы пользователей и исправляю их, но это все). Статья Брайана подтолкнула меня к критическому взгляду на код, который я написал за последние два года (когда я изучал скрипт Google Apps и создавал надстройки Google Doc / sheet и веб-приложения с помощью скрипта Google App. ).

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

При обработке (данных) сети с использованием API и JSON

Веб-API предоставляют доступ к базам данных с обширной информацией, которую может использовать ваша программа. Вот введение с подробным примером использования New York Times Web API. Большинство современных веб-API возвращают данные в формате JSON. JSON - это подмножество Javascript, и преобразование строки в объект JSON (т.е. Javascript) является тривиальным.

var data = JSON.parse(string_result_of_api_call)

Бум! Объект Javascript datanow содержит всю информацию, которая была отправлена ​​обратно в ответ на вызов API.

С этого момента все становится немного запутанным.

«Беспорядок» объяснил

Использование веб-API для получения данных из веб-службы концептуально очень похоже на выполнение запроса в базе данных. Например, запрос SQL select * from cars where price <10K (получите мне все автомобили по цене ‹10K) вернет таблицу со строками, соответствующими критериям запроса.

В JSON результаты выглядели бы немного иначе.

[{make:'Toyota', model:'Camry', year:1999, price:7K, doors:'2DR'},{make:'Nissan', model:'Sentra', year:1988, price:3K, doors:'2DR'},{make:'Jeep', model:'Cherokee', year:1988, price:7K, doors:'4DR'}{make:'Jeep', model:'Wrangler', year:1984, price:9K, doors:'2DR'}]

  1. Результатом является действительный объект Javascript (в этом примере массив).
  2. Каждая строка результата представлена ​​как элемент массива, а имена полей даны для каждого значения.

Хотя внешний вид отличается, основная структура по-прежнему не той.

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

Если бы результаты были возвращены в виде строк в стиле SQL, они бы выглядели следующим образом (где отсутствует информация о годе выпуска Nissan и его трансмиссии, введите модель одного из двух Jeep).

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

В JSON данные будут примерно такими:

[{make:'Toyota', model:'Camry', year:1999, price:7K, doors:'2DR'}, {make:'Nissan', model:'Sentra', price:3K},{make:'Jeep', year:1988, price:7K, doors:'4DR'}, {make:'Jeep', model:'Wrangler', year:1984, price:9K, doors:'2DR'}]

У Ниссана, как и положено, нет ключа на год и двери. Для одного из джипов модель отсутствует.

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

if (key != undefined) {do_some_thing(object[key]}

Это работало хорошо, пока я не столкнулся со сложными (то есть реальными) JSON.

JSON - это вложенная древовидная структура, а не структура таблицы. Хотя ключи объекта JSON должны быть строкой или числом, значения могут быть объектами. Значения ключей этих дочерних объектов могут снова быть объектами. Многие реальные JSON могут иметь 8 или 9 уровней. Если использовать мой шаблон, это будет означать, что у меня будут вложенные if-thens 8 или 9 уровней.

Попробуйте отладить это.

«Плохой вкус» - подробный пример.

Продолжим автомобильный домен. Допустим, нам поставили задачу распечатать значения определенных полей из инвентаря. Мы отобразим значение полей, если они доступны. Если поля отсутствуют или значение поля отсутствует, мы ничего не будем отображать (т.е. напишем пробел).

Проверить модель, обрезку и год легко, потому что ключи находятся на первом уровне. Но wheel_size и wheel_metal - вложенные поля. Нам нужно сначала проверить, существует ли родительское поле (в данном случае wheel), прежде чем мы получим к ним доступ. Вы можете увидеть, как возрастает сложность в строках 21-29. Снова представьте, что обрабатываемые поля имеют 8 или 9 уровней глубины.

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

Короткое замыкание - логические значения

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

1. false && (anything) короткое замыкание оценивается как ложное

2. true || (anything) короткое замыкание оценивается как истина

Вот полезная таблица частичной истины

Воспользовавшись правилом № 1, если вы напишете cars["wheel"] && cars["wheel"]["wheel_size"] AND, если cars["wheel"] не существует (т.е. оно неверно в Javascript), остальное никогда не оценивается.

По сути, короткое замыкание может преобразовать вложенную проверку ошибок для неопределенных полей в простую единственную строку кода. Глубина резкости не увеличит сложность, она просто добавит больше предложений с помощью && s.

Наконец, вот очищенный код

TL; DR: используйте короткое замыкание && для проверки ключей в глубоком JSON вместо вложенного if-else. Это значительно упростит ваш код. Соедините вместе все ключи с верхнего уровня, пока не дойдете до ключа, значение которого вы хотите, с помощью связки && s.

k_0: {k_1: {k_2: {k3:… kn}} должно стать k_0 && k_0 [k_1] && k_0 [k_1] [k_2] &&… && k_0 [k_1] [k_2]…. [kn]

За последние два года я потратил 2300 часов на кодирование и написал 23 342 строки кода. В этом коде я сделал 349 вызовов JSON из реального мира, за которыми следовали вложенные if-then-else. Скажем, на код / ​​отладку каждого из них у меня уходил в среднем 1 час. Это все еще 350 часов или 15% моего времени написания кода.

Написание этого шаблона занимает буквально минуту или меньше, и это в основном доказательство ошибок. Это 350 минут или около 6 часов.