Стандарт код-ревью На что обращать внимание Навигация по CL Скорость ревью Как писать комментарии Обработка обратной связи Основная цель код-ревью — убедиться, код со временем улучшается. Этой цели должны служить все инструменты и процессы. Для того, чтобы добиться этого, необходимо сбалансировать ряд компромиссов. Во-первых, разработчики должны решать свои задачи. Если вы не пишете код, он не становится лучше. Если рецензент сильно тормозит внесение каких-либо изменений, у разработчиков не будет стимула улучшать код в будущем. С другой стороны, рецензент должен убедиться, что CL (changelist - список изменений, аналог Pull Request) не ухудшает код. Это бывает сложно, поскольку со временем код и так ухудшается, особенно когда команда работает в условиях дедлайнов и вынуждена выбирать быстрые решения. Рецензент отвечает за рецензируемый код. Он должен быть уверен, что код полностью отвечает разделу «На что обращать внимание при проверке кода». Таким образом, мы получаем следующее правило: Рецензенты должны одобрять CL, если он улучшает код, даже если CL не идеален. Это главный принцип среди всех подобных руководств. Конечно, есть ограничения. Например, если CL добавляет функцию, которая в сервисе не нужна, рецензент может отказать в апруве, даже если это хороший код. Не существует такого понятия, как «идеальный» код — есть только лучший код. Рецензенты не должны требовать от автора полировки каждой строчки CL. Рецензент должен стремиться не к совершенному коду, а к постоянному совершенствованию кода. CL, который в целом улучшает гибкость, удобочитаемость и понятность системы, не надо откладывать на дни или недели, потому что он не «идеален». Не ограничивайте себя в комментировании. Если комментарий не обязателен к исполнению, ставьте перед ним что-то вроде «Nit:» ("придирка"), чтобы автор знал, что его можно игнорировать. Примечание. CL, который ухудшает код, апрувить нельзя ни под каким предлогом. Единственный случай, когда это допустимо - аврал. Код-ревью может существенно прокачать разработчика в плане языка, архитектуры или принципов ПО. Всегда приятно оставлять комментарии, которые помогают разработчику узнать что-то новое. Коллаборации прокачивают также и код. Просто имейте в виду, что если ваш комментарий носит чисто образовательный характер, но не является критическим, добавьте к нему префикс «Nit:» или иным образом укажите, что автор не обязан разрешать его в этом CL. Технические факты и данные преобладают над мнениями и личными предпочтениями. В вопросах стиля руководство по стилю является абсолютным авторитетом. Если в руководстве нет какого-то правила, используемого разработчиком, допускается стиль, используемый разработчиком. Должен быть хоть какой-то стиль. Если предыдущего стиля нет, примите авторский. Архитектурные аспекты почти никогда не являются вопросом личных предпочтений. Они должны быть основаны на основополагающих принципах, а не просто на личных предпочтениях. Иногда есть несколько допустимых вариантов реализации. Если автор может продемонстрировать (либо с помощью данных, либо на основе твёрдых инженерных принципов), что несколько подходов одинаково верны, рецензент принимает предпочтение автора. В противном случае, выбор диктуется стандартными принципами проектирования. Если никакое другое правило не применяется, рецензент может попросить автора придерживаться практик, применяемых в коде на данный момент, если это не ухудшает общее состояние кода. В любом конфликте разработчик и рецензент первым делом должны попытаться прийти к консенсусу на основе содержания этого документа и других документов в Руководстве автора CL и этом Руководстве рецензента. Если стороны так и не пришли к консенсусу, вместо того, чтобы просто продолжать перепалку в комментариях к код-ревью, назначается личная встреча или видеоконференция между рецензентом и автором (если вы сделаете это, обязательно запишите результаты обсуждения в комментариях к CL для будущих поколений). Если и это не разрешило ситуацию, эскалируйте. Часто эскалация заключается в обсуждении в более широким кругом, при участии техлида и других авторитетов. Не позволяйте CL пылиться без апрува из-за того, что автор и рецензент не смогли прийти к соглашению. Самое важное, на что нужно обратить внимание в код-ревью, — это общая архитектура. Осмысленно ли взаимодействие компонентов? Затрагивает ли изменение ваш проект или библиотеку? Хорошо ли код интегрируется с остальной частью системы? Не пора ли добавить эту функцию? Выполняет ли CL задуманное разработчиком? Хорошо ли задуманное разработчиком для пользователей этого кода? «Пользователи» обычно являются как конечными пользователями, так и разработчиками (которые будут «использовать» этот код в будущем). Мы ожидаем, что перед код-ревью CL будет покрыт тестами. Тем не менее, как рецензент, вы всё равно должны помнить о пограничных случаях, искать проблемы многопоточности, стараться думать как пользователь и следить за тем, чтобы не было ошибок, заметных при чтении кода. Если хотите, можете проверить CL в работе — например, при изменении пользовательского интерфейса. По коду трудно понять, как некоторые изменения повлияют на пользователя. Вы можете попросить разработчика продемонстрировать функциональность, если неудобно сделать это самостоятельно. Очень важно вспомнить о функциональности, если в CL реализована многопоточность, которая теоретически может вызвать deadlock или race condition. Такого рода проблемы очень трудно обнаружить при простом запуске, и они требуют тщательного обдумывания разработчиком и рецензентом (лучше вообще не использовать многопоточность, где возможны race condition или deadlock, поскольку это может сильно усложнить проверку кода или его понимание). Является ли CL слишком сложным? Проверяйте на сложность каждую строчку. Функции слишком сложны? Классы слишком сложны? «Слишком сложный» обычно означает «читатель не может его быстро понять». Это также может означать, что «разработчики могут допустить баги при вызове или изменении этого кода». Особым случаем является оверинжениринг, когда разработчики написали слишком много лишнего кода или добавили лишнюю функциональность. В отношении оверинжиниринга нужно быть особенно бдительным. Поощряйте разработчиков решать проблему, которую, по их мнению, необходимо решить сейчас, а не проблему, которую, по предположению разработчика, потребуется решить в будущем. Лучше решать будущие проблемы по мере их появления. Запросите для CL модульные, интеграционные или сквозные тесты. Тесты должны быть в том же CL, если только CL не лечит критический баг. Убедитесь, что тесты правильные, осмысленные и полезные. Тесты не проверяют сами себя, и мы редко пишем тесты для наших тестов — вы должны убедиться, что тесты валидны. Будут ли тесты на самом деле падать на багах? А если под ними изменится код? Делает ли тест простые и полезные проверки? Правильно ли разделены тесты между различными методами тестирования? Помните, что тесты — это такой же код, который необходимо поддерживать. Не апрувьте проблемные тесты только потому, что они не являются основной частью кода. Хорошие ли имена выбрал разработчик? Хорошее имя должно быть достаточно длинным для полного описания того, что делает функция, но не настолько длинным, чтобы его было трудно читать. Написал ли разработчик чёткие комментарии на понятном языке? Все ли комментарии действительно нужны? Обычно комментарии полезны, если они объясняют, почему существует код, и не объясняют, что он делает. Если код недостаточно понятен, его нужно упростить. Есть некоторые исключения (например, комментарии к регулярным выражениям и сложным алгоритмам бывают необходимы), но в основном, комментарии объясняют то, что не может содержать код, например, обоснование решения. Также может быть полезно просмотреть предыдущие комментарии. Возможно, есть неактуальное TODO, комментарий, который не рекомендует вносить это изменение, и т. д. Обратите внимание, что комментарии отличаются от документации. В комментариях должно быть описано назначение комментируемого кода. У нас в Google есть руководства по стилю для всех наших основных языков и даже для большинства второстепенных. Убедитесь, что CL следует этим руководствам. Если вы хотите улучшить стиль кода, которого нет в руководстве, добавьте к своему комментарию префикс «Nit:», чтобы разработчик знал, что это придирка, которая должна улучшить код, но делать её необязательно. Не блокируйте апрув только на основании личных предпочтений. Рефакторинг не должен перемешиваться с другими изменениями в рамках одного CL. Это затрудняет просмотр изменений, усложняет мёрджи и откаты и вызывает другие проблемы. Например, если автор хочет отрефакторить весь файл, попросите его отправить вам сначала рефакторинг отдельно, а затем изменения по задаче отдельно. Что делать, если существующий код не соответствует руководству по стилю? В соответствии с нашими принципами код-ревью, руководство по стилю является абсолютным авторитетом: если оно чего-то требует, CL должен этому следовать. В некоторых случаях, руководство по стилю рекомендует, а не требует. В этих случаях нужно решить, должен ли новый код соответствовать этим рекомендациям, или же он должен соответствовать уже написанному коду. Лучше следовать руководству по стилю, если только локальное несоответствие не будет слишком запутанным. Если никакое другое правило не применяется, автор должен придерживаться стиля существующего кода. В любом случае, попросите автора сообщить об ошибке и добавить TODO на рефакторинг. Если CL затрагивает создание, тестирование, взаимодействие и релиз кода, убедитесь, что при этом обновляется документация. Если CL удаляет или объявляет устаревшим код, подумайте, может быть, стоит удалить и документацию. Если документация отсутствует, запросите её. Просмотрите каждую строку кода. Можно бегло просмотреть сгенерированный код или дата-классы, но если код написан человеком, не пробегайте его вскользь. Какой-то код нужно изучить тщательнее — убедитесь, что понимаете, что делает весь код. Если код слишком сложный, и это замедляет проверку, пусть разработчик объяснит его. Если вы не смогли понять код, вполне вероятно, что и другие разработчики тоже не смогут. Поэтому, когда вы просите объяснить код, вы помогаете будущим разработчикам. Если вы понимаете код, но чувствуете, что вам не хватает квалификации, убедитесь, что в CL есть квалифицированный рецензент, особенно когда это касается конфиденциальности, безопасности, многопоточности, доступности, интернационализации и т. д. Что, если не нужно просматривать каждую строку? Например, вы являетесь одним из нескольких рецензентов CL, и вас могут привлечь: Для просмотра только определенных файлов. Для просмотра определённых аспектов - общей архитектуры, конфиденциальности, безопасности и т. д. В этих случаях, отметьте в комментарии, какие части вы просмотрели. Предпочтительно ставить отметку "мне нравится" (LGTM - Looks Good To Me) в комментарии. Если вместо этого вы хотите поставить LGTM после просмотра CL другими рецензентами, отметьте это явно в комментарии. Стремитесь быстро реагировать, как только CL будет к этому готов. Посмотрите на CL в широком контексте. Обычно вам видно только те строки, которые были изменены. Просмотрите весь файл, чтобы убедиться, что изменение действительно имеет смысл. Например, изначально вы видите, что добавлены только четыре новые строки, но если посмотреть весь файл, вы увидите, что эти четыре строки находятся в 50-строчном методе, который пора отрефакторить. Также полезно рассматривать CL в контексте системы в целом. Влияет ли этот CL на работоспособность кода, сложность, тестируемость и т. д.? Не принимайте CL, которые ухудшают работоспособность. Системы постоянно усложняются из-за множества небольших изменений, поэтому важно не допускать даже небольших усложнений. Если вы увидели в CL что-то хорошее, сообщите об этом разработчику, особенно если он откликается на ваши комментарии. В код-ревью мы стараемся замечать только ошибки, но хорошие практики тоже надо замечать. С точки зрения наставничества, лучше похвалить разработчика, чем пожурить. Выполняя код-ревью, вы должны убедиться, что: Код хорошо написан. Функциональность хороша для всех пользователей кода. Изменения пользовательского интерфейса хороши и разумны. Многопоточность выполняется безопасно. Код не переусложнён. Разработчик не оверинжинирит. Код покрыт модульными тестами. Тесты хорошо продуманы. Разработчик использовал понятные имена. Комментарии ясны и полезны, и в основном объясняют, почему, а не что. Код задокументирован. Код соответствует принятым руководствам по стилю. Просмотрите каждую строчку кода, посмотрите на контекст, убедитесь, что ваши комментарии на пользу, и чаще хвалите разработчиков за хорошее. Теперь, когда вы знаете, на что обращать внимание, как же эффективнее ревьюить код, разбросанный по нескольким файлам? Есть ли смысл в изменении? Достаточно ли описание? Сначала обратите внимание на самую важную часть изменений. Хорошо ли она спроектирована в целом? Посмотрите на остальную часть CL в обычной последовательности. Посмотрите описание CL и вообще, что он делает. Есть ли смысл в этих изменениях? Если так не было написано с самого начала, то почему сейчас? При отклонении CL, предложите разработчику альтернативное решение. Например, можно сказать: «Отличная работа, коллега! Однако, эта система будет скоро удалена, и в ваших изменениях нет смысла. Как насчет того, чтобы отрефакторить наш новый класс?» Обратите внимание, что рецензент не только отклонил текущий CL и предложил альтернативное предложение, но и сделал это вежливо. Быть вежливым очень важно, потому что мы хотим показать профессиональное уважение, даже когда мы отклоняем CL. Если вы получаете на ревью несколько необязательных CL по вашему продукту, переосмыслите работу вашей команды, или дайте более подробное описание вашему продукту, прежде чем другие команды начнут в нём что-то менять. Лучше сказать людям «нет» до того, как они проделают массу бесполезной работы. Начните с "основных" файлов CL. Часто это один файл с основной бизнес-логикой. Начните с него. Вы поймёте общий контекст CL, и это ускорит ревью. Если CL слишком большой для понимания, спросите у разработчика, с чего начать смотреть, или попросите его разделить CL на несколько CL. Если вы обнаружите серьезные проблемы с архитектурой, немедленно сообщите об этом, даже если у вас нет сейчас времени на весь CL. Возможно, потребность в ревью отпадёт вообще, поскольку, если эти проблемы большие, большая часть проверяемого кода после доработок потеряет актуальность. Две основные причины для таких комментариев: Разработчики часто отправляют CL по почте и тут же продолжают писать новый код, ожидая ревью по старому CL. Если в CL, который вы просматриваете, проблемная архитектура, им также придется переработать последующий CL. Лучше перехватить их, прежде чем они проделают слишком много дополнительной работы поверх проблемной архитектуры. На серьезные архитектурные изменения уходит больше времени, чем на небольшие изменения. Почти у всех разработчиков есть дедлайны; чтобы уложиться в эти сроки и по-прежнему поддерживать качество кода, разработчик должен как можно скорее приступить к крупной доработке CL. После того, как вы убедились в отсутствии серьезных проблем с архитектурой в целом, определите логическую последовательность просмотра файлов, не пропуская ни один файл. После просмотра основных файлов, смотрите остальные файлы в обычном порядке. Иногда полезнее начать с тестов до просмотра основного кода, потому что тогда вы лучше понимаете, что этот код делает. Скорость команды важнее скорости одного разработчика. Медленный код-ревью приводит к следующим вещам: Снижается скорость команды. Да, человек, который не отвечает быстро на ревью, занят чем-то важным. Однако, работа остальной команды существенно задерживается, поскольку каждый CL ожидает проверки. Разработчики начинают бунтовать против код-ревью. Если рецензент отвечает только раз в несколько дней, но каждый раз при этом требует серьёзных изменений, это разочаровывает разработчиков. Они начинают жаловаться на "строгость" рецензента. Если рецензент требует одни и те же существенные изменения, но быстро отвечает после каждого обновления разработчика, жалобы прекращаются. Большинство жалоб код-ревью на самом деле решается за счет ускорения процесса. Код может ухудшиться. Медленные ревью вынуждают разработчиков отправлять CL не в лучшем виде. После медленных ревью не остаётся времени на рефакторинг. Если вы не погружены в собственную задачу, проведите код-ревью сразу после его поступления. Максимальное время, необходимое для ответа на новый CL - рабочий день (т. е. первым делом на следующее утро). Типичный CL должен пройти несколько раундов проверки (при необходимости) в течение одного дня. Бывает, личная скорость важнее скорости команды. Если вы заняты какой-то конкретной задачей, например, кодингом, не прерывайтесь для код-ревью. Исследования показали, что чтобы вернуться в контекст задачи после перерыва, может потребоваться много времени. Таким образом, отрывы от задач на самом деле дороже для команды, чем небольшое ожидание код-ревью для другого разработчика. Прежде чем отвечать на код-ревью, дождитесь перерыва в работе. Это может быть по завершении вашей текущей задачи, после обеда, митинга, отдыха и т. д. Говоря о скорости код-ревью, нас интересует время отклика, а не время, потраченное на CL в целом. В идеале, быстрым должен быть весь процесс, но скорость ответов важнее скорости процесса. Даже если на весь процесс уходит много времени, быстрые ответы рецензента на протяжении всего процесса меньше раздражают разработчиков. Если у вас нет времени на полный обзор CL, быстро сообщите разработчику, когда у вас появится это время, предложите более свободных рецензентов, или предоставьте первоначальные общие комментарии. (Примечание: собственный кодинг прерывать нельзя даже для этого). Необходимо тратить достаточно времени, чтобы быть уверенными, что ваш «LGTM» означает «этот код соответствует нашим стандартам». Но ответы в идеале должны быть быстрыми. Если у вас с автором разные часовые пояса, ответьте ему до конца его рабочего дня. Если его рабочий день уже закончился, постарайтесь проревьюить его код до наступления следующего его рабочего дня. Чтобы ускорить ревью, можно заапрувить CL с неразрешёнными комментариями. Это делается в случаях, когда: Рецензент уверен, что разработчик примет к сведению все оставшиеся комментарии рецензента. Остальные изменения незначительны и их необязательно выполнять. Рецензент должен указать предпочтительный вариант. Апрув с комментариями особенно подходит, когда разработчик и рецензент находятся в разных часовых поясах, и разработчику придётся ждать целый день, чтобы получить апрув. Если кто-то присылает вам такую кучу кода, на которую вообще не найти времени, попросите разработчика разбить CL на более мелкие. Обычно это возможно, даже если разработчику придётся потратить своё время. Если CL нельзя разбить на более мелкие, а у вас нет времени быстро просмотреть все целиком, то хотя бы напишите несколько комментариев по общей архитектуре CL и отправьте его разработчику для доработки. Одна из ваших целей как рецензента должна состоять в том, чтобы как можно быстрее высвободить разработчика или дать ему возможность начать что-то исправлять. Если следовать этим рекомендациям и строго проводить код-ревью, ревью будут проходить всё быстрее и быстрее. Разработчики будут знать, какой вы хотите видеть код, и будут отправлять вам отличные CL с самого начала. Рецензенты станут быстро реагировать и не задерживать процесс. Но не идите на компромисс со стандартами или качеством проверки кода ради воображаемого увеличения скорости — в долгосрочной перспективе работу это не ускорит. В некоторых ситуациях можно пойти на быстрый код‑ревью с более мягкими требованиями. Смотрите, Что такое аврал, чтобы понимать, для каких ситуаций это подходит. Будьте благожелательны. Объясните свою мысль. Указывайте на проблемы, но решает их пусть разработчик. Пусть разработчики упрощают код и пишут документации, вместо объяснений, почему код сложный. Важно быть вежливым и уважительным, а также очень понятным и полезным для разработчика. Комментируйте код и никогда не комментируйте разработчика. Например: Плохо: «Зачем ты втащил сюда многопоточность, когда она тут совсем не нужна?» Хорошо: «Многопоточность усложняет систему без какого-либо реального выигрыша в производительности. Поскольку выигрыша в производительности нет, лучше, чтобы код был однопоточным, а не многопоточным». В примере выше разработчик понимает, почему вы оставили такой комментарий. Не обязательно всегда давать такой развёрнутый комментарий, но лучше дать больше пояснений насчёт лучших практик, чистого кода и т. д. За исправление CL отвечает разработчик, а не рецензент. Не нужно детально проектировать решение или писать код за разработчика. Тем не менее, рецензент должен быть полезен. Вы должны найти баланс между простым комментарием и руководством. Предоставление разработчику свободы действий учит разработчика и упрощает проверку кода. Он также может обнаружить лучшее решение, потому что разработчик ближе к коду, чем рецензент. Однако, иногда полезнее прямые инструкции или даже код. Основная цель ревью — получить наилучший CL. Второстепенная цель — прокачать разработчиков, чтобы со временем их требовалось меньше ревьюить. Помните, что благодаря поддержке люди закрепляют хорошие практики, а не только узнают лучшие. Если вам что-то нравится в CL, сообщите об этом! Пример: разработчик подчистил беспорядочный алгоритм, добавил тестовое покрытие или вы, как рецензент, узнали что-то из CL. Укажите, почему вам что-то понравилось, поощряя разработчика продолжать использовать передовой опыт. Маркируйте комментарии в соответствии с их серьёзностью, отличая необходимые изменения от простых рекомендаций. Примеры: Nit: Незначительно. Технически это можно сделать, но на ситуацию это не повлияет. Optional (или Consider): идея интересная, но не обязательная. FYI: необязательно делать это в этом CL, но на будущее это интересная идея. Маркировка помогает авторам расставлять приоритеты важности комментариев. Она также помогает избежать недоразумений; например, без маркировки авторы могут принять все комментарии за обязательные, даже если обязательные среди них не все. Если вы просите разработчика объяснить непонятный кусок кода, в идеале он должен переписать его на более понятный. Но иногда достаточно комментария в коде. Объяснения, написанные только в инструменте ревью, бесполезны для будущих читателей кода. Они приемлемы, например, когда автор объясняет код, незнакомый лично вам. Иногда разработчик отказывается исполнять ваши комментарии. Либо он с вами не согласен, либо считает, что вы придираетесь. Если разработчик с вами не согласен, сначала подумайте, правы ли вы. Разработчик ближе к коду, чем вы, и поэтому может лучше понимать некоторые его аспекты. Имеет ли его аргумент смысл? Если так, признайте, что он прав, и забудьте об этом. Однако, разработчик не всегда прав. В этом случае, объясните ещё раз, почему вы считаете своё предложение правильным. Хорошим объяснением вы не только показываете, что понимаете, что имеет в виду разработчик, но и более детально описываете своё предложение. В частности, когда рецензент считает, что его предложение улучшит код, он должен продолжать выступать за исправление. Улучшение работоспособности кода, как правило, происходит небольшими шагами. Иногда объяснять приходится несколько раз, прежде чем разработчик действительно поймёт, чего вы от него хотите. Просто старайтесь всегда оставаться вежливым и дайте разработчику понять, что вы слышите его позицию, но не согласны. Иногда кажется, что разработчик расстроится, если вы будете настаивать на улучшении. Бывает и такое, но, во-первых, разработчик обычно быстро остывает, а во-вторых, позже он скажет спасибо, что вы ему помогли. Обычно, если вы вежливы в своих комментариях, разработчики вообще на них не обижаются. Обычно разработчики обижаются на то, как написаны комментарии, чем на требования качества кода. Часто разработчики сопротивляются замечаниям, потому что они (по понятным причинам) хотят завершить ревью как можно скорее. Поэтому они обещают исправить позже, "а сейчас давайте уже заапрувим этот CL и пойдём дальше". Бывает, что разработчик действительно не врёт и исправит замечания как можно быстрее в следующем же CL. Однако опыт показывает, что чем больше времени пройдёт после написания такого кода, тем меньше вероятность того, что разработчик что-то сделает из обещанного. Обычно "потом" означает "никогда". Это происходит не потому, что разработчики безответственны, а потому, что работы меньше не становится, и рефакторинг просто некогда делать. Таким образом, лучше настоять на том, чтобы разработчик подчистил свой CL сейчас, до того, как код будет в кодовой базе в статусе "готов". Позволить людям "сделать это когда-нибудь потом" — распространенный путь к вырождению кодовой базы. Если CL слишком сложный, его необходимо отрефакторить перед мёрджем, если только это не аврал. Если проблемы, обнаруженные в CL, нельзя исправить прямо сейчас, разработчик должен создать на себя баг на исправление. Он также может написать комментарий TODO в коде, который ссылается на заведённый баг. Если требования к ревью резко ужесточатся, разработчики начнут роптать. Повышение скорости проверки кода обычно разрешает эту ситуацию. Иногда на разрешение недовольства могут потребоваться месяцы, но поскольку общее улучшение качества кода сразу бросается в глаза, разработчики принимают строгие ревью. Иногда самые громкие протестуны становятся вашими самыми сильными сторонниками, когда они видят ценность такой строгости. Если вы соблюдаете все вышеперечисленное, но конфликты с разработчиком по-прежнему имеют место, ознакомьтесь с рекомендациями и принципами, которые могут помочь разрешить конфликт, в разделе «Стандарт проверки кода».  backend.developer { java, kotlin } in Sber