1. Не пытайтесь одновременно производить реорганизацию и добавлять функциональные возможности.
2. Перед тем как начинать реорганизацию, убедитесь, что тестирование прошло успешно. Проводите тестирование как можно чаще. В этом случае вы сразу увидите нарушение, которое было вызвано внесенными изменениями.
Автоматическая реорганизация
Исторически сложилось так, что пользователи Smalltalk всегда применяли средство просмотра классов как неотъемлемую часть интегрированной среды разработчика. В отличие от web-браузеров, средства просмотра классов позволяют пользователям перемещаться по иерархиям и методам класса и проверять их.
Обычно средства просмотра классов позволяют редактировать текст программы, создавать новые методы, классы и т. д. Следующей вариацией на эту тему является браузер реорганизации.
Этот браузер может в полуавтоматическом режиме проводить операции, обычные при реорганизации: разбивать длинную подпрограмму на несколько более коротких, автоматически перенося изменения на имена методов и переменных, а также осуществлять операцию «буксировки и перетаскивания», что помогает в перемещении текста программы и т. д.
Во время написания данной книги этой технологии еще предстояло выйти за пределы мира Smalltalk, но скорее всего она начнет меняться с той же скоростью, что и язык Java, – быстро. В то же время исторический браузер реорганизации Smalltalk можно отыскать в Интернете [URL 20].
3. Двигайтесь обдуманно и не спеша: переместите поле из одного класса в другой, объедините два подобных метода в суперкласс. Часто при реорганизации вносится много локальных изменений, которые приводят к серьезным сдвигам. Если вы двигаетесь без спешки и проводите тестирование после каждого шага, вы избежите длительной процедуры отладки.
На данном уровне тестирование будет обсуждаться в разделе «Программа, которую легко тестировать», тестирование на более высоком уровне – в разделе «Безжалостное тестирование»), но мнение г-на Фаулера о тщательном регрессионном тестировании является ключом к надежной реорганизации.
Также весьма полезно удостовериться в том, что серьезные изменения в некоем модуле, такие как изменения его интерфейса или его функциональной возможности неподобающим способом, приведут к нарушению процесса сборки. Это означает, что прежние клиенты этой программы не смогут пройти компиляцию. Тогда вы можете отыскать старых клиентов и внести необходимые изменения, чтобы осовременить их.
Поэтому в следующий раз, когда вам попадется фрагмент программы, который не совсем такой, каким ему надлежит быть, исправьте и его, и все то, что от него зависит. Научитесь управлять этой головной болью: если она досаждает вам сейчас, то потом будет досаждать еще больше, у вас есть шанс устранить ее совсем. Помните уроки, полученные в разделе «Энтропия в программах»: не живите с разбитыми окнами.
Другие разделы, относящиеся к данной теме:
• Мой исходный текст съел кот Мурзик
• Энтропия в программах
• Суп из камней и сварившиеся лягушки
• Пороки дублирования
• Ортогональность
• Программирование в расчете на стечение обстоятельств
• Программа, которую легко тестировать
• Безжалостное тестирование
Упражнения
38. По всей вероятности, за последние годы представленная ниже программа переписывалась несколько раз, но эти изменения никак не способствовали улучшению ее структуры. Проведите ее реорганизацию. (Ответ см. в Приложении В.)
if (state==TEXAS) {
rate=TX.RATE;
amt=base * TX_RATE;
calc=2*basis(amt) + extra(amt)*1.05;
}
else if ((state==OHIO) || (state==MAINE)) {
rate=(state==OHIO) ? OH_RATE : MN_RATE;
amt=base*rate;
calc=2*basis(amt) + extra(amt)*1.05;
if (state==OHIO)
points = 2;
}
else {
rate=1;
amt=base;
calc=2*basis(amt) + extra(amt)*1.05;
}
39. Класс Java, представленный ниже, нуждается в поддержке дополнительных форм. Произведите реорганизацию этого класса, чтобы подготовить его к этим дополнениям. (Ответ см. в Приложении В.)
public class Shape {
public static final int SQUARE = 1;
public static final int CIRCLE = 2;
public static final int RIGHTTRIANGLE = 3;
private int shapeType;
private double size;
public Shape(int shapeType, double size) {
this.shapeType = shapeType;
this.size = size;
}
//… другие методы…
public double area() {
switch (shapeType) {
case SQUARE: return size*size;
case CIRCLE: return Math.PI*size*size/4.0;
case RIGHT TRIANGLE: return size*size/2.0;
}
return 0;
}
40. Данная программа на языке Java представляет собой часть некоего скелета, который будет использоваться во всем вашем проекте. Произведите реорганизацию этой программы, чтобы сделать ее более общей и упростить ее расширение в будущем. (Ответ см. в Приложении В.)
Читать дальше