Чеклист плохого кода

Как-то часто на глаза стала попадаться вечная тема, соберу мысли в кучку: как определить и как доказать автору, что перед тобою говнокод (далее ГК, дабы не засеять весь текст подцензурным словом). Благо, давно ждал времени черновик.
Очень хочется сказать «никак» и уползти дальше кодить понятное. У меня нет особо удачного положительного опыта с ГК. Что сам убивался кому-либо доказывать (если человек написал ГК, обычно он считает, что написал норм, у него не хватает чего-то, чтобы услышать и понять доказательства обратного), что об меня убивались (по той же причине, что в предыдущих скобках). Т.ч. эссе считаю теоретическим и моделирующим. Вы так же считайте.
Итак, чеклист ГК.

Во-первых, он на 100% не работает. Сразу заворачивать обратно автору. Может быть сколь угодно красивым, изящным, правильным, но если он вообще совсем в принципе не работает, он нафиг не нужен. Это очень очевидный пункт, казалось бы, но я встречал и другое мнение, потому пусть будет.
Этот код может быть заведомо нерабочим, что норм. Например, заработает он лишь в составе чего-то будущего. Или не работает из-за баги в библиотеке, библиотеку исправят через месяц. Разные причины бывают. ГК же подаётся как рабочий, как финал решения задачи.

Во-вторых, в ГК есть ненужный код. Пожалуй, это самое близкое слово. Может собираться, может работать, но… Классический пример (b — boolean): if (b == true) return true; else return false; — обычно, конечно, вот прям настолько детские конструкции не пишут, но, честное слово, я видел этот if в продакшене, и написано оно было человеком, а не генератором. Чаще не умеют применить циклы к обработке списков / массивов (видели десяток if’ов, ищущих символ в строке? а я видел), например. Ясный понятный глупый код, сворачиваемый в правильную конструкцию.
Чудеса социологии и психологии начинаются там, где заканчивается ясность и начинается тьма. Сегодня на Хабре прочёл, что хороший код также и «использование всех возможностей современных языков программирования». Вы уже встрепенулись? Я-то с автором согласен. Только практика работает не так. На практике совмещается богоугодное «хороший код должен быть читаемым» и растущее «Вася Пупкин вместо языка X знает только подмножество X’, уместившееся в голову Пупкина, которому вместо программирования хочется нюхать ромашки на кокосовых полях». Потому Пупкин может лбом упереться в свои десять строк кода, которые ему понятны, а вот однострочная цепочка битовых операций уже свернёт ему шею, ибо непонятно. Пусть его ГК в сто раз избыточнее и в тысячу раз неоптимальнее, не докажешь, пока не научишь битам и байтам.
Есть тонкий-тонкий момент. Иногда ненужный код оказывается нужным потому, что поддерживать его будут люди определённого уровня. Есть фирма A, в ней 5 седых senior’ов, набирают раз в год такого же, ибо прежний на покой внуков качать уходит. Есть фирма B — бадишоп с дичайшей текучкой, берёт высоты полками джуниоров, оригиналов и хипстеров, в слезах убегающих через три месяца. И если по заказу первой фирмы вы можете написать крутой код, который хоть на IOCCC подавай, то по такому же заказу второй фирмы вы напишете код, в котором ещё и каждую строчку снабдите пояснением «это квадратная скобка, она нужна, чтобы закрыть ранее открытую».

В-третьих, в ГК есть элементы «кода Маугли» (я придумал термин для такого класса). Скажем, человек самоучка и учился писать программы в отрыве от нашей цивилизации. Программы работают и формально все требования ТЗ соблюдены. Но он игнорирует гайды. Игнорирует мануалы вроде «Совершенного кода». Про декомпозицию что-то слышал, но и только.
Результатом работы Маугли был первый вариант моего первого проекта. Монолитная портянка на C с диким зоопарком нейминга, с магическими числами, даже без blank lines почти. Как N.N. тогда меня не утопил в чайнике, не знаю. Уверен, хотел. Так вот, прикол в том, что даже подсовывание гайдов и нужных книг может не сработать, т.к. у ГКодера сначала надо выработать понимание и принятие оных. Ну подсунул ты чуваку гайд. Он его пролистал, пожал плечами и смотрит, мол, а чё? да ну, фигня, имена переменных сплошным капсом ведь нагляднее и понятнее (и снова реальный человек)!
Эта беда характерна для разработчиков, пришедших в разработку с совсем не разработческой стороны и потому успешно избежавших теорию всех областей (информатика, программирование, разработка). Правда, я всего два-три раза встречал настолько упоротых, что после ознакомления с культурой упирались. Чёт сломано изначально в голове. Остальные говорил «вона чё, Вадимыч… ок, понял, ща переделаю», т.ч. беда излечима. Но есть и обратная сторона (на которую очень боюсь попасть) — разработчики, которых не успели научить, но они успели попасть на позиции senior / руководитель, с которых толкают свой уникальный взгляд Маугли на то, как должен быть оформлен код, например. Та ещё жесть бывает.

В-четвёртых, ГК будущего. Сейчас работает, через год сломается или здорово усложнит внесение изменений. Одной из хороших (как считаю) привычек разработчика является привычка вставлять возможность масштабирования там, где это хотя бы не дорого. Ну, на всякий случай. Лучший способ познакомиться с тем, кто будет после тебя — писать код ровно и только под текущие требования. Не самый наглядный пример: в схеме данных базы сделать sex булевым полем по логике «is male». Прошли годы. И вот уже народ не хочет вообще пол указывать (тут матерящийся Петров вносит NULL как «не указано»). А тут вдруг ваш сервис развернули в UK, интегрировали с FB, а FB задорно выдал десятки вариантов. Весело же.
Но это же и самый сложный для обсуждения тип ГК. Что скажете? Иванов, у тебя ГК потому, что через год он взорвётся, если… Иванов отвечает «этого если не будет, ничего через год не произойдёт». Вы не можете метнуться в будущее и показать Иванову потную лысину Щеглова, на которого валятся тикеты «почему на тысяче яблок оно упало?», «почему мы не можем добавить новое поле?», «почему вы не можете логировать?», «почему вы не можете отдавать JSON?» и т.д. Потому, что Иванов посчитал, что тысячи яблок не бывает, новые поля юзерам не понадобятся, логирования и так хватает, а JSON никому не нужен. Не докажете. Никак. Это вопрос интеллекта и опыта.
Иногда и в самом деле не происходит никаких «если». Потому выше и есть деталька «хотя бы не дорого». Вполне реальны варианты, в которых на гибкость и масштабирование тратят половину ресурса, а потом ничего не пригождается. Более того, на самом деле такой вид ГК бывает определяем строго post factum. Ну не мог Сидоров предугадать, скажем, форсированное импортозамещение. А когда оно началось и в сервис воткнули продукт Ухмятского комбината операторов ЭВМ, сервис взорвался, ибо на ЭТО его гибкости не хватило. Удобно, конечно, в этот момент сказать, что Сидоров редиска и наГКодил, но… нет. Нормальный код. Это жизнь такая.

В-пятых, happy path ГК. Если рассматривать программирование как процесс переработки входных данных в выходные, задача кода в том, чтобы из N входных наборов обработать M наборов. Чем дальше M от N, тем жить страшнее. И если для каких-нибудь продуктовых решений можно найти оправдания (да и решения эти залегают на уровнях выше кода), мол, давайте в 2005 году мы осилим ноги мамонта, а вот импорт бивней сделаем в 2006 году, если денег хватит, то на уровне кода сплошь вопросы.
Скажем, сделали вы API и вытащили его наружу. Пользуйтесь, дорогие, не обляпайтесь. Что делают дорогие первым делом (и продолжают)? Используют API поперёк документации, пытаются передать в полях мусор, усеивают всё null’ами, забывают закрывать скобки с кавычками. Не со зла, просто так выглядит изучение API. Что делает ГК в ответ? Роняет сервера и процессы. Типичный ГК этой категории пишется с мыслью «всё будет хорошо, меня все любят». Потому падает первым как прибережные деревни в цунами.
Часто такой код не потому, что Селёдкин ушёл из школы в 7-м классе, но по требованиям бизнеса. Вернее, не бизнеса (им рекламации не особо нравятся), но выдвигаемых сроков. Любая работа занимает время. Если продукт нужен ещё вчера, продукт будет написан по кратчайшему и наивероятному пути, углы которого будут срезаться, например, документацией: «Не передавайте null в API, нельзя, фу-фу». Или, скажем, сегодня выпускается продукт, в котором ФИО может состоять только из трёх частей, разделённых пробелом (прости, Авиценна aka Абу Али Хусейн ибн Абдуллах ибн аль-Хасан ибн Али ибн Сина), а вот заааавтра мы выпустим продукт, учитывающий и другие варианты ФИО. Ну или не завтра, если про масштабирование ФИО Водочкин забыл.

В-шестых, академический ГК. Открываешь код свежего джависта. У джависта красный диплом топового вуза, в анамнезе топовые учебники, в глазах огонь. Открываешь с предчувствием, ну и закрываешь. Ибо для того, чтобы пройтись по дереву, джавист делает десять классов, пять фабрик, три уровня абстракции и два итератора. И это лишь для начала. Только заложил фундамент решения задачи, так сказать. Теперь-то фабрики нагенерируют всё нужное. Вообще, если задача формулируется просто и в формулировке выглядит простой для реализации, а в коде много абстракций, должен загореться красный звоночек в голове.
Учебники учат инструментам и принципам. Вам на десяти страницах жуют, запивая водой, один наивный, но очень демонстрирующий пример. Предполагается, что усвоите саму концепцию, которую потом уместно примените. Могут даже широкими мазками описать области применения, но всякий конкретный раз решение за вами. Крайне редко попадается автор, умудряющийся скрестить ежа, коня и трепетную лань. Либо теоретик (даст формулу удара по гвоздю, но не расскажет, что микроскопом лучше не бить), либо практик (даст десять примеров разных гвоздей, но не расскажет, что есть формула, которую всё же иногда можно применить и к микроскопу).
Пожалуй, это самый положительный ГК. Единственное, что требуется, так объяснить (и показать) бойцу разницу между теорией и практикой. Он бы и сам со временем понял, наработав примеров, но пока не успел. В идеале объясняющий знаком с учебником и может тут же объяснить, что на самом деле сказал автор. Тем не менее, даже с лучшими намерениями ГК остаётся ГК.

Таким макаром шесть основных видов ГК:

  1. Неработающий ГК.
  2. Ненужный ГК.
  3. ГК Маугли.
  4. ГК post factum.
  5. Happy path ГК.
  6. Академический ГК.

Так-то их больше, конечно. Пути разработчиков неисповедимы, TMTOWTDI, ага.

Чеклист плохого кода: Один комментарий

  1. Можно выделить ещё неряшливый ГК. Одни и те же вещи делаются в нём по-разному. Например, если в разных местах надо прочитать файл, то для этого могут использоваться разные API (например, fopen/fread и open/read) без видимой необходимости. Или там для количества одних и тех же штук разные типы в разных местах.

    Есть ещё говносаппорт/говнобагфикс. Человек исправляет какой-нибудь баг, но не правит/удаляет старый код, а комментирует его. И потом непонятно, что бы это значило. Исправление не совсем готово, не совсем правильно? Автор в нём не уверен?

Добавить комментарий