Я потерпел неудачу в алгоритмическом тесте с Codility, потому что пытался найти лучшее решение, и в итоге у меня ничего не было.
Так что это заставило меня задуматься, могу ли я использовать подход, аналогичный TDD? Т.е. могу ли я, как правило, постепенно разрабатывать решение подобным образом?
Если бы я писал алгоритм сортировки, я мог бы перейти от стандартной Bubblesort к двухсторонней пузырьковой сортировке, но тогда что-то более продвинутое, например, Quicksort, было бы «квантовым скачком», но по крайней мере у меня были бы тестовые данные, которые я мог бы легко проверить.
Другие советы для таких тестов? В следующий раз я бы использовал больше методов / функций, чем внутренних циклов. Например, при сортировке вам часто требуется своп. Если бы это был метод, мне просто нужно изменить вызывающий код. Я мог бы даже иметь более продвинутые решения в качестве производных классов.
Под «Алгоритмическими» против «обычных» задач я имею в виду проблемы, в которых важна временная сложность. Таким образом, вместо того, чтобы проходить больше тестов, как в TDD, вы должны заставить его «вести себя лучше».
С "подобным TDD" я имею в виду:
- Напишите относительно автоматический тест, чтобы сэкономить время при ручном тестировании или приращении.
- Инкрементальное развитие.
- Регрессионное тестирование, способность обнаруживать, если код нарушается или, по крайней мере, если функциональность изменяется между приращениями.
Я думаю, что это должно быть довольно легко понять, если вы сравните
- Написание шелл-сортировки напрямую
- Переход от пузырьковой сортировки к быстрой сортировке (полное переписывание)
- Переход от односторонней сортировки пузырьков к сортировке оболочек (если возможно).
Ответы:
Смотрите также попытку Рона Джеффриса создать решатель судоку с TDD , который, к сожалению, не сработал.
Алгоритм требует значительного понимания принципов проектирования алгоритма. С этими принципами действительно возможно действовать постепенно, с планом, как это сделал Питер Норвиг .
На самом деле, для алгоритмов, требующих нетривиальных усилий по проектированию, почти всегда это усилие носит инкрементный характер. Но каждый «прирост», который является крошечным в глазах разработчика алгоритмов, выглядит как квантовый скачок (если позаимствовать вашу фразу) для человека, который не обладал такими же знаниями или знаниями в этом конкретном семействе алгоритмов.
Вот почему базовое образование по теории CS в сочетании с большим количеством практики программирования алгоритмов одинаково важны. Знание того, что существует особая «техника» (небольшие строительные блоки алгоритмов), - долгий путь к этим постепенным квантовым скачкам.
Однако есть некоторые важные различия между постепенным прогрессом в алгоритмах и TDD.
JeffO упомянул одно из различий : тест, который проверяет правильность выходных данных , отделен от теста, который утверждает производительность между различными реализациями одного и того же алгоритма (или различными алгоритмами, претендующими на то же решение).
В TDD добавляется новое требование в форме теста, и этот тест первоначально не должен проходить (красный). Тогда требование удовлетворяется (зеленый). Наконец код реорганизован.
При разработке алгоритма требование обычно не меняется. Тест проверки правильности результата пишется первым или вскоре после завершения черновой (очень уверенной, но медленной) реализации алгоритма. Этот тест на корректность данных редко изменяется; никто не меняет его на неудачный (красный) как часть обряда TDD.
Однако в этом аспекте анализ данных заметно отличается от разработки алгоритма, поскольку требования к анализу данных (как входные наборы, так и ожидаемые результаты) определены в человеческом понимании лишь слабо. Таким образом, требования часто меняются на техническом уровне. Это быстрое изменение ставит анализ данных где-то между разработкой алгоритмов и разработкой общих программных приложений - хотя они все еще тяжелы для алгоритмов, требования также меняются «слишком быстро» на вкус любого программиста.
Если требование изменяется, оно обычно требует другого алгоритма.
При разработке алгоритма менять (ужесточать) тест сравнения производительности на неудачу (красный) глупо - это не дает вам никакого представления о потенциальных изменениях в вашем алгоритме, которые могут повысить производительность.
Следовательно, при разработке алгоритма тест на корректность и тест производительности не являются тестами TDD. Вместо этого оба являются регрессионными тестами . В частности, регрессионный тест на корректность не позволяет вносить изменения в алгоритм, которые нарушают его корректность; Тест производительности не позволяет вносить изменения в алгоритм, который замедляет его работу.
Вы все еще можете включить TDD в качестве личного стиля работы, за исключением того, что ритуал «красный - зеленый - рефактор» не является строго необходимым или особенно полезным для мыслительного процесса разработки алгоритма.
Я бы сказал, что усовершенствования алгоритма на самом деле являются результатом создания случайных (необязательно правильных) перестановок в диаграммах потоков данных текущего алгоритма или их смешивания и сопоставления между ранее известными реализациями.
TDD используется, когда есть несколько требований, которые можно постепенно добавлять к вашему тестовому набору.
В качестве альтернативы, если ваш алгоритм управляется данными, каждый фрагмент тестовых данных / тестового примера можно добавлять постепенно. TDD также будет полезен. По этой причине «TDD-подобный» подход «добавлять новые тестовые данные - улучшать код, чтобы он правильно обрабатывал эти данные - рефакторинг» также будет работать для аналитической работы с открытыми данными, в которой цели алгоритмов описаны на человеке. -центрические слова и их мера успеха также оцениваются в человеческих терминах.
Он направлен на то, чтобы научить тому, как сделать его менее сложным, чем пытаться удовлетворить все (десятки или сотни) требований за одну попытку. Другими словами, TDD включается, когда вы можете диктовать, что определенные требования или цели могут быть временно проигнорированы, пока вы реализуете некоторые предварительные проекты своего решения.
TDD не заменяет информатику. Это психологическая опора, которая помогает программистам преодолеть шок от необходимости выполнять множество требований одновременно.
Но если у вас уже есть одна реализация, которая дает правильный результат, TDD посчитает свою цель достигнутой и код будет готов к передаче (рефакторингу или другому программисту-пользователю). В некотором смысле это побуждает вас не преждевременно оптимизировать код, объективно давая вам сигнал о том, что код «достаточно хорош» (чтобы пройти все тесты на корректность).
В TDD акцент также делается на «микро-требованиях» (или скрытых качествах). Например, валидация параметров, утверждения, создание и обработка исключений и т. Д. TDD помогает обеспечить правильность путей выполнения, которые не часто используются при нормальном ходе выполнения программного обеспечения.
Некоторые типы кода алгоритма также содержат эти вещи; они поддаются TDD. Но поскольку общий рабочий процесс алгоритма не является TDD, такие тесты (по проверке параметров, утверждениям, выбрасыванию и обработке исключений), как правило, пишутся после того, как код реализации уже (хотя бы частично) написан.
источник
Для вашей проблемы у вас будет два теста:
Что тестировать или полное тестовое покрытие является спорным, но я думаю, что сложные части вашего приложения, которые должны быть настроены (много изменены), являются идеальными кандидатами для автоматического тестирования. Эти части приложения обычно определяются очень рано. Использование подхода TDD с этим фрагментом имело бы смысл.
Способность решать сложные проблемы не должна ограничиваться нежеланием пробовать разные подходы. Наличие автоматизированного теста должно помочь в этой области. По крайней мере, вы будете знать, что вы не делаете это хуже.
источник
Вроде.
Вы можете проверить время выполнения и сложность. Испытания во время выполнения должны быть немного прощающими, чтобы допустить конкуренцию за системные ресурсы. Но во многих языках вы также можете переопределять или внедрять методы и считать реальные вызовы функций. И, если вы уверены , что ваш текущий алгоритм не является оптимальным, вы можете ввести тест , который просто требует , чтобы
sort()
Invokecompare()
меньшего количества раз , чем наивная реализация.Или вы можете сравнить
sort()
два набора и убедиться, что они масштабируются вcompare()
вызовах в зависимости от вашей целевой сложности (или около того, если вы ожидаете некоторой несогласованности).И, если вы не можете теоретически доказать , что множество размеров
N
должно требовать строго не болееN*log(N)
сравнений, это может быть разумно ограничить уже работаетsort()
наN*log(N)
призыванияcompare()
...Однако ...
Выполнение требования к производительности или сложности не гарантирует, что базовой реализацией является {AlgorithmX} . И я бы сказал, что это нормально. Неважно, какой алгоритм используется, при условии, что ваша реализация соответствует вашим требованиям, включая любые важные требования к сложности, производительности или ресурсам.
Но если вы хотите убедиться в том, что используется определенный алгоритм, вам нужно быть более утомительным и углубляться в детали. Вещи как..
compare()
иswap()
(или чего-либо еще)Но опять же, если вы пытаетесь убедиться, что {AlgorithmX} используется в частности, вероятно, есть какие-то особенности {AlgorithmX}, которые вас интересуют, которые важнее проверить, чем то, использовался ли {AlgorithmX} в конце концов ...
Также имейте в виду, что TDD не отменяет необходимость исследования, мышления или планирования в разработке программного обеспечения. Это также не отменяет необходимости мозгового штурма и экспериментов, даже если вы не можете легко утверждать о своем поиске и поиске в своем автоматизированном тестовом наборе.
источник