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

 

 

 

238m

 

 

 

 

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

 

 

 

 

 

Глава 10. Код, который построил ДжекClick

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

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

Задача, состоящая в том, чтобы преобразовать тщательно отшлифо% ванный код на языке высокого уровня в исполняемый модуль, кото% рый можно распространять среди пользователей, обычно называется сборкой кода (building code), хотя в большинстве случаев этот термин используют наравне с компиляцией (making, compiling).

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

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

Языковые барьеры

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

Три основных механизма – это интерпретируемые языки, компили# руемые языки и языки, компилируемые в байт#коды. Они представле% ны на рис. 10.1.

Интерпретируемые языки

Коду, написанному на интерпретируемом языке, не требуется прохо% дить через особую фазу сборки. Написав некий код, нужно лишь сооб% щить интерпретатору, где он лежит; интерпретатор станет анализиро% вать код и выполнять инструкции в реальном времени. Распространен% ными интерпретируемыми языками являются Perl, Python и Java% Script. Большинство OO%языков является интерпретируемыми, в основ%

 

 

 

 

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

 

 

 

 

 

 

Файлы

 

 

 

1

с исходным

3

 

 

кодом

 

 

 

 

 

Интерпретатор

 

2

 

 

 

 

 

 

 

Компилятор

 

 

 

Выполняемый модуль

4

 

Выполнение

JIT7компилятор

 

 

 

 

 

01010101

 

 

 

 

Выход

 

 

 

 

01010101

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

239Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

1.Интерпретируемые языки

2.Компилируемые языки

3.Языки, компилируемые в байт7код

4.Выполнение с JIT7компиляцией

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

Байт7компилятор

Байт7код

Интерпретатор

Рис. 10.1. Методы сборки и выполнения языков программирования

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

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

Но у интерпретируемых программ есть недостатки: они выполняются медленнее, чем компилированные эквиваленты, поскольку на этапе ис% полнения нужно прочесть, проанализировать, интерпретировать и вы% полнить каждую отдельную команду кода. Это большая работа. Совре% менные машины настолько быстры, что проблемы интерпретации воз% никают только в приложениях, требующих особенно интенсивных вы% числений. Существуют также различные технологии интерпретации, увеличивающие производительность кода: в некоторых языках исход% ные тексты компилируются перед выполнением (что увеличивает вре% мя запуска программы) или применяют компиляцию Just#In#Time (JIT), когда каждая функция компилируется непосредственно перед ее исполнением (что замедляет первое обращение к каждой функции). Для большинства программ такие накладные расходы приемлемы, а работа в режиме JIT%компиляции неотличима от выполнения обыч% ного скомпилированного кода.

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

X

 

 

 

 

 

-

 

 

 

 

 

d

 

F

 

 

 

 

 

 

t

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

to

 

 

 

 

w Click

 

 

 

240m

 

 

 

 

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

 

 

 

 

 

Глава 10. Код, который построил ДжекClick

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Действительно ли мы собираем программы?

«Сборка» часто используется в качестве метафоры программиро% вания, равносильной тому, что происходит в «нормальной» сбо% рочной промышленности. Между ними есть много глубоких па% раллелей, поскольку в том и другом случае мы имеем дело со строительными процессами. И мы действительно наблюдали в известной мере частичное совпадение и сотрудничество между двумя отраслями в виде движения «паттернов программирова% ния» (см. «Шаблоны проектирования» на стр. 334), примером чего служит книга Кристофера Александра (Christopher Alexan% der) об архитектуре (Alexander 79).

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

Положительное

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

Отрицательное

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

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

 

 

 

 

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

 

 

 

 

 

241Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Самое страшное

В целом процедура разработки похожа на процесс физическо% го строительства, включая в себя замысел системы, проекти% рование, реализацию и пробную эксплуатацию. Но в данной главе мы озабочены несколько иным – компиляцией и проце% дурами, входящими в такого рода строительные задачи. Здесь метафора тоже оказывается не вполне удачной. Каж% дый раз, взяв новый экземпляр исходного кода, вы «строите» его, создавая выполняемую программу – об этом здесь и идет речь. Обратите внимание на два разных употребления терми% на «build» (сборка, строительство).

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

Языки сценариев часто являются интерпретируемыми. У этих языков очень быстрый цикл разработки благодаря терпимому отношению к сомнительному коду (в языке нет строгих правил и слабая типизация) и отсутствию сложных функций. Языки сценариев часто используют% ся в качестве связующей среды для более удобного вызова других ути% лит. Примерами языков сценариев служат сценарии оболочки UNIX, пакетные файлы Windows и Tcl.

Компилируемые языки

В компилируемых языках для преобразования файлов исходного кода

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

впромежуточные объектные файлы, а затем эти объекты компонуются

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

Из компилируемых языков наиболее популярны C и C++, хотя компи% лируется большинство структурированных языков. Совершенно естест% венно, что скомпилированное приложение будет выполняться быстрее, чем его интерпретируемый аналог (по крайней мере, в отсутствие JIT% компиляции), хотя на практике вы этого не заметите; большинство

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

X

 

 

 

 

 

-

 

 

 

 

 

d

 

F

 

 

 

 

 

 

t

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

to

 

 

 

 

w Click

 

 

 

242m

 

 

 

 

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

 

 

 

 

 

Глава 10. Код, который построил ДжекClick

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Рис. 10.2. Кухня компиляции

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

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

Языки, компилируемые в байтNкоды

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

1Целевые платформы различаются по типам процессоров и операционных систем. Могут иметь значение и другие факторы, такие как имеющееся пе%

риферийное оборудование.