Что такое контрактная программа

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

контрактное программирование (design by contract (DbC), programming by contract, contract-based programming) — это метод проектирования программного обеспечения. Он предполагает, что проектировщик должен определить формальные, точные и верифицируемые спецификации интерфейсов для компонентов системы. При этом, кроме обычного определения абстрактных типов данных, также используются предусловия, постусловия и инварианты. Данные спецификации называются «контрактами» в соответствии с концептуальной метафорой условий и ответственности в гражданско-правовых договорах.

История

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

Описание

Контрактное программирование

#ПэЧе КОНТРАКТНАЯ СИСТЕМА

рис. проектирование модуля по контракту

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

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

Многие языки программирования позволяют учитывать такие обязательства. Контрактное программирование подразумевает эти требования критическими для корректности программ, поэтому они должны быть утверждены при проектировании. Таким образом, контрактное программирование предписывает начинать писать код с написания формальных утверждений корректности (assertions).

В объектно-ориентированном программировании контракт метода обычно включает следующую информацию:

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

При использовании контрактов сам код не обязан проверять их выполнение . Об этом говорит сайт https://intellect.icu . Обычно в таких случаях в коде делают жесткое падение[уточнить] («fail-fast»), таким образом облегчая отладку выполнения контрактов. Во многих языках, таких как C, C++, Delphi, PHP, такое поведение реализуется оператором assert. В релизовом варианте кода это поведение может быть сохранено, либо проверки могут быть убраны чтобы повысить производительность.

Урок № 1 Контрактная система понятие и принципы, правовые источники

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

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

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

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

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

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

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

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

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

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

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

Реализация в языках программирования

Поддержка DbC на языковом уровне

Языки, изначально поддерживающие средства для контрактного программирования:

Поддержка DbC с помощью сторонних библиотек

  • C и C++ посредством CTESK, библиотеки Contract++, препроцессора DBC for C, GNU Nana или компилятора C++ от Digital Mars.
  • C# посредством Code Contracts
  • Java посредством JavaTESK, iContract2, Contract4J, jContractor, Jcontract, C4J, CodePro Analytix, STclass, Jass preprocessor, OVal with AspectJ, Java Modeling Language (JML), SpringContracts для Spring Framework, или Modern Jass, Custos с использованием AspectJ, JavaDbC с использованием AspectJ, cofoja(разработанная компанией Google).
  • JavaScript посредством Cerny.js или ecmaDebug.
  • Lisp
  • Common Lisp с помощью макросов или протокола метаобъектов CLOS.
  • Scheme посредством расширения PLT, а именно тот факт, что любое нарушение контракта должно указывать на виновного и иметь точное объяснение.

Общие инструменты

  • Perfect Developer посредством Perfect specification language может проверять контракт, используя статический анализ кода и генерируя программы на языках типа C++ и Java.
Читайте также:
Какие параметры предусмотрены для настройки параметров учета в программе 1с бухгалтерия 8

Вау!! Ты еще не читал? Это зря!

  • Тестирование на основе модели
  • Компонентная разработка программного обеспечения
  • Корректность ( информатика )
  • Защитное программирование
  • Быстро
  • Формальные методы
  • Логика Хоара
  • Модульное программирование
  • Вывод программы
  • Доработка программы
  • Сильная типизация
  • Разработка через тестирование
  • Типосостояний анализ

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

Источник: intellect.icu

Контрактное программирование

Контрактное программирование (designbycontract – DbC) — это метод проектирования ПО. Он предполагает, что проектировщик должен определить формальные, точные и верифицируемые спецификации интерфейсов для компонентов системы. При этом, кроме обычного определения абстрактных типов данных, также используются предусловия, постусловия и инварианты.

Основная идея контрактного программирования — это модель взаимодействия элементов программной системы, основывающаяся на идее взаимных обязательств и преимуществ. Контракт некоторого метода или функции может включать в себя (в списке ниже поставщик – это метод):

· конкретные обязательства, которые любой клиентский модуль должен выполнить перед вызовом метода — предуслови я, которые дают преимущество для поставщика — он может не проверять выполнение предусловий;

· конкретные свойства, которые должны присутствовать после выполнения метода — постусловия, которые входят в обязательства поставщика;

· обязательства по выполнению конкретных свойств — инвариантов, которые должны выполняться при получении поставщиком сообщения, а также при выходе из метода.

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

· возможные типы входных данных и их значение;

· типы возвращаемых данных и их значение;

· условия возникновения исключений, их типы и значения;

· присутствие побочного эффекта метода;

· предусловия, которые могут быть ослаблены (но не усилены) в подклассах;

· постусловия, которые могут быть усилены (но не ослаблены) в подклассах;

· инварианты, которые могут быть усилены (но не ослаблены) в подклассах;

· (иногда) гарантии производительности, например, временная сложность или сложность по памяти.

Таким образом, для выражения ожидаемого поведения используются утверждения(assertions), а для того, чтобы понять, кто в программе не прав, вызывающий или вызываемый код, то добавлено несколько видов утверждений:

1. Предусловия – нарушения которых говорит о баге в вызывающем коде («клиент не прав»).

2. Постусловия – нарушения которых говорят о баге в вызываемом коде («сервис не прав»).

3. Инварианты класса – нарушения которых также говорят о баге в вызываемом коде. Это ОО-специфическая штука, которая позволяет четко сказать, чем же является валидное состояние объекта, чтобы не множить предусловия и постусловия. Тут нужно помнить, что инвариант валиден от момента создания объекта до момента его уничтожения – вызова деструктора/метода Dispose, но может быть не валидным *внутри* вызова метода. Инвариант должен быть валидным в *видимых точках*.

4. Утверждения о корректности реализации – нарушения которых также говорят о баге в вызываемом коде. Это макросы Asserts, вставленные в разные точки приложения и упрощающие отлов багов.

5. Инварианты цикла присутствуют в языке Eiffel, их можно игнорировать.

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

В чем же разница между контрактами и Asserts? Разница в том, что контрактное программирование подразумевает «интеграцию» утверждений в инструменты (среду разработки). Т.е. любаяполноценная реализация механизма «контрактов» должна предоставлять следующие возможности:

1. Возможность задавать уровень утверждений:

· оставить только предусловия;

· оставить предусловия и постусловия;

· оставить все утверждения.

2. Возможность генерации документации и удобный способ «обнаружения» контрактов в среде исполнения.

3. Возможность доказать корректность программы на этапе компиляции (статический верификатор).

Замечание о понятии корректности ПО. Д ан простейший пример. Что вы можете сказать о следующей функции:

int DoSomething(int y)

Сама по себе, эта функция не является ни корректной, ни не корректной. Понятие корректности приобретает смысл только в контексте ожидаемого результата. Эта функция является корректной к утверждению “Возвращаемое значение в два раза меньше аргумента”, но является некорректным к утверждению “Возвращаемое значение должно быть положительным”, поскольку нет никаких гарантий того, что в эту функцию не будет передано отрицательное значение. Таким образом, понятие корректности ПО можно рассматривать только по отношению к некоторой спецификации

Контракты C#. Класс Contractы (Пространство имен: System.Diagnostics.Contracts )

Для работы с контрактами кода можно использовать классы, доступные в пространстве имен System.Diagnostics.Contracts в.NET 4. И выше. Однако в VisualStudio15необходимый инструмент отсутствует. Понадобится загрузить расширение для VisualStudio из сайта MicrosoftDevLabs. Для проведения статического анализа с помощью этого инструмента требуется версия VisualStudioTeamSystem, а для анализа времени выполнения достаточно версии VisualStudioStandardEdition. На рис ниже показано окно свойств проекта с требуемым расширением.

Класс Contractсодержит статические методы для представления контрактов программы, таких как предусловие, постусловие и инвариантность объектов.

1. Предусловия -методы Requires () и Requires (). Метод Requires() принимает в качестве 1-го аргумента булевское значение, в качестве 2-го необязательного параметра – текстовую строку с сообщением, которое появляется при невыполнении контракта. Метод в случае невыполнения условия генерирует по умолчанию исключение типаContractsRuntime+ContractException. Метод Requires() генерирует исключение определенного типа.

Читайте также:
Почему вылетает программа видеомонтаж

2. Постусловия. Для задания постусловий используются Ensures() и EnsuresOnThrow(). Аргументы метода Ensures() определяются аналогично предыдущему случаю. EnsuresOnThrow() гарантирует, что разделенное состояние удовлетворит условию в случае генерации указанного исключения.

Метод Result() используется для указания гарантированного возвращаемого значения.

OldValue(T)Представляет значения, какими они были в начале метода или свойства. По умолчанию тип int.

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

Предусловия позволяют проверить условия на входе метода, постусловия – на выходе из метода. Реальный код, обслуживающий контракты, генерируется утилитой ccrewrite, находит все вызовы утверждений контрактов и вставляет в их место соответствующий код. В результате методContract.Ensures, который стоит в начале метода фактически происходит при выходе из метода.

4. Можно также назначить глобальный обработчик событияContractFailed, который будет вызываться при каждом нарушении контракта во время выполнения. При нарушении контракта возбуждается исключение ContractException. Но поставить обработчик на ContractException не получится, в пользовательском коде оно доступно как экземпляр Exception.

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

Contract.ContractFailed += (sender, args) =>

args.SetHandled();

В данном примере при нарушении контракта будет выведено диагностическое сообщение. Вызов методе args.SetHandled() означает что исключение ContractException возбуждаться не будет.

5. Инварианты. Contract.Invariant() определяет условия, которые должны соблюдаться на протяжении времени жизни метода:

[ContractInvariantMethod] //обязательныйатрибут

private voidИмя_метода() //методбезаргументов, private – обязательно

Contract.Invariant (условие,необязательное_сообщение);

Тело метода – последовательность вызовов методов Contract.Invariant ().

Источник: studopedia.ru

Контракты. Что это и с чем едят. Часть 1

Многие из вас, вероятно, слышали об упоминаний контрактов во время обсуждения кода. Фразы наподобии: «Код должен соблюдать контракт интерфейса», «Юнит-тестами тестируется не код, а контракт класса», «Тестируйте не код, а контракты» и т.п. Сегодня постараемся понять: что такое контракты и что они дают. Статья будет состоят из двух частей:

  1. Введение в контракты, что такое контракты, свойство контрактов и т.д
  2. Примеры использование контрактов в коде и объяснение о том, что определенные выражения об контрактах (пример: «Тестировать нужно контракты, а не реализацию» и т.п).

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

Содержание:

  1. Что такое контракты, аналогии в реальном мире
  2. Что такое контракт в коде
  3. Из чего состоит контракт:постусловия, предусловия и инварианты
  4. Виды контрактов

Что такое контракт?

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

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

  • Что мы ожидаем от того, с кем мы заключили контракт, т.е то что он должен выполнить
  • Какие последствия будут если наш контракт будет нарушен
  • И т.д

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

И это понятие контракт из реального мира, попытались внедрить в код. Теперь объясним что такое контракт в рамках кода.

Что такое контракт в коде?

Контракт — это описание “правил” взаимодействия сущностей друг с другом в рамках кода. Примеры «правил» для класса бывают примерно такими: “метод этого класса обязуется предоставить результат, если будут выполнены все условия”. Если привести более понятный пример с кодом:

Допустим, у нас есть класс ProductService и у него метод uploadImage, и если попытаться составить контракт к этому методу, то он будет выглядит так:

Метод выполнится если:

  • Передан аргумент file — который является типом N-класса
  • В случае передачи неправильного типа — выходит ошибка
  • В случае передачи неправильного типа — выходит ошибка (исключение)

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

В настоящее время, прописать контракт для метода становится легче, потому что в языки введены, type hint (указание типов передаваемых аргументов), возможность указать тип возвращаемого результата и т.д.

В последствии, писать проверки в теле метода на подобии: аргумент “a” соответствует типу “б” теряет актуальность, все это теперь работает на уровне ядра языка. Но из-за этого не снизилась значимость контрактов, потому что не все условия можно указать в аргументах.

Свойства контракта:

Обычно контракт состоит из некоторых свойств, с помощью которого описывается контракт:

  • Предусловия
  • Постусловия
  • Инварианты

Предусловия — это условие которое, мы выполняем в теле метода, до выполнение основного действия. Все это описывается именно в методе, с помощью простых if и т.д. Пример (будет псевдокод, укороченный PHP):

class ProductService < public function uploadImage(FileUpload file): bool < // Предусловия if (file.size >5000) < throw new Exception(‘File size is more than 5mb’); >// Выполнение основного кода // . > >

Читайте также:
Программа которая снимает галочки

Думаю из примера понятно, что тут ничего сложного нету, предусловия — это проверки перед выполнение основного кода метода.

Постусловия — это такие же условия как и предусловия только наоборот. Под “наоборот”, я имею ввиду, что они выполняются после выполнение основного кода метода, перед возвращением результата. Тот же пример:

class ProductService < public function uploadImage(FileUpload file): bool < // Предусловия if (file.size >5000) < throw new Exception(‘File size is more than 5mb’); >// Выполнение основного кода result = . ; // Постусловия if (!result) < throw new Exception(‘Fail during upload file’); >return true; > >

Инварианты — это проверки на то, что состояние объекта является валидным после изменения. Допустим пример, у нас есть класс Balance (Баланс) и метод который обновляет значение баланса. Инвариант в этом случае будет проверка состояния объекта (в нашем случае баланса), находится ли он в дозволенном, нашей системой состоянии.

Если мы обновим наш баланс с помощью метода changeBalance , то состояние нашего объекта изменится, и инвариант в этом случае будет проверка на то, что наш баланс не меньше 0. То есть теперь определение будет более понятно, инварианты — это специальные условия, которые описывают целостное состояние объекта.

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

Если рассматривать контракты в PHP, их там можно придерживаться только с некоторыми ограничения, проблема в том, что везде писать проверки на инварианты сложно (но есть реализации библиотек которые работают с помощью Reflection API, применяя парсинг док-блоков). Обычно программирование на контрактах называются “Контрактное программирование”.

Разные виды контрактов:

По-моему мнению, контракт можно описать двумя способами:

  1. Контракт который описан с помощью интерфейса
  2. Контракт который описан с помощью реализации без интерфейса или с интерфейсом.

Сейчас поговорим об их различии.

Контракт который описан с помощью интерфейса. Он имеет некоторые ограничения. Как мы знаем, в интерфейсе можно описать только сигнатуру метода, возвращаемый тип и т.д, но не тело самого метода. Из-за этого, у нас бывают некоторые ограничения, при описании контракта для метода, а именно, мы не можем определить в интерфейсе, предусловия, постусловия и инварианты. Рассмотрим пример:

В этом примере, мы описали контракт с помощью док-блока и с помощью type hint. Контракт метода звучит так:

  1. Передаваемый параметр value, должен иметь тип int
  2. Возвращаемое значение метода будет типом boolean
  3. Метод может выкинуть исключение RuntimeException

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

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

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

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

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

Итог:

Контракты в программировании — это описание то, как будет ввести себя модуль (класс, метод и т.д), с помощью контрактов мы получаем удобства, такие как:

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

Их можно описать и с помощью сигнатуры методов (указание type hint, указание возвращаемых значении), и с помощью блока-комментария. Контракты имеют свойства, которые нужно соблюдать, чтобы контракт был целостным, это — предусловия, постусловия и инварианты.

Описание контрактов можно разделить на два вида: первый — описание контракта с помощью интерфейса, второй — описание контракта с помощью реализации класса.

В первом случае, мы не можем использовать свойства контракта (предусловия, постусловия и инварианты), т.к интерфейс не может иметь тело метода, этот тип контракта можно назвать — неполноценным или неконкретизированным

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

Вот на этом все, если заметили ошибку или неточность пишите в комментариях. Можете также писать о вашем понимании контрактов.

Советую прочитать эти ресурсы для хорошего понимания материала:

  • Прочитать книгу “Адаптивный код”, глава по SOLID, там пролистать до третьего принципа, O — OCP и там описываются контракты
  • https://youtu.be/oMi2ReGtXrI — посмотреть это видео, более подробно описывает контракты и показывает пример на PHP.
  • https://habr.com/en/post/214371/ — другая статья, про контракты и как они реализованы в PHP, также даётся список библиотек которые позволяют описать свойства контракта в док-блоке
  • Прочитать про «Контрактное программирование» и как реализуется в других языках

Источник: habr.com

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru