Электронная библиотека » Джонатан Расмуссон » » онлайн чтение - страница 11


  • Текст добавлен: 13 сентября 2023, 12:34


Автор книги: Джонатан Расмуссон


Жанр: Зарубежная деловая литература, Бизнес-Книги


Возрастные ограничения: +12

сообщить о неприемлемом содержимом

Текущая страница: 11 (всего у книги 13 страниц)

Шрифт:
- 100% +

Часть V
Создание гибкого ПО

Глава 12
Тестирование компонентов: убеждаемся в том, что все работает

Неважно, сколько времени было потрачено на планирование и управление ожиданиями, – гибкие процессы могут работать лишь в том случае, если они опираются на надежные практики разработки программного обеспечения. Некоторые такие практики (например, работа в паре, принятая в экстремальном программировании) вызывают противоречивые отзывы, а другие (такие как автоматическое тестирование компонентов) получили широкое распространение.

В четырех последних главах книги мы поговорим о том, что я считаю элементарными составляющими гибкого программирования:

♦ тестирование компонентов;

♦ рефакторинг;

♦ разработка на основе тестирования;

♦ непрерывная интеграция.

Я просто познакомлю вас с этими концепциями, чтобы вы в достаточной степени понимали механизмы, обеспечивающие работу вашей команды.

Все примеры написаны на языке Microsoft.NET C# (хотя сами концепции применимы к любому языку программирования). Не беспокойтесь, если вы не технарь. Вам все равно не помешает прочитать обо всем этом, и по мере повествования я буду отдельно подчеркивать самые важные места.

Начнем с практики, на которой основана большая часть гибкого программирования, – тщательного и обширного тестирования компонентов.

12.1. Добро пожаловать в Вегас, малыш!

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

Вот первый фрагмент кода, описывающего колоду карт[17]17
  Ссылка для скачивания: http://media.pragprog.com/titles/jtrap/code/tdd/src/Deck.cs.


[Закрыть]
:


public class Deck

{

private readonly IList<Card> cards = new List<Card>();

public Deck()

{

cards.Add(Card.TWO_OF_CLUBS);

cards.Add(Card.THREE_OF_CLUBS);

//… оставшиеся трефы

cards.Add(Card.TWO_OF_DIAMONDS);

cards.Add(Card.THREE_OF_DIAMONDS);

//… оставшиеся бубны

cards.Add(Card.TWO_OF_SPADES);

cards.Add(Card.THREE_OF_SPADES);

//… оставшиеся пики

cards.Add(Card.TWO_OF_HEARTS);

cards.Add(Card.THREE_OF_HEARTS);

//… оставшиеся червы

// джокер

cards.Add(Card.JOKER);

}

Напишите заведомо неуспешный тест перед тем, как исправлять ошибку

Когда вы обнаруживаете в программе ошибку, существует соблазн сразу ее исправить. Не делайте этого. Лучше отследить ошибку, написав заведомо неуспешный тест компонента (failing unit test), и только потом ее исправить. При этом вы:

• понимаете природу ошибки;

• убеждаетесь, что действительно ее исправили;

• удостоверяетесь, что эта ошибка больше никогда не появится в вашей программе.

Наступает время равноправного анализа (peer review). Все, кажется, идет хорошо, и перед самой сдачей продукта отдел контроля качества находит ошибку.

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

Затем, через пару недель, вы получаете от менеджера из отдела контроля качества жесткое письмо, в котором он сообщает вам, что прошлым вечером в программе проявилась серьезная ошибка. Пришлось выплатить несколько десятков тысяч долларов, так как кто-то поместил абстракцию джокера в класс Card!

«Что? – восклицаете вы. – Это невозможно. Я лично исправил эту ошибку две недели назад». Но, разобравшись в проблеме подробнее, вы обнаруживаете, что практикант, работавший летом под вашим руководством, понял вас буквально, когда вы попросили его убедиться, что ваша колода карт ведет себя точно так же, как настоящая бумажная колода, с которой вы попросили сверять программу.

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

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

Что вы ему скажете? Что можете сделать вы (или он), чтобы гарантировать, что ошибка с джокером не вкрадется в базу кода после того, как ее устранят?

В свете всего сказанного давайте рассмотрим самый простой тест компонента.

12.2. Приступаем к тестированию компонентов

Тесты компонентов – это небольшие тесты на уровне метода (method-level tests), которые разработчик пишет всякий раз, когда вносит в программу изменения и проверяет, работает ли программа так, как он задумывал.

Например, мы хотим проверить, на самом ли деле в нашей колоде 52 карты (а не 53). Можно написать тест компонента, который будет выглядеть примерно так[18]18
  Ссылка для скачивания: http://media.pragprog.com/titles/jtrap/code/tdd/test/DeckTest.cs.


[Закрыть]
:

[TestFixture]

public class DeckTest

{

[Test]

public void Verify_deck_contains_52_cards()

{

var deck = new Deck();

Assert.AreEqual(52, deck.Count());

}

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

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

Тесты компонентов просто неоценимы, так как при автоматизации и упрощении тестирования мы можем проводить тест всякий раз, когда вносим изменения в программу. В итоге мы сразу же узнаем, не сломалось ли что-нибудь (подробнее об этом читайте в главе 15).

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

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

♦ Вы мгновенно узнаете, какова ситуация. Если вы внесли изменения в свой код, а тестирование компонента не проходит, вы узнаете об этом сразу (а не через три недели после того, как программа начнет использоваться на практике).

Тестируйте все, что может сломаться

В экстремальном программировании есть постулат «тестируй все, что может сломаться». Это напоминание разработчикам: если им начинает казаться, что есть определенная вероятность сбоя в системе, то вызывающий опасения фрагмент системы нужно проверить автоматическим тестом.

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

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

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

♦ Значительно сокращается длительность отладки. Когда тест компонента не удается, вы знаете наверняка, где искать проблему. Больше не нужно запускать отладчик и пробираться сквозь сотни строк кода, отыскивая фрагмент, вызывающий сбои. Тесты компонентов подобны лучу лазера, прорезающему туман, они избавляют вас от долгого поиска проблемы.

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

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


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



Предупреждаю: вам придется сталкиваться со случаями, когда написать автоматизированный тест непросто. Например, сложно написать тест, проверяющий, можем ли мы перетасовать колоду карт (поскольку результат теста является случайным и всякий раз изменяется). Кроме того, тестирование конкурентных и многопоточных приложений, мягко говоря, может представлять проблему.

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

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

В таком случае пусть все остается как есть. Признайте, что все протестировать не удастся. Убедитесь, что вы провели по-настоящему качественное ручное и исследовательское тестирование, и двигайтесь дальше.

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

Можете также почитать книгу Майкла Фэзерса Working Effectively with Legacy Code [Fea04], в которой содержится масса бесценных советов о том, как работать с устаревшим кодом и легко вносить в него изменения.



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



Если ваш тест выглядит примерно так, вы на правильном пути. Нужно протестировать все, что теоретически может сломаться либо сработать неправильно. Сделайте глубокий вдох и выдох и напишите тест[19]19
  Ссылка для скачивания: http://media.pragprog.com/titles/jtrap/code/tdd/test/DeckTest.cs.


[Закрыть]
.

[TestFixture]

public class DeckTest2

{

[Test]

public void Verify_deck_contains_52_cards()

{

var deck = new Deck();

Assert.AreEqual(52, deck.Count());

}

[Test]

public void Verify_deck_contains_thirteen_cards_for_each_suit()

{

var Deck = new Deck();

Assert.AreEqual(13, Deck.NumberOfHearts());

Assert.AreEqual(13, Deck.NumberOfClubs());

Assert.AreEqual(13, Deck.NumberOfDiamonds());

Assert.AreEqual(13, Deck.NumberOfSpades());

}

[Test]

public void Verify_deck_contains_no_joker()

{

var Deck = new Deck();

Assert.IsFalse(Deck.Contains(Card.JOKER));

}

[Test]

public void Check_every_card_in_the_deck()

{

var Deck = new Deck();

Assert.IsTrue(Deck.Contains(Card.TWO_OF_CLUBS));

Assert.IsTrue(Deck.Contains(Card.TWO_OF_DIAMONDS));

Assert.IsTrue(Deck.Contains(Card.TWO_OF_HEARTS));

Assert.IsTrue(Deck.Contains(Card.TWO_OF_SPADES));

Assert.IsTrue(Deck.Contains(Card.THREE_OF_CLUBS));

Assert.IsTrue(Deck.Contains(Card.THREE_OF_DIAMONDS));

Assert.IsTrue(Deck.Contains(Card.THREE_OF_HEARTS));

Assert.IsTrue(Deck.Contains(Card.THREE_OF_SPADES));

// остальные

}


Гуманитариям скажу, что в этом фрагменте кода выполняется тестирование компонентов, позволяющее решить следующие задачи:

♦ проверить, на самом ли деле в колоде содержится 13 карт каждой масти;

убедиться, что в колоде нет джокеров (присутствие джокеров – это ошибка, замеченная нами ранее);

♦ проверить каждую карту из колоды (всего их 52).


Где подробнее изучить эту тему

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

Любому разработчику, желающему понять принципы этого метода, рекомендую для начала познакомиться с классической статьей Кеннета Бека[20]20
  http://junit.sourceforge.net/doc/testinfected/testing.htm.


[Закрыть]
.

Кроме того, отсылаю вас к книгам Pragmatic Unit Testing in C# with NUnit [HT04] и Pragmatic Unit Testing in Java with JUnit [HT03].



УЧЕНИК: Мастер, а разве тестирование компонентов не замедляет работу команды? Я имею в виду, что нам ведь требуется писать вдвое больше кода.

МАСТЕР: Если бы программирование сводилось к набору кода на клавиатуре, то ты был бы прав. Но тесты компонентов нужны для того, чтобы гарантировать следующее: по мере того как мы вносим в программу изменения, все в целом по-прежнему работает именно так, как мы того ожидаем. И мы экономим время, избавляя себя от регрессивного тестирования всей системы при внесении каждого изменения.

ВОПРОС: Да, Мастер. Но не делают ли тесты компонентов код непрочным? Как быть уверенным в том, что тесты компонентов не будут давать сбои всякий раз, когда я изменяю свой код?

ОТВЕТ: Действительно, существует возможность написать некачественный тест, основанный на жестко закодированных данных, характеризующийся тесным связыванием и плохой структурой, но когда ты привыкнешь руководствоваться тестированием при разработке (см. главу 14), то обнаружишь, что твои тесты не дают сбоев и действительно оптимизируют общую структуру приложения. Самые современные интегрированные среды разработки (integrated development environments, IDE) также облегчают работу с изменениями и тестирование кода. Можно переименовать метод во всей базе кода, просто нажав несколько клавиш. Таким образом, тестирование и написание кода идут нога в ногу.

ВОПРОС: Должны ли я и моя команда стремиться к стопроцентному тестированию компонентов?

ОТВЕТ: Нет. Основная цель тестирования компонентов заключается не в полном охвате. Такое тестирование обеспечивает команде достаточную уверенность в том, что программа готова к реальному использованию.

ВОПРОС: В таком случае насколько полное тестирование компонентов должны обеспечивать я и моя команда?

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


Что дальше?

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

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

Эта важнейшая практика называется рефакторингом.

Глава 13
Рефакторинг: погашение технического долга

Подобно дому, купленному в ипотеку, любая программа имеет долги, которые постоянно приходится отдавать.

В этой главе мы рассмотрим практику рефакторинга и увидим, как, регулярно отдавая технический долг, мы поддерживаем программу легкой и гибкой и в этом «доме» становится приятно жить и работать.

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

Теперь давайте окунемся в мир рефакторинга и посмотрим, что требуется, чтобы «развернуться на пятачке».

13.1. Как «развернуться на пятачке»

Кажется, конкуренты только что выпустили «детскую» версию создаваемого вашей компанией онлайн-симулятора игры блек-джек. И эта программа продается на ура.

Чтобы ответить на этот выпад со сторон конкурентов, вы и команда немедленно беретесь за работу, и какое-то время дела идут нормально. Но затем начинается что-то странное. То, что на первый взгляд не составляло никакого труда, теперь кажется по-настоящему сложным.

Значительная часть кода попала в базу путем копирования и вставки. Таким образом, вносить изменения становится сложно, так как при каждом исправлении в одном месте его нужно продублировать в десятках других мест.

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

Вот пример такого проблемного кода[21]21
  Ссылка для скачивания: http://media.pragprog.com/titles/jtrap/code/Refactoring/src/BlackJack.cs.


[Закрыть]
:

public bool DealerWins(Hand hand1)

{

var h1 = hand1; int sum1 =0;

foreach (var c in h1)

{

sum1 += Value(c.Value, h1);

}

var h2 = DealerManager.Hand; int sum2 =0;

foreach (var c in h2)

{

sum2 += Value(c.Value, h2);

}

if (sum2>=sum1)

{

return true;

}

else

return false;

return false;

}


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

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

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

Что же пошло не так? Может ли код, который был красивым, простым и легким в использовании, превратиться в нечто настолько громоздкое, уродливое и неудобное?

Давайте рассмотрим феномен, который называется техническим долгом (technical debt).

13.2. Технический долг

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

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


Технический долг – это не просто код

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

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

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

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

В гибкой разработке такая методика называется рефакторингом.

13.3. Погашение долга с помощью рефакторинга

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

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

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



Обратите внимание на следующие фрагменты кода и задайте себе вопрос: какой из них проще читается и более понятен?



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

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



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


Занимайтесь рефакторингом на совесть и непрерывно

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

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

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



Но хватит теории. Давайте напряжем мозг и опробуем рефакторинг сами.



Какие изменения можно внести в «детскую» версию игры блек-джек, которая была рассмотрена в начале этой главы?



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



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



Вы только посмотрите! После извлечения метода GetPlayerHandValue наш метод DealerWins сократился всего до трех строк кода. Теперь хорошо видно, какие функции выполняются в этом методе. Читать его стало гораздо проще. А если мы захотим узнать, как вычисляются карты, попадающие на руки пользователю, эта информация всегда найдется в методе GetPlayerHandValue.


Код совершенно ясен. Но если есть желание усовершенствовать его еще на порядок, потребуется сделать нечто подобное:



Итак, в процессе рефакторинга мы выполнили всего три простые операции:

♦ переименовали переменные и методы;

♦ встроили переменную;

♦ извлекли метод,

но при этом значительно облегчили чтение и поддержку кода.

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

Чтобы не тратить бесконечные часы, пытаясь понять, что делает этот код, можно прямо приступать к работе и вносить изменения.

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


Дурная слава рефакторинга

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

Неудивительно, что менеджеры не долго думая стали презирать понятие «рефакторинг» (для них он сводился к переработке старого без добавления чего-либо нового), и вскоре сверху стали приходить приказы бросить заниматься рефакторингом.

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


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

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

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



Сложнее справляться с многочисленными субъективными ситуациями, с которыми может столкнуться наш брат-наемник. Но затраты на внесение таких изменений могут сторицей окупиться на дальнейшем пути.

Если вы планируете крупный рефакторинг, относящийся к такой «серой» области, ответьте на два вопроса, прежде чем приниматься за него.

♦ Близок ли конец проекта?

♦ Можно ли сделать необходимые изменения постепенно?

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

В постепенном рефакторинге клиента убедить проще, так как эта работа не будет отбирать у вас и у команды все рабочее время. Клиент будет радоваться новым функциям своего приложения, а вы тем временем будете понемногу выделять время на рефакторинг.

Действуйте в зависимости от ситуации. Посмотрите, что нужно сделать. И если считаете, что рефакторинг сэкономит вам немало времени, то начинайте его выполнять – возможно, вы действительно не пожалеете.


Где подробнее изучить эту тему

Мы лишь слегка коснулись очень важной темы рефакторинга. И в этой небольшой главе, конечно, не рассмотрены все вопросы, заслуживающие внимания.

По данной теме вам действительно стоит прочитать книгу Мартина Фаулера Refactoring: Improving the Design of Existing Code [FBB+99].

Другая стоящая книга принадлежит перу Майкла Фэзерса и называется Working Effectively with Legacy Code [Fea04].



УЧЕНИК: Мастер, бывают ли случаи, когда вообще не требуется заниматься рефакторингом кода?

МАСТЕР: Не считая масштабных серий рефакторинга, о которых мы говорили выше, – нет. Обычно рефакторинг кода нужно делать всякий раз, внося изменения в программу.

УЧЕНИК: Нужно ли что-то исправить, если мне регулярно приходится тратить целую итерацию на один только рефакторинг?

МАСТЕР: Нет. Просто такая ситуация неидеальна. Старайся выполнять рефакторинг небольшими порциями, и тогда не придется тратить на эту работу много времени. К тому же без неудач не обойтись, и иногда тебе потребуются крупные изменения. Но на них нужно идти только в крайнем случае. Не стоит заниматься ими регулярно.


Что дальше?

Мы хорошо поработали. Тестирование компонентов и рефакторинг вместе образуют сильнейшую связку, которой не сможет противостоять большинство плохо сработанных программ.

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

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


Страницы книги >> Предыдущая | 1 2 3 4 5 6 7 8 9 10 11 12 13 | Следующая
  • 0 Оценок: 0

Правообладателям!

Это произведение, предположительно, находится в статусе 'public domain'. Если это не так и размещение материала нарушает чьи-либо права, то сообщите нам об этом.


Популярные книги за неделю


Рекомендации