Я тоже 'умные' для чтения младшего устройства? Слишком много функциональное программирование в мои Джорданы?

Я'м переднего плана-старший Дэв, кодирование в Вавилоне на ES6. Часть наше приложение делает вызов API, и на основе модели данных, мы возвращаемся из вызова API, определенные формы должны быть заполнены.

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

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

Это, как, я думаю, начинающий программист справится.

в

export const addPages = (apiData) => {
   let pagesList = new PagesList(); 

   if(apiData.pages.foo){
     pagesList.add('foo', apiData.pages.foo){
   }

   if (apiData.pages.arrayOfBars){
      let bars = apiData.pages.arrayOfBars;
      bars.forEach((bar) => {
         pagesList.add(bar.name, bar.data);
      })
   }

   if (apiData.pages.customBazes) {
      let bazes = apiData.pages.customBazes;
      bazes.forEach((baz) => {
         pagesList.add(customBazParser(baz)); 
      })
   } 

   return pagesList;
}

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

Теперь, для тестирования это одно, а так это чтения и мне интересно, если я'м, что делает вещи менее читабельным здесь.

// file: '../util/functor.js'

export const Identity = (x) => ({
  value: x,
  map: (f) => Identity(f(x)),
})

// file 'addPages.js' 

import { Identity } from '../util/functor'; 

export const parseFoo = (data) => (list) => {
   list.add('foo', data); 
}

export const parseBar = (data) => (list) => {
   data.forEach((bar) => {
     list.add(bar.name, bar.data)
   }); 
   return list; 
} 

export const parseBaz = (data) => (list) => {
   data.forEach((baz) => {
      list.add(customBazParser(baz)); 
   })
   return list;
}

export const addPages = (apiData) => {
   let pagesList = new PagesList(); 
   let { foo, arrayOfBars: bars, customBazes: bazes } = apiData.pages; 

   let pages = Identity(pagesList); 

   return pages.map(foo ? parseFoo(foo) : x => x)
               .map(bars ? parseBar(bars) : x => x)
               .map(bazes ? parseBaz(bazes) : x => x)
               .value

}

Здесь's не моя забота. Для меня дно более организованной. Сам код разбит на более мелкие куски, которые можно исследовать в отдельности. Но я'м мышления: если мне приходилось читать, что в качестве младшего разработчика, привыкшего к таким понятиям, как личность, используя функторы, заискивания, или тройных заявления, я был бы в состоянии даже понять, что последнее решение делает? Это лучше делать в "неправильно, проще" в сторону иногда?

Комментарии к вопросу (18)

В ваш код, вы сделали несколько изменений:

  • реструктуризующее присваивание полям доступ в "страниц" - это хорошее изменение.
  • извлечение `parseFoo функции () и т. д. это возможно, неплохо изменить.
  • введение функтор-это ... очень запутанно.

Один из самых запутанных частей здесь является, как вы смешиваете функционального и императивного программирования. С вашим функтор вы еще'т действительно преобразование данных, вы используете его, чтобы пройти список изменяемых с помощью различных функций. Это вовсе'т, кажется, как очень полезная абстракция, у нас уже есть переменные для этого. Дело в том, что, возможно, должны были абстрагироваться – только разбор этого элемента, если он существует – пока есть в коде явно, но сейчас надо думать не за горами. Например, это'ы несколько не очевидно, что parseFoo(ФОО) будет возвращать функция. В JavaScript не'т иметь статический тип системы, чтобы уведомить вас, будет ли это законно, так что такой код действительно подвержен ошибкам без лучшего названия (makeFooParser(ФОО)?). Я не'т вижу никакой пользы в этой несуразице.

Что я'd не ожидал увидеть вместо этого:

в

if (foo) parseFoo(pages, foo);
if (bars) parseBar(pages, bars);
if (bazes) parseBaz(pages, bazes);
return pages;

Но, что's не подходит, потому что непонятно от призыва сайте, что товар будет добавлен в список страниц. Если вместо разбора функции являются чистыми и возвращает (возможно, пустой) список, что можно явно добавить на страницы, что может быть лучше:

pages.addAll(parseFoo(foo));
pages.addAll(parseBar(bars));
pages.addAll(parseBaz(bazes));
return pages;

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

Так что да, код был слишком умен. Пожалуйста, примените свой ум, чтобы не писать умный код, но найти умные способы, чтобы избежать необходимости откровенную умность. Лучшие проекты Дон'т взгляд необычные, но выглядят очевидна для любого, кто их видит. И хорошие абстракции существуют, чтобы упростить Программирование, не добавить дополнительные слои, которые мне придется распутывать сперва в голове (вот, выясняя, что функтор-это эквивалентно переменной, и может эффективно быть упраздненным).

Просьба: если вы сомневаетесь, держите ваш код простой и глупый (принцип KISS).

Комментарии (4)

Если вы сомневаетесь, это, наверное, слишком умный! Второй пример представляет случайное сложности с выражениями типа фу ? parseFoo(ФОО) : х => х, и в целом код является более сложным, что означает это тяжелее, чтобы следовать.

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

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

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

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

Комментарии (7)

Этот ответ Мой несколько запоздал, но я все равно хочу помочь. Просто потому, что вы're, используя новейшие методики ЕС6 или через самые популярные парадигмы программирования не'Т означает, что ваш код является более правильным, или, что младший's код является неправильным. Функциональное программирование (или любую другую технику) следует использовать, когда это'ы на самом деле нужны. Если вы пытаетесь найти самый крошечный шанс впихнуть новейших технологий программирования в каждую проблему, вы всегда будете в конечном итоге с более-технические решения.

Сделайте шаг назад и попытаться вербализовать проблему вы'вновь пытается решить для второй. По сути, вы просто хотите, чтобы функция addPages для преобразования различных частей apiData в набор пар ключ-значение, а затем добавить их все в PagesList`.

И если это's все существует к нему, зачем заморачиваться с помощью функции личности " с " тернарный операторили черезфунктордля ввода разбора? Кроме того, почему вы даже думаете, что это'ы правильный подход, чтобы применитьфункциональное программирование`, что вызывает побочные эффекты (по мутируют список)? Почему все эти вещи, когда все, что вам нужно-это:

const processFooPages = (foo) => foo ? [['foo', foo]] : [];
const processBarPages = (bar) => bar ? bar.map(page => [page.name, page.data]) : [];
const processBazPages = (baz) => baz ? baz.map(page => [page.id, page.content]) : [];

const addPages = (apiData) => {
  const list = new PagesList();
  const pages = [].concat(
    processFooPages(apiData.pages.foo),
    processBarPages(apiData.pages.arrayOfBars),
    processBazPages(apiData.pages.customBazes)
  );
  pages.forEach(([pageName, pageContent]) => list.addPage(pageName, pageContent));

  return list;
}

(выполнимую jsfiddle [здесь][1])

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

Теперь сравните этот код с тем, что вы'вэ пришел с выше, ты видишь разницу? Несомненно, функциональное программирование и на ES6 синтаксиса мощный, но если вы нарезаете проблема в ту сторону с этими методами, вы'll итоге даже Мессье код.

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

Комментарии (6)

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

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

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

Комментарии (0)

ТД;Д-Р

  1. Вы можете объяснить ваш код для младший разработчик в 10 минут или меньше?
  2. Через два месяца, ты можешь понять свой код?

Детальный Анализ

Ясность и удобочитаемость

Исходный код-это невероятно простой и понятный для любого уровня программиста. Это в стиле на слуху.

Удобочитаемость в значительной степени основана на знакомстве, не какой-то математический подсчет жетонов. ИМО, на данном этапе времени, у вас слишком много ЕС6 в вашем перезаписи. Может быть, через пару лет я'будете менять эту часть моего ответа. :-) Кстати, мне тоже нравится @b0nyb0y ответ как разумные и четкие компромиссы.

Проверяемость

if(apiData.pages.foo){
   pagesList.add('foo', apiData.pages.foo){
}

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

if (apiData.pages.arrayOfBars){
      let bars = apiData.pages.arrayOfBars;
      bars.forEach((bar) => {
         pagesList.add(bar.name, bar.data);
      })
   }

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

if (apiData.pages.customBazes) {
      let bazes = apiData.pages.customBazes;
      bazes.forEach((baz) => {
         pagesList.add(customBazParser(baz)); 
      })
   } 

Этот код также очень проста. Предполагая, что customBazParser проверена и не'т вернуться слишком много на "особый" и результаты. Итак, еще раз, если нет сложных ситуаций с PagesList.добавить(), (который может быть, как я'м не знаком с вашим доменом) я не'т вижу, почему этот раздел требует особого испытания.

В общем, испытывать все функции должны работать нормально.

Предупреждение: при наличии особых причин, чтобы испытать все возможности 8 трех операторов if ()`, то да, делать сплит тестов. Или, если PagesList.добавить () - это чувственный, да, разделить тесты.

Структура: стоит ли распадаясь на три части (например, Галлия)

Здесь у вас есть лучший аргумент. Лично я не'т думаю, что исходный код "не давно" (Я'м не ПСП фанатик). Но, если было несколько больше `если (apiData.страниц.разделы мля), то ПСП поднимает это'ы уродливую голову, и это стоило бы разделить. Особенно если сухой применяется и функции могут быть использованы в других местах кода.

Мое предложение

YMMV. Чтобы сохранить строку кода и какой-то логикой, я мог бы сочетать в Ли А но в одну строку: например

let bars = apiData.pages.arrayOfBars || [];
bars.forEach((bar) => {
   pagesList.add(bar.name, bar.data);
})

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

Комментарии (0)