Дерьмо, говорят кодеры Javascript

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

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

1. Давайте использовать машинописный текст.

Серьезно, какого черта вы используете Typescript? Ах да, тебе нравится Angular. Достаточно.

Но моя IDE любит Typescript и помогает мне писать хороший чистый код.

Нет, это не так. Он превращает ваш код в раздутое, невыносимое, трудно поддающееся отладке дерьмо. Ваша IDE - это костыль. Не относитесь к Javascript как к врагу. Прекратите пытаться навязать ему свои старые шаблоны Java и C #.

См. также 2, 3, 4 и 7 ниже.

2. Давайте воспользуемся расширениями Flow для Javascript.

Какая часть Javascript является слабо типизированным языком, которого вы не понимаете?

Следуя пунктам, изложенным в пункте 1 выше, перестаньте бояться Javascript. Слабый набор текста - это сила, а не слабость. Это дает вам гибкость. Если вам нужна строгая типизация, используйте Go, или Java, или, черт возьми, я не знаю, Ada.

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

3. Давайте превратим все в класс

Просто нет. Если вы пишете Javascript как традиционный объектно-ориентированный объект, вы делаете это неправильно. Составляйте и карри все вещи.

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

Вот что-то подобное, что я вижу все время

class Utilities {
  static doSomeThing(data) {
    return data.whatever()
  }
  static someOtherThing() {
    return 'yay, a thing'
  }
}
module.exports = Utilities

Зачем тебе это делать, когда ты мог просто сделать

const doSomething = (data) => data.whatever()
const someOtherThing = () => 'yay, a thing'
module.exports = {
  doSomething,
  someOtherThing
}

4. Давайте создадим интерфейс на Angular [1 | 2 | 4 | независимо]

Angular предназначен для людей, которые боятся кода. Используйте 1_. Будь взрослым.

Я никогда не видел хорошо структурированного, элегантного, хорошо протестированного проекта Angular. Angular - это PHP в мире Javscript. Удивительно, но я видел много проектов, в которых используются как Angular, так и jQuery. Вы заметите, что я даже не упоминаю jQuery в этом списке, потому что никто больше не использует jQuery.

Как мог бы сказать Боно:

Давайте сделаем историю Angular

5. Давайте использовать immutable.js.

Нет. Не используйте дополнительные библиотеки, которые заставляют вас кодировать их недостатки только потому, что вы боитесь случайно что-то изменить. Просто используйте нотацию распределения объектов, которая теперь является стандартной функцией в Node 9+, и напишите правильные тесты для ваших редукторов.

Каким образом

return immutable(state, { goodTimes: { $set: myAmazingData })

лучше чем

return { ...state, goodTimes: myAmazingData }

Не изменяйте состояние, но последнее намного легче читать.

6. Давайте использовать [lodash | подчеркивание | что угодно].

Нет. Давайте не будем использовать lodash. В lodash почти нет ничего, что можно было бы улучшить с помощью современного ванильного JavaScript. В Javascript уже много лет используются map и reduce.

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

7. Давайте напишем это в Coffeescript.

Звонили Naughties и просят вернуть их трудно поддающееся отладке вредоносное ПО.

Раньше я любил Coffeescript, но затем эволюционировал Javascript, и внезапно в Coffeescript больше не было необходимости. Конечно, это красиво и лаконично, и вам не нужны запятые в списках, но кроме этого он ничего не добавляет и вынуждает вас добавлять много return nil в конце функций из-за его раздражающей привычки `` давайте будем как Ruby '' возвращает последнее, что он видел из любой функции. Добавьте console.log ‘is thing thing on’ в конце функции и сломайте случайные вещи. Нет, спасибо.

См. также пункт 1 выше.

8. Давайте создадим наш проект с помощью [Gulp | Grunt | something]

Нет. Используйте Webpack и простые npm скрипты. Избегайте древних систем сборки, которые заставляют вас производить и поддерживать собственные конвейеры активов.

9. Давайте воспользуемся генераторами.

Серьезно нет. Генераторы - это только для записи кода! Практически невозможно понять, что делает трясина кода генератора. Вместо этого используйте async и await. Намного приятнее.

Эти две вещи имеют одинаковый основной эффект

function* doTheThing() {
  const x = yield somethingReturnsPromise()
  // do something with x
  return x
}

а также

const doTheThing = async () => {
  const x = await somethingReturnsPromise()
  // do something with x
  return x
}

Последнее - это код, о котором люди могут рассуждать.

Конечно, есть несколько причин использовать генераторы, но на самом деле такие варианты использования очень редки. В большинстве случаев вы можете просто использовать async / await и сохранять понятный код.

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

Также код async / await быстрее, почти вдвое быстрее в современных версиях Node.

10. Давайте использовать Sagas в Redux / React.

Саги полагаются на Генераторы, и, как указано в пункте 9 выше, Генераторы медленные и уродливые.

Используйте promises, async / await и Thunks и делайте свои действия понятными.

Сравните этот тривиальный Saga код

function* fetchThing(id) {
  try {
    const thing = yield fetch(`${BASE}/things/${id}`)
    yield put(Actions.fetchThingSuccess({ thing }))
  } catch (err) {
    console.error('Caught', err)
    yield put(Actions.fetchThingFail({ err }))
  }
}

с той же функцией, что и Thunk

const fetchThing = id => async (dispatch) => {
  try {
    const thing = await fetch(`${BASE}/things/${id}`)
    dispatch(Actions.fetchThingSuccess({ thing }))
  } catch {
    console.error('Caught', err)
    dispatch(Actions.fetchThingFail({ err }))
  }
}

Они выглядят одинаково, правда? Но даже в этом тривиальном примере рассуждать о Thunk гораздо проще.

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

Напротив, рассуждения о потоке кода async и await не могут быть проще.

Конечно, люди будут говорить о том, что все саги pull по сравнению с традиционными действиями, которые push, и как это каким-то образом делает их отличными, но 99% действий просто не должны быть такими сложными, и если они ты наверное делаешь не так.

См. пункт 9 выше.

11. Давайте использовать пряжу.

Почему? Что Yarn дает вам по сравнению с современными версиями на NPM?

Хорошо, конечно, с NPM version 5.0.0 по NPM 5.3.x были собаки. Появление файла package-lock.json, являющегося прямым ответом на файл yarn.lock Yarn, было обработано особенно ужасно и вызвало массу ненужных хлопот разработчикам. Но это был почти год, и, если не считать случайных глупостей, NPM версии 5.6.0 и выше превосходны, а npm 5.7.1 действительно супербыстрая.

Просто используйте NPM и пропустите глобальную зависимость.

Заключение

Как я уже сказал выше, это все мое мнение, но это мнение, основанное на двух десятилетиях разработки Javascript. В целом соблюдайте следующие правила:

  1. Не используйте внешние пакеты, которые хорошо справляются с тем, что делает сам язык.
  2. Для серверных проектов не используйте языки более высокого уровня, которые компилируются до Javascript. Для проектов на стороне клиента старайтесь свести объем предварительной обработки к минимуму.
  3. Отдайте предпочтение простоте и удобочитаемости перед умом.

Спасибо.

Нравится, но не подписчик? Вы можете поддержать автора, присоединившись через davesag.medium.com.