Делаем TDD привычкой: проблемы и внедрение

Автор оригинала: Mark Levison
  • Перевод
imageОт переводчика. На Хабре довольно много статей, посвященных TDD. Но к сожалению в них нет подробной информации о том как внедрять TDD комплексно, на уровне компании. Как мне показалось, данная статья дает на это ответ и если вы поставили перед собой такую цель, то эта статья может вам пригодиться.

Я столкнулся с командами в нашей организации, которые пытаются внедрить Test Driven Development (TDD).Иногда одному или двум разработчикам удается применить его без посторонней помощи, но у большинства этого не выходит. Чтобы лучше понять проблему я провел опрос среди членов команды и обнаружили, что даже после обучения еще многое предстоит сделать. Эта стратегия была разработана, чтобы помочь любому внедрить TDD в организации, хотя некоторые из идей применимы лишь для средних и крупных компаний.

Мое исследование членов команды (все они прошли обучение) показало следующие проблемы:
  • Люди с трудом использубт TDD сам по себе, когда они не имеют большого опыта работы с ним.
  • В обучение TDD используются упрощенные примеры, в отличие от реальных систем.
  • Требуется больше времени, чтобы экспериментировать и пробовать без обычного давления со стороны менеджмента, который требует выпускать ПО регулярно.
  • Существуют языки, используемые в реальном мире, такие как Visual Basic и JavaScript, которые никогда не используются в качестве примеров.
  • Типичный проект полон унаследованного кода, при этом не было объяснено, как улучшить этот код.
  • И как всегда нет времени на учебу — нужно выпускать продукт.


Основные проблемы

Исходя их этих симптомов, что же является основными проблемами?

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

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

Обучение в классах страдает от двух ключевых проблем: примеры слишком просты и не связаны с реальными проблемами, и почти нет шансов попробовать это на практике.

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

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

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

И наконец: унаследованный код делает и без того трудную задачу сложнее в сотни раз. Разработчики справедливо задают вопрос: «Как я могу протестировать эти тесно связанные объектов? Этот код сложный, как я могу проверить этот алгоритм? „

Один из подходов

Что же может сработать? Предыдущие подходов страдают от двух ключевых проблем: отсутствием глубины и общения. Полная стратегия содержит в себе комбинацию подходов.

  • Обучение в классах — Разработчикам нужно введение в TDD, и занятия в классе по-прежнему является лучшим вариантом для большинства людей.Хитрость заключается в том, чтобы понять, что обучение само по себе не приведет людей к TDD.
  • Online Training — это поможет закрепить основные идеи.Кстати, если и есть необязательный шаг в ходе обучения, то это он и есть.
  • Терпение — это займет больше времени, чем вы планировали.
  • Метрики — с помощью инструментов покрытия кода (например, Emma, Cobetura, NCover, ...) и объяснения членам команды, что измерение будет лишь одним способом сказать, что дела вещи пошли лучше или хуже.Очевидно, что это не измеряет качество тестирования и результат должны быть приняты с недоверием.
  • Внушать гордость — Разработчики должны знать, как выглядит чистый и простой код и тесты, и они должны чувствовать, что это стоит того, чтобы напрягаться. Боб Мартин только что написал книгу под названием “Чистый код», которая на хорошо про это рассказывает.
  • Менеджмент — Разработчикам нужно четкое заявление от руководства, что они понимают, что переход к TDD потребует времени и замедлит команду. Им нужно, чтобы было ясно, что ценится качество по сравнению со скоростью и накоплением технических долга. Большинство разработчиков находятся под давлением, чтобы производить, производить и производить «полезный» код.Управленцам, вероятно, придется повторять это утверждение более чем один раз. Чем выше уровень в организации, от которого это заявление исходит, тем больше люди будут слушать.
  • Парное программирование — если вы застряли и не знаете, куда идти дальше партнер может часто помочь, даже работы с другим новичком может быть хорошим началом.
  • Сообщество — Создание сообщества в вашей организацией (или городе) с целью обмена опытом.Место для общения с другими людьми, которые учатся применять TDD, учатся друг у друга чужим успехи и ошибки.Место, чтобы помочь вырасти культуру необходимую для TDD. Возможность поделиться новыми идеями.
  • Coding Dojo — Место для практики решения небольшой проблемы вместе.Это безопасная среда совместной работы с акцентом на изучение проблемы в группе и не обязательно ее решения.
  • Чтение семинаров — группа не более восьми человек собираются на регулярной основе, чтобы обсудить главу из книги.
  • Периодические визиты тренера — могут помочь команде вернуться на правильный путь, когда они сошли с пути и прекратили практиковать TDD. В этих случаях, простая паре с одним или двумя людьми может помочь вновь заразить всю команду.

В основе этого плана лежит: создание постоянного общения и расширения сотрудничества вокруг TDD. Три из этих стратегий сосредоточены в этой области: парное программирование, Coding Dojo и чтения семинаров.

Coding Dojo

Coding Dojo (с помощью формата Рандори) является мероприятием, где небольшая группа людей (не более 15), решает задачи с использованием TDD (адаптировано из Danilo Sato):

  • Работа выполняется на одном компьютере с проектором
  • Кодирование выполняется в парах
  • Один из членов пары переключается каждые 5-10 минут (у нас все отлично сработало для 7 минут).
  • Разработчики должны объяснять, что они делают, так чтобы зрители понимают, что происходит «на клавиатуре».
  • Зрители должны комментировать только дизайн, в случае когда тесты пройдены чисто.Когда тест завален, они должны задавать вопросы.
  • Если аудитория находится в замешательстве, то работа останавливается и разработчики должны объяснить, что происходит.

Из опыта я рекомендую вам выбрать для начала очень небольшие задачи.

Чтение семинаров

Для чтения семинаров существует целый ряд книг:


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

Преимущества совместного обучения

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

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

Делаем TDD привычкой

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

  • Терпение, практика, глубина
  • Поддержка менеджмента
  • Многосторонний подход
  • Разработчики помогают разработчикам
ScrumTrek
0,00
Мы помогаем компаниям стать крутыми!
Поделиться публикацией
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 28

    +4
    Семинары с пиццей — это всегда хорошо :)
      +1
      Один из способов внедрения TDD в команду это техника «infection by example».
      http://wiki.agiledev.ru/doku.php?id=tdd:tdd_into_command тут хорошо описано
        0
        Статья интересная, но есть одно замечание — почему книга Kent Beck's Test Driven Development: By Example отнесена к .NET? В ней два примера, один на Java, другой на Python
          +1
          В книге описывается хорошо сам принцип TDD на примерах, а в качестве тестового фреймворка используют xUnit, что не вызывает сложности в проецировании на NUnit
            0
            Согласен что для .net наиболее уместна «The Art of Unit Testing» от Roy Osherove
            0
            Кстати, на правах пиара — сейчас развивается подобное русскоязычное сообщество Russian Software Craftsmanship Community. Мы проводим два типа встреч — XP Battle (ежемесячные встречи с целью изучения одной из инженерных практик) и Code&Coffee (утренние встречи с целью покодить в свободной обстановке). Так же зову всех в группу на FaceBook. В планах есть и CodingDojo, и StudyGroup для изучения книг и многое другое.
              0
              Кстати, было бы интересно услышать мнение людей, минусующих статья — что их не устроило?
                +1
                Я не ставил минуса, но близок к этому. Дело в том что не совсем понимаю, а что нового в этой статье? На хабре как минимум 5 статей по поводу TDD. Хаброюзеры чего только не обсудили в комментариях к ним. Каких только статей и книг друг другу не на советовали. Что конкретно еще не знает хабр? Я бы хотел это услышать в первых словах перед статьей, к примеру Вы могли бы предварить словами: «От переводчика: на хабре еще не было ...» или что-то в этом духе.
                  +1
                  Спасибо, обновил пост.
                    +2
                    Кстати, рекомендую:
                    experience.openquality.ru/alexey-pakhunov-interview/. Очень грамотный текст про TDD.

                    От себя, мой опыт юзания TDD:
                    1) Оно требует жертв. Нет возможности один раз написал и забыл. Написал новый код, поменял интерфейс, поменял логику — Поменялись тесты.
                    2) Тесты портят настроение, падает уровень азарта, который так необходим при разработки. Т.е. после запуска тестов, когда запилил новую фичу можно увидеть что-то красное и как вывод вместо прилива радости о запиливании новой фичи приходится фиксить, пока еще помнишь что и как работает.
                    3) Тесты приходится пересматривать, т.к. их главная характеристика — скорость работы. Если будет слишком мало, можно чтото пропустить, а если много будет медленно работать. Т.е. к временным затратам в п.1 еще + постоянный обзор имеющихся тестов

                    Плюсы которые получил:
                    1) Более менее уверен в том что сделал хорошо. Однажды пойманная когда-то бага, сейчас проверена и если тест зеленый, то я ее не повторил
                    2) Проектируя сперва тест, чаще понимаю что и как должно в конечном итоге выглядеть. Достаточно часто вижу «чтото я лажу напридумывал»
                    3) Если питон-скрипт показывает мне о том, что все плохо, то юнит-тест указывает достаточно часто функцию где конкретно. Экономлю время на поиске баги.

                    Нерешенные мною вопросы и которые хотел бы узнать:
                    1) В виду того что я работаю с файлами и достаточно часто возникает ситуация, когда мне надо подавать разные файлы, то что лучше сделать: 1.1. один файл — один тест или 1.2. setUp должен «кушать» объект конфигурации, которую можно задавать во внешнем ini-файле? Если второе, то это мне кажется нарушает концепцию юнит-тестов
                      0
                      Первый вариант более правильный, имхо, так как если что, неактуальный тест проще удалить и написать заново, чем пытаться что-то разобрать в связке unit-тестов. По поводу второго варианта — есть возможность задавать данные не из внешнего файла, а из кода; наглядный пример — TestFabric в TestNG для Java. Думаю что-то похожее есть, я думаю, и для других фреймворков/языков.

                      P.S.: мое имхо, если unit-тест, особенно написанный в процессе TDD, работает с файлами, то это уже не unit-тест, а интеграционный. По-крайне мере я это видел в ряде литературы.

                      P.P.S.: за ссылку спасибо, интересно!
                        +1
                        Ппо миинус номер один: время потраченное на тдд возвращается сторицей. Я заметил, что все чаще и чаще код начинает работаьь сразу. Все чаще и чаще рефакторнги в 1000 строк до 300 не наносят вреда информационной системе в целом. Т.о. сейчас, потратив два часа на тесты, на выходе, получаю 5 часов экономии на отладке, и это при том что писатель тестов из меня, скажем, так себе. Это же распространяется на уже готовый код…
                        Про минус номер два: гораздо больше падает настроение после того как приходит шеф и негодует
                        При минус номер три: если среда разработки интерпретируема, то тесты могут проходить в режиме (autotest). И, как показывает моя практика, после очередного перекура, или после обеда, или, в тяжелых случаях, к утру, тесты догоняют внесенные изменения в покрытый тестами код. Т.о. мне удалось добиться ситуации, когда я пишу и никого неттрогаю, а оно тестируется помигивая push-уведомлениями.
                          +1
                          А я и не говорил, что это минусы. Мною было написано «мой опыт». Написал лишь то, что нужно учитывать при написании тестов, а то очень многие думают что все дается бесплатно или требует только вложения времени при одноразовом написании тестов.
                            0
                            Наверное только дети думают все дается бесплатно.
                              0
                              Нет, даже начинающие юзать юнит-тесты это могут делать. К примеру, когда я только начал использовать эту методику я писал почти на каждый метод любого класса по 1-2 хорошему случаю и по 5 с ошибками. Это было излишне. Потом пришло понимание как улучшить, а потом что нужно, а что нет и какие задавать себе вопросы перед написанием юнит-теста )
                                0
                                Так этот промах не связан с мнимой бесплатностью тестов. Вы говорите в принципе о том, что не нужно производить действие ради действия. Этот лозунг применим почти везде, не считая некоторых буддистских практик :) Почему излишне писать по 7 тестов на «почти каждый метод» тоже не объясняете. Почему же это излишне? У меня к одному методу написано более 40 тестов, но есть причины не считать это излишним. Практика написания тестов сложна, нужно чтобы пришло понимание почему, зачем и как пишутся тесты. Или почему в отдельных случаях тесты не пишутся совсем. и дело здесь вовсе не в стоимости владения тестами. А ваши пространные комментарии даже меня вводят в заблуждение.
                                  +1
                                  >>действие ради действия
                                  Оно может возникать само собой, т.к. разрабатывая класс, метод можно быть уверенным что пишешь правильно и он не поменяется поэтому надо затестировать. Отсюда вывод: «чем больше тестов, тем больше уверенность что не пропустишь багу».

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

                                  В задачу разработчика не входит протестировать абсолютно весь свой результат, ведь для этого есть выделенные тестировщики. Однако ему самому же и выгодно создать тесты там, где они подскажут в след.раз «Где же у него ошибка?» или «Где и что сломалось?».
                                  Поэтому основной навык при использовании юнит-тестов это суметь получить достаточно адекватные ответы на вопросы «Что нужно тестировать, а что нет?» и «Согласуется ли с требованием, задачей каждый написанный мною метод при решении задачи?»

                                  Когда начинаешь использовать юнит-тестирования, то культуры и дисциплины их использования почти на нуле. Все приходит с практикой. Сейчас мое видение такое: «Если разработан метод являющийся точкой входа в модуль\библиотеку нужно написать тесты. 1 в случае правильного использования и по одному на каждый вид ошибки о которой он сигнализирует, ведь отрицательный результат тоже результат. Если это внутренний инструмент используемый в методе первого типа, то нужно обязательно поставить assert хотя бы уровня debug-сборки».
                                    0
                                    Ну, во первых, если вы думаете о том, нужно ли тестировать тот или иной метод, то это уже не тдд. С юнит-тестированием все относительно просто — не нужно тестирвать очевидные вещи.

                                    Разработчику нужно всячески избегать ситуаций с компромисами. Разработчику нужно выкатить качественный результат в разумный срок. Все остальное от лукавого!

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

                                    На мой взглят юнит-тесты выполняют несколько другие функции. Во первых, метод будет производить именно те вещи которые вам необходимы. Во вторых, изменение конкретного метода не нарушит работу всей системы. Но тесты никак не скажут вам, согласуется ли метод с задачей, например потому, что у вас и у заказчика может быть разное видение задачи и соотвественно решения. Но у ваших тестов и вашего кода видение решения будет согласовано с вашим всегда. Иначе — вы шизофреник, и юниты вам не помогут :)
                    0
                    За свою полезность статья заслуживает плюс, но качество перевода и масса опечаток требуют минуса. Так что я лично воздержусь от оценки.
                    0
                    Так ведь подмена понятий!

                    Из всех, так называемых, преимуществ ТДД (из ссылки в статье) кое-каким преимуществом является только первое. С оговоркой, — «в некоторых случаях». Остальные преимущества являются преимуществами использования юнит-тестирования в общем (с этим уже трудно спорить) и к собственно ТДД имеют довольно косвенное отношение.

                    Таким образом, вы доказали преимущества использования юнит-тестирования, но необходимость внедрения обязательного ТДД лично мне, по-прежнему, кажется более чем сомнительной.
                      0
                      Суть данного поста не сводилась к описанию пользы от TDD, я только хотел передать мысль о том, как его внедрять. Сами преимущества описаны по ссылке.
                      Ключевые из них, на мой взгляд:
                      • Когда пишешь тест в начале, думаешь о том, как написать правильный код
                      • Детальная документация кода
                      • Эволюционный и адаптивный дизайн

                        0
                        Ну, у вас же написано, что преимущества ТДД якобы очевидны и в качестве «доказательства» дана вот эта самая ссылка, описывающая преимущества. Ну, так я и говорю, что из этих преимуществ очевидно только одно — иногда подход «тесты вперёд» позволяют написать правильный код (хотя чаще просто сносно тестируемый). Остальные относятся к использованию тестов вообще, а не практике ТДД в целом.
                          0
                          Подход «тесты вперед» всегда позволяет писать правильный код и при этом только минимальное количество. Эволюционный и адаптивный дизайн тоже возникает только при TDD. Детальная документация кода возникает когда тестов много — это раз, и когда в тестах проверяется только нужное — это два. Это тоже возможно только когда они появляются в ходе TDD.
                          И да, TDD это не юнит-тестирование, это дизайн кода через тесты.
                            0
                            >Подход «тесты вперед» всегда позволяет писать правильный код

                            «правильный» только с точки зрения юнит-тестирования

                            >Эволюционный и адаптивный дизайн тоже возникает только при TDD

                            Ого! Сильное заявление! Так таки и «только»? А доказать?

                            >Детальная документация кода возникает когда тестов много — это раз, и когда в тестах проверяется только нужное — это два

                            «Детальная документация» в виде юнит-тестов — это не документация. Опять подмена понятий.

                            >Это тоже возможно только

                            Опять только? А, по-моему, чушь. Как минимум, существует контрактное программирование, которое большинство этих ваших задач (правильный код, Эволюционный и адаптивный дизайн, Детальная документация!) позволяет выполнить куда лучше, нежели TDD. Да, с TDD тоже можно, но это ведь инструмент для другого, а гвозди лучше забивать молотком, чем отвётркой, хотя отвёрткой тоже можно, конечно, но… хм… зачем? :)

                            >И да, TDD это не юнит-тестирование

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

                              Вообще, с TDD такая же история как с Agile вцелом, каждый понимает его по своему с налета, не пробую посмотреть по сторонам и поучиться у других. Жаль(
                                0
                                >потому что оно является следующим этапом программирования по контракту

                                Хи-хи-хи. «Даже» BDD является следующим этапом TDD (особенно по части документирования кода — не пожелаю даже и врагу «документацию» в виде тестов и если дело действительно настолько катастрофично сначала всё-равно буду читать непосредственно код). Контрактное программирование не имеет непосредственного отношения наследования к обоим, но по многим критериям превосходит многие преимущества и того и другого.

                                >Именно отсюда и возникает эволюционный дизайн

                                Угу. А до ТДД при каждом баге или изменении требований всю систему по-вашему, редизайнили и переписывали заново? Вы очень сильно ошибаетесь.

                                >Опять же, важным этапом TDD является рефакторинг

                                См. предыдущий пункт. Нет проблем НЕ далать рефакторинг при ТДД — это легко и просто. Равно как нет проблем делать его без ТДД относительно легко (при хорошем покрытии тестами) либо тяжело (без таковых).

                                >не пробую посмотреть по сторонам и поучиться у других. Жаль(

                                Адресую это вам. Похоже вы, «внезапно» открыли для себя ТДД и теперь, как новообращённый адепт восторженно приписываете этой практике всё подряд, присущее ей или нет (подменяя, при этом, понятия) и не пробуете даже посмотреть вокруг. Жаль (

                                Поверьте, мне, в общем-то, всё равно, нравится оно вам или нет. Просьба только не подменять понятия. Нравиться — ну, каждый извращается по-своему. Приемлите для себя «документацию» в виде юнит-тестов (бррррр) — ну, дело ваше. Но, поверьте, есть вещи поудобнее :).
                                  0
                                  Не привык принимать что-то на веру — реквестирую примеры вещей поудобнее) и чем программирование по контракту лучше и мощнее?

                                  И да, ТДД я открыл достаточно давно, но это так, к слову)
                                    0
                                    >реквестирую примеры вещей поудобнее)

                                    BDD в части документирования. Остальное — почти то же самое :)

                                    >чем программирование по контракту лучше и мощнее?

                                    Написанием «правильного» кода. Формулирование контрактов куда более мощный способ заставить себя думать, как написать «правильный код». Тесты — лишь [последующая] проверка частных случаев.
                                    Документирование. Во-первых, она находится «по месту», во-вторых куда более внятная, чем лежащие непонятно где тестs, в-третьих, тесты легко отстают от кода при простом манкировании дисциплиной, с контрактами же проделать такой фокус куда сложнее :).

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

                    Самое читаемое