Принятие минимализма в разработке пользовательского интерфейса

DX означает опыт разработчика.

Некоторые функции языка JavaScript лучше оставить неиспользованными или использовать умеренно в современных приложениях React, Дуглас Крокфорд однажды написал книгу в том же духе. Когда я говорю современные, я имею в виду приложения, которые используют хуки для управления состоянием компонентов и жизненным циклом.

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

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



Итак, вот список:

класс, новый, расширяет, instanceof, конструктор, супер

Для тех, кто в восторге от TypeScript, позволяющего писать ООП-код на основе классов, например Java, это шокирует. Класс - это синтаксический сахар ES6 над прототипным наследованием JavaScripts.

typeof class C {} === 'function'

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



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

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



extends позволяет создавать наследование с классами. Держитесь подальше от наследования и примите композицию.

instanceof - ключевое слово, связанное с конструкторами классов, имеющее несколько причуд.

супер и новый сочетается с классом. Используйте литералы объекта / массива и оператор распространения для создания новых.

╔═══════════╦════════════════════╗
║ use       ║  instead of        ║
╠═══════════╬════════════════════╣
║ {}        ║ new Object()       ║
║ []        ║ new Array()        ║
╚═══════════╩════════════════════╝

Большинство сторонних библиотек, которые я использую, отошли от использования new. Но иногда у вас нет выбора, когда вы имеете дело со многими встроенными объектами JavaScript. Опять же, у меня здесь только список запахов кода. Это не список неиспользованных.

это

this представляет собой запутанную конструкцию, как объясняется здесь:



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

позволять

К нашему удивлению, мы обнаружили, что использовали let только внутри тестов. Другое исключение было внутри компонентов, которые управляли своим поведением с помощью флагов. В другом месте всегда было const. Используйте eslint / tslint. Он предупредит вас о «let», где это применимо.

функция 😱

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

typeof (() => 0) === "function"

… Но без багажа new, this и аргументов .

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

  1. генераторы функций, function *. На данный момент нет возможности выразить генератор функций в виде стрелочной функции.
  2. Использование дженериков с TypeScript. Синтаксис стрелочной функции недоступен.

аргументы

Еще один запутанный… объект? множество? Переменная?

function add(a, b) {
  console.log(arguments[0]); //a
  console.log(arguments[1]); //b
}

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

const add = (...args) => { 
  console.log(args[0]);
  console.log(args[2]);
}

if / else возвращают выражения

Тройка намного лучше. Даже вложенные блоки предпочтительнее вложенного блока if / else. Prettier красиво его отформатирует.

Используйте экономно

удалять

delete напрямую изменяет объект, удаляя из него определенное свойство. Если вам нужна неизменяемость, рассмотрите возможность использования функции пропуска в ramda или lodash. Или вы можете сделать это:

const apiResult = {
  id: 1,
  name: "Joe",
  city: "San Jose"
};
const { id, ...cleanResult } = apiResult;
// cleanResult is now void of the id property

for, for in, for, while, do while, continue, break

Циклы поощряют императивный стиль с изменением состояния и побочными эффектами внутри цикла. Даже в локальном масштабе и в меньшем масштабе это риск ошибок. Таким образом, эти ключевые слова должны быть тщательно изучены во время проверки кода. map / filter / reduce предлагают лучший декларативный стиль, чем циклы. У нас огромная база кода React (1000 плюс файлы js), и в ней нет циклов for / while.

Для итерации по объекту в большинстве случаев будет достаточно Object.keys () и Object.entries ().

для каждого

forEach по-прежнему является обязательным, его функция-итератор будет содержать побочные эффекты, поскольку вы ничего не возвращаете из выражения forEach. В большинстве случаев я гарантирую, что вы сможете переписать цикл forEach () с помощью reduce.

выключатель

Аргумент в том, что переключатель нарушает принцип Открыто / Закрыто. Я согласен. switch также имеет тенденцию создавать длинные функции. дело проваливается, когда вы забываете вернуться или сломаться - это риск.

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

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

Никогда не использовать

вар

var имеет только область функционального уровня. Это также приводит к странным проблемам с подъемом. Всегда используйте const. Если вам нужно изменить, используйте let. Опять же, используйте хороший линтер, который посоветует избегать рискованного использования.

с участием

Что он вообще делает? Я больше не могу вспомнить.

оценка

Eval позволяет анализировать строку и выполнять ее в глобальной области видимости. Для этого он вызовет интерпретатор JavaScript. Это кандидат на злонамеренные взломы, и вам никогда не следует его использовать. Обратитесь к документации для альтернативного использования с функцией ()

Принять функциональные шаблоны

Это приведет к лучшему, выразительному, декларативному стилю кода. Это ведет к:

  1. меньшая поверхность кода.
  2. построение вашей логики с использованием проверенных временем конструкций, таких как map / reduce / compose и т. д.

И то, и другое снижает вероятность появления ошибок.

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