Недавно я наткнулся на структуру Microsoft для контрактов кода.
Я прочитал немного документации и обнаружил, что постоянно спрашиваю: «Зачем мне это когда-либо хотеть, потому что он не делает и часто не может выполнить статический анализ».
Теперь у меня уже есть своего рода защитный стиль программирования с такими исключениями:
if(var == null) { throw new NullArgumentException(); }
Я также часто использую NullObject Pattern и редко сталкиваюсь с какими-либо проблемами. Добавьте модульные тесты, и все готово.
Я никогда не использовал утверждения и никогда не пропускал их. Наоборот. Я действительно ненавижу код, в котором много бессмысленных утверждений, который просто шумит для меня и отвлекает меня от того, что я действительно хочу увидеть. Контракты с кодами, по крайней мере, Microsoft так же, и даже хуже. Они добавляют много шума и сложности в код. В 99% случаев, в любом случае, будет выдано исключение - поэтому мне все равно, от утверждения или контракта или от реальной проблемы. Просто очень, очень мало случаев, когда состояния программы действительно искажаются.
Так что, честно говоря, в чем выгода использования кодовых контрактов? Есть ли вообще? Если вы уже используете модульные тесты и код для защиты, я чувствую, что введение контрактов просто не стоит затрат и создает шум в вашем коде, который ругается сопровождающему, когда он обновляет этот метод, так же, как я делаю, когда не вижу, что делает код из-за бесполезных утверждений. Я до сих пор не вижу веской причины платить эту цену.
источник
Ответы:
Вы могли бы также спросить, когда статическая типизация лучше, чем динамическая. Дебаты, которые бушуют годами, конца не видно. Итак, взгляните на такие вопросы, как изучение языков динамически и статически типизированных
Но основной аргумент - это возможность обнаруживать и исправлять проблемы во время компиляции, которые в противном случае могли бы попасть в производство.
Контракты против Охранников
Даже с охраной и исключениями вы все еще сталкиваетесь с проблемой, что система в некоторых случаях не сможет выполнить свою намеченную задачу. Возможно, это будет критический и дорогостоящий случай.
Контракты против модульных тестов
Обычный аргумент в пользу этого - тесты подтверждают наличие ошибок, а типы (контракты) - отсутствие. F.ex. используя тип, который вы знаете, что ни один путь в программе не может предоставить неверный ввод, в то время как тест может только сказать вам, что пройденный путь предоставил правильный ввод.
Образцы контрактов против нулевого объекта
Теперь это, по крайней мере, в том же парке. Такие языки, как Scala и Haskell, добились большого успеха благодаря этому подходу к полному исключению пустых ссылок из программ. (Даже если Scala формально разрешает нулевые значения, соглашение никогда не использует их)
Если вы уже используете этот шаблон для устранения NRE, вы, по сути, удалили самый большой источник сбоев во время выполнения, в основном, как это позволяют контракты.
Разница может заключаться в том, что в контрактах есть возможность автоматически запрашивать весь ваш код, чтобы избежать нуля, и, таким образом, заставлять вас использовать этот шаблон в большем количестве мест для прохождения компиляции.
Кроме того, эти контракты также дают вам гибкость в достижении целей, выходящих за рамки нуля. Поэтому, если вы больше не видите NRE в своих ошибках, вы можете использовать контракты, чтобы задушить следующую наиболее распространенную проблему, которая может у вас возникнуть. Выкл по одному? Индекс вне диапазона?
Но...
Все это, как говорится. Я согласен с тем, что контракты по синтаксическому шуму (и даже структурному шуму) добавляют к коду довольно существенный результат, и влияние анализа на время сборки не следует недооценивать. Поэтому, если вы решите добавить контракты в свою систему, вероятно, было бы целесообразно сделать это очень осторожно, с узким фокусом на том, к какому классу ошибок можно обратиться.
источник
Я не знаю, откуда исходит утверждение, что «он не выполняет и часто не может выполнять статический анализ». Первая часть утверждения явно неверна. Второй зависит от того, что вы подразумеваете под «часто». Я бы предпочел сказать, что часто он выполняет статический анализ и редко терпит неудачу. В обычных бизнес-приложениях редко становится намного ближе к никогда .
Итак, первое преимущество:
Преимущество 1: статический анализ
Обычные утверждения и проверка аргументов имеют недостаток: они откладываются до выполнения кода. С другой стороны, контракты кода проявляются на более раннем уровне, либо на этапе кодирования, либо при компиляции приложения. Чем раньше вы поймаете ошибку, тем дешевле ее исправить.
Выгода 2: вроде всегда актуальная документация
Контракты на кодекс также предоставляют своего рода документацию, которая всегда актуальна. Если XML-комментарий метода
SetProductPrice(int newPrice)
говорит, что онnewPrice
должен быть больше или равен нулю, вы можете надеяться, что документация обновлена, но вы также можете обнаружить, что кто-то изменил метод так, чтобы онnewPrice = 0
вызывалArgumentOutOfRangeException
, но никогда не изменял соответствующую документацию. Учитывая корреляцию между контрактами кода и самим кодом, у вас нет проблемы с несинхронизированной документацией.Документация, предоставляемая контрактами на код, также полезна тем, что часто XML-комментарии плохо объясняют приемлемые значения. Сколько раз я был интересно , если
null
илиstring.Empty
или\r\n
является авторизированным значение для метода, а также комментарии XML ничего не говорится о том , что!В заключение, без контрактов кода, много частей кода таковы:
С контрактами кода это становится:
Преимущество 3: контракты интерфейсов
Третье преимущество заключается в том, что контракты кода расширяют возможности интерфейсов. Допустим, у вас есть что-то вроде:
Как бы вы, используя только утверждения и исключения, гарантировали, что
CommitChanges
можно вызывать только тогда, когдаPendingChanges
не пусто? Как бы вы гарантировали, чтоPendingChanges
никогда не будетnull
?Преимущество 4: применение результатов метода
Наконец, четвертое преимущество заключается в возможности получить
Contract.Ensure
результаты. Что если при написании метода, который возвращает целое число, я хочу быть уверенным, что значение никогда не будет меньше или равно нулю? В том числе пять лет спустя, после того, как многие из разработчиков пострадали от изменений? Как только метод имеет несколько точек возврата, этоAssert
становится кошмаром обслуживания.Считайте кодовые контракты не только средством корректности вашего кода, но и более строгим способом написания кода. Аналогичным образом, человек, который использовал исключительно динамические языки, может спросить, зачем вам применять типы на уровне языка, тогда как вы можете делать то же самое в утверждениях, когда это необходимо. Вы можете, но статическая типизация проще в использовании, менее подвержена ошибкам по сравнению с кучей утверждений и самодокументированием.
Разница между динамической типизацией и статической типизацией чрезвычайно близка к разнице между обычным программированием и программированием по контрактам.
источник
Я знаю, что это немного поздно для вопроса, но есть еще одна выгода для Code Contracts, о которой стоит упомянуть
Контракты проверяются вне метода
Когда у нас есть защитные условия внутри нашего метода, это место, где происходит проверка и где сообщается об ошибках. Тогда нам, возможно, придется исследовать трассировку стека, чтобы выяснить, где в действительности находится ошибка.
Контракты кода находятся внутри метода, но предварительные условия проверяются вне метода, когда что-либо пытается вызвать этот метод. Контракты становятся частью метода и определяют, может ли он быть вызван или нет. Это означает, что мы получаем сообщение об ошибке гораздо ближе к фактическому источнику проблемы.
Если у вас есть защищенный контрактом метод, который вызывается во многих местах, это может быть реальным преимуществом.
источник
На самом деле две вещи:
источник