Статьи

Основные правила рецензирования кода Groovy и Grails

Я уже некоторое время преподаю Grails не-Java программистам. Это также означало научить их некоторым способам работы, которые мне очень дороги, таким как парное программирование и анализ кода .

код-обзор-разработчик

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

Здесь я опишу некоторые руководящие принципы и передовые практики для проведения коллегиального обзора кода (работы). Это не исчерпывающий список, и некоторые из них довольно просты для опытных разработчиков, но он помог мне охватить некоторые основы для не-Java младших команд, начиная с Java, Groovy и Grails.

Генеральная

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

Именование

Используйте правильные структуры и имена. Используйте правильные имена артефактов Grails, таких как классы доменов, контроллеры, сервисы, метки TagLib, а также методы и переменные.

  • Пакеты должны начинаться с nl.<company> nl.first8.myapp nl.<company> за которым следует имя приложения, например nl.first8.myapp
  • Классы начинаются с CAPITALS, например Animal , методы и переменные записываются в camelCase , например displaySummary() или animalInstanceList
  • Старайтесь избегать сокращений. Предпочитаю domainCode dmnCd
  • Имя действительно покрывает предмет?

читабельность

Общие рекомендации по удобочитаемости и форматированию, позволяющие легко читать код и составлять его единообразно. Часть может быть выполнена автоматически с помощью встроенного средства форматирования в IDE, например, Ctrl-Shift-F в Eclipse или GGTS, но не все.

Не все однострочники

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

1
out << body() << ( (attrs.int('offset')) + "-" + ( Math.min(attrs.int('count'), attrs.int('offset') + attrs.int('max') ) ) + " " + title + " " + attrs.int('count') )

мог стать

1
2
3
4
5
int start = attrs.int('offset')
int total = attrs.int('count') )
int end = Math.min(total, start + attrs.int('max') )
  
out << body() << start + "-" + end + " " + title + " " + total

Спок тесты и этикетки

Можно много сказать о «правильном» написании тестов Спока , но это выходит за рамки этого поста.

Используйте правильные метки в тестах Спока для удобства чтения. Используйте and: для разделения нескольких меток — с дополнительным «текстовым описанием» после них — чтобы они выделялись. Напишите

1
2
3
4
5
6
when: "searching for existing animal"
...
then: "we have results"
model.animalSearchResults.animalsCount == 1
flash.successMessage == "animal.all.found.message"
session.selected.size() == 1

в виде

01
02
03
04
05
06
07
08
09
10
11
when: "searching for existing animal"
...
  
then: "one found animal is returned"
model.animalSearchResults.animalsCount == 1
  
and: "all found message is displayed"
flash.successMessage == "animal.all.found.message"
  
and: "animal has been auto-selected"
session.selected.size() == 1

Бело-пространство

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

1
Integer.valueOf(params.offset?:attrs.offset)

в виде

1
Integer.valueOf(params.offset ?: attrs.offset)

Пробел и скобки

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

1
2
3
if ( params )
if ( total > 0 )
if ( end < begin )

в виде

1
2
3
if (params)
if (total > 0)
if (end < begin)

Фигурные скобки

Используйте фигурные скобки для однострочников. Напишите

1
2
if ( end < begin )
      end = begin

в виде

1
2
3
if (end < begin) {
  end = begin
}

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

сравнить

1
2
3
if (end < begin)
end = begin
end = end + 1

с участием

1
2
3
4
if (end < begin) {
  end = begin
}
end = end + 1

Комментарии

Используйте комментарии, чтобы указать назначение классов и методов, прояснить сложные фрагменты кода и документировать принятые решения («почему?»). Для Java en Groovy-кода мы можем использовать Javadoc для генерации документации API в формате HTML в исходном коде.

Ага на занятиях

Используйте комментарии Javadoc вверху класса для описания общего назначения, такого как

1
2
3
4
/**
 * General convenience tags for layout - header, body and footer - purposes.
 */
class LayoutTagLib {

Ага по методам

Используйте Javadoc для открытых методов, чтобы описать цель и ее параметры. Вы можете использовать @param для параметров, @return для того, что он возвращает, когда или если исключения @thrown с @thrown и т. Д.

1
2
3
4
5
6
7
8
/**
 * Gets the user for specified code and role.
 *
 * @param code The code, either username or email address
 * @param role The role identification e.g. A, B or C. Default is A.
 * @return the user or null if not found
 */
User findUser(String code, String role = "A")

Убирать

Удалите устаревшие комментарии, например, которые остались позади, или которые просто неверны, или исправьте их!

Simplicitly

Является ли код простым и выполняет ли он свою работу самым простым способом … но не проще

Интуитивно понятный API

Используйте интуитивно понятный API. Используйте похожие структуры или названия. Требуется ли только фактический требуемый вход и используются ли другие разумные значения по умолчанию? Если вы создаете тег betterPaginate , не слишком обременяйте пользователя всеми видами ввода. У него вместо

1
<g:betterPaginate offset="${params.offset?:0}“ count="${results.animalsCount?:0}" max="${params.max?:0}"/>

разрешить использовать ваш тег как

1
<g:betterPaginate count="${results.animalsCount}" />

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

Простое написание

Чем сложнее используемые строки, тем сложнее понять, что происходит и куда должны идти изменения. Оказывается, что следующие 10 строк созданы сотрудником

01
02
03
04
05
06
07
08
09
10
11
12
int offset = 0
int total  = 0
int max    = 0
   
if (params) {
    offset = Integer.valueOf(params.offset ?: attrs.offset ?: 0)
    max    = Integer.valueOf(params.max ?: attrs.max ?: 0)
} else if (attrs) {
    offset = Integer.valueOf(attrs.offset ?: 0)
    max    = Integer.valueOf(attrs.max ?: 0)
}
total = Integer.valueOf(attrs.total ?: 0)

можно переписать всего за 3 строки с таким же поведением:

1
2
3
int offset = Integer.valueOf(params.offset ?: attrs.offset ?: 0)
int max = Integer.valueOf(params.max ?: attrs.max ?: 0)
int total  = Integer.valueOf(attrs.total ?: 0)

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

Ох и:

дружественный код-обзор

Кредиты изображений:

  1. Что такое Code Review? http://smartbear.com/all-resources/articles/what-is-code-review/
  2. Как облегчить дружественные обзоры кода — http://www.syncano.com/friendly-code-review/