TDD проти продуктивності


131

У своєму теперішньому проекті (грі, на C ++) я вирішив, що під час розробки я буду використовувати тестово керовану розробку на 100%.

Щодо якості коду, це було чудово. Мій код ніколи не був настільки добре розроблений або настільки без помилок. Я не переслідую під час перегляду коду, про який писав рік тому на початку проекту, і я набув набагато кращого розуміння того, як структурувати речі, не тільки для того, щоб їх було легше перевірити, але щоб було простіше в застосуванні та використанні .

Однак ... минув рік, як я розпочав проект. Зрозуміло, я можу працювати над цим лише у вільний час, але TDD все ще значно уповільнює мене порівняно з тим, до чого я звик. Я читав, що повільна швидкість розвитку з часом стає кращою, і я, безумовно, придумую тести набагато легше, ніж раніше, але я працюю на цьому вже рік, і я все ще працюю з темпом равлики.

Кожного разу, коли я замислююся над наступним кроком, який потребує роботи, я мушу щоразу зупинятися і думати, як би я написав для нього тест, щоб дозволити мені написати фактичний код. Я інколи застрягаю годинами, точно знаючи, який код я хочу написати, але не знаючи, як його тонко розбити, щоб повністю покрити його тестами. В іншому випадку я швидко придумаю десяток тестів і витрачу годину на написання тестів, щоб висвітлити крихітний фрагмент реального коду, який би інакше зайняв би кілька хвилин, щоб написати.

Або, закінчивши 50-й тест, щоб охопити певну сутність у грі та всі аспекти її створення та використання, я переглядаю свій список справ і бачу, що наступна сутність повинна бути закодована, і в жаху при думці писати ще 50 подібних тестів для його впровадження.

Дійшло до того, що, переглядаючи прогрес минулого року, я розглядаю можливість відмовитися від TDD заради "завершення проклятого проекту". Однак я відмовляюся від якості коду, що поставляється разом із нею. Я боюся, що якщо я перестану писати тести, то я вислідую від звички робити код таким модульним і перевіряючим.

Чи я можу зробити щось не так, щоб все ще бути таким повільним? Чи існують альтернативи, які прискорюють продуктивність, не втрачаючи при цьому повністю переваг? TAD? Менше тестового покриття? Як інші люди виживають TDD, не вбиваючи всієї продуктивності та мотивації?


@Nairou: Ви завжди можете спробувати "завершити проект"! Зробіть гілку зараз. Просто напишіть там код. Але обмежте, чим займаєтесь, чи часом, чи кількістю ігрових утворень, і побачите, чи пішли ви швидше. Потім ви можете проігнорувати цю гілку, повернутися до магістралі та TDD і побачити, у чому різниця.
квамрана

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

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

2
Ще коли я вчився, у нас був хитрість, коли нам потрібно було надати проектні документи. Ми написали код спочатку, потім написали документи для опису коду. Можливо, вам потрібно навчитися середнього рівня цього прагматизму для вашого TDD. Якщо ви вже маєте на увазі план, можливо, краще взяти більшу частину цього коду до написання тестів. Що б не підказав ідеалізм, іноді краще робити те, що ви вже готові зробити, а не відволікатися на щось інше, а потім повертатися, коли вже не свіжий.
Steve314

4
Я збираюся суперечити поширеній думці і сказати, що TDD не завжди може бути правильним вибором, якщо ви робите ігри. Так як хто - то на gamedev.stackexchange вже відповів на це питання ефектно, я просто зв'язати це тут .
l46kok

Відповіді:


77

Дозвольте почати з того, щоб подякувати вам, щоб поділитися своїм досвідом та висловити свої занепокоєння ... що, маю сказати, не рідкість.

  • Час / продуктивність: Написання тестів відбувається повільніше, ніж не написання тестів. Якщо ви обмежите це, я погодився б. Однак якщо ви докладете паралельних зусиль, коли застосовуєте не-TDD підхід, велика ймовірність, що час, який ви витратите на розрив-виявлення-налагодження та виправлення існуючого коду, поставить вас у чистий мінус. Для мене TDD - це найшвидший показник, який я можу пройти без шкоди для своєї впевненості в коді. Якщо ви знайдете речі у своєму методі, які не мають додаткової цінності, усуньте їх.
  • Кількість тестів: Якщо ви кодуєте N речей, вам потрібно перевірити N речей. перефразовуючи один із рядків Кента Бека " Тестуйте лише, якщо ви хочете, щоб він працював ".
  • Застрягати годинами: я теж (іноді, а не> 20 хвилин, перш ніж зупиняти лінію). Це просто ваш код, який говорить вам, що дизайн потребує певної роботи. Тест - це ще один клієнт для вашого класу SUT. Якщо у тесті важко використовувати тип, швидше за все, будуть і ваші виробничі клієнти.
  • Подібні тестування тесту: Для написання контргументу мені потрібен ще якийсь контекст. Це сказав: Стоп і подумай про схожість. Чи можете ви якось керувати цими тестами на даних? Чи можна писати тести на базовий тип? Тоді потрібно просто запустити один і той же набір тестів проти кожної деривації. Слухайте ваші тести. Будьте правильним виглядом лінивих і подивіться, чи зможете винайти спосіб уникнути тугі.
  • Перестати думати, що вам потрібно зробити далі (тест / специфікація) - це не погано. Навпаки, рекомендується, щоб ви будували «правильну річ». Зазвичай, якщо я не можу придумати, як його протестувати, я зазвичай не можу також придумати реалізацію. Хороша ідея звільнити ідеї впровадження, поки ви не потрапите. Можливо, більш просте рішення буде затьмарене передумовим дизайном YAGNI-ish.

І це підводить мене до остаточного запиту: як мені стати краще? Моя (або An) відповідь - читати, розмірковувати та практикувати.

наприклад, пізно, я продовжую вкладки

  • чи відображає мій ритм RG [Ref] RG [Ref] RG [Ref] чи це RRRRGRRef.
  • % часу, витраченого в режимі помилок Red / Compile.
  • Я застряг у стані Red / Broken build?

1
Мені дуже цікаво ваш коментар щодо тестів, що керують даними. Ви просто маєте на увазі єдиний набір тестів, які обробляють зовнішні дані (наприклад, з файлу), а не повторне тестування подібного коду? У моїй грі є декілька сутностей, і кожен з них значною мірою відрізняється, але є деякі загальні речі, які можна зробити з ними (серіалізувати їх по мережі, переконайтеся, що вони не надсилаються до неіснуючих гравців тощо) Поки що я не знайшов способу консолідувати це, і тому для кожного з них є набори тестів, які майже однакові, різні лише в тому, яку сутність вони використовують та які дані вони містять.

@Nairoi - Не впевнений, який тестовий бігун ви використовуєте. Я щойно дізнався ім’я для того, що хотів передати. Абстрактний малюнок кріплення [ goo.gl/dWp3k] . Це все ще вимагає, щоб ви написали стільки світильників, скільки є конкретних типів SUT. Якщо ви хочете бути ще більш лаконічними, подивіться документи своїх бігунів. наприклад, NUnit підтримує параметризовані та загальні тестові прилади (тепер, коли я це шукав) goo.gl/c1eEQ Здається, саме те, що вам потрібно.
Gishu

Цікаво, що я ніколи не чув про абстрактні світильники. Зараз я використовую UnitTest ++, який має світильники, але не абстрактні. Це кріплення дуже буквально, це лише спосіб консолідації тестового коду, який ви інакше повторили б у кожному тесті, для даної групи тестів.

@asgeo - не можу редагувати цей коментар .. посилання набрала кінцеву дужку. Це повинно працювати - goo.gl/dWp3k
Gishu

+1 для "застрягання - симптом, що дизайн потребує більшої роботи", хоча .. що станеться, коли ти застрягнеш (як я) на дизайні?
Люршер

32

Вам не потрібно 100% -ве покриття тесту. Будьте прагматичними.


2
Якщо у вас немає 100% тестового покриття, ви не маєте 100% впевненості.
Крістофер Махан

60
Ви не маєте 100% впевненості навіть при 100% тестовому покритті. Це тест 101. Тести не можуть засвідчити, що код не містить дефектів; навпаки, вони можуть лише продемонструвати, що він містить дефекти.
CesarGon

7
Для чого це варто, один з найстрашніших прихильників TDD, Боб Мартін, не рекомендує 100% охоплення - blog.objectmentor.com/articles/2009/01/31/… . У виробничій галузі (надається, багато в чому відрізняється від програмного забезпечення) ніхто не йде на 100% впевненість, оскільки вони можуть витратити частину зусиль, щоб бути впевненими на 99%.
Шанс

Також (принаймні останній раз, коли я перевіряв інструменти, які ми маємо), звіти про покриття коду стосуються того, чи виконувались рядки, але не включає покриття значення - наприклад, сьогодні я повідомив про помилку, де я мав усі шляхи через код, виконаний у тестах, але оскільки існував такий рядок a = x + yі хоча всі рядки в коді були виконані в тестах, тести перевірялися лише у випадку, коли y = 0, тому помилка (вона мала бути a = x - y) ніколи не була знайдена в тестах.
Піт Кіркхем,

@Chance - я прочитав книгу Роберта Мартіна "Чистий кодер ..." якусь довгу назву. У цій книзі сказано, що це повинно бути асимптотично на 100% покрито тестами, що близько 100%. І посилання на блог більше не працює.
Дарій.V

22

TDD все ще значно уповільнює мене

Це насправді помилково.

Без TDD ви витрачаєте кілька тижнів на написання коду, який здебільшого працює, і наступний рік проводите на "тестування" та виправлення багатьох (але не всіх) помилок.

З TDD ви витрачаєте рік на написання коду, який насправді працює. Потім ви робите остаточне інтеграційне тестування протягом декількох тижнів.

Минулий час, ймовірно, буде однаковим. Програмне забезпечення TDD буде значно кращої якості.


6
Так навіщо мені потрібен TDD? "Час минув той самий"

21
@ Peter Long: Якість коду. Рік "тестування" - це те, як ми закінчуємо програмне забезпечення, яке працює в основному.
С.Лотт

1
@ Петер, ти маєш жартувати. Якість рішення TDD буде набагато вище.
Марк Томас

7
Навіщо мені потрібен TDD? Кент Бек перераховує душевний спокій як великий, і це дуже переконливо для мене. Я живу в постійному страху поламати речі, коли працюю над кодом без одиничних тестів.

7
@ Peter Long: "Час минув той самий" ... і в будь-який момент за цей час ви можете доставити робочий код .
Френк Шірар

20

Або, закінчивши 50-й тест, щоб охопити певну сутність у грі та всі аспекти її створення та використання, я переглядаю свій список справ і бачу, що наступна сутність повинна бути закодована, і в жаху при думці писати ще 50 подібних тестів для його впровадження.

Це змушує мене замислитися, скільки ви дотримуєтесь кроку TDD "Refactor".

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

Якщо у вас є два об'єкти, які об'єднуються в одне, щоб дозволити повторне використання коду, також подумайте про об'єднання їхніх тестів. Вам дійсно потрібно лише перевірити додаткові відмінності у вашому коді. Якщо ви не регулярно проводите технічне обслуговування на своїх тестах, вони можуть швидко стати непростими.

Кілька філософських моментів про TDD, які можуть бути корисними:

  • Якщо ви не можете зрозуміти, як скласти тест, незважаючи на великий досвід написання тестів, то це, безумовно, кодовий запах . У вашому коді чомусь бракує модульності, що ускладнює написання невеликих, простих тестів.
  • Видалення трохи коду цілком прийнятно при використанні TDD. Напишіть потрібний код, щоб уявити, як він виглядає, а потім видаліть код і починайте з тестів.
  • Я бачу практикувати надзвичайно суворі TDD як форми фізичних вправ. Коли ви вперше починаєте, обов'язково пишіть тест спочатку кожен раз і впишіть найпростіший код, щоб зробити тестовий прохід, перш ніж рухатися далі. Однак це не обов'язково, як тільки ви станете більш комфортними у практиці. У мене немає одиничного тестування для кожного можливого шляху коду, який я записую, але за допомогою досвіду я можу вибрати те, що потрібно перевірити за допомогою тесту на одиницю, і що може бути замінено функціональним або інтеграційним тестуванням. Якщо ви протягом року строго практикуєте TDD, я б подумав, що ви також близькі до цього моменту.

EDIT: На тему філософії одиничного тестування, я думаю, це може бути цікавим для вас, щоб прочитати: Шлях Тестівуса

І більш практичний, якщо не обов'язково дуже корисний, пункт:

  • Ви згадуєте C ++ як мову свого розвитку. Я широко практикував TDD на Java, використовуючи чудові бібліотеки, такі як JUnit та Mockito. Однак я виявив, що TDD в C ++ дуже неприємно через відсутність бібліотек (зокрема, глузуючих фреймворків). Хоча цей момент не дуже допомагає тобі у вашій нинішній ситуації, я сподіваюся, що ви це врахуєте перед тим, як взагалі скинути TDD.

4
Тести на рефакторинг небезпечні. Здається, ніхто про це не говорить, але це так. У мене, звичайно, немає одиничних тестів, щоб перевірити мої одиничні тести. Якщо рефактор зменшує дублювання, ви зазвичай збільшуєте складність (оскільки ваш код стає загальнішим). Це означає, що більша ймовірність помилок у ваших тестах .
Скотт Вітлок

2
Я не згоден, що тести на рефакторинг небезпечні. Ви переробляєте лише тоді, коли все проходить, тож якщо ви зробите рефакторинг, і все ще зелене, то ви просто добре. Якщо ви думаєте, що вам потрібно написати тести для своїх тестів, я вважаю, що це показник того, що вам потрібно написати простіші тести.
jaustin

1
Тест на C ++ важко одиничний (мова не дуже легко робить речі, які спрощують макети). Я помітив, що функції, які є "функціями" (працюють лише на аргументах, результати виходять як значення повернення / парами), перевірити набагато простіше, ніж "процедури" (return void, відсутні аргументи). Я виявив, що фактично простіше перевірити добре складений модульний код C, ніж код C ++. Не потрібно писати на C, але ви можете наслідувати модульний приклад C. Це звучить абсолютно божевільно, але я поставив одиничні тести на "поганий C", де все було глобальним, і це було дуже просто - вся держава завжди доступна !.
анонс

2
Я думаю, що це дуже правда. Я дуже багато RedGreenRedGreenRedGreen (або, частіше, RedRedRedGreenGreenGreen), але я рідко рефактор. Мої тести, безумовно, ніколи не були реконструйовані, тому що я завжди вважав, що втратить ще більше часу, не кодуючи. Але я бачу, як це може бути причиною проблем, з якими я зараз стикаюся. Я час серйозно задуматися над тим, як зробити якийсь рефакторинг і консолідацію.
Найру

1
Google C ++ знущальна рамка (інтегрована з тестовою програмою google C ++) - дуже, дуже потужна глузуюча бібліотека - гнучка, насичена функціями - цілком порівнянна з будь-якою іншою глузливою рамкою.
ratkok

9

Дуже цікаве запитання.

Що важливо відзначити, це те, що C ++ не дуже легко перевірити, а ігри, загалом, також є дуже поганим кандидатом на TDD. Ви не можете перевірити, чи OpenGL / DirectX малює трикутник червоним кольором з драйвером X, а жовтим - з драйвером Y легко. Якщо нормальна векторна збірна карта не перегортається після перетворення шейдера. Ви також не можете перевіряти проблеми із відсіканням на версії драйверів з різною точністю тощо. Невизначена поведінка малювання через неправильні дзвінки також може бути перевірена лише за допомогою точного огляду коду та SDK. Звук також поганий кандидат. Багатопотокове читання, що знову ж таки є досить важливим для ігор, є досить марним для тестування одиницями. Так що важко.

В основному ігор - це багато графічного інтерфейсу, звуку та потоків. GUI, навіть із стандартними компонентами, на які можна надіслати WM_, важкий для одиничного тесту.

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

Знову ж таки, я не гуру TDD або євангеліст, тому прийміть все це з зерном солі.

Я, певно, написав би кілька тестів для основних основних компонентів (наприклад, матрична бібліотека, бібліотека зображень). Додайте купу abort()несподіваних входів у кожну функцію. І найголовніше, зосередитись на стійкому / стійкому коді, який не виходить з ладу.

Що стосується однієї помилки, розумне використання C ++, RAII та хороший дизайн проходять довгий шлях, щоб їх запобігти.

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


3
+1 Мені дуже подобається концепція TDD і використовую її куди завгодно, але ти підкреслюєш дуже важливий момент, про який адвокати TDD цікаво мовчать. Як ви вже вказали, існує багато типів програмування, для яких написання значущих одиничних тестів є надзвичайно важким, якщо не неможливим. Використовуйте TDD там, де це має сенс, але деякі типи коду краще розробити і перевірити іншими способами.
Марк Хіт

@ Марк: так, зараз ніхто, мабуть, не переймається інтеграційними тестами, думаючи, що, оскільки у них є автоматизований тестовий набір, все буде магічно спрацьовувати, коли збирати і випробовувати реальні дані.
gbjbaanb

Погодьтеся з цим. Дякуємо за прагматичну відповідь, яка не догматично призначає TDD як відповідь на все, а не на те, що це є, що є лише ще одним інструментом у наборі інструментів для розробників.
jb

6

Я погоджуюся з іншими відповідями, але хочу також додати дуже важливий момент: Рефакторинг коштує !!

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


4

Як інші люди виживають TDD, не вбиваючи всієї продуктивності та мотивації?

Це абсолютно відрізняється від мого досвіду. Ви або дивовижно розумні і пишете код без помилок (наприклад, вимкнено однією помилкою), або не розумієте, що в коді є помилки, які перешкоджають роботі вашої програми, і тому насправді не закінчено.

TDD - це смирення знати, що ти (і я!) Робиш помилки.

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

Якщо ви не помилитесь, то, можливо, TDD для вас не так важливий, як для мене!


Що ж, у вашому TDD-коді є помилки;)
Coder

Це правда! але вони, як правило, бувають різного типу помилок, якщо TDD зроблено належним чином. Я думаю, що казати, що код повинен бути на 100% помилкою, щоб закінчити, це неправильно. Хоча якщо хтось визначає помилку як відхилення від визначеної поведінки тесту, то я вважаю, що це помилка :)
Том

3

У мене є лише кілька зауважень:

  1. Схоже , ви намагаєтеся перевірити всі . Ви, мабуть, не повинні, лише високий ризик та конкретні випадки певного коду / методу. Я впевнений, що тут застосовується правило 80/20: Ви витрачаєте 80% на написання тестів за останні 20% коду або випадків, які не охоплені.

  2. Поставте пріоритет. Займіться спритною розробкою програмного забезпечення та складіть список того, що вам дійсно потрібно насправді зробити, щоб випустити за один місяць. Тоді відпустіть, просто так. Це змусить задуматися про пріоритетність функцій. Так, було б здорово, якби ваш персонаж міг зробити зворотній переворот, але чи має це ділова цінність ?

TDD - це добре, але тільки якщо ви не прагнете до 100% тестового покриття, і це не так, якщо це не дозволяє вам створювати фактичну цінність бізнесу (тобто функції, які додають щось у вашу гру).


1

Так, написання тестів та коду може зайняти більше часу, ніж просто написання коду - але написання коду та пов'язані з ним тести на одиницю (з використанням TDD) набагато передбачуваніше, ніж написання коду, а потім його налагодження.

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

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


0

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.