Процесс программирования псевдокодов против разработки на основе тестирования

Для тех, кто не читал Code Complete 2, процесс программирования псевдокода - это в основном способ разработки подпрограммы, сначала описав ее на простом английском языке, а затем постепенно пересматривая ее до более подробного псевдокода и, наконец, кода. Основное преимущество этого состоит в том, чтобы помочь вам оставаться на правильном уровне абстракции, создавая системы сверху вниз, а не снизу вверх, тем самым развивая чистый API на разных уровнях. Я считаю, что TDD менее эффективен в этом, потому что он слишком сосредоточен на выполнении минимума, чтобы пройти тест, и поощряет небольшую предварительную разработку. Я также считаю, что поддерживать набор модульных тестов для нестабильного кода (код, который постоянно подвергается рефакторингу) довольно сложно, потому что обычно у вас есть дюжина модульных тестов для процедуры, которая требуется только один или два раза. Когда вы выполняете рефакторинг - например, меняете сигнатуру метода - большая часть работы, которую вы выполняете, заключается в обновлении тестов, а не кода продукта. Я предпочитаю добавлять модульные тесты после того, как код компонента немного стабилизировался.

Мой вопрос - тех, кто пробовал оба подхода, что вы предпочитаете?

6 ответов

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

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

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

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

С помощью Test Driven Development вы все равно должны сначала заняться планированием. Сначала следует посмотреть на то, что вы пытаетесь сделать. Не придумывайте все детали, но получите представление на простом английском языке о том, как решить проблему.

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

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

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

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

То, что тест пройден, не означает, что вы закончили.

TDD лучше всего характеризуется Red-Green-Refactor.

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

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

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

Настоящая цель - хорошее программное обеспечение. TDD не может исключать "добро".

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

Я использовал оба вместе с Big Upfront Development, все три имеют свои места в зависимости от таких вопросов, как язык, динамика команды и размер / сложность программы.

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

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

Если вы работаете в одиночку над чем-то небольшим на языке со статической типизацией, подход с использованием списка является разумным и сэкономит вам много времени по сравнению с TDD (обслуживание тестов НЕ БЕСПЛАТНО, хотя написание тестов в первую очередь не слишком плохо)- Когда в системе, над которой вы работаете, нет никаких тестов, добавление в тесты не всегда вызывает восхищение, и вы можете даже привлечь какое-то нежелательное внимание.

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

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

Я не должен развиваться органически.
Псевдокод является убийцей разума.
Это маленькая смерть приносит забвение памяти проекта.
Я буду сталкиваться с моей методологией 90-х.
Я позволю ему пройти через меня и через меня.
И когда оно пройдет, я поверну внутренний глаз, чтобы увидеть его путь.
Куда пропал псевдокод, там будет TDD.
Только юнит-тесты останутся.

(пожалуйста, не сердитесь на меня за это, я только наполовину серьезен:P)

Другие вопросы по тегам