Влияние TDD на дизайн кода
От: umnik  
Дата: 27.12.04 09:23
Оценка:
Попробовал TDD в своей последней программе и заметил, что очень сильно поменялся не только стиль работы, но и дизайн кода.
Для того, чтобы корректно писать unit-тесты, приходится дробить код на более мелкие классы с четко выделенной функциональностью.

Например, класс, работающий с внешним объектом пришлось поделить на ЧЕТЫРЕ сущности — класс для обработки поступающих данных, интерфейс для чтения данных, класс от него порожденный, непосредственно читающий данные извне, и fake-объект порожденный о этого же интерфейса для тестирования корректной работы первого класса.
С другим кодом ситуация похожая — в результате эксперимента кол-во классов в системе возросло раза в три (качество при этом, кстати, заметно повысилось, да и собственно процесс был затеян для того, чтобы сократить время на общение с заказчиком по поводу возникших ошибок)

Это нормально? Так и должно быть? А как же принцип "не плоди сущностей без надобности"?
Может ли многоуважаемый all поделиться своими наблюдениями в этой области?
Re: Влияние TDD на дизайн кода
От: kavlad Россия http://www.wavesoft.ru
Дата: 27.12.04 09:55
Оценка:
Здравствуйте, umnik, Вы писали:

U>Это нормально? Так и должно быть?


По идее, да.

U>А как же принцип "не плоди сущностей без надобности"?


Я не уверен, что этой самой надобности "нет".
Такое разбиение классов на более мелкие обычно приводит либо к "расползанию" системы (ее становится трудно модифицировать, если классы сильно связаны друг с другом), либо к высокой гибкости (тогда модифицировать становится легко).
Т.е. на самом деле был проведен рефакторинг кода А, ИМХО, рефакторинг и TDD — два конца одной палки.

U>Может ли многоуважаемый all поделиться своими наблюдениями в этой области?


ИМХО, можно классы и не дробить. Просто тесты тогда будут совсем другие, возможно менее "корректные"
... По ушам лупит Obituary — By The Light
Re[2]: Влияние TDD на дизайн кода
От: umnik  
Дата: 27.12.04 10:07
Оценка:
U>>А как же принцип "не плоди сущностей без надобности"?
K>Я не уверен, что этой самой надобности "нет".
надобностью можно назвать то, что "по-другому тестов не напишешь"

K>Такое разбиение классов на более мелкие обычно приводит либо к "расползанию" системы (ее становится трудно модифицировать, если классы сильно связаны друг с другом), либо к высокой гибкости (тогда модифицировать становится легко).

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

вообще, получившийся код у меня вызвал ассоциации с конструктором:
было — взяли железную болванку, обработали ее напильником, в результате получилась единая неделимая монолитная хрень, заточенная под конкретную задачу, в которой кроме как напильником ничего не изменишь
стало — взяли и наклепали много мелких деталек, пошлифовали их, проверили винтики-болтики на совместимость (подходил ли размер, правильная ли резьба), шестеренки на смазанность, потом все это вместе собрали, в результате получилась сложная хрень из множества компонент, которую, правда, легко переделать
Re: Влияние TDD на дизайн кода
От: krulez  
Дата: 09.01.05 14:49
Оценка:
В XP есть правило, что надо использовать самое простое решение. То что
ты описал под этот подход слабо походит. Можешь поподробней рассказать о
своей программе.

По моим наблюдениям, код который я пишу Test-First получается короче и
проще, чем тот который я пишу без тестов.

Вообще почитай книжку Кента Бека про TDD и многое прояснится.

umnik wrote:
>
> From: *umnik* </Users/Profile.aspx?uid=12381> </search/?group=72>
> </Users/Private/AddFav.aspx?mid=966129> <NewMsg.aspx?gid=72>
> <NewMsg.aspx?mid=966129> <?mid=966129> <Message.aspx?mid=966129#966129>
> <NewMsg.aspx?mid=966129&edit=1> <Private/Self.aspx?mid=966129>
>
> Попробовал TDD в своей последней программе и заметил, что очень сильно
> поменялся не только стиль работы, но и дизайн кода.
> Для того, чтобы корректно писать unit-тесты, приходится дробить код на
> более мелкие классы с четко выделенной функциональностью.
>
> Например, класс, работающий с внешним объектом пришлось поделить на
> ЧЕТЫРЕ сущности — класс для обработки поступающих данных, интерфейс для
> чтения данных, класс от него порожденный, непосредственно читающий
> данные извне, и fake-объект порожденный о этого же интерфейса для
> тестирования корректной работы первого класса.
> С другим кодом ситуация похожая — в результате эксперимента кол-во
> классов в системе возросло раза в три (качество при этом, кстати,
> заметно повысилось, да и собственно процесс был затеян для того, чтобы
> сократить время на общение с заказчиком по поводу возникших ошибок)
>
> Это нормально? Так и должно быть? А как же принцип "не плоди сущностей
> без надобности"?
> Может ли многоуважаемый all поделиться своими наблюдениями в этой области?
> Влияние TDD на дизайн кода <?mid=966129> Оценить
> <RateList.aspx?mid=966129> <Private/Rate.aspx?mid=966129&rate=-3>
> <Private/Rate.aspx?mid=966129&rate=1>
> <Private/Rate.aspx?mid=966129&rate=2>
> <Private/Rate.aspx?mid=966129&rate=3>
> <Private/Rate.aspx?mid=966129&rate=-1>
> <Private/Rate.aspx?mid=966129&rate=-2>
> <Private/Rate.aspx?mid=966129&rate=-4>
> <Private/Rate.aspx?mid=966129&rate=0>
>
Posted via RSDN NNTP Server 1.9
Re[2]: Влияние TDD на дизайн кода
От: Александр Игрушкин  
Дата: 10.01.05 06:52
Оценка:
Здравствуйте, krulez, Вы писали:

K>В XP есть правило, что надо использовать самое простое решение. То что

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

class DataProcessor
{
public:
DataProcessor( IDataReader* reader );

void DoProcessData()
{
Data* data = reader.ReadData();
ProcessData(data);
}

SomeInternalStatistics GetStatistics();
};

class IDataReader
{
public:
virtual Data* ReadData() = 0;
};

и писать две реализации для IDataReader: для реальной работы и для тестирования, т.е.
class DeviceDataReader : public IDataReader
{
...
}

class FakeDataReader :public IDataReader //(вариант FileDataReader)
{
...
};

Соответственно в unit-тестах я делаю
DataProcessor* proc = new DataProcessor( new FakeDataReader() );
прогоняю через него данные и проверяю получившуюся статистику.


K>Вообще почитай книжку Кента Бека про TDD и многое прояснится.

читал
не помогает
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.