Идеей о том, что нужно писать человекочитаемый код, уже никому Америку не откроешь. О том, как это стратегически важно для бизнеса и почему так полезно для разработчиков, написано много. Все, плюс-минус, это понимают, но контексты бывают разные, и каждый по-своему переносит это в свой опыт.
Код Хабра день за днём впитывает в себя время, мысли и чаяния многих людей. А этому коду, на минуточку, уже более 10 лет. За это время он оброс множеством знаний, в том числе и тайных, добавилось множество функций – в том числе и полезных, а места c bus factor = 1 – уже не “эка невидаль”, но вполне конкретные люди с ответами на часто задаваемые вопросы.
В такой ситуации сложно мечтать о чем-то большом и светлом. Можно, конечно… но очень больно. Но мечтать то хочется, и чтоб работа приносила удовольствие тоже хочется, и развития для проекта и себя – тоже хочется.
Меня зовут Антон Каракулов, я тимлид команды бэкенд-разработки Хабра. Хабр стартовал в 2006 году, и за всё время здесь поработало, наверное, команд пять. Мне посчастливилось быть в двух из них, забегал в третью.
Все события утрированы, а совпадения — беспочвенны.
Четыре года назад я вернулся на Хабр и стал собирать новую бэкенд-команду. Главная проблема, с которой я столкнулся, — когнитивная нагрузка при работе с кодом. Этот код не всегда был логичным, простым и вообще актуальным — и это для человека, который был с ним знаком. Застарелые наслоения логики приходилось раскручивать, как неберущиеся вопросы из «Что? Где? Когда?». Казалось, для новых людей это будет ещё той охотой на ведьм.
А хотелось видеть код, который даёт в процессе его чтения простую и ясную картинку происходящего. Тот, что можно читать как увлекательную книгу, где не просто текст из слов и предложений, а есть сюжет — и ты за ним с интересом следишь.
Оставалось понять, как подружить хабракод с понятием «чистый, поддерживаемый и масштабируемый» и сформулировать в виде термина «человекочитаемый».
Теперь, по прошествии времени, вот какие выводы можно сделать.
Соблюдай статус-кво
Пиши, как уже было спроектировано, доверяй накопленному опыту. На пути к желаемому качеству важно уметь придерживаться прежних договоренностей и паттернов написания кода, какими бы ужасными они ни казались.
Основная цель — это поддержка общего представления о том, как тут всё работает, и умение этим пользоваться для уверенного движения вперёд. Это та база, к которой всегда можно вернуться, перевести дух, выбрать направление и, оттолкнувшись, продолжить движение. В долгосрочной перспективе однородность проекта важнее набора уникальных решений.
Особенно остро это ощущается, когда в проекте сменяются команды/люди и в коде начинают проявляться разные подходы, знания о которых утрачены или не полны. В этом плане Хабру повезло: на начальном этапе проведена хорошая работа и за всю свою богатую историю принципиально мало что менялось.
Но соблюдение статус-кво — это не только про понимание, но и про принятие. У нас был случай, когда новый коллега вроде всё прекрасно понимал, но в стандартных реализациях прослеживалась инородная логика, от которой каждый раз приходилось избавляться. Это не значит, что этот код был плохим. Но в нашем случае умение двигаться в общем направлении оказалось важнее частных решений.
Следуй гайдлайнам. Стандартизируй
Стандартизация и формализм — наше всё. Это палочка-выручалочка, которая приходит на помощь, когда при чтении кода устал размениваться по мелочам и пытаешься сразу погрузиться в суть.
Для меня настоящая работа состоит не столько в написании кода, сколько в своевременном принятии решений. Чем быстрее вникнешь в задачу, тем быстрее найдешь решение, которое даже может оказаться правильным.
Стандартизация позволяет убирать из поля внимания часть заурядных решений и сосредоточиться на том, что важно и интересно — развитии проекта.
Например, в нашем проекте быстро стало ясно: как именно мы пишем код, как оформляем, на какие компромиссы готовы идти и где. Это вдохновляло, но, несмотря на эту ясность, время от времени возникали вопросы.
Бывало, что на ревью половина комментариев были примечаниями о несоблюдении той или иной нормы оформления. Самое обидное, что это было следствием автоматизма автора или смещением его фокуса на более важные аспекты задачи — неконцептуальным расхождением или несогласием.
Когда эта ясность была формализована, вначале в виде документа в базе знаний, а затем как часть непрерывной интеграции, уровень шума такого рода уменьшился до приемлемого. И как-то сразу стало легче.
Думай командно
Был период, месяца два-три, когда мне пришлось стать единоличным владельцем кода. Я мог делать с ним всё, что захочу, и даже чуть больше. Признаюсь, это был один из самых сложных моментов.
До какого-то момента всё шло хорошо. Но потом я начал экспериментировать с кодом, который или предъявлял слишком большие требования по сложности, или явно попахивал чем-то. Что-то мне нравилось — я это оставлял, что-то не очень — переписывал или откатывал. Даже начал составлять техническую документацию, представляя (порой тщеславно), сколько времени это сэкономит новым членам команды. Дошло до того, что один из компонентов даже захотелось заопенсорсить.
Скоро новая команда начала потихоньку собираться, и мне показалось, что всё это время я просидел в «башне из слоновой кости». С новым кодом никто, кроме меня, не работал. Ревью он не проходил. Документацию люди видели впервые. Но всё обошлось — всем всё было понятно. Это была победа.
Всё же код — это командное повествование. Эстафета, где важно уметь не только интересно поддержать уже начатую историю, но и ярко продолжить давно забытую. Вот несколько усвоенных правил.
Понятность важнее правильности. Когда ты что-то не понимаешь, становится уже неважно, правильно это сделано или нет.
Поведение важнее состояния. Или: ясные интерфейсы важнее понятной реализации. Если представляешь, как с этим работать, то вопрос «почему?» не возникнет.
Чем сложнее, тем декларативнее. Когда начинается путаница, порой важнее зафиксировать, ЧТО нужно сделать, а КАК — оставить на потом.Упрощай. Думай о сложности — старайся её уменьшить. Уровни абстракций — на последнем месте.
Блюди контекст. Пока ты в рамках контекста — ты в безопасности, всё остальное неважно.
Пиши тесты
Тесты всегда расскажут и покажут, где ты был не прав. Позволят увидеть код со стороны. Заметят его слабые стороны. Они — как близкие друзья, которых сложно завести и невозможно потерять. И это, чёрт возьми, не поэзия, — сам в шоке.
Каждый разговор о тестах у нас на Хабре заканчивался чем-то вроде «Да-да, мы хотим, но…». Сейчас вы продолжите фразу, и, скорее всего, этот аргумент у нас в команде уже был. Справедливости ради, время от времени тесты всё же писались, но это выглядело скорее исключением, чем осознанным процессом.
Однажды случилось так, что только что написанный код вроде выглядел неплохо, но вызывал интуитивное беспокойство: то ли из-за сложности, то ли из-за лишней чашки кофе. Решено было покрыть его тестами, и вдруг выяснилось: тут ошибка, там нарушена неявная логика, здесь кусок легаси всем мешает. Работа закипела.
Каково же было моё удивление, когда после написания этих тестов код преобразился, стал вдруг внятным. В этот момент я по-настоящему почувствовал силу тестов.
До TDD мы так и не дошли, чётко отлаженного процесса не запустили, но скомпилировали понятную нам стратегию по написанию тестов, благодаря которой они стали появляться регулярно.
Рефакторить нужно
Куда же без рефакторинга? Рано или поздно все приходят к этому. В одних случаях — это боль и страдания от старой парадигмы, в других — накопившаяся сложность, в третьих — способ поменять шило на мыло.
Что бы за этим ни стояло, это надежный инструмент поддержки кода в актуальном состоянии и возможность проявить заботу о нём. Кстати, эволюция того самого статус-кво, который нужно соблюдать всеми силами, происходит именно так.
Порой сложно заставить себя сделать сразу всё хорошо: мысль не идёт, решение не на поверхности, поджимают сроки или кто-то в интернете неправ. А если и можно, то получается непростительно долго и с большими ментальными издержками.
Вариант выделения отдельного времени для переработки требует дополнительных согласований, наличия чётко описанного решения и плана реализации. А все эти условия не всегда выполнимы.
Но чтобы всё-таки иметь возможность заниматься этим, мы сформулировали для себя концепцию перманентного рефакторинга. Это как обычный рефакторинг, только постоянный, без отрыва от производства. Вот основные моменты.
Всегда фиксировать слабые места. Если тебе попался код, который нарушает принятые стандарты, кажется лишним, сложным, непонятным или неэффективным — отметь. Обычно для этих целей мы пользуемся набором doc-тегов, реже заводим отдельную задачу в Jira.
Решил — расскажи, понравилось — опиши. Если тебе удалось переписать код для ранее зафиксированной проблемы, который укладывается в принятые стандарты, обязательно расскажи коллегам. Если решение тебе понравилось и ты хочешь начать использовать его в качестве основного — опиши в документации.
Не больше одного «слоя» за раз. Начиная переписывать, старайся затронуть за раз не больше одного слоя приложения. В погоне за качеством главное — не терять голову.
Следи за контекстом. Не надо браться переписать сразу несколько компонентов за один раз. Лучше меньше да лучше.
@deprecated
должен быть удалён. Держи такой код ровно столько, сколько он реально нужен для работы кода. Ни больше, ни меньше. Соблюдай чистоту.
Пиши документацию, читай документацию
У документации есть удивительное свойство: когда она есть — ты её не замечаешь, а когда нет — страдаешь.
В стародавние времена, когда солнце было ярче, зимы холоднее, а мои амбиции не выходили за рамки «здесь и сейчас», мне казалось, что техническая документация по проекту — удел разгильдяев, которым лень запоминать, что и как работает. Ведь когда ты работаешь с одним и тем же кодом долгое время, может сложиться ложное ощущение всё-и-так-понятности.
На Хабре период всё-и-так-понятности возникал в жизни каждой команды. Дополнительные знания о том, как работают разные части системы, долгое время передавались преимущественно из уст в уста или в лучшем случае на берестяных грамотах разношёрстных ad-hoc-документов, которые быстро теряли актуальность.
Это было чудное время, полное манящих тайн и бесконечного пересказывания одного и того же, но это работало. В определённый момент я рьяно подключился к этому процессу. Но постепенно во мне созрела крамольная RTFM-мысль. Стало ясно, что это отнимает слишком много времени и сильно отвлекает.
Вначале я делал заметки для себя и собирал их в одном месте, чтобы быстрее находить нужные ответы. Затем начал давать ссылки на них коллегам. Понял, что они и сами не против этим заниматься. Мы собрали все заметки в одном месте, назвали это документацией и определили для себя несколько ключевых моментов.
RTFM. Да-да, банально. Если найти так и не получается, то спроси в команде. В тебя или кинут ссылкой, или всем будет ясно, чего не хватает.
Фиксируй личный опыт. В случаях, когда ты с чем-то долго разбирался и наконец понял, как с этим работать, — сделай рабочую заметку. Потенциально это будущий документ.
Абстракция — это интуиция. Для реализаций на базе абстракций иногда нужен толчок в виде описания концепции, чтобы это выстроилось в сочную картинку. Заодно это тест на её жизнеспособность.
Усложняя — документируй. Нетривиальное поведение и логику в коде нужно описывать в первую очередь. Всегда. Для гарантии корректного использования кода и возможности быстрее восстанавливать контекст — это неотложная помощь.
Актуальность. Это краеугольный камень любой документации, её ахиллесова пята. Важно помнить и найти свой путь, который порой не очень-то и тернист.
Анонсируй любые изменения. Обязательно. Важная часть работы с документацией — её внутреннее продвижение. Это решает сразу несколько задач: сбор обратной связи на тему понятности, обмен знаниями, актуализация предметной области.
RTFM. Ах да, об этом уже было.
Документация помогает формировать статус-кво, освобождает личное время для насущных дел, делает кодовую базу прозрачнее и приносит радость и уют.
Общайся
Общение — это здоровье команды, а здоровье команды — это неотъемлемый атрибут здорового кода. Знать свой код — хорошо. Думать о нём — прекрасно. Обсуждать его — настоящая роскошь, и это того стоит. В такие моменты ты начинаешь чётко представлять, с кем ты здесь, зачем и для чего.
Вам знакомо понятие «дух стартапа»? Это когда все со всеми общаются, голову пучит идеями, возникает ощущение будущего «тут и сейчас», все на одной волне и понимают друг друга с полуслова — и тебя переполняет энергия и задор. Именно такое было у меня впечатление, когда я оказался в Хабре впервые. Мне такое нравится.
Сегодня Хабр взрослее, солиднее. Повысилась сложность задач и процессов. Признаюсь, приятно видеть рост компании, в которой работаешь. Эти изменения отразились и в коде. Он стал интереснее, но сложнее и требовательнее. С усложнением пришла формализация.
И вдруг стало казаться, что код не такой уж и интересный, скорее сложный. А идеи — какие-то несбыточные. Энергия и задор стали проявляться всё реже. Команда поплыла по течению, и код вслед за ней. А всё потому, что формализация неожиданно отодвинула общение о коде на второй план.
В такие моменты важно не опускать руки и постараться воссоздать внутри команды пресловутый дух стартапа. Путь к этому лежит через общение, а форматов уже немало.
Вместо заключения
В сухом остатке это набор несложных практик и идей, которые при регулярном использовании позволяют приблизиться к тому самому человекочитаемому коду — чистому, масштабируемому, понятному всем.
Коду, работая с которым, можно получать такое же удовольствие, как от любимой книги, музыки или фильма.
Работа с таким кодом воспринимается не как каторга, а как творчество. Вместо бесконечной борьбы со сложностью, можно позволить себе не только мечтать, но и воплощать.
Ведь мечтать-то хочется, и чтоб работа приносила удовольствие — тоже хочется, и развития для проекта и себя — тоже хочется.
Комментарии (22)
speshuric
00.00.0000 00:00+2Статья хорошая, но что за "кодоэйджизм" в заголовке? 10 лет для года не возраст - даже в "новых" ЯП типа Rust/Go/Kotlin есть уже код такого возраста (и не факт, что плохой). А в крупных компаниях и проектах и код постарше вполне себе трудится. Что-то из этого, конечно, надо переписать/причесать/документировать, что-то на вид от вчера написанного и не отличить. Причина плохого кода совсем не в возрасте, что и ваша статья подтверждает.
Parondzhanov
00.00.0000 00:00Человекочитаемость и понятность кода — важная мысль. Пытаясь решить эту задачу, я разработал язык ДРАКОН. К языку были предъявлены нетрадиционные требования:
предложить средства для описания не только алгоритмов, но и структуры человеческой деятельности в любой отрасли знаний (включая бизнес-процессы);
предоставить пользователю языковые средства, которые заставляют человека мыслить продуктивно;
облегчить межотраслевое и междисциплинарное общение между представителями разных организаций;
устранить или уменьшить барьеры взаимного непонимания между работниками различных специальностей и профессий;
за счёт использования когнитивно-эргономического подхода к проектированию синтаксиса и семантики добиться улучшения качества программного обеспечения по критерию «понятность алгоритмов».
На Хабре см. посты:
Как улучшить блок-схемы алгоритмов по ГОСТ 19.701-90? Эргономичный визуальный алгоритмический язык ДРАКОН. Критерии.
Умеет ли человечество писать алгоритмы? Безошибочные алгоритмы и язык ДРАКОН.
Медицинский алгоритмический язык ДРАКОН против пандемии и не только. Статья для профессиональных врачей.
Лабиринты из линий: превращаем сложный сценарий в понятную схему на языке ДРАКОН.
Визуальный язык ДРАКОН: математические истоки алгоритмической макроконструкции «силуэт» и метод Ашкрофта-Манны.
Клинические алгоритмы при пандемии COVID-19 на медицинском языке ДРАКОН. Часть 1.
anonymous
00.00.0000 00:00НЛО прилетело и опубликовало эту надпись здесь
vvzvlad
00.00.0000 00:00+1Потому что он делится ими в любых местах и уже всех задолбал.
anonymous
00.00.0000 00:00НЛО прилетело и опубликовало эту надпись здесь
vvzvlad
00.00.0000 00:00+3Вместе с тем, разделяю чувства Parondzhanov, т.к. это невероятно сложно чисто психологически держать в себе накопленные знания и опыт в том виде, в котором он здесь продвигает свое детище в массы.
Мне вчера на корпоративе было психологически сложно держать в себе отзыв на моего начальника. К чему это я? К тому, что когда меня спрашивают сегодня «почему ты начальника вчера матом обругал», ответ «ну мне было психологически сложно» никак не оправдывает меня и ситуацию не исправляет.
Но и в целом, никто не судит: человек принес ссылку, человек получил минус. Повторять до исчерпания терпения/кармы. Процесс самостоятельно регулируется. Я лишь ответил на вопрос «Почему минусы?»
VladimirFarshatov
00.00.0000 00:00Поддержу. ДРАКОН как раз позволяет визуализировать ТЗ и часто определить "Царскую дорогу", одновременно снижая цикломатическую сложность решения разработчика.
brutto Автор
00.00.0000 00:00+1Спасибо за замечание. Про "эйджизм" согласен — убрал из заголовка путающее уточнение. Дополнительно во вступлении уточнил что именно имелось ввиду под этими более чем 10 годами жизни кода.
blackibe
00.00.0000 00:00+5Я вот не пойму только одного, с каких пор сайт по типу "БЛОГ" стал технически сложным? Что тут сложного? Весь хабр можно сделать за неделю. У вас пафоса будто шаттл космический запускаете в космос...
GinoPane
00.00.0000 00:00Видимо, это верхушка айсберга, и так «для души», а на самом деле там рокет саенс. На самом деле было бы интересно реальные кейсы сложности увидеть
brutto Автор
00.00.0000 00:00А вы верно подметили по поводу космического корабля. Правда для меня, космический корабль Хабра уже создан и запущен. Своей задачей вижу тут наладку процесса безболезненного обслуживания и модернизации этого корабля еще в течение хотя бы лет 20-30. =)
ChVI-dev
00.00.0000 00:00+1зачем этот очередной холивар ? достали любители каллиграфии, особенно в менежменте. Красивый код лучше работать не станет, если у писателя кода понятия нет ,с какими аппаратными ресурсами он имеет дело. Или опять абстракция вывезет?
AlekseiVB
00.00.0000 00:00Замечательная статья и очень интересная тема. Постоянно встречающаяся при разработке, да и наверняка и другом кодинге, особенно если коллектив давненько сработавшийся. Люди доверяют друг другу и не анализируют код, и даже если случаются баги, исправляет код тот кто его писал привычным ему способом.
avshkol
Статью бы украсили примеры кода "было-стало"... ;)
brutto Автор
Действительно вначале была идея с иллюстрацией кодом. Даже, вроде, получилось раскопать пару примеров, которые не требовали бы копания в git-истории. Но после вставки этих примеров в текст они выглядели скорее какой-то вкусовщиной, нежели иллюстрацией моих слов. А что бы они приобрели действительно иллюстрирующую функцию пришлось бы выгружать много контекста, что уже сильно размывало бы смысл самой статьи (IMO).
По поводу "было/стало" могу сказать что удалось уменьшить сложность (cyclomatic complexity) с ~18 (для старого) до ~3.5 (для нового). А добились этого при помощи следующих шагов:
Didimus
Ожидание-реальность