Провел беседу ИванПономарев
Разработка через тестирование (TDD) — это практика, известная уже довольно давно.
Разработка через короткие циклы «сначала пишем юнит-тест, потом код, потом рефакторим, повторяем» принята в качестве стандарта в ряде компаний.
Но обязательно ли команда, достигшая хорошего уровня зрелости процесса разработки, применяет TDD? Как и в большинстве других практик экстремального программирования, Споры о TDD до сих пор не утихло.
Оправданы ли первоначальные затраты на изучение и внедрение TDD? Обеспечивает ли TDD ощутимые преимущества? Можно ли измерить этот выигрыш? Бывают ли случаи, когда TDD вредит проекту? Бывают ли ситуации, когда без TDD решить задачу просто невозможно? Об этом мы поговорили с экспертом-разработчиком Андреем Солнцевым.
асольнцев (разработчик из таллинской компании Codeborne, практикующий экстремальное программирование и придерживающийся TDD) и Тагир Валеев Лэни (разработчик в JetBrains, также разрабатывает библиотеку с открытым исходным кодом StreamEx и анализатор байт-кода Java HuntBugs; убежден, что TDD — бесполезная практика).
Интересный? Добро пожаловать коту! Группа JUG.ru:
– Добрый день, Андрей, добрый день, Тагир! Таллинн, Москва и Новосибирск на связи через Skype. И чтобы ваша позиция была понятна читателям, первый вопрос короткий: вы работаете в TDD?
А.
Солнцев: – Да, мы работаем над разработкой через тестирование каждый день.
То есть пишем тест и код. И я считаю, что это очень полезная и правильная практика.
В идеале почти каждый должен работать таким образом, чтобы быть эффективным.
Т.
Валеев: — Я не занимаюсь разработкой через тестирование в том смысле, в котором работает Андрей.
Для нового функционала я обязательно сначала пишу код, а потом только тестирую его.
В случае с исправлением ошибок — 50/50: если у меня уже есть готовый код и я получаю отчет, что он где-то крашится, я могу написать тест, воспроизводящий эту проблему, и потом его исправить, а могу исправить.
сначала, а потом напиши тест. Но мой код все еще покрывается модульными тестами.
Я всегда покрываю весь новый код, который пишу, модульными тестами.
Группа JUG.ru: – Разработка через тестирование известна очень давно, с начала 2000-х годов.
Однако в большинстве своем разработчики работают не по TDD, на мой взгляд. Почему это происходит? я спросил этот вопрос к Николаю Алименкову xpinjection .
Он назвал две причины.
Во-первых, они просто не знают, как это сделать.
Их никто не учил, как это делать правильно.
А во-вторых, они ошибочно считают себя крутыми архитекторами: «Сейчас я быстро сформирую из шаблонов некую структуру, и она сразу заработает».
Каково твое мнение? Почему TDD широко не используется? А.
Солнцев: – Я согласен с Николаем.
Действительно, это так.
Не знать как.
И беда в том, что недостаточно прочитать какой-нибудь мануал или книгу, чтобы это уметь: так не работает. Ты все равно делаешь что-то не так, когда начинаешь пытаться.
Например, когда я впервые прочитал о юнит-тестах и начал использовать их в своем рабочем проекте, то уже постфактум понял, что делаю это абсолютно, в корне неправильно.
И все, что я сделал за год, можно выбросить.
Группа JUG.ru: – Тагир, почему ты не работаешь в TDD? Т.
Валеев: – Я просто думаю, что в этом нет необходимости.
То есть я понимаю исключительную важность юнит-тестов, важность хорошего тестового покрытия, но писать тесты раньше кода — это пустая трата времени и ресурсов.
Результат от этого лучше не станет, да и времени, скорее всего, на это уйдет больше.
Быстрое исправление и завершение кода
А.Солнцев:
– Как вы думаете, почему это так? Если вы по-прежнему пишете ровно такое же количество тестов, то почему при первом их написании требуется больше времени? Т.Валеев:
– Как минимум, у вас не будет автодополнения кода в IDE. Если вы пишете тест, для которого нет кода, вы не сможете написать его достаточно эффективно.А.
Солнцев: - Ну, это легко решаемо.
Вы не пишете тест от начала до конца.
Сначала вы пишете вызов метода, которого не существует. Да, здесь у вас нет автодополнения кода, и это хорошо, потому что потом вы будете думать, как будет вызываться метод. Написал вызов метода — можно нажать Alt+Enter, в IDE сгенерируется пустой метод. Вот и все, тогда у вас будет автодополнение кода.
Группа JUG.ru: — Более того, вы будете думать не просто о том, как он будет называться, а какие у него будут параметры и как его называть наиболее удобным способом.
Т.
Валеев: — Я не согласен, что для генерации кода использовать быстрые исправления проще, чем автодополнение кода.
Но, возможно, это дело вкуса.
А.
Солнцев: – Не проще, но примерно одинаково в обе стороны.
Нажмите Alt + Enter в обоих случаях.
Т.
Валеев: – Нет, я думаю, что использовать быстрые исправления сложнее.
Я потрачу больше времени.
И нужно нажать не только Alt+Enter. Например, я вызываю в тесте такой-то метод и, скажем, думаю, что с такой-то строкой и с таким-то числовым параметром он должен выдать такое-то значение.
Я написал эссе.
У меня пока нет метода и класса.
Поэтому мне приходится сначала сказать: «Создайте класс, которого еще не существует».
Выберите пакет для него.
То есть я не просто нажал Alt+Enter, я еще в диалоге заполнил область действия пакета и класса.
А.
Солнцев: — Так что все эти дела ты все равно будешь делать, так или иначе, неважно.
Т.
Валеев: – Но я буду писать их в текстовом редакторе, а не в диалоге.
Ладно, с классом разобрались, вот название метода.
В этом случае я нажимаю Alt+Enter и получаю диалог, в котором меня просят заполнить название параметров.
Поскольку мой тест содержит строку и число, IDE не может угадать, как следует называть эти параметры.
То есть мне придется вводить их имена в диалог.
Возможно, она тоже неправильно угадает их типы, особенно если я предположу, что у меня сложный тип какой-то.
Мне гораздо проще вручную ввести это в редактор.
А.
Солнцев: – Еще раз повторю, это то же самое время.
То есть вам все равно придется в конечном итоге, если имя вашего параметра состоит из десяти символов, нажать десять клавиш.
В любом случае, TDD или не TDD, это будет абсолютно одинаково.
Т.
Валеев: - Здесь есть два варианта.
Первый: я оставлю все как есть в диалоге, а потом в текстовом редакторе просто отредактирую то, что мне сгенерировали (или в диалоге исправлю то, что мне сгенерировали).
Второе: я просто сразу впишу то, что хочу, в пустой текстовый файл, не исправляя.
А.
Солнцев: - Абсолютно никакой разницы.
Т.
Валеев: – На мой взгляд, разница есть.
Простота использования и эффективность внедрения
Группа JUG.ru: – Но, коллеги, есть еще один факт, говорящий в пользу TDD. Если вы пытаетесь сначала написать тест, вам сначала придется запустить установку.Тест — это не только вызов метода, это еще и настройка.
Собираетесь ли вы создать тестируемый объект, используя конструктор или фабрику? Будете ли вы передавать какие-либо параметры конструктору или свойствам? Где вы возьмете эти параметры? И этот момент очень ценен, потому что если сразу начать думать о том, как его использовать, то в итоге получится более красивое API. А.
Солнцев: - Совершенно верно, я согласен.
Т.
Валеев: – Это очень хорошая тема.
И здесь можно поспорить, ведь любое API нужно рассматривать как с точки зрения удобства использования, так и с точки зрения простоты реализации.
А еще эффективность и вообще возможная реализация, потому что может оказаться, что API, удобный с точки зрения использования, неудобен с точки зрения реализации, потому что ему просто не хватает данных.
Например, я пишу IDE. Это то, чем я действительно сейчас занимаюсь.
Например, мне нужен новый метод, который класс найдет для меня.
Я хочу иметь возможность найти класс по имени «java.util.Collection» и узнать, какие методы там есть.
Я, естественно, думаю: «Что мне нужно? Мне нужно имя типа String».
Окей, пишу, скажем, метод findClass(String name), передаю ему строку «java.util.Collection» и проверяю, что он должен что-то найти.
Хороший, удобный тест? Много Но когда вы начнете реализовывать, вы поймете, что «java.util.Collection» непонятно, потому что, например, у вас могут быть подключены разные JDK в разных модулях или разных проектах и это имя может соответствовать разным классам, в.
которые имеют разное количество методов.
Когда вы это реализуете, вы не сможете не подумать об этом, потому что сразу поймете, что есть проблема.
Вам нужно подключение к проекту или какая-то область разрешения.
вашему удобному методу использования просто не хватает данных для реализации результата.
Так что написание теста не сделает хорошего API. В данном случае мы написали тест, нам было удобно пользоваться, но API получилось.
Будь плохим.
А.
Солнцев: - Ну и что? Данных мало, это правда, но я не вижу здесь никакой проблемы.
Вы начинаете писать с теста.
Я написал тест так, чтобы его было максимально удобно использовать.
По мере реализации вы видите, что некоторых данных не хватает, вы возвращаетесь на шаг назад и понимаете: «Ладно, это невозможно, нам нужны новые данные».
И вы снова дополняете тест и думаете, как наиболее удобным образом передать эти данные в этот метод через конструктор, через сервис инъекции, да что угодно.
Соответственно, вы расширяете тест, чтобы передать эти данные и начинаете дальнейшую реализацию.
Я не вижу проблемы.
Все именно так.
Т.
Валеев: «В том-то и дело, что вы не видите проблемы, а я не понимаю, зачем писать тест только для того, чтобы потом увидеть, что этот тест бесполезен, что он не будет работатьЭ» Зачем делать эти шаги вперед и назад, если можно сразу написать реализацию? Причем это будет сделано максимально удобным образом и вам не придется переписывать тест ни разу.
Вы сразу напишете реализацию, потом тест. Вы не делаете ни шагу назад. Это эффективно.
А.
Солнцев: – Ээффективно для кого? Мы возвращаемся к основам: зачем нам вообще нужен TDD? Это позволяет заранее продумать, как использовать API наиболее удобным образом.
Вы только что упомянули в своем примере, что нужно передать, во-первых, имя класса, плюс нужно как-то передать дополнительные параметры, скажем, проект, версию Java — нужно передать какой-то контекст. А как это передать - есть разные варианты.
Может быть параметром метода.
Вы можете внедрить его в этот класс, в сервис.
Вы можете внедрить через конструктор.
Вы можете заставить его просто извлечь откуда-нибудь какую-нибудь статическую переменную или статический метод. Или я бы их из базы подгрузил, блин.
То есть есть разные варианты.
И когда начинаешь делать настройку в тесте, как уже упомянул Иван, в этот момент начинаешь задумываться: как удобнее всего перенести все эти вещи туда? Т.
Валеев: — Кстати, вы сказали очень интересную вещь: «Статические методы».
То есть у меня где-то снаружи есть какой-то статический контекст. А может оказаться, что я на самом деле напишу этот свой метод findClass, у него будет только один строковый параметр, и я подумаю: «Вообще-то в этом режиме с этим методом тоже можно работать».
То есть реализация возможна, если я смогу откуда-то в глобальном контексте узнать, какой у меня проект, JDK и так далее.
Но со временем поддержание этого глобального контекста может стать более накладным.
Просто в каком-то конкретном месте становится непонятно, каков текущий контекст. Здесь возникает многопоточность: у меня есть один контекст в одном потоке и другой контекст в другом потоке.
То есть, исходя из соображений удобства использования, если я буду уделять этому слишком много внимания, то может оказаться, что реализация станет совершенно неподдерживаемой.
А.
Солнцев: – Вы все правильно назвали.
Есть такие проблемы.
Именно это и происходит во многих проектах.
И я просто хочу подчеркнуть, что тест позволит вам это выявить гораздо раньше, как только вы в своем тесте поймете, что вам теперь нужно как-то инициализировать глобальный контекст перед запуском теста.
Создайте какую-нибудь статическую переменную.
Вы сразу увидите: «Ой, это неудобно.
А что, если я запущу два разных теста и каждый должен запускаться по-своему, например, параллельноЭ» И вместо того, чтобы инициировать статическую переменную, как-то лучше и удобнее передать ее, например, в качестве параметра.
Тест покажет это мгновенно.
В том-то и дело.
Группа JUG.ru: — Да, из моего опыта: если код становится сложно поддаваться модульному тестированию, то чаще всего это происходит именно из-за каких-то глобальных контекстов.
Вот здесь и звучит сигнал, что мы не очень грамотно спроектировали API даже не с точки зрения удобства, а именно с точки зрения общей корректности.
Вот так и возникают проблемы.
Что делать, если мне нужно запустить тест для разных глобальных контекстов, но мне сложно их настроить? Что, если окажется, что юнит-тест вообще зависит от того, какая программная среда установлена на машине разработчика? Вот и обнаруживается проблема, что мы что-то не продумали.
Например, некоторые вещи, которые нам придется передавать в качестве параметров, действительно зависят от глобального контекста.
Т.
Валеев: – А вот с последними замечаниями я вообще не спорю! Не забывайте, что я абсолютно не против юнит-тестов.
Я за модульные тесты.
То есть с последними замечаниями в контексте того, что тесты и код у нас уже есть, и в какой-то момент мы понимаем, что что-то не так — я абсолютно согласен.
Должен быть тест и код. Но мы расходимся только в том, в каком порядке они должны появиться.
Позиция Андрея, насколько я понимаю, заключается в том, что если мы сначала напишем тест, то мы немного продвинемся в сторону удобства использования.
Моя позиция такова: если мы сначала не напишем тест, то нас сместит в сторону простоты разработки.
А.
Солнцев: - Мы не будем.
Давайте не будем волноваться.
Мы ни в коем случае не будем предвзято относиться к простоте разработки.
Это не верно.
Написание теста раньше никак не мешает разработке, совсем.
Это ложное предположение.
Т.
Валеев: - Ладно, у тебя одно мнение, а у меня другое.
Дешевле, качественнее – или и то, и другое?
Группа JUG.ru: – До нашего разговора я думал, что он может перейти в такую фазу, когда каждый будет настаивать на своей субъективной позиции.Но возможен ли здесь объективный взгляд, можно ли как-то измерить продуктивность команды, работающей так или иначе? Я поискал в Google и нашел ссылку на исследовать , которые прошли в Microsoft и IBM. Две команды были вынуждены работать параллельно над одним и тем же проектом: некоторые работали с TDD, другие — без TDD. И вывод был такой: трудозатраты на TDD немного выше, но качество на TDD существенно выше.
То есть при несколько более высоких трудозатратах (это важный момент, там отметили, что трудозатраты на разработку TDD выше), судя по количеству дефектов, которые потом пришлось исправлять, TDD имеет существенно более высокое качество.
То есть, возможно, выбор между TDD и не-TDD — это простой выбор между ценой и качеством.
А.
Солнцев: – Прокомментирую цену и качество.
Чуть больше затрат было подсчитано на каком-то первом этапе, когда шла разработка.
Но не забывайте, что проект на этом не умирает. Проект продолжает жить.
Его нужно как-то поддерживать и развивать.
А проект худшего качества потребует гораздо больше времени и усилий на поддержку, ошибок будет больше, рефакторинг будет сложнее и так далее.
И поэтому в итоге через определенное время оно окажется дороже.
Поэтому неверно говорить, что TDD будет иметь более высокие затраты.
В долгосрочной перспективе они меньше.
Это то же самое, что купить более дешевое пальто прямо здесь и сейчас.
TDD — дорогое пальто.
Прямо здесь и сейчас вы купите дешевое пальто без TDD: да, сейчас оно кажется дешевым, но через два года вы обнаружите, что вам придется каждый год покупать новое пальто.
Группа JUG.ru: — Разве ты не настолько крут, что можешь сразу писать отличный код без TDD? Т.
Валеев: — Конечно, я не сразу пишу красивый код. Я сразу пишу более-менее хороший код, потом пишу юнит-тест. И после этого исправляю этот более-менее хороший код в соответствии с проваленными юнит-тестами.
А затем я также отправляю его на проверку кода и после этого дорабатываю.
А.
Солнцев: – Но, тем не менее, получается, что какие-то множественные изменения все равно происходят, так или иначе? Т.
Валеев: – В любом случае изменений будет много.
Какая разница? Сначала вы пишете тест, затем пишете код. После этого вам все равно придется запустить этот пакет. Если вы обнаружите, что тест не пройден, вы это исправите.
У меня то же самое, я просто сначала пишу код, потом тест. А потом запускаю, потом то же самое.
Вам все равно придется думать о том, что вы пишете.
Удержание задачи: «в голове», на бумаге или в тестах?
А.Солнцев:
– Я хотел бы сказать, в чем я вижу главное преимущество TDD. Я рассматриваю это как инструмент, который помогает мне думать.То есть в качестве альтернативы TDD можно, например, заранее продумать в голове, что вы будете делать.
И я верю, что многие люди так делают. Они думают: «Зачем мне писать тесты заранее, я ведь сразу все в голове придумаю».
Возможно, Тагир так думает. И, может быть, это хорошо до определенного момента, когда изменений не слишком много и когда есть хороший, свежий ум.
Действительно, в голове можно все довольно детально продумать, но начиная с определенного момента голова уже не справляется.
Второй вариант — заранее нарисовать его на листе бумаги, а может быть и другой вариант — обсудить с кем-нибудь.
То есть это все варианты, которые позволяют заранее продумать, что вы будете писать, но, на мой взгляд, юнит-тест — лучший из них, потому что он наиболее близок к коду.
Всё равно: если ты думаешь головой и тебе кажется, что ты всё отлично продумал, то когда ты садишься и начинаешь писать код, становятся понятны нюансы, о которых ты не подумал.
На листе бумаги то же самое: ты все подробно нарисовал, начинаешь писать код, становятся понятны нюансы, о которых ты не подумал.
Т.
Валеев: — Я просто привел пример с findClass(.
) для того, чтобы показать, что даже если написать тест, всё равно выявляются нюансы, о которых вы не задумывались.
А.
Солнцев: – Вы правы: да, нюансы, конечно, уточняются в любом случае, это бесспорно.
А когда окажется, что ты о чем-то не подумал – какой вариант? Должен ли я вернуться и переосмыслить это в своей голове? Ваша голова просто раздуется и сломается, и вы не сможете много думать.
Вариант вернуться и перерисовать все на бумаге? В принципе это вариант, но, на мой взгляд, гораздо эффективнее и быстрее вернуться к юнит-тесту и завершить его.
Это будет проще, чем перерисовывать все на бумаге.
Проще, быстрее, эффективнее.
Хочу провести аналогию: юнит-тест, листок бумаги и мышление в голове — это примерно одни и те же инструменты.
Т.
Валеев: — Если задача слишком сложна, чтобы полностью уместиться в вашей голове, то я не думаю, что TDD придет сюда и волшебным образом всех спасет. Задачу необходимо разбить на подзадачи.
Решил небольшую подзадачу, протестировал — хорошо.
Этот кусок в вашей голове уже не детализирован, он превратился в рабочую абстракцию.
Затем вы работаете над каким-то новым кирпичиком, в котором используется предыдущий.
А.
Солнцев: - Это тоже метод. Я с этим вообще не спорю.
Да, его нужно сломать.
Никакого противоречия.
Но дело в том, что когда за день складываешь в голову много этих маленьких кирпичиков, голова устает гораздо быстрее.
Вопрос в том, где именно хранить это рабочее пространство: в голове, на листе бумаги или в тесте.
Утверждения в коде — TDD или нет?
Группа JUG.ru: — Я сам не все делаю с помощью TDD, хотя и стремлюсь к этому.Но в моей практике встречались сложные проблемы, в которых я бы не «разобрался», если бы сразу не решил их с помощью TDD. Есть проблемы, решение которых, как я себе представляю, выглядит как взаимодействие большого количества мелких «шестереночек».
Алгоритмически или структурно сложные задачи.
Сначала я должен быть абсолютно уверен, что каждая «шестеренка» работает правильно.
Затем я пытаюсь собрать эти «шестеренки» в какой-то сложный механизм и добиться их правильного взаимодействия на более высоком уровне.
Возможно, это вопрос внутреннего убеждения, но я уверен, что без TDD я бы не смог решить некоторые задачи.
Но это возможно, в зависимости от того, кто вы.
Некоторые люди, возможно, решили.
Итак, Тагир, как ты решаешь самые алгоритмически сложные задачи? Т.
Валеев: – Основной подход, естественно, заключается в разбиении проблемы на более простые.
То есть нужно выделить какие-то шаги.
На каждом этапе у вас должны быть инварианты.
Это некоторые утверждения, некоторые утверждения, которые должны быть верными на этом этапе.
Возможно, еще проще это прототипировать не с помощью юнит-тестов, а поместив в код утверждения, что в этом месте правильный такой-то инвариант, в этом месте правильный такой-то инвариант. А.
Солнцев: - Так это то же самое.
Утверждения аналогичны тестам.
Группа JUG.ru: — Если мы продумываем инварианты и превращаем их в утверждения в коде, то это такая же работа, как создание утверждений в модульных тестах.
Используете ли вы утверждения в своем коде? Т.
Валеев: – Я использую их именно в случае алгоритмически сложных задач.
И, как правило, я их все равно удаляю.
Но это зависит от ситуации, от общей политики проекта.
Например, в моей библиотеке StreamEx были действительно нервные части, где мне приходилось ее распараллеливать и все делать правильно.
Был миллион особых случаев, когда потоки заказов могли прийти в определенную точку.
Помимо модульных тестов я разместил утверждения для проверки не только внешнего API, но и некоторых внутренних частей.
Я все это отладил вдоль и поперёк.
Когда нужно было сделать релиз, я удалил утверждения.
Я сделал это по некоторым причинам, в том числе потому, что они могут замедлить работу, если их разрешить во время выполнения.
Группа JUG.ru: – И они также могут вызывать побочные эффекты.
Т.
Валеев: - Ну, это плохие утверждения, если они способствуют. Но они могут привести к потере производительности.
Если человек хранит «-ea» на весь проект, то зачем ему внутри моего кода триггерное утверждение? Никакой выгоды от этого он все равно не получит. А.
Солнцев: — Да, я согласен, что ассерты — это по сути те же юнит-тесты, только написанные в другом месте.
Единственное преимущество модульных тестов заключается в том, что их не нужно удалять, и они никак не влияют на производительность.
А поскольку вы пишете утверждения, а затем модульные тесты, означает ли это, что вы выполняете двойную работу? Т.
Валеев: – В процессе прототипирования иногда проще писать утверждения, потому что когда вы прототипируете алгоритм, вы можете, например, поместить утверждение внутрь цикла, а затем придумать, как, например, поместить тело этого зациклитесь на отдельный метод и откройте его для модульного теста.
А.
Солнцев: – То есть мы на самом деле говорим почти об одном и том же, просто называем это немного разными словами.
Но на мой взгляд, юнит-тест правильнее утверждения, хотя бы потому, что об этом думаешь заранее.
И тогда вам не придется его переделывать.
Т.
Валеев: — Если мы говорим не о внешнем API, а о внутренней структуре алгоритма, то то, как он разделен на методы, не очень важно, потому что этого никто не видит. Главное, чтобы это было правильно и быстро.
И вполне может оказаться, что все те места, куда вы хотите поставить утверждения, если в этих точках разбить их на методы и поставить юнит-тесты, то код слишком превратится в «лапшу» и его будет сложнее воспринимать.
Я говорю об алгоритмически сложном коде.
Но это также может быть делом вкуса.
Некоторые люди думают, что сотня однострочных методов лучше, в то время как другие думают, что десять десятистрочных методов тоже хороши.
Прописывать интерфейсы перед их реализацией — TDD или нет?
Т.Валеев:
— И еще хочу добавить по поводу дизайна API. Казалось бы, это та вещь, для которой TDD на самом деле очень полезен, ведь если будет создано новое API, то мы сразу задумаемся, как его удобно использовать.И из моей практики, если я действительно в голове не понимаю, удобно ли так или иначе, когда у меня есть варианты, то мой подход, наверное, ближе всего к классическому TDD, но все равно я не пишу тест вперед. Я пишу исключительно интерфейсы без реализации и пишу тесты для этих интерфейсов.
И сначала я отлаживаю это соединение.
То есть я заранее смотрю, будет ли тест удобен или не удобен.
Тест необходимо компилировать вместе с интерфейсом.
Естественно, никакой реализации.
И после этого, когда интерфейс мне покажется удобным, я могу написать реализацию.
А.
Солнцев: – Но это вполне приемлемо.
Примерно так мы тоже работаем.
Т.
Валеев: — Но опять же, интерфейс всё равно появляется впереди, если мы говорим о порядке написания кода.
А.
Солнцев: – Это как раз не принципиальный момент. Это просто означает, нажмете ли вы Alt + Enter немного раньше или немного позже, но я не думаю, что это имеет большое значение.
Т.
Валеев: - ХОРОШО! Получается, что у нас нет принципиальных различий.
То есть мы все согласны с тем, что тестирование необходимо и это очень важно, а различия лишь в мелких деталях, на мой взгляд, которые могут быть более субъективными.
А.
Солнцев: - Да.
Возможно.
Может ли TDD когда-нибудь повредить проекту?
Группа JUG.ru: – Действительно, мы пришли к определенному консенсусу.Главное, конечно, в ответ на вопрос «Есть ли вред от TDD на проектеЭ» Является ли TDD зломЭ», в конце концов, ответ: «Нет, это не зло».
В частности, модульные тесты сами по себе очень хороши.
И я думаю, каждый должен понимать, что нет оправдания тем, кто не использует модульные тесты и чья реализация сильно отстает от покрытия модульными тестами.
Это просто зло, конечно.
А.
Солнцев: - Да! Т.
Валеев: — Могу с уверенностью сказать, что ни при каких обстоятельствах нельзя коммитить без тестов, даже если у вас есть локальный репозиторий.
В одном коммите у вас должна быть и реализация, и тесты, которые хоть как-то более-менее покрывают эту реализацию.
То есть тесты можно писать и позже, как я, но коммитить их нужно одним коммитом.
Бывает ли когда-нибудь, что TDD вредит проекту? Поскольку я не использую TDD, у меня нет примеров, когда бы это причиняло вред. На мой взгляд, TDD — это не зло, но TDD избыточен.
Мне кажется, он ненужный, но он не злой.
Если кому-то понравится, я совершенно не против.
Даже если я буду работать над проектом с человеком, использующим TDD, мне совершенно не будет жаль.
А.
Солнцев: – Конечно, я обязательно скажу, что я не лишний.
Из сегодняшнего разговора я сделал вывод, что вы делаете минимум столько же движений, а может и больше.
Поэтому я не могу согласиться с тем, что это избыточно.
И ответить на вопрос: «Приносит ли когда-нибудь TDD вредЭ» - Мне действительно очень интересно.
Не могу сразу сказать, что у меня есть такие очевидные примеры, но могу себе представить, что TDD, наверное, вреден, когда людей заставляют этим заниматься.
Например, когда они не знают как, но им сказали: «Надо».
Сделали и сделали, написали кучу тестов, а в итоге пошли дальше и сделали всё по старинке.
Тогда действительно окажется, что TDD будет чрезмерными трудозатратами.
Т.
Валеев: – Но это тоже то, что сложно контролировать, если не использовать парное программирование.
То есть, какой код написал человек, можно отслеживать на code review. Что он написал первым, а что потом, если ты не стоишь за ним - как ты это поймешь? А.
Солнцев: – Контролировать невозможно, но по своему опыту скажу, что это всегда видно.
Когда вы видите коммит, вы всегда видите: если тесты были написаны после кода, то он хуже по качеству, зависимостей больше и так далее.
Это видно невооруженным глазом.
Т.
Валеев: – Не знаю, здесь, наверное, довольно сложно рассуждать подробно.
Можно ли объективно измерить пользу или потерю TDD?
А.Солнцев:
– Да, это очень субъективно, я согласен.Но я могу привести пример.
Обычно мы используем парное программирование, но однажды я ехал один в автобусе и мне нужно было решить сложную задачу.
Задача примерно такая: клиент загружает файл с платежами, и ему нужно было проверить кучу всего, нет ли повторяющихся номеров платежей, не слишком ли велики суммы и так далее.
И я сделал это один в автобусе без TDD, а на следующее утро мы пришли и сделали то же самое с коллегой полностью с нуля, используя TDD. И сравнивали между собой.
И разница была абсолютно разительной.
Группа JUG.ru: – Но эксперимент нечистый.
Однажды ты уже решил проблему в автобусе.
Теперь нам следует сначала решить еще одну задачу с использованием TDD, а затем без TDD, чтобы сравнить результаты.
А.
Солнцев: – Это правильное замечание, да.
Кстати, это хорошая идея.
Такой эксперимент тоже можно провести.
В целом идея экспериментов замечательная.
Мне бы очень хотелось это сделать, но как? Ведь нельзя дважды войти в одну и ту же реку? Как это возможно? Т.
Валеев: — Даже эти результаты, о которых Иван упомянул, что Microsoft что-то измерила и оказалось, что TDD выдаёт лучший код: всё это очень сложно сравнивать объективно.
Наверняка это были разные команды, люди разного уровня и т. д. Теги: #программирование #тестирование #тестирование ИТ-систем #разработка через тестирование #Идеальный код #tdd #heisenbug #heisenbug #Андрей Солнцев #Тагир Валеев
-
Асинхронное Программирование (Полный Курс)
19 Oct, 24 -
Интеллектуальный Анализ Данных На Службе Hr
19 Oct, 24 -
Покупка Github Завершена. Что Будет Дальше?
19 Oct, 24