Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
книги хакеры / Питер_Гудлиф_Ремесло_программиста_Практика_написания_хорошего_кода.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

 

 

 

 

 

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

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

13

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

Как правильно проектировать программный продукт

В этой главе:

Внутреннее устройство кода

Что проектировать

изачем

Каким должен быть хороший проект

Инструменты

иметодологии

проектирования

Верблюд – это лошадь, разработанная комитетом.

Сэр Алек Иссигонис

Иногда встречается код, глядя на который остается только вздохнуть.

Однажды мне нужно было написать драйвер устройства для встроенного продукта. Ин% терфейс драйвера с ОС был достаточно слож% ным. Интерфейс с устройством, с которым я работал, был тоже сложным. Поразмыслив, я разбил свой код на две части. В первой час% ти была внутренняя библиотека для доступа к устройству, осуществлялась буферизация некоторых данных и предоставлялся про% стой API для доступа к этим буферизован% ным данным. Затем я написал второй, от% дельный уровень, в котором реализовал ка% призный интерфейс драйвера ОС на языке моей внутренней библиотеки. Структура драйвера устройства показана на рис. 13.1.

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

X

 

 

 

 

 

-

 

 

 

 

 

d

 

F

 

 

 

 

 

 

t

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

to

 

 

 

 

w Click

 

 

 

318m

 

 

 

 

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

 

 

 

 

 

Глава 13. Важность проектированияClick

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Интерфейс ОС

Интерфейс аппаратуры

 

Рис. 13.1. Разумная конструкция

Рис. 13.2. Как не надо

программы, сделанная Питом

проектировать программы

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

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

Ч. Э. Р. Хоар писал: «Есть два пути конструирования программ. Пер% вый путь – сделать конструкцию настолько простой, что в ней очевидно нет недостатков. Второй – сделать ее настолько сложной, что в ней нет очевидных недостатков. Первый путь намного труднее». (Hoare 81)

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

Программирование как конструкторская работа

Распространено мнение, что «проектирование» – это этап, который должен быть завершен перед началом написания кода. Его результа% том является спецификация проекта в той или иной форме, которую сможет реализовать любой ремесленник.

На самом деле все совсем иначе. Программирование – действие, за% ключающееся в написании кода, – представляет собой конструктор# скую работу.

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

 

 

 

 

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

 

 

 

 

 

319Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

ектная работа. При этом выявляются пробелы, несоответствия и ошиб% ки и отыскиваются решения этих проблем. «Кое%кто из программистов не замечает, что во время программирования он занимается конструк% торской работой, тем не менее, когда вы пишете код, вы всегда занима% етесь проектированием, прямо или косвенно» (Page Jones 96).

Программирование – это работа по проектированию. Это творческий и ху& дожественный акт, а не механическое написание кода.

При правильном процессе разработки это учитывают и не воздерживают% ся писать код, когда это целесообразно. Те, кто практикует экстремаль# ное программирование, утверждают, что проект и есть код. (Beck 99) Проектирования как отдельного вида деятельности при этом нет; нет группы проектировщиков. Сами программисты постоянно совершен% ствуют и расширяют проект путем совершенствования и расширения кода. Это закреплено в их методе проектирования на основе тестов: прежде чем писать любой код, пишутся тесты как средство проверки правильности проектных решений. Это мудрая мысль.

Следует ли из этого, что необязательно думать перед тем, как начать кропать код? Ни в коей мере! Погрузившись в текстовый редактор, поздно планировать, что вы собираетесь написать. Все равно что от% правиться на машине из Берлина в Рим и не подумать сначала, каким маршрутом ехать. Так вы очутитесь в Москве, еще не выяснив, в ка% кой стороне север. По определению проект – это то, что делается в са# мом начале.

Думайте, прежде чем стучать по клавишам; составьте понятный проект. Иначе у вас получится не код, а хаос.

Что нужно проектировать?

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

Эти уровни проектирования программного продукта таковы:

Архитектура системы

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

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

X

 

 

 

 

 

-

 

 

 

 

 

d

 

F

 

 

 

 

 

 

t

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

to

 

 

 

 

w Click

 

 

 

320m

 

 

 

 

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

 

 

 

 

 

Глава 13. Важность проектированияClick

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Модули/компоненты

Подсистемы, входящие в архитектуру, обычно слишком велики для непосредственной реализации в коде, поэтому следующим ша% гом будет разбиение их на обозримые модули. Говоря о проектиро% вании на уровне модулей, трудно добиться четкости. В некотором смысле такой вещи, как «модуль», реально не существует. Модуль может иметь разный смысл в зависимости от подхода к проектиро% ванию; это может быть логически обособленная часть кода, воз% можно, физический объект типа пакета Java, пространства имен C++/C# или многократно используемая библиотека. Модулем можно считать иерархию классов или даже отдельную выполняе% мую программу.

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

Классы и типы данных

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

Функции

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

ИзNза чего весь этот шум?

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

1Важнейшие алгоритмы часто реализуются набором нескольких функций;

они определяются на стадии проектирования модуля.