Читаемый код — самообман
Когда я вижу такой код
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
,
отбивать каждую строку кода двумя переводами строки и тд. — это не более чем
комформизм и вопрос привычки.
Похожие статьи:
-
Сфокусируйтесь!
или «Во всем виноват IE8».
-
О сиськах и о программировании
И о том, как не прослыть диванным экспертом.
-
Музыка для работы #5
Немного мурашек по спине…
-
Белый шум
Баттхёрта нить начинается здесь
-
CommonJS для браузера
Видео моего доклада на MoscowJS
-
Музыка для работы #4
Трогательный chillwave, dream pop & glich
-
Instapaper и Pocket
К чёртовой матери ссылки!
-
Byobu
Текстовый тайловый менеджер для Linux и OS X