Я не знаю, откуда исходит утверждение, что «он не выполняет и часто не может выполнять статический анализ». Первая часть утверждения явно неверна. Второй зависит от того, что вы подразумеваете под «часто». Я бы предпочел сказать, что часто он выполняет статический анализ и редко терпит неудачу. В обычных бизнес-приложениях редко становится намного ближе к никогда .
Итак, первое преимущество:
Преимущество 1: статический анализ
Обычные утверждения и проверка аргументов имеют недостаток: они откладываются до выполнения кода. С другой стороны, контракты кода проявляются на более раннем уровне, либо на этапе кодирования, либо при компиляции приложения. Чем раньше вы поймаете ошибку, тем дешевле ее исправить.
Выгода 2: вроде всегда актуальная документация
Контракты на кодекс также предоставляют своего рода документацию, которая всегда актуальна. Если XML-комментарий метода SetProductPrice(int newPrice)
говорит, что он newPrice
должен быть больше или равен нулю, вы можете надеяться, что документация обновлена, но вы также можете обнаружить, что кто-то изменил метод так, чтобы он newPrice = 0
вызывал ArgumentOutOfRangeException
, но никогда не изменял соответствующую документацию. Учитывая корреляцию между контрактами кода и самим кодом, у вас нет проблемы с несинхронизированной документацией.
Документация, предоставляемая контрактами на код, также полезна тем, что часто XML-комментарии плохо объясняют приемлемые значения. Сколько раз я был интересно , если null
или string.Empty
или \r\n
является авторизированным значение для метода, а также комментарии XML ничего не говорится о том , что!
В заключение, без контрактов кода, много частей кода таковы:
Я приму некоторые значения, но не другие, но вам придется угадывать или читать документацию, если таковые имеются. На самом деле, не читайте документацию: она устарела. Просто переберите все значения, и вы увидите те, которые заставляют меня выдавать исключения. Вы также должны угадать диапазон значений, которые могут быть возвращены, потому что даже если бы я рассказал вам немного больше о них, это может быть неверно, учитывая сотни изменений, внесенных в меня за последние годы.
С контрактами кода это становится:
Аргумент title может быть ненулевой строкой длиной 0..500. Целое число, которое следует, является положительным значением, которое может быть нулевым, только если строка пуста. Наконец, я верну IDefinition
объект, никогда ноль.
Преимущество 3: контракты интерфейсов
Третье преимущество заключается в том, что контракты кода расширяют возможности интерфейсов. Допустим, у вас есть что-то вроде:
public interface ICommittable
{
public ICollection<AtomicChange> PendingChanges { get; }
public void CommitChanges();
...
}
Как бы вы, используя только утверждения и исключения, гарантировали, что CommitChanges
можно вызывать только тогда, когда PendingChanges
не пусто? Как бы вы гарантировали, что PendingChanges
никогда не будет null
?
Преимущество 4: применение результатов метода
Наконец, четвертое преимущество заключается в возможности получить Contract.Ensure
результаты. Что если при написании метода, который возвращает целое число, я хочу быть уверенным, что значение никогда не будет меньше или равно нулю? В том числе пять лет спустя, после того, как многие из разработчиков пострадали от изменений? Как только метод имеет несколько точек возврата, это Assert
становится кошмаром обслуживания.
Считайте кодовые контракты не только средством корректности вашего кода, но и более строгим способом написания кода. Аналогичным образом, человек, который использовал исключительно динамические языки, может спросить, зачем вам применять типы на уровне языка, тогда как вы можете делать то же самое в утверждениях, когда это необходимо. Вы можете, но статическая типизация проще в использовании, менее подвержена ошибкам по сравнению с кучей утверждений и самодокументированием.
Разница между динамической типизацией и статической типизацией чрезвычайно близка к разнице между обычным программированием и программированием по контрактам.