Рецензирование кода иногда может быть сложной задачей как для человека, ищущего рецензию, так и для рецензента. Но этого не должно быть!

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

Недавно я нашел время, чтобы просмотреть заметки, которые я сделал для себя в ходе нескольких обзоров кода, в которых я участвовал, и с помощью отличных руководств по качеству кода, с которыми я столкнулся.

Правило №1: время рецензента - золото.

Будьте вашим собственным обозревателем кода и выявляйте ошибки на раннем этапе, чтобы ваш рецензент мог сосредоточиться на предоставлении вам качественной обратной связи и не терять голову из-за ошибок отступов.

Вот некоторые из вещей, которые мы можем проверить, прежде чем запрашивать проверку кода:

Ясность

  • Код должен быть легко читаемым для новичков. Вы должны сразу понимать, что делает каждая линия и функция.
  • Принцип единой ответственности требует: «У класса должна быть одна и только одна причина для изменений». Каждая функция должна иметь одно краткое намерение (независимо от того, является ли эта цель обработкой запроса API или просто функцией использования даты и времени, зависит от того, на каком уровне абстракции вы находитесь).
  • Предпочитайте удобочитаемость небольшим оптимизациям. Не поддавайтесь искушению сжать абзац кода в одну строку, чтобы он выглядел круто. Делать жизнь других (и себя в будущем) проще - круче :)
  • Закомментирован код? Очень мало случаев, когда это уместно.
  • Отдельные функциональные и нефункциональные изменения. Если ваше изменение связано с изменением двухстрочного кода, но вы отформатировали файл кода, чтобы изменить табуляции / пробелы, и выдвинули его как часть той же проверки кода, вашему рецензенту будет сложно определить фактические изменения.

Функциональность

  • Есть ли в коде логические ошибки?
  • Обрабатывает ли код крайние случаи?
  • Полностью ли это изменение отвечает всем требованиям, предъявляемым к функции / проблеме? Есть ли двусмысленность в интерпретации требований?
  • Является ли код, который вы добавили, безопасным для потоков? Документированы ли потокобезопасность и параллелизм на уровне класса или API?

Тесты

  • Существуют ли модульные тесты, которые адекватно тестируют код, и выполнялись ли они?
  • Есть ли инструмент покрытия кода, который автоматически запускается со сборками? (например, JaCoCo)

Абстракция

  • Не сообщайте о реализации клиентам. Хотя имя функции должно отражать ее полезность, оно не должно раскрывать детали реализации, которые вызывающий не использует. Что еще более важно, клиентская документация по API не должна раскрывать детали реализации. Представьте, если бы документация по API Карт Google сообщила вам, откуда они, из какой базы данных они берут свои данные.
  • Абстрагируются ли операции доступа к базе данных (DAO) в собственные классы?
  • Когда мы разрабатываем приложение, мы начинаем с дизайна высокого уровня, а затем продвигаемся вниз до реализации низкого уровня. Точно так же и наш код должен это отразить. Каждая функция должна соединять один уровень абстракции, вызывая функции более низкого уровня.

Стиль

  • Код должен соответствовать руководству по стилю для этого языка. Например, camelCase - это соглашение об именах в Java, а Python предлагает snake_case.
  • При этом код должен соответствовать стилю (отступы, интервалы, соглашения об именах и т. Д.), Уже используемому в модуле. В некоторых случаях руководство по стилю дает рекомендации, а не декларирует требования. В этих случаях необходимо принять решение, должен ли новый код соответствовать рекомендациям или окружающему коду.

Документация

  • Ясна ли цель каждой функции или помогут минимальные комментарии, описывающие ожидания?
  • Документированы ли общедоступные методы и классы с помощью Javadoc (Java) или Doxygen (C / C ++)?
  • Документирование намерений - самая важная форма документации. Самый большой вопрос, который возникает у других инженеров при просмотре кода (или даже своего собственного): «Почему этот код здесь?» Или «Почему они (я) сделали это таким образом?» Или «Какая конкретная проблема вызывает этот код решить? ».
  • Напишите четкое описание изменения - если вы используете инструмент для генерации обзоров кода, отправляете свой код в отдельную ветку или просто отправляете им изменения кода в zip-архиве (yikes!), Вы должны кратко описать свои изменения. Вы можете думать об этом как о диаграмме дизайна высокого уровня, но используя слова.
  • Если ваше изменение заключается в добавлении новой функции или значительном обновлении существующей, подумайте о том, чтобы иметь специальный проектный документ, чтобы помочь людям легко подключиться к нему. Диаграммы высокого или низкого уровня - это бонус.

Повторное использование и дублированный код

  • Дублируется ли код внутри пакета? Если даже несколько строк кода дублируются в модуле более одного раза, это признак необходимости рефакторинга.
  • Не изобретайте велосипед. Есть ли код, который можно полностью удалить или заменить существующими библиотеками? Нет кода, как нет кода!
  • По возможности используйте аннотации, чтобы код было легче читать и не было ошибок, при этом устанавливая общий стандарт для всей вашей команды (например, Lombok для Java)

Конфигурация и константы

  • Есть ли магические числа или строковые константы, разбросанные или, что еще хуже, повторяющиеся по всему коду?
  • Есть ли в коде произвольные постоянные значения , которые следует настраивать?
  • По возможности определяйте переменные с такими модификаторами, как final (Java) или const (JS) . Хотя такие ключевые слова, как final, обеспечивают незначительную оптимизацию производительности, важным аспектом, связанным с человеческим фактором, является семантика ключевого слова. Это означает, что переменная останется постоянной во всем объеме и, таким образом, улучшит удобочитаемость и ремонтопригодность.

Зависимости

  • Держитесь подальше от звездного импорта. Импортируйте только те зависимости библиотеки, которые вам нужны.
  • Вводятся ли новые внешние зависимости, которые могут привести к новому риску безопасности или операционному риску?
  • Можно ли вместо этого использовать альтернативные облегченные зависимости?
  • Вы каждый раз создаете зависимости вместо того, чтобы вводить или повторно использовать их? Принцип инверсии зависимостей гласит, что зависимости должны быть слабо связаны. Он требует, чтобы модуль кода (класс, метод, модуль) объявлял зависимости, а не создавал их.

Обработка исключений

  • Является ли код устойчивым к мусору и нулевым входным данным (даже из вызываемой библиотеки)?
  • Есть ли четкая и последовательная стратегия обработки исключений?
  • Вы регистрируете ошибки, с которыми вы сталкиваетесь в функции в блоке catch, а затем бросаете их, чтобы вызывающая функция снова уловила? Брось и брось - известный антипаттерн. Вы можете сослаться на этот отличный ответ о переполнении стека.

Представление

  • Есть ли признаки чрезмерной инженерии или преждевременной оптимизации?
  • Есть ли очевидные проблемы с производительностью или эффективностью, которые легко решить?

Приборы

  • Есть ли у нас показатели для анализа воздействия наших изменений? Цифры говорят гораздо больше, чем «Мы заметили большое улучшение».
  • Существует ли соответствующее количество журналов для всех уровней от ошибки до отладки?
  • Содержит ли каждое сообщение журнала достаточно релевантной информации, чтобы кто-то мог понять поведение системы, просто прочитав сообщение журнала? Используйте ведение журнала с соответствующими идентификаторами.

Общий

  1. Разбейте большие обзоры кода на более мелкие. Хорошее правило - не включать в анализ кода более 150 новых строк кода. Чем крупнее изменение, скорее всего, вашему рецензенту потребуется гораздо больше внимания уделять контексту при его проверке, и небольшие ошибки могут остаться незамеченными.
  2. Попробуйте написать код, используя последние разработки на этом языке, который может улучшить читаемость или масштабируемость. Например, в Java предпочитают потоки циклам. В JS используйте синтаксис ES6.
  3. Относитесь к критике конструктивно. Проверка кода не является личной атакой, даже если тон рецензента может показаться обвинительным. Посмотрите на это объективно, как будто вы коллективно пытаетесь улучшить код.
  4. Автоматизируйте скучные вещи. Хуки Git - это круто, чтобы автоматизировать самые разные вещи.
  5. Будьте терпеливы, если ваш рецензент ошибается. Не поддавайтесь искушению огрызнуться и вместо этого задайтесь вопросом, не хватает ли ясности в вашем коде, что привело их к путанице.

К счастью, есть много других хороших методов кодирования, которым мы можем следовать, чтобы улучшить наш код и наши проверки кода.

Вот одна из моих любимых (и та, которая вдохновила на название статьи).

Надеюсь, ваш рецензент вас обожает! Всего наилучшего.