Аннотация:
Проектирование по контракту – это мощная техника разработки программного обеспечения (ПО), которая путем формализации взаимоотношений между компонентами позволяет создавать качественное, надежное и расширяемое ПО. В данной статье рассматриваются теоретические аспекты проектирования по контракту, изначально изложенные Бертраном Мейером, которые позволят понять всю ценность этой методики при разработке ПО.
Здравствуйте, Тепляков Сергей Владимирович, Вы писали:
А неплохо написано!
Одно замечание лишь, что все описанное специфично для .net, и слегка заангажированно ("но именно сегодня, после появления контрактов на платформе .net, началось бурное обсуждение этого явления компьютерным сообществом.")
Здравствуйте, Wolverrum, Вы писали:
W>А неплохо написано!
А тут для этого кнопочка специальная есть
W>Одно замечание лишь, что все описанное специфично для .net, и слегка заангажированно ("но именно сегодня, после появления контрактов на платформе .net, началось бурное обсуждение этого явления компьютерным сообществом.")
В этой статье я вообще старался минимально касаться специфики реализации Design by Contract конкретным языком или платформой. Все эти примеры в считанные минуты переписываются на Eiffel-е без каких-либо проблем, но поскольку Eiffel ну уж никак нельзя назвать mainstream-языком, а также потому, что примеры на C# просто легче читаются большинством разработчиков я выбрал именно .net.
Теперь по поводу "легкой заангажированности": здесь нет "ничего личного, только факты"
А если серьезно, то ведь на самом деле этим идеям (Design by Contract) уже два с хвостом десятка лет, но если сейчас погуглить на эту тему, то большая часть материала будет касаться именно Code Contracts. Ведь до этого времени, единственном языком с полноценной поддержкой ППК был Eiffel, но несмотря на все его достоинства он ведь так и не получил достаточного распространения. В других же популярных языках и платформах встроенной поддержки ППК нет; хотя многие из них поддерживают часть функционала с помощью "лома и какой-то матери", поэтому практически никто не использует нечто подобное в промышленном коде.
.net — это первая (и пока единственная) mainstream-платформа с поддержкой не только самих контрактов (которые являются только частью ППК), но и статистического анализа и возможностей генерации документации по самим контрактам. А когда за дело берется кто-то таких крупных игроков, то к этой вещи присматриваются гораздо сильнее; об этом сразу пишут в книгах (тот же Джон Скит посвятил Code Contracts отдельную статью в своей новой книге C# in Depth 2nd Edition), об этом начинают писать в статьях и говорить на форумах.
Одним из главных принципов проектирования по контракту является отсутствие проверок предусловий внутри тела программы. Это правило противоречит принципам защитного программирования, в котором «открытые методы класса предполагают, что данные небезопасны и отвечают за их проверку и исправление.
С точки зрения DbC противоречий нет: предусловия таких метов вырождаются в {true}, которое не нужно проверять, а проверка данных (исправление) является частью их работы (т.е. фактически эти проверки не являются предусловиями в терминах DbC).
Проектирование по контракту предназначено для формализации взаимоотношения двух программных элементов внутри доверенной среды и не предназначено для взаимодействия программного элемента с внешним миром.
Аналогично: внешний мир вполне может вызывать функции с предусловием {true}.
PS: В примере с ковариантностью на С++ допущена ошибка: типы B1 и D1 не являются ковариантными, в отличии от ссылок или указателей на них.
Одним из главных принципов проектирования по контракту является отсутствие проверок предусловий внутри тела программы. Это правило противоречит принципам защитного программирования, в котором «открытые методы класса предполагают, что данные небезопасны и отвечают за их проверку и исправление.
ЮЖ>С точки зрения DbC противоречий нет: предусловия таких метов вырождаются в {true}, которое не нужно проверять, а проверка данных (исправление) является частью их работы (т.е. фактически эти проверки не являются предусловиями в терминах DbC).
Может быть я тебя не совсем понял, ведь я написал о противоречии принципам защитного программирования, а не DbC.
ЮЖ>
Проектирование по контракту предназначено для формализации взаимоотношения двух программных элементов внутри доверенной среды и не предназначено для взаимодействия программного элемента с внешним миром.
ЮЖ>Аналогично: внешний мир вполне может вызывать функции с предусловием {true}.
Технически все верно, но логически — контракты для этого просто не предназначены. Ведь ты не ставишь утверждения (asserts) непосредственно в модулях ввода, поскольку ты не можешь гарантировать, что пользователь (или внешний мир) введет (или передаст) корректные данные. Тебе в любом случае нужны нормальные проверки, на выходе которых уже можно что-либо гарантировать. Так и получается, что ты вполне можешь использовать DbC на выходе модулей ввода, обеспечивая тем самым выполнение постусловий, необходимых для связи с другими модулями.
Вот что пишет Бертран Мейер:
Полезно сосредоточиться на некоторых неявно обсуждавшихся свойствах контрактов. Заметьте, контракты описывают только взаимодействие двух программ (программа — программа). Контракты не задают другие виды взаимодействий: человек — программа, внешний мир — программа. Предусловие не заботится о корректировке ввода пользователя, например программа read_positive_integer, ожидающая в интерактивном режиме ввода пользователем положительного целого.
...
При получении информации извне нельзя опираться на предусловия. Задача модулей ввода — гарантировать, что никакая информация не будет передана обрабатывающим модулям, пока она не будет удовлетворять условиям, требуемым для корректной обработки. При таком подходе утверждения будут широко использоваться в коммуникациях программа — программа. Постусловия модулей ввода должны соответствовать или превосходить предусловия, продиктованные обрабатывающими модулями. Фильтры играют охраняющую роль, обеспечивая корректность входных данных.
ЮЖ>PS: В примере с ковариантностью на С++ допущена ошибка: типы B1 и D1 не являются ковариантными, в отличии от ссылок или указателей на них.
Здравствуйте, SergeyT., Вы писали:
ST>я написал о противоречии принципам защитного программирования, а не DbC.
А в чём противоречие? Котракты и защитное программирование решают разные задачи. Упрощённо и грубо, контракты — система раннего оповещения об ошибках в логике программы, защитное программирование — стиль обработки грязных данных. Т.е. первое — средство динамической (и частично статической) верификации кода, второе — часть программной логики, оговорённая требованиями к программе.
Одним из главных принципов проектирования по контракту является отсутствие проверок предусловий внутри тела программы. Это правило противоречит принципам защитного программирования, в котором «открытые методы класса предполагают, что данные небезопасны и отвечают за их проверку и исправление.
ЮЖ>>С точки зрения DbC противоречий нет: предусловия таких метов вырождаются в {true}, которое не нужно проверять, а проверка данных (исправление) является частью их работы (т.е. фактически эти проверки не являются предусловиями в терминах DbC).
ST>Может быть я тебя не совсем понял, ведь я написал о противоречии принципам защитного программирования, а не DbC.
Смысл в том, что defeinsive programming вполне укладывается в рамки DbC (только бенефиты от этого никакие), а не противоречит им (даже с учетом цитат Мейера).
Нет никаких сомнений в полезности контрактов для документирования. Но взглянем на рисунок 3. Указаны модули ввода, в которых должна проводиться штатная проверка ошибок. Там не нужны контракты? А как же документирование? Видимо, без дублирования в таких местах не обойтись...
Здравствуйте, andrew_333, Вы писали:
_>Еще одна мелочь:
_>Нет никаких сомнений в полезности контрактов для документирования. Но взглянем на рисунок 3. Указаны модули ввода, в которых должна проводиться штатная проверка ошибок. Там не нужны контракты? А как же документирование? Видимо, без дублирования в таких местах не обойтись...
Еще раз напомню, что в модулях ввода не проводится проверка ошибок, в модулях ввода проводится валидация входных данных.
Модули ввода не могут полагаться на предусловия (поскольку суть контрактов — взаимоотношения программа-программа), но там могут быть (точнее должны быть) постусловия. Вот именно эта информация (ожидания на выходе модулей ввода) и будут задокументированы.
Местами написано так, что черт ногу сломит. Например:
Каждый конструктор, применимый к аргументам, удовлетворяющим его предусловию в состоянии, в котором атрибуты имеют значения, установленные по умолчанию, вырабатывает заключительное состояние, гарантирующее выполнение Inv.