Каждый раз когда заходит обсуждение качества кода, например на код-ревью, то сталкиваешься с тем, что для всех это очень относительное понятие. Сколько людей столько и мнений. Даже если взять какие-то объективные метрики, то объединение этих метрик под вывеской "качественный код" всё равно объективным не будет, всё зависит от точки отсчёта. Проекты бывают разные, на разных этапах своего развития, у них свои приоритеты и как обычно ответ на все вопросы "it depends".
Но мне стало любопытно абстрагироваться и формализовать у себя в голове что же такое качественный код. Как отличить качественный от некачественного?
Абсолют
На мой взгляд эталон качества кода - это его отсутствие. Если кода нет, то и волноваться за него не нужно, он не устаревает, поддерживать его не нужно, человеческие, экономические и технические ресурсы на него не тратятся - красота. И я тут не имею ввиду модные zero-code решения, если очень грубо упростить, то под кодом я имею ввиду буквально любые продукты жизнедеятельности людей - код, документация, натыканные в визуальном интерфейсе галочки, всё что угодно что должно делать какую-либо работу. Вот мы и подходим к тому, что основная проблема отсутствия кода - он не делает никакую работу. А иногда нужно.
Простота
Когда нужно мы его пишем. И главный критерий качества на мой взгляд - это простота, что впрочем красиво переплетается с предыдущей мыслью: отсутствие кода - это простота возведённая в абсолют. Что такое простой код? А вот это вопрос уже посложнее. Отличный показатель простоты - это то, насколько легко его понимают не очень опытные или только только погрузившиеся в проект разработчики. То, насколько много человеку приходится задать себе вопросов перед тем, как понять его и тем более изменить. Чем меньше вопросов - тем лучше. Вопреки очевидной логике, сеньор - не тот кто пишет сложный код, сеньор - тот кто пишет самый простой код в текущей ситуации. То есть простой для простых, сложный для сложных.
Время
Так уж получалось, что на всех проектах, где я работал, качество кода во много раз улучшалось просто добавлением статического анализа с настройками по-умолчанию. Ведь до этого момента качество кода не проверялось никак. Из-за этого у меня есть некоторая предвзятость немного в сторону кода, а не в сторону бизнеса, хотя предельно ясно, что здесь должен быть какой-то trade-off. Бизнес в моменте очень слабо волнует как у вас в коде расставлены пробелы, ему важно чтобы он был написан "вчера". Это естественно тоже нельзя забывать. Хороший код - это тот, который написан настолько быстро, насколько это возможно для продолжения функционирования бизнеса. Вспомните хоть один взлетевший стартап, который не был ужасен в первое время. Это всё от того, что качество до какой-то степени жизненной важности там игнорируется, а когда дела идут в гору и появляются ресурсы, то можно уже и выделить на это ресурсы. Через боль и страдания работников, конечно, но никакие Instagram и Twitter бы просто не появились если бы они целились сразу на многомиллионную аудиторию не срезая никакие углы. Надо понимать какие задачи решает бизнес прямо сейчас и какие у него планы. Ведь какой смысл заморачиваться и делать невероятно расширяемую архитектуру, тратить на это кучу времени, если проект вообще никому не будет нужен уже через месяц? Этот пункт тоже неплохо переплетается с первой мыслью: отсутствие кода - это код, написанный максимально быстро, быстрее просто невозможно.
Где грань?
Грани между качественным и некачественным кодом по правде нет, это градиент. Грани можно задать только на уровне конкретного человека, и у всех они будут разными. Всё зависит от предыдущего опыта и кругозора. Для меня основная направляющая метрика - если я понимаю, что на постоянной основе делаю задачи гораздо медленнее чем мог бы (чем на другом проекте, например), задаю себе слишком много вопросов или существующий код вынуждает генерировать ещё больше техдолга. И это конечно не значит что такой код сразу ПЛОХОЙ в абсолюте. Это значит что мне с ним в силу моего опыта работать некомфортно, я буду прилагать все усилия к тому, чтобы его улучшить до уровня нормальности в моей голове. Если движения к этому не будет месяцами и годами, то это прямой путь к потере мотивации и выгоранию. При этом, хочу заметить, у человека с меньшим опытом может быть совершенно позитивное отношение в силу того что он ещё не видел как бывает. Воистину меньше знаешь - крепче спишь. С другой стороны часто время и силы на написание "плохого" и "хорошего" кода отличается не так сильно, первый пишут из-за того что не знают как написать второй. Это как раз то, чем опыт и побеждает.
Какой техдолг приемлем, а какой нет? Если какая-то легаси фича лежит где-то в уголке проекта и почти не обращает на себя внимания, то это ок. Если каждый разработчик на проекте каждый день теряет на этом время - это серьёзный повод задуматься. Особенно если разработчиков много. И это конечно тоже градиент.
Долгосрок
В предыдущих абзацах я упоминал что волнует бизнес в моменте, но также бизнес должен понимать и долгосрочные последствия закрытых на техдолг глаз. Люди могут расстраиваться, ссориться, увольняться, как это часто бывает унося с собой жизненно важную экспертизу, т.к. раньше не позаботились о том, чтобы диверсифицировать её по разным людям или документации, всё это может развалиться по эффекту домино, где увольнение одного сотрудника влечёт за собой цепочку других. Да и просто потеря человека на текущем рынке кандидата чревата огромными финансовыми потерями, ведь если вы не Google, то очереди из топовых кандидатов у вас за дверью скорее всего нет.
Практика
Количество предупреждений статического анализа, количество возвратов и новых созданных багов тестировщиками, количество крашей у пользователей - всё это в какой-то степени показатели качества кода. Да даже психологическое состояние каждого человека на проекте от него непосредственно зависит. Обычно чем больше проект и чем больше работников на нём, то тем больше рамок и бюрократии. Это не случайно, рамки помогают всем участникам придерживаться какой-то общей парадигмы. Код-ревью - сейчас вещь базовая, если у вас работает хотя бы два человека, то время пришло. Я считаю что нужно смотреть только на потенциальные баги, возможность замены нового велосипеда на какой-то существующий компонент, читаемость кода с точки зрения нейминга и невынужденной комплексности. Статический анализ - ещё одна из таких рамок, начните с дефолтной конфигурации, запретите писать новые предупреждения. Так вы освободите разработчиков от споров на кодревью и в личках. Любые споры должны оканчиваться документацией или автоматизацией кастомными линтовыми правилами или тестами, чтобы такой ситуации больше не возникало. Сделайте CI пайплайн, который будет прогонять всю автоматизацию, например на pull-реквесты, merge или по расписанию. Да и в целом - начните считать метрики, любые цифры от которых вы считаете зависит качество проекта. Всё в голове удержать почти невозможно, да и ощущения могут быть обманчивы. С точки зрения архитектуры главный принцип в том, что явное всегда лучше неявного, пиши код так, чтобы можно было выкинуть небольшой кусок и заменить на другой, не переусложняй без причины. В плохом проекте говнокод размазан ровным слоем по всему проекту, в хорошем - сконцентрирован по небольшим обособленным кучкам.
Выводы
- Объективной метрики нет, для всех критерии качества разные
- Каждый проект и команда разные, всегда нужно отталкиваться от конкретной ситуации
- Иногда нужно быстро
- Иногда нужно просто
- Понимание того как вообще бывает - это главное в опыте
- Нужно придерживаться идеальной картины мира, но корректировать под окружение
- Иногда быстрее написать качественно, чем нет
- Ловите себя на своих ощущениях и раскручивайте их в пользу улучшения проекта
- Если вам кажется что вы делаете одно и то же - автоматизируйте
- Если вам кажется что что-то сложно - упрощайте, это не только вам сложно