РСС

Ношу шлем, тяжело дышу…

Меня зовут Антон Шувалов. Я работаю в Lazada. Кроме программирования я пишу музыку и иногда занимаюсь дизайном интерфейсов. Я есть в Twitter, Facebook, и на GitHub. Вы можете написать мне email.

Если вы задумали порадовать меня небольшим подарком (не может быть!) — вот список моих мещанских мечт.

Читаемый код — самообман

Когда я вижу такой код return (~ memo.indexOf(item) ? null : memo.push(item)), memo; — хочется обратиться ко всем начинающим (или «продолжающим») JS разработчикам — не пишите так никогда. Совсем никогда. Вы можете подумать, что это какой-то крутой, «джедайский» код — который позволяет очень лаконично выразить вашу бизнес-логику, используя доступные только «гуру» «экзотические» операторы и конструкции. Это абсолютно не так.

мнение эксперта Хабрахабр.ру

Подобные речи я слышал много раз. Раньше я озадаченно кивал головой и соглашался, но затем, набираясь опыта, постепенно, я пришел к противополож­ному выводу — все эти заявления — самообман. Да, не считая того, что код из примера действительно корявый, в целом посыл цитаты ошибочный — «читаемый» код не нужен.

Ну как, не нужен — есть прописные истины: DRY, KISS, маленькие методы, тонкие контроллеры, паттерны проектирования, линтинг, тесты, не ударяться в «однострочники», цикломатическая сложность и далее по списку. Все это, действительно, важно, потому что это делает код понятным и единообразным. Эти принципы, в силу разных причин (дедлайн, оплата за строки кода, пристрастие к героину и тд.), не вседа получается соблюдать, это нормально. Но, все равно, к этому нужно всеми силами стремиться.

Все остальное, что обычно пытаются навязать под «читаемым» кодом — это чей-то личный опыт и привычки, которые совсем не обязательно будут работать на вас, и которым совершенно точно не нужно слепо следовать.

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

Стайлгайды

Единообразие — это сверхзадача читаемого кода. Это идея, это «ради чего». Именно единообразие определяет подходящие лексемы и конструкции языка: если команда использует тернарные операторы — пишешь их, если в коде есть лексемы ~arr.indexOf(item) — используешь их. Если никто не говорит на крутом джедайском кокни, то тебе тоже не стоит хвастаться. Для оттачивания своего стиля есть GitHub, Open Source и разные диванные проекты по захвату мира — там можно придерживаться своих правил, и лучше бы делать это, опять же, единообразно. Главное, не забывать, что эксперименты это здорово, и проводить их нужно в правильном месте.

Вернемся же к этим великолепным тернаркам (вы ведь уже поняли по аватарке, что на джедайском наречии я немного понимаю?). В JavaScript есть некоторые «неудобные конструкции» — hoisting, автоподстановка точки с запятой, у которой найдется пара стрел для всех двух ваших колен, а предназначение конструкций ;(function () {…})(); или !function () {}(); я разгадывал несколько месяцев. Но все это не значит, что этими штуками грешновато пользоваться. Отнюдь! Только присмотритесь, сколько команд не используют точку с запятой, сколько действительно великолепных JavaScript-разработчиков пишут тернарные операторы вместо if/else там, где это уместно. TJ Holowaychuk, Isaac Schlueter — у каждого состоявшегося разработчика есть предпочтения, и это не просто нормально. Это отлично! А best-practices к написанию плагинов для jQuery? Пишут же ;(function () {…})();, и ничего.

«Читаемый» код

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

Если вы не знакомы с побитовым оператором ~ — разберитесь с ним. Если вы знакомы, то в чем проблема запомнить лексему ~arr.indexOf()? Вы же не думаете, что больше никто не будет ее писать, потому что она вам не нравится?

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

Возвращаясь к примеру

return (~ memo.indexOf(item) ? null : memo.push(item)), memo; даже мне кажется довольно странной конструкцией. Я бы предпочел такой вариант:

return ~memo.indexOf(item)
  ? memo
  : memo.concat([item]);

Смущают меня две вещи: null в одном из полей тернарного оператора — верный признак задуматься, действительно ли он должен быть тернарным; запятую же после тернарки я нахожу немного двусмысленной — в однострочнике немного неочевидно относится ли она к третьему операнду тернарки, или она выполнится после всей конструкции, да и причина ее возникновения — push, который возвращет длинну нового массива вместо самого массива.

Итог

В любом случае, указывать другим как писать код — это весело, но нужно иметь свою голову на плечах и понимать причины тех или иных гайдов. А «читаемость» кода, призывающая вас использовать пробелы между всеми словами, только if/else, отбивать каждую строку кода двумя переводами строки и тд. — это не более чем комформизм и вопрос привычки.

«Как рушатся комплексные системы», Ричард И. Кук
О фундаментальных проблемах больших запутанных систем
7 паттернов для рефакторинга JavaScript-приложений
Перевод отличной серии статей о проектировании и рефакторинге проектов
Музыка для работы
Мои плейлисты: теплый glitch, нежные девичьи голоса, интересная электроника и chillwave
Ссылколог
Коллекционирую полезные ссылки