Подтвердить что ты не робот

Почему дизайн по контракту не так популярен по сравнению с разработкой, основанной на тестах?

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

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

Если вы следуете книге Бертран Мейерса "Объектно-ориентированное программирование" словом, сам класс имеет внутренние и внешние контракты, так что он делает только то, что он должен делать, и ничего больше. Никаких внешних тестов не требуется, так как код для обеспечения выполнения контракта является частью класса.

Быстрый пример, чтобы прояснить ситуацию

TDD

  • Создайте тест, чтобы во всех случаях значение варьировалось от (0-100)

  • Создайте класс, содержащий метод, который проходит тест.

DBC

  • Создайте класс, создайте контракт для этого члена var для диапазона от (0-100), установите контракт для нарушения контракта, определите метод.

Мне лично нравится подход DBC.


Есть ли причина, почему чистый DBC не так популярен? Являются ли это языками или инструментами или являются Agile или это только я, которому нравится иметь код, ответственный за себя?

Если вы думаете, что я не думаю правильно, я был бы более чем готов учиться.

4b9b3361

Ответ 1

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

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

Если вы читаете руководство Sun для написания JavaDocs, в нем говорится, что документация должна в основном заключить контракт, достаточный для написания плана тестирования. Следовательно, дизайн по контракту не обязательно является взаимоисключающим с TDD.

Ответ 2

TDD и DbC - две разные стратегии. DbC разрешает отказоустойчиво во время выполнения, в то время как TDD действует "в время компиляции" (точнее, он добавляет новый шаг сразу после компиляции для запуска модульных тестов).

Это большое преимущество TDD над DbC: оно позволяет получить более раннюю обратную связь. Когда вы пишете код TDD-способом, вы одновременно получаете код и его модульные тесты, вы можете убедиться, что он "работает" в соответствии с тем, что, по вашему мнению, должен, который вы закодировали в тесте. С DbC вы получаете код со встроенными тестами, но вам все равно придется его использовать. ИМО, это, безусловно, одна из причин того, что Dbc не так популярен.

Другие преимущества: TDD создает автоматический набор тестов, который позволяет обнаруживать (предотвращать чтение) регрессии и делать Refactoring безопасно, чтобы вы могли наращивать свой дизайн постепенно. DbC не предлагает эту возможность.

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

Ответ 3

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

Простой факт, что вы используете технику DbC, не делает правильный код. Поэтапный договор устанавливает четко определенные правила для вашего кода и его пользователей в виде контрактов. Это полезно, но вы всегда можете все испортить, только вы, вероятно, заметите раньше.

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

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

Ответ 4

Я думаю, что лучше использовать оба метода в совокупности, а не только один или другой.

Мне всегда казалось, что полное выполнение контракта внутри класса и его методы могут быть непрактичными.

Например, если функция говорит, что она будет хешировать строку каким-то методом и вернуть хешированную строку в качестве вывода, как функция обеспечивает, чтобы строка была правильно хеширована? Хеш его снова и посмотреть, совпадают ли они? Кажется глупым. Отмените хэш, чтобы узнать, получаете ли вы оригинал? Невозможно. Скорее, вам нужен набор тестовых примеров, чтобы обеспечить правильную работу функции.

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

Ответ 5

В моем сознании TDD более "индуктивен". Вы начинаете с примеров (тестовых примеров), и ваш код воплощает общее решение этих примеров.

DBC кажется более "дедуктивным", после сбора требований вы определяете поведение объекта и контракты. Затем вы кодируете конкретную реализацию этих контрактов.

Написание контрактов несколько сложнее, чем тесты, которые являются конкретными примерами поведения, это может быть причиной того, что TDD более популярен, чем DBC.

Ответ 6

Я использовал оба в прошлом и нашел DBC-стиль менее "навязчивым" . Драйвер для DBC может быть обычным запуском приложения. Для Unit Tests вам нужно позаботиться о настройке, потому что вы ожидаете (проверяете) некоторые ответы. Для DBC вам не обязательно. Правила написаны в режиме, не зависящем от данных, поэтому нет необходимости настраивать и насмехаться.

Подробнее о моих опытах с DBC/Python: http://blog.aplikacja.info/2012/04/classic-testing-vs-design-by-contract/

Ответ 7

Прежде всего, я инженер-программист Eiffel, поэтому я могу поговорить с этим по опыту.


Посылка TDD vs DbC неверна

Две технологии не расходятся друг с другом, но дополняют друг друга. Дополнение связано с размещением утверждений и целей.

Цель TDD имеет как компоненты, так и область. Основными компонентами TDD являются логические утверждения и функция объекта (например, метод). Шаги просты:

  • Создайте объект.
  • Выполните некоторый код в функции.
  • Сделать утверждения о состоянии данных об объекте.

Утверждения, которые терпят неудачу, не проходят тест. Передача всех утверждений является целью.

Подобно TDD, контракты по контракту имеют цель, объем и компоненты. В то время как TDD ограничивается единичным тестированием, контракты могут жить через весь SDLC (жизненный цикл разработки программного обеспечения)! В рамках TDD выполнение объектных методов (функций) будет выполнять контракты. В настройке автотеста Eiffel Studio (TDD) создается один объект, выполняется вызов (точно так же, как TDD на других языках), но здесь заканчивается то, что подобие заканчивается.

В Eiffel Studio с автотестированием и кодом Эйфеля с контрактами цель несколько меняется. Мы хотим проверить отношения между клиентом и поставщиком. Наш код TDD притворяется клиентом нашего метода Поставщика на его объекте. Мы создаем наши объекты и вызываем методы, основанные на этой цели, а не просто упрощенное тестирование TDD-ish. Поскольку вызовы наших методов (функций) имеют контракты, эти контракты будут выполняться как часть нашего TDD-кода в Auto-test. Поскольку это верно, утверждения контракта (тесты), которые мы размещаем в нашем коде, НЕ должны появляться в нашем тестовом коде TDD. Наша задача (как программиста) состоит в том, чтобы просто обеспечить: A) кодовые + контракты выполняются вдоль всех N-путей, а B) кодовые + контракты выполняются с использованием всех разумных типов данных и диапазонов.

Возможно, больше написано о взаимосвязи TDD-DbC, но я не буду хамским с вами по этому вопросу. Достаточно сказать, что TDD и DbC НЕ расходятся с другими - не длинным выстрелом!

Сила контрактов DbC, выше которой TDD может достигать

Теперь мы можем обратить внимание на силу контрактов Design-by-Contract, за пределами которых TDD может достичь!

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

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

Кроме того, TDD не может выполнять инварианты класса, но в малейшей степени. Я попытался изо всех сил получить мой код автотестирования (который на самом деле является только версией Eiffel Studios для прикладного TDD), чтобы сделать инвариантную мимику класса. Это невозможно. Чтобы понять, зачем вам нужно знать, как и как работают инварианты класса Эйфеля. Итак, на данный момент вам просто нужно либо поверить мне на слово (или нет), что TDD неспособен к этой задаче, что DbC обрабатывает так легко, хорошо и элегантно!

Досягаемость DbC не заканчивается вышеуказанными понятиями

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

  • Workbench: вы, как программист, используете код, чтобы увидеть его работу (например, до TDD-времени или в сочетании с TDD-временем).

  • Единичный тест: ваше непрерывное интеграционное тестирование, модульное тестирование, TDD и т.д.

  • Альфа-тест: ваши первые опытные пользователи будут путешествовать по контрактам, поскольку они запускают исполняемый файл

  • Бета-тест: более широкая аудитория пользователей также будет преодолевать контракты.

  • Производство: окончательный исполняемый файл (или производственная система) может иметь постоянное тестирование, применяемое через контракты (TDD не может).

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

И если этого недостаточно, контракты (по дизайну) могут делать то, что никогда не может сделать утверждение TDD: скажите, где в стеке вызовов и какие отношения клиент-поставщик нарушены, и почему (что также немедленно предлагает, как это исправить). Почему это так?

Утверждения TDD предназначены для того, чтобы рассказать вам о результатах выполнения кода (выполнения) после факта. Утверждение TDD может видеть только до текущего состояния рассматриваемого метода. Какие утверждения TDD не могут сделать из их положения снаружи базы кода, это сказать вам, какой именно вызов был неудачен и почему! Вы видите, что ваш первоначальный вызов TDD для некоторого метода вызовет этот метод. Много раз этот метод будет вызывать другой, а другой, а другой - иногда, когда стек вызовов взлетает вверх и вниз, а затем и yon, происходит поломка: что-то неправильно записывает данные, не записывает их вообще или записывает это когда это не должно быть.

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

Резюме

Пусть повторяется.

  • TDD не расходится с DbC.

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

  • Договор расширяется и раскрывает больше о вашем коде при его разрыве.

  • TDD - это одна из форм катализатора для контрактов, которые должны быть выполнены.

В конце дня: я хочу обоих! Прочитав все это (если вы выжили), я надеюсь, что вы тоже это сделаете.

Ответ 8

Я вижу дизайн по контракту как спецификацию успеха/неудачи во ВСЕХ случаях, тогда как Test Driven Development нацеливается на один конкретный случай. Если случай TDD преуспевает, то предполагается, что функция выполняет это задание, но не учитывает другие случаи, которые могут привести к его сбою.

Дизайн по контракту, с другой стороны, не обязательно гарантирует желаемый ответ, только тот ответ "правильный". Например, если возвращаемая функция должна возвращать непустую строку, единственное, что вы можете принять в ENSURE, это то, что она не будет равна null.

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

Итак, эти два являются дополнительными.

Грег

Ответ 9

Я не вижу причин, по которым оба они не могут сосуществовать. Замечательно смотреть на метод и точно знать, что такое контракт. Также замечательно знать, что я могу выполнять свои модульные тесты и знать, что с моим последним изменением ничего не сломалось. Эти два метода не являются взаимоисключающими. Почему дизайн по контракту не является более популярным, это тайна.