Чистый код. Создание, анализ и рефакторинг (Мартин) - страница 21

Имена должны передавать намерения программиста

Легко сказать: имена должны передавать намерения программиста. И все же к выбору имен следует относиться серьезно. Чтобы выбрать хорошее имя, понадобится время, но экономия окупит затраты. Итак, следите за именами в своих программах и изменяйте их, если найдете более удачные варианты. Этим вы упростите жизнь каждому, кто читает ваш код (в том числе и себе самому).

Имя переменной, функции или класса должно отвечать на все главные вопросы. Оно должно сообщить, почему эта переменная (и т.д.) существует, что она делает и как используется. Если имя требует дополнительных комментариев, значит, оно не передает намерений программиста.

>int d; // Прошедшее время

Имя d не передает ровным счетом ничего. Оно не ассоциируется ни с временными интервалами, ни с днями. Его следует заменить другим именем, которое указывает, что именно измеряется и в каких единицах:

>int elapsedTimeInDays;

>int daysSinceCreation;

>int daysSinceModification;

>int fileAgeInDays;

Содержательные имена существенно упрощают понимание и модификацию кода. Например, что делает следующий фрагмент?

>public List getThem() {

>  List list1 = new ArrayList();

>  for (int[] x : theList)

>    if (x[0] == 4)

>      list1.add(x);

>  return list1;

>}

Почему мы не можем сразу сказать, что делает этот код? В нем нет сложных выражений. Пробелы и отступы расставлены грамотно. В коде задействованы только три переменные и две константы. В нем нет никаких хитроумных классов или полиморфных методов, только список массивов (по крайней мере на первый взгляд).

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

1. Какие данные хранятся в theList?

2. Чем так важен элемент theList с нулевым индексом?

3. Какой особый смысл имеет значение 4?

4. Как будет использоваться возвращаемый список?

Ответы на все эти вопросы не следуют из примера, хотя и могли бы. Допустим, мы работаем над игрой «Сапер». Игровое поле представлено в виде списка ячеек с именем theList. Переименуем его в gameBoard.

Каждая ячейка игрового поля представлена простым массивом. Далее выясняется, что в элементе с нулевым индексом хранится код состояния, а код 4 означает «флажок установлен». Даже простое присваивание имен всем этим концепциям существенно улучшает код:

>public List getFlaggedCells() {

>  List flaggedCells = new ArrayList();

>  for (int[] cell : gameBoard)

>    if (cell[STATUS_VALUE] == FLAGGED)