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

 

 

 

 

 

325Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Проект не пестрит особыми случаями.

Аналогичные вещи связаны между собой.

Отсутствуют неприятные сюрпризы.

Изменения затрагивают небольшую область: одно простое измене% ние в одном месте не требует модификации кода во многих других местах.

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

Модульность

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

Основными качествами модульности являются связность (cohesion) и сцепление (coupling). Мы стремимся к тому, чтобы у модулей были:

Сильная связность

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

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

Слабое сцепление

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

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

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

X

 

 

 

 

 

-

 

 

 

 

 

d

 

F

 

 

 

 

 

 

t

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

to

 

 

 

 

w Click

 

 

 

326m

 

 

 

 

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

 

 

 

 

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

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

Хорошие интерфейсы

Модули помогают нам разбить задачу на части, разделить проблемы. В каждом модуле определяется интерфейс – открытый публике фа% сад, за которым скрывается внутренняя реализация. Этот набор допус% тимых операций часто называется интерфейсом прикладного про# граммирования (API). Он образует единственный путь к функциям, предоставляемым модулем, и его качество определяет качество самого модуля, по крайней мере с внешней стороны.

Проведите черту, за которую никто не должен переступать: определите четкие API и интерфейсы.

Чтобы определить хороший интерфейс, действуйте следующим обра% зом:

1.Определите клиента и его потребности.

2.Определите поставщика и его возможности.

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

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

3.Вывести заключение о типе требуемого интерфейса.

Будет ли это функция, класс, сетевой протокол или нечто другое? Это может определяться поставщиком функциональности, но ин% терфейс можно заключить в оболочку, которая будет представлять

его иным способом. Например, создание объекта CORBA вокруг

 

 

 

 

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

 

 

 

 

 

327Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

библиотеки делает ее функциональность доступной в сети взаимо% действующих компьютеров.

4.Определить сущность операции.

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

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

Разделение

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

Хорошо спроектированный код четко устанавливает роли и ответ# ственности. Определение в системе главных действующих лиц и их обязанностей обеспечивает четкость и эффективность интерфейсов.

Хороший пример представляет мой дом. Его главный интерфейс – входная дверь. Дверь разделяет жителей и гостей и определяет ме%

Рис. 13.3. Интерфейсы, которые предоставляет дом

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

X

 

 

 

 

 

-

 

 

 

 

 

d

 

F

 

 

 

 

 

 

t

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

to

 

 

 

 

w Click

 

 

 

328m

 

 

 

 

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

 

 

 

 

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

Абстракция

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

Если у вас есть ваза с фруктами, можно просто сказать: «Съешь фрукт, который сверху», а потом – «Съешь следующий», и нис% колько не заботиться о том, что это за собой влечет, а именно: если это грейпфрут, его нужно очистить от кожуры, а если это ревень, то его нужно сварить и посыпать сахаром. Детали скрыты за абстракт% ным съесть; нам нужно, чтобы фрукт был съеден, и неинтересно, как это будет сделано.1

Абстракции могут образовывать иерархии. Мой дом может рас% сматриваться с различных уровней абстракции в зависимости от того, кто вы такой: строитель, физик%ядерщик или банковский слу% жащий. Например, он может рассматриваться в виде:

Совокупности помещений

Структуры, состоящей из стен, потолков и полов

Сооружения из кирпичей и деревянных деталей

Совокупности молекул или даже атомов

Закладной, требующей выплат

Компрессия

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

Заменяемость

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

1Возможность скрыть различное физическое поведение за единой логиче% ской абстракцией называется полиморфизмом. Это понятие описывается

в разделе «Полиморфизм» на стр. 533.