Дизайн по контракту (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, включают:
Различные библиотеки, препроцессоры и другие инструменты были разработаны для существующих языков программирования без собственной разработки по контракту: