Лекция: О СРАВНЕНИИ ПРОГРАММ

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

В связи с этим возникает проблема эквивалентности программ: даются две программы и ставится вопрос, вызывают ли они вычисле­ния, приводящие к одинаковым результатам. После надлежащей формализации (как способа задания программ, так и машины, ко­торая выполняет вычисления, вызываемые этими программами, а также «результатов» вычислений) можно, по-видимому, свести нашу проблему к корректно сформулированной задаче абстрактной математики. Однако я не собираюсь рассматривать эту проблему в такой общей форме. Напротив, вместо того чтобы начинать с двух произвольных заданных программ (например независимо приду­манных двумя различными авторами), я интересуюсь различными программами, которые могут считаться изобретениями одного и того же разума; при этом возникает вопрос: как нам задумать (и структурно организовать) такие две различные программы, с тем чтобы облегчить работу по их сравнению.

Я проделал много экспериментов, и могу следующим образом подытожить накопленный мною опыт. Две программы, которые вызывают вычисления, приводящие к одинаковым результатам, эк­вивалентны именнов этом смысле и заведомо ни в каком другом. Если мы хотим сравнивать программы с целью сравнения соответ­ствующих им вычислений, то основной вывод состоит в следующем. Это невозможно (или бесполезно, непривлекательно, или ужасно трудно, или подберите любой другой отрицательный эпитет), если по-разному организовано следование по двум программам, которые мы пытаемся сравнить. Точнее говоря, сравнивать две программы и вычисления, которые могли бы быть ими вызваны, имеет смысл только тогда, когда удается разложить сопоставляемые вычисления на временную последовательность действий, которые допускают взаимное отображение, причем соответствующие тексты программ могут быть точно так же разложены на инструкции, каждая из кото­рых соответствует одному из таких действий. Это очень сильное ограничение. Сейчас я приведу первый пример.

Исключая побочный эффект логической проверки и предполагая значение «В2» постоянным (т. е. не изменяемым при выполнении как «S1», так и «S2»), мы можем установить эквивалентность сле­дующих двух программ:

if B2 then

begin while B1 do S1 end

else

begin while Bl do S2 end (1)

и

while B1 do

begin ifB2 then S1 else S2 end (2)

В первой конструкции следование на первом уровне управляется заголовком выбора, а во второй конструкции — заголовком повторе­ния. Я могу доказать эквивалентность результатов вычислений, од­нако я не могу считать эти программы эквивалентными при какой- либо другой полезной интерпретации понятия эквивалентности. Я вынужден был прийти к заключению, что «трудно сравнивать» программы (1) и (2). Сначала такой вывод весьма удручал меня. Однако со временем я смирился с тем, что такая несравнимость явля­ется реальным фактом; в этом одна из основных причин того, что вы­бор между (1) и (2) приходится рассматривать как волевое решение, которое должно приниматься с учетом детального изучения вариан­тов. Именно кажущаяся тривиальность выбора побуждает меня придавать особое значение изучению, которое должно влиять на та­кой выбор. Это изучение вариантов программ выходит за рамки данного раздела, но я собираюсь вернуться к нему в дальнейшем.


 

32. Понятие рефакторинга. Рефакторинги «Согласование различий», «Миграция данных», «Выделение метода».

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

Отсюда следует, что на программиста, работающею о стиле TDD, возлагается важная обязанность: он должен иметь лопаточное количество тестов» описываю­щих семантику программы. Достаточное по крайней мере настолько, настолько он может судить на момент завершения работы над кодом. Необходимо понимать, что рефакторинг выполняется не с учетом всех существующих тестов, а с учетом всех шзможнмх гсстов. Фраза наподобие: «Я знаю, что там была проблема, но все тесты сработали, поэтому я посчитал код завершенным и интегрировалсто и сис­тему», — не может считаться оправданием. Пишите больше тестов.

еще рефераты
Еще работы по информатике