Формирование эффективной и целостной культуры ревью кода

Программирование  —  одно из увлекательнейших занятий в моей жизни. 

Процесс написания кода сложен, а получившийся результат иногда становится полной неожиданностью даже для самого автора. Но вот все усилия уже позади: успешно проведен рефакторинг, тесты пройдены, код работает. Вы с радостью и гордостью любуетесь очередным созданным шедевром, пока не начинается ревью кода. 

Проверка чужого кода и отправка собственного на ревью стали неотъемлемой частью моей деятельности разработчика. Но будь вы автор или рецензент, данный процесс всегда дает возможность узнать что-то новое самому, научить другого и совместно найти решение проблемы. Кроме того, ревью зарекомендовало себя как отработанная практика для поддержания и улучшения кода, который определяет внутреннее качество продукта. 

Однако в практической деятельности приходилось сталкиваться со случаями неэффективного и изматывающего ревью, которое не назовешь иначе, чем упущенной возможностью.

К счастью, есть решение, и оно начинается с контекста. 

“Решений, оторванных от контекста, встречается ничтожно мало. Наоборот, большинство правильных решений вытекают именно из него”,  —  Дейв Сноуден. 

Чего ждать от ревью кода?

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

Ожидания от ревью в контексте “автор-рецензент” 

Виды контекстов ревью кода, представленные на изображении выше:

  • education  —  обучение;
  • conceptional integrity  —  концептуальная целостность;
  • problem-solving  —  поиск вариантов решения;
  • maintaining norms  —  соблюдение стандартов;
  • readability  —  удобочитаемость;
  • gatekeeping  —  фильтрация поступающего на проверку кода;
  • defect finding  —  обнаружение недостатков;
  • accident prevention  —  предотвращение непредвиденных случаев.

Различные контексты ревью кода 

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

Поиск вариантов решения 

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

Требование: Глубокое понимание проблемной задачи для выявления скрытых недочетов в решении. Грамотный подход к выбору партнера. 

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

Обнаружение недостатков нацелено на выявление ошибок и минусов в решении, тогда как поиск решения направлен на выбор наиболее подходящего его варианта.

Обнаружение недостатков 

После утверждения подходящего способа решения и написания первых строк кода следует остановиться и проверить его на наличие возможных ошибок и недочетов. Анализ решения позволяет убедиться в целесообразности общей концепции разработки, выборе правильных абстракций и способности основных алгоритмов выполнять требуемые операции. 

Требование: Глубокие знания специфики задачи и понимание ее предметной области для выявления скрытых недочетов, ошибок и других недостатков, снижающих качество продукта. 

Соблюдение стандартов

Соблюдение стандартов означает приверженность правилам, утвержденных организацией. Этот процесс включает форматирование кода, общие идиомы программирования и принципы оформления кода. Однако данные факторы могут и не играть ключевой роли в поддержании здоровой базы кода. 

Фильтрация поступающего на проверку кода 

В отличии от принципа коллективного владения кодом, который размывает ответственность, я твердо придерживаюсь позиции “ваш код  —  ваша ответственность”. Это значит, что в собственности каждой команды находится один или более репозиториев, и каждая часть дерева репозитория принадлежит разработчику, известному как владелец кода. 

Владелец кода должен быть осведомлен о любом коде, поступающем “со стороны” (как правило, не от участников команды). Необходимо обезопасить код от посторонних продуктов, авторы которых могут быть несведущи в предметной области деятельности команды. 

Важное примечание: Данное требование не исчерпывается вопросом удобочитаемости кода. 

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

Предотвращение непредвиденных случаев 

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

Данный контекст похож на обнаружение недостатков. Отличие состоит в том, что он характерен для поздней стадии разработки и охватывает меньшую область применения. В этой ситуации глубокие знания и понимание проблемы отходят на второй план, а чрезвычайную важность приобретает высокий профессионализм специалиста. 

Обучение 

Выполняя ревью кода с новым участником команды следует ознакомить его со сложностями предметной области и объяснить особенности базы кода. 

Акцент делается на обучении и использовании ревью как средства для обмена опытом и знаниями. 

Удобочитаемость 

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

Суть проблемы: У каждого разработчика свое представление о чистоте и читаемости кода. Это значит, что код проверяется и принимается на основе субъективной точки зрения. А такой подход приводит к нарушениям качества, связности и чистоты. 

Эта проблема решается путем создания руководств по стилю для команды и всей организации. Они дают объективное определение чистого и читаемого кода. На основе таких руководств разработчики могут беспристрастно анализировать представленный на рассмотрение код. 

Рекомендации для рецензентов 

Помните  —  у кода есть автор 

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

Из этого следует, что: 

  • комментарии в духе “Я бы сделал по-другому” нецелесообразны; 
  • если автор не соглашается с вашими предложениями, задумайтесь, ведь он может быть прав. Даже если аргументы автора звучат для вас неубедительно, помните, что это все-таки его код. 

Вы распоряжаетесь комментариями 

Комментарии и запросы, которые вы открываете как рецензент, должны закрываться/проверяться только вами. Если чувствуете давление со стороны автора, требующего закрыть комментарии, задумайтесь о причинах такого поведения. Возможно, он считает, что вы тормозите рабочий процесс. 

Следует оперативно отвечать комментариями на пул-реквесты и не удерживать их у себя в “заложниках”. 

Иногда приходится настаивать на каких-то решениях, поскольку это представляется единственным способом добиться исправлений. Придерживаясь следующих правил, вы сможете повысить продуктивность работы: 

  • проявляйте уважение; 
  • сосредоточьтесь на вопросах “почему”, выявляя причинно-следственные связи; 
  • будьте объективными (по возможности ссылайтесь на официально утвержденные источники); 
  • работайте быстро. 

Выполняйте ревью кода как можно быстрее 

Даже самое лучшее ревью окажется под давлением критики, если на его выполнение уйдет один день. Есть большая разница между получением ответов на уточняющие вопросы через 1 час или 1 день после отправки запроса. Своевременные и оперативные ревью кода позволяют компенсировать многие из обычных жалоб на строгость и т.д. 

Ускоряйтесь. 

Рекомендации для авторов изменений 

Мудро выбирайте рецензентов 

Хороший рецензент обладает следующими качествами: 

  • регулярно работает с актуальным кодом; 
  • обладает надлежащими знаниями в предметной области; 
  • является экспертом по фреймворкам и языкам программирования.  

Как правило, лучшие рецензенты  —  это владельцы кода. Зачастую именно они проводят ревью кода максимально подробно и качественно.  

Готовьте код для ревью 

  • Объединяйте комментарии TODO, максимально сокращая количество этих пометок. Оставляйте только действительно сложные случаи. 
  • Задайте контекст, предлагая содержательное описание и ссылку на тикет для объяснения проблемы и намеченного решения. 
  • Не забудьте очистить историю коммитов (git rebase и git squash). 
  • Проверьте, что все тесты пройдены. 

Устраняйте замечания 

Следует избегать одностороннего отношения к запросам на изменения и необходимости устранять замечания.  

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

Добивайтесь одобрения кода 

Автор должен добиться одобрения своего кода для последующего слияния. В этом деле помогут несколько правил.

  • Не действуйте по принципу “отправил и забыл”. Активно ищите рецензентов и отслеживайте степень выполнения ревью. 
  • Исправляйте замечания. Если рецензенты указывают на непонятные моменты в коде, проясните все, что нужно: код, комментарии, документацию и т.д. 
  • Разрешайте конфликты, стараясь достичь согласия с рецензентом. Он с вами заодно. 

Улучшение разработки проекта 

Сфокусируйтесь на конвергентных практиках.  

1) При работе над небольшими функциональностями и стабильными базами кода: 

  • вносите небольшие локализованные изменения в один файл/класс; 
  • создавайте ветки с коротким жизненным циклом (1–3 дня максимум);
  • для проведения 90% ревью достаточно 2-х рецензентов (в большинстве случаев справится и один); 
  • программируйте в паре с квалифицированным рецензентом, чтобы обеспечить проверку кода по ходу работы; 
  • проводите ревью в очной форме. В этом случае автор может подробно разбирать код с рецензентом, а тот может задавать вопросы в режиме онлайн;
  • в процессе ревью обучайтесь, фокусируйтесь на читаемости кода, удобстве его сопровождения, предотвращении непредвиденных случаев. 

2) При работе над большими функциональностями и новыми проектами: 

  • запрашивайте ревью на ранних этапах разработки; 
  • создавайте ветки с более длительным жизненным циклом (до 2 недель); 
  • предоставляйте сопроводительную документацию; 
  • в процессе ревью фокусируйтесь на концептуальной целостности, качественном проектировании, совместном решении проблем, обучении, обнаружении недостатков, фильтрации поступающего на проверку кода;
  • оставляйте при себе архитектора/руководителя разработки на первые итерации. 

Ревью проектного решения 

Разработка большого проекта начинается с анализа проектного решения, которое занимает от 2-х и более недель. 

  • Общая картина. Знакомство с исходным проектом. Код отсутствует или представлен в малых количествах. Акцент на рассмотрении документов. Основное внимание направлено на понимание требований и подготовку вопросов к последующим ревью. Рецензентами и участниками выступают архитекторы ПО и заинтересованные стороны. 
  • Промежуточные этапы разработки. Проведение серии ревью с использованием частично предоставленного кода. Происходит автоматическая кодогенерация ПО. Как правило, на данной стадии разрабатываются и проверяются одна или несколько концепций (англ. POC). Рецензентами (и частично исполнителями) выступают архитекторы ПО/технические руководители. 
  • Предварительное ревью кода. Поиск скрытых недостатков и ошибок в проекте разработки. Рецензенты должны хорошо понимать требования.  
  • Ревью кода. Проходит аналогично рабочему процессу “стабильных/унаследованных систем”. 

Читайте также:

Читайте нас в TelegramVK и Дзен


Перевод статьи Vlad Lyga: Moving Towards an Effective Yet Supportive and Inclusive Code Review Culture

Предыдущая статьяКак использовать WebGL для интерактивной 3D-графики
Следующая статьяКак вызвать из C# генерируемую на Rust библиотеку