Красный, зеленый, рефактор - почему рефакторинг?

Я пытаюсь изучить концепции TDD и модульного тестирования, и я видел мантру: "красный, зеленый, рефактор". Мне интересно, почему вы должны реорганизовать свой код после прохождения тестов?

Это не имеет никакого смысла для меня, потому что если тесты проходят, то почему вы возитесь с кодом? Я также вижу, что TDD-мантры типа "достаточно писать достаточно кода, чтобы пройти тест".

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

EDIT:

Я нашел эту ссылку в другой записи stackoverflow, которая, я думаю, подтверждает единственную причину, по которой я пришел, что исходный код для прохождения теста может быть очень простым, даже жестко запрограммированным: http://blog.extracheese.org/2009/11/how_i_started_tdd.html

Ответ 1

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

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

Ваш вопрос - это перефразирование возраста "если он работает, не исправляйте". Однако, как объясняет Мартин Фаулер в Рефакторинге, код может быть разбит разными способами. Даже если он проходит все тесты, это может быть трудно понять, поэтому его трудно расширить и поддерживать. Более того, если он выглядит неряшливым, будущие программисты будут уделять меньше внимания тому, чтобы держать его в чистоте, поэтому он будет ухудшаться все быстрее и, в конечном счете, превратится в полный недостижимый беспорядок. Чтобы предотвратить это, мы реорганизуем, чтобы всегда держать код в чистоте и порядке как можно больше. Если мы (или наши предшественники) уже позволили ему стать беспорядочным, рефакторинг - это огромные усилия без очевидной непосредственной выгоды для руководства и заинтересованных сторон; таким образом, их вряд ли можно убедить в поддержке широкомасштабного рефакторинга на практике. Поэтому после каждого изменения кода мы реорганизуем небольшие, даже тривиальные шаги.

Ответ 2

Я видел мантру: "красный, зеленый, рефактор".

это не "мантра", это рутина.

Я также вижу, что TDD-мантры типа "достаточно написать достаточно кода, чтобы пройти тест".

Это руководство.

теперь ваш вопрос:

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

Ты почти там. Ключ находится в разделе "Дизайн" TDD. Вы не только кодируете, вы все еще разрабатываете свое решение. Это означает, что точный API не может быть установлен на камне, и ваши тесты могут не отражать окончательный дизайн (потому что он еще не выполнен). В то время как кодирование "достаточно для прохождения теста", вы столкнетесь с некоторыми проблемами, которые могут изменить ваше мнение и управлять дизайном. Только после того, как у вас есть рабочий код, вы сможете его улучшить.

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

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

Ответ 3

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

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

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

Ответ 4

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

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

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

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

Ответ 5

Трудно понять, как скептицизм ОП не оправдан. Рабочий процесс TDD коренится во избежании преждевременных дизайнерских решений путем наложения значительных затрат, если не исключая, кодирования "места штанов", которое может быстро перерасти в необдуманное сафари YAGNI. [1]

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

Кроме того, тесты в TDD должны: a) помочь прояснить требования к дизайну, b) поверхностные проблемы с проектом [2], и c) служить активами проекта, которые фиксируют и документируют усилия, приложенные к определенной истории, таким образом, заменяя собой направленное усилие по рефакторингу для правильно составленного теста не только исключает какую-либо проницательность, которую может дать тест, но также лишает руководство и проектировщиков информации о реальной стоимости реализации конкретной функции. [3]

Соответственно, я хотел бы предположить, что новый контрольный пример, предназначенный для введения в проект дополнительного требования, является надлежащим способом устранения любых предполагаемых недостатков, помимо стилистического изменения в текущем тестируемом коде, и фазы "Рефакторинг", однако. благими намерениями, вопреки этой философии, и на самом деле является приглашением сделать очень преждевременное сафари на дизайн YAGNI, которое TDD должен предотвратить. Я считаю, что версия 3 правил Роберта Мартина согласуется с этой интерпретацией. [4 - вопиющее обращение к власти]


[1] Ранее цитированный http://blog.extracheese.org/2009/11/how_i_started_tdd.html изящно демонстрирует ценность отложенных дизайнерских решений до самого последнего возможного момента. (Хотя, возможно, последовательность Фибоначчи является несколько искусственным примером).

[2] См. Https://blog.thecodewhisperer.com/permalink/how-a-smell-in-the-tests-points-to-a-risk-in-the-design

[3] Добавление "технической" или "всплесковой" истории (запаха или нет) в резерв будет подходящим методом для обеспечения соблюдения формальных процессов и документирования и обоснования усилий по разработке... и если вы не можете убедить Владелец продукта, чтобы добавить его, тогда вы не должны тратить время на это.

[4] http://www.butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd

Ответ 6

Итеративный, эволюционный рефакторинг - хороший подход, но сначала...

Понятия, которые не должны быть недосказанными...

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

Чувствительная зависимость от начальных условий (теория хаоса):

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

Энтропия:

Существует множество определений энтропии; одна из которых я нахожу в Software Engineering: количество энергии в системе, которая не может использоваться для дополнительной работы. Вот почему повторное использование имеет решающее значение. Энтропия встречается в основном с точки зрения дублирования логики и понятности. Кроме того, это тесно связано с эффектом Бабочки (чувствительная зависимость от начальных условий) и Broken Windows - чем больше дублируется логика, тем больше CopyPaste для дополнительных реализаций и составляет более 1 раза на каждую реализацию для поддержки все это.

Переменная амплификация и увлажнение (теория возникновения и сетевая теория):

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

Ключом всего этого является объединить ваши модули в свои собственные дискретные подсистемы и предоставить определенную архитектуру, которая может позволить им общаться - например, посредник. Это приносит коллекцию (развязанного) поведения в систему Bottom-Up, которая затем может сфокусировать свою сложность на компоненте, разработанном именно для него.

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

Ответ 7

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

Ответ 8

Во-первых, спасибо, что заглянули в Test Driven Development. Это потрясающий метод, который может применяться ко многим ситуациям кодирования, которые могут помочь вам разработать отличный код, а также дать вам уверенность в том, что код может и не может сделать.

Если вы посмотрите на подзаголовок на обложке книги Мартина Фаулера "Рефакторинг", он также ответит на ваш вопрос - "Улучшение дизайна существующего кода"

Рефакторинг - это преобразования в ваш код, который не должен изменять поведение программы.

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