Хороший вопрос! Мой главный совет - подходить к проблеме систематически. Если вы разрабатываете функцию f
, вот как я думаю о ее спецификации:
Каким абсолютным требованиям должен соответствовать абонент f
? Этими условиями являются f
* предварительное условие .
Что f
делает для своего абонента? Когда возвращается f
, каково возвращаемое значение и каково состояние машины? При каких обстоятельствах f
создает исключение и какое исключение выдается? Ответы на все эти вопросы составляют f
постусловие .
Предварительное условие и постусловие вместе составляют f
контракт с вызывающими абонентами.
Только вызывающий абонент, удовлетворяющий предварительному условию, может положиться на постусловие.
И, наконец, непосредственно касаясь вашего вопроса, что произойдет, если вызывающий f
не выполнит предварительное условие? У вас есть два варианта:
Вы гарантируете остановку программы, надеетесь с информативным сообщением. Это проверенная ошибка времени выполнения.
Все идет. Может быть, есть ошибка, может быть, повреждена память, возможно f
молча возвращает неправильный ответ. Это не проверено ошибка времени выполнения.
Обратите внимание на некоторые элементы, которых нет в этом списке: вызов исключения или возврат кода ошибки. Если на это поведение можно положиться, оно становится частью f
контракта.
Теперь я могу перефразировать ваш вопрос:
Что должна делать функция, если вызывающая сторона нарушает свой контракт?
В большинстве видов приложений функция должна останавливать программу с проверено ошибка во время выполнения. Если программа является частью приложения, которое должно быть надежным, либо приложение должно предоставить внешний механизм для перезапуска приложения, которое останавливается с проверенной ошибкой во время выполнения (обычно в коде Erlang), или, если перезапуск затруднен, все функции «Контракты должны быть очень разрешительными, чтобы« плохой вклад »по-прежнему соответствовал контракту, но обещал всегда выдвигать исключение.
В каждой программе не проверено ошибки времени выполнения должны быть редкими . Непроверенная ошибка времени выполнения обычно оправдывается только соображениями производительности и даже тогда, когда код критичен к производительности. Другим источником неконтролируемых ошибок во время выполнения является программирование на небезопасных языках; например, в C нет способа проверить, была ли указанная память действительно инициализирована.
Еще один аспект вашего вопроса
Какие контракты делают лучшие проекты?
Ответ на этот вопрос зависит от проблемной области.
Поскольку ни одна из выполняемых мною работ не должна быть высокой доступности или критичной для безопасности, я использую ограничительные контракты и множество проверенных ошибок во время выполнения (как правило, ошибки проверки). Когда вы проектируете интерфейсы и контракты большой системы, это будет на намного проще, если вы будете сохранять контракты простыми, вы сохраняете предварительные условия ограничительными (жесткими) и полагаетесь на проверенные ошибки времени выполнения, когда аргументы «плохие».
У меня есть функция, которая передает его в список, и он возвращает список списков, основанный на ваших параметрах для разделения. НО, прежде чем передать его список, я сначала проверяю параметры в своем MAIN во время процесса getops, поэтому в основном я проверяю, чтобы убедиться, что пользователь не передал никаких негативов, я удостоверяюсь, что пользователь не запрашивал разбиение на скажем, 4 части, но просим вывести часть 5.
Я думаю, что это именно правильный способ решения этой конкретной проблемы:
Ваш контракт с пользователем заключается в том, что пользователь может сказать что-нибудь, и если пользователь отправит бессмысленный запрос, ваша программа не упадет & mdash; он выдаст разумное сообщение об ошибке, а затем продолжит.
Ваш внутренний контракт с вашей функцией обработки запросов заключается в том, что вы будете передавать ей только разумные запросы.
Таким образом, у вас есть третья функция, помимо второй, задача которой состоит в том, чтобы отличать смысл от бессмыслицы и действовать соответствующим образом - ваша функция обработки запросов получает «смысл», пользователю сообщается о «бессмыслице», и все контракты выполнены.
Одна из моих главных проблем заключается в том, является ли правильным его кодирование, чтобы вы проверяли, что ввод пользователя действителен ВНЕ ОТ функции.
Да. Почти всегда это лучший дизайн. На самом деле, где-то есть шаблон дизайна с причудливым названием. Но если нет, опытные программисты видели это снова и снова. Происходит одно из двух:
Этот вид дизайна имеет один тип данных (запрос) и четыре функции. Поскольку на этой неделе я пишу тонны кода на Haskell, я приведу пример на Haskell:
data Request -- type of a request
parse :: UserInput -> Request -- has a somewhat permissive precondition
validate :: Request -> Maybe ErrorMessage -- has a very permissive precondition
process :: Request -> Result -- has a very restrictive precondition
Конечно, есть много других способов сделать это. Сбои могут быть обнаружены как на этапе анализа, так и на этапе проверки. «Действительный запрос» может фактически быть представлен другим типом, чем «неподтвержденный запрос». И так далее.