Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
книги хакеры / Питер_Гудлиф_Ремесло_программиста_Практика_написания_хорошего_кода.pdf
Скачиваний:
16
Добавлен:
19.04.2024
Размер:
9.23 Mб
Скачать

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

X

 

 

 

 

 

-

 

 

 

 

 

d

 

F

 

 

 

 

 

 

t

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

to

 

 

 

 

w Click

 

 

 

98m

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

.

 

 

 

 

 

.c

 

 

p

 

 

 

 

g

 

 

 

 

df

 

 

n

e

 

 

 

 

-xcha

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

Глава 4. ЛитературоведениеClick

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

{

return 1;

}

int previousButOne = 1;

int

previous

=

1;

int

answer

=

2;

for (int n = 2; n < position; ++n)

{

previousButOne

= previous;

previous

= answer;

answer

= previous + previousButOne;

}

 

return answer;

 

}

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

Техника написания самодокументируемого кода

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

Следующие разделы содержат описание важных приемов самодоку% ментирования кода. Можно заметить, что они во многом перекрыва% ются с другими главами в первой части книги. И это неудивительно – есть много общих признаков хорошего кода; достоинства отдельного метода проявляются в различных характеристиках качества кода.

Пишите простой код с хорошим форматированием

Формат представления оказывает огромное влияние на легкость пони% мания кода. Разумное представление передает структуру кода: функ% ции, циклы и условные операторы становятся понятнее.

Стремитесь к тому, чтобы ход «нормального» выполнения вашего кода был очевиден. Обработка ошибок не должна отвлекать от нор% мальной последовательности выполнения. Условные конструкции if#then#else должны иметь единообразный порядок ветвей (напри% мер, всегда помещайте ветвь «обычного» хода перед ветвью «обра% ботки ошибок», или наоборот).

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

последовательности Фибоначчи. Какую из них вам удобнее читать?

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

Техникаm

написания самодокументируемого кода

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

99Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Избегайте большого количества уровней вложенных операторов. В противном случае код становится сложным и требует простран% ных пояснений. Принято считать, что у каждой функции должна быть только одна точка выхода; это известно как код Single Entry, Single Exit (SESE, один вход – один выход). Но обычно это ограни% чение затрудняет чтение кода и увеличивает количество уровней вложенности. Мне больше нравится приведенный выше вариант функции fibonacci, чем следующий вариант в стиле SESE:

int fibonacci(int position)

{

int answer = 1;

if (position >= 2)

{

int previousButOne = 1; int previous = 1;

for (int n = 2; n < position; ++n)

{

previousButOne = previous;

previous

= answer;

answer

= previous + previousButOne;

}

 

}

 

return answer;

 

}

Я бы отказался от такой излишней вложенности в пользу дополни% тельного оператора return – читать функцию стало гораздо труднее. Весьма сомнительна целесообразность прятать return где%то в глу% бине функции, зато простые сокращенные вычисления в ее начале очень облегчают чтение.

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

Выбирайте осмысленные имена

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

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

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

X

 

 

 

 

 

-

 

 

 

 

 

d

 

F

 

 

 

 

 

 

t

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

to

 

 

 

 

w Click

 

 

 

100m

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

.

 

 

 

 

 

.c

 

 

p

 

 

 

 

g

 

 

 

 

df

 

 

n

e

 

 

 

 

-xcha

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

Глава 4. ЛитературоведениеClick

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Разбивайте код на самостоятельные функции

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

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

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

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

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

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

Определяя величину, которая не будет меняться, назначьте для нее тип константа (используйте const в C).

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

Пользуйтесь перечислениями для описания связанного набора дан% ных.

Правильно выбирайте тип переменных. В C/C++ записывайте раз% мер в переменные типа size_t, а результаты арифметических опера% ций с указателями – в переменные типа ptrdiff_t.

Применяйте именованные константы

Код типа if (counter == 76) вызывает недоумение. Каково волшебное значение числа 76? В чем смысл этой проверки?

Практика волшебных чисел порочна. Они затеняют смысл кода. Гораз% до лучше написать так:

const size_t bananas_per_cake = 76;

...

if (count == bananas_per_cake)

{

// испечь банановый пирог

}

Если в коде часто встречается константа 76 (простите, bananas_per_cake), достигается дополнительное преимущество: когда потребуется изме%

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

Техникаm

написания самодокументируемого кода

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

101Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

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

Избегайте волшебных чисел. Пользуйтесь именованными константами.

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

Выделяйте важные фрагменты кода

Старайтесь выделить важный код на фоне обычного материала. В нуж% ном месте следует привлечь внимание читателя. Для этого есть ряд приемов. Например:

Разумно располагайте объявления в классе. Сначала должна идти информация об открытых объектах, поскольку именно она нужна пользователю класса. Закрытые детали реализации следует распо% лагать в конце, поскольку они менее интересны большинству чита% телей.

По возможности скройте всю несущественную информацию. Не ос% тавляйте ненужного мусора в глобальном пространстве имен. В C++ есть идиома pimpl, позволяющая скрыть детали реализации клас% са. (Meyers 97)

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

Ограничьте глубину вложенности условных операторов. В против% ном случае за нагромождением if и скобок трудно заметить обра% ботку действительно важных случаев.

Важные участки кода должны выделяться на общем фоне и быть легко чи& таемыми. Спрячьте все, что не должно интересовать клиентов.

Объединяйте взаимосвязанные данные

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