Дизайн по контракту - Design by contract

Дизайн по контрактной схеме

Дизайн по контракту ( DBC ), также известный как контракт программирование , программирование по контракту и дизайн по-контракту программирования , является подход к разработке программного обеспечения .

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

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

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

История

Этот термин был введен Бертраном Мейером в связи с его разработкой языка программирования Eiffel и впервые описан в различных статьях, начиная с 1986 года и в двух последовательных изданиях (1988, 1997) его книги « Конструирование объектно-ориентированного программного обеспечения» . Eiffel Software подала заявку на регистрацию торговой марки Design by Contract в декабре 2003 года, и она была предоставлена ​​в декабре 2004 года. Текущим владельцем этой торговой марки является Eiffel Software.

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

Описание

Центральная идея DbC - это метафора того, как элементы программной системы взаимодействуют друг с другом на основе взаимных обязательств и выгод . Метафора пришла из деловой жизни, где «клиент» и «поставщик» договариваются о «контракте», который определяет, например, следующее:

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

Аналогичным образом , если метод из класса в объектно-ориентированном программировании обеспечивает определенную функциональность, она может:

  • Ожидайте, что определенное условие будет гарантировано при входе любым клиентским модулем, который его вызывает: предварительное условие метода - обязательство для клиента и выгода для поставщика (сам метод), поскольку он освобождает его от необходимости обрабатывать случаи вне рамок предварительное условие.
  • Гарантировать определенное свойство при выходе: постусловие метода - обязательство для поставщика и, очевидно, выгода (основное преимущество вызова метода) для клиента.
  • Поддерживать определенное свойство, предполагаемое при входе и гарантированное при выходе: инвариант класса .

Контракт семантически эквивалентен тройке Хоара, которая формализует обязательства. Это можно резюмировать «тремя вопросами», на которые проектировщик должен неоднократно отвечать в контракте:

  • Что ожидает контракт?
  • Что гарантирует договор?
  • Что содержится в контракте?

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

Понятие контракта простирается до уровня метода / процедуры; контракт для каждого метода обычно содержит следующую информацию:

Подклассам в иерархии наследования разрешено ослаблять предусловия (но не усиливать их) и усиливать постусловия и инварианты (но не ослаблять их). Эти правила приблизительно соответствуют поведенческим подтипам .

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

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

При использовании контрактов поставщик не должен пытаться проверить выполнение условий контракта - практика, известная как наступательное программирование - общая идея состоит в том, что код должен «терпеть неудачу», а проверка контракта является подстраховкой.

Свойство DbC «жесткий сбой» упрощает отладку поведения контракта, поскольку предполагаемое поведение каждого метода четко указано.

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

Дизайн по контракту также определяет критерии корректности программного модуля:

  • Если инвариант класса И предварительное условие истинны до того, как поставщик вызывается клиентом, то инвариант И постусловие будет истинным после того, как услуга будет завершена.
  • При обращении к поставщику программный модуль не должен нарушать предварительные условия поставщика.

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

Последствия для производительности

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

Во многих языках программирования контракты реализуются с помощью assert . Утверждения по умолчанию компилируются в режиме выпуска в C / C ++ и аналогичным образом деактивируются в C # и Java.

Запуск интерпретатора Python с «-O» (для «оптимизировать») в качестве аргумента также приведет к тому, что генератор кода Python не будет генерировать какой-либо байт-код для утверждений.

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

Отношение к тестированию программного обеспечения

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

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

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

Языковая поддержка

Языки с нативной поддержкой

Языки, которые изначально реализуют большинство функций DbC, включают:

Языки со сторонней поддержкой

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

Смотрите также

Примечания

Библиография

  • Митчелл, Ричард и МакКим, Джим: Дизайн по контракту: на примере , Addison-Wesley, 2002
  • Wikibook описания DBC близко к исходной модели.
  • Макнейл, Эшли: структура семантики поведенческих контрактов . Труды Второго международного семинара по моделированию поведения: основы и приложения (BM-FA '10). ACM, New York, NY, USA, 2010. В этой статье обсуждаются обобщенные понятия контракта и взаимозаменяемости .

внешние ссылки