JavaScript антипаттерны

JavaScript антипаттерны

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

Замены продолжительных условий

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

Смысл в том, чтобы выровнять длинный запутанный список условий, например, для if:

Второй отрывок кода выглядит более читабельно и декларативно: мы видим список условий, каждое из которых должно выполниться. Меньше визуального шума: скобок и операторов &&, легче понять вложенные условия с || (это отдельный вопрос о том, что стоило бы вынести их за скобки в виде переменных с понятными именами).

Такой же подход можно применить к условиям со множеством логических или и методом some().

В чём подвох: в отличии от первоначального вида условия с логическими операторами, не произойдёт вычислений по короткой схеме, и каждый элемент списка будет предварительно вычислен, даже если это не повлияет на результат. Про Short-circuit evaluation я писал в отдельной статье.

Это может привести к неожиданным последствиям, и однажды привело, когда я, не думая, переписал условия:

Код был одобрен и отправлен на прод, где падал при определённых условиях. Тогда я и понял, что интуитивно (но ошибочно) перенёс ленивое вычисление условий на понравившийся мне паттерн.

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

Перегрузка switch (true)

Об этом я прочитал в Вы не знаете JavaScript (и увидел на проде): иногда, вместо цепочки if, можно встретить  switch с «перегруженным» условием:

В чём подвохswitch использует строгое сравнение, эквивалентное оператору ===. Это приводит к неожиданному, на первый взгляд, поведению: код в ветке case array.length || object.prop: не выполнится, даже если массив не пустой, а свойство объекта существует, но является чем-то, кроме true.

«Починить» поведение этой конструкции можно завернув каждое выражение в Boolean. Это кажется лишним, если в оригинальных условиях с if и так происходит неявное приведение типов.

Почему я не пользуюсь этим подходом:

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