Мой профессор продолжает ссылаться на этот пример Java, когда говорит о «надежном» коде:
if (var == true) {
...
} else if (var == false) {
...
} else {
...
}
Он утверждает, что «надежный код» означает, что ваша программа учитывает все возможности, и что не существует такой вещи, как ошибка - все ситуации обрабатываются кодом и приводят в правильное состояние, отсюда и «другое».
Я сомневаюсь, однако. Если переменная является логическим значением, какой смысл проверять третье состояние, когда третье состояние логически невозможно?
«Отсутствие такой вещи как ошибка» также кажется смешным; даже приложения Google показывают ошибки непосредственно пользователю вместо того, чтобы молча глотать их или как-то считать их действительным состоянием. И это хорошо - мне нравится знать, когда что-то идет не так. И кажется, что заявление о том, что приложение никогда не будет иметь ошибок, вполне оправдано.
Итак, каково фактическое определение «надежного кода»?
источник
Ответы:
Как насчет того,
Boolean?
которое допускаетNULL
состояние, которое не является ни истинным, ни ложным. Что должно делать программное обеспечение? Некоторое программное обеспечение должно быть очень устойчивым к сбоям, как кардиостимуляторы. Вы когда-нибудь видели, чтобы кто-то добавил столбец в базу данных, которая былаBoolean
и инициализировал текущие данныеNULL
изначально? Я знаю, что видел это.Вот несколько ссылок, которые обсуждают, что значит быть надежным с точки зрения программного обеспечения:
Если вы думаете, что здесь есть одно общепринятое определение «робастный», удачи. Там могут быть некоторые синонимы, такие как бомба или идиот. Duct Tape Programmer был бы примером кого-то, кто обычно пишет надежный код, по крайней мере, в моем понимании терминов.
источник
Ради моей дискуссии у Bool может быть 2 состояния: True или False. Все остальное не соответствует спецификации языка программирования. Если ваша цепочка инструментов не соответствует ее спецификации, вы будете заняты независимо от того, что вы делаете. Если разработчик создал тип Bool с более чем двумя состояниями, это будет последнее, что он когда-либо сделает на моей базе кода.
Вариант А.
Вариант Б
Я утверждаю, что вариант B является более надежным .....
Любой твик может сказать вам, чтобы обрабатывать неожиданные ошибки. Обычно их легко обнаружить, если подумать о них. Пример, который дал ваш профессор, не может произойти, поэтому это очень плохой пример.
А невозможно протестировать без запутанных жгутов. Если вы не можете создать его, как вы собираетесь его протестировать? Если вы не проверяли код, как вы узнали, что он работает? Если вы не знаете, как это работает, значит, вы не пишете надежное программное обеспечение. Я думаю, что они все еще называют это Catch22 (Отличный фильм, смотрите его когда-нибудь).
Вариант B тривиален для тестирования.
Следующая проблема, задайте вам, профессор, этот вопрос: «Что вы хотите, чтобы я сделал с этим, если логическое значение не является ни истинным, ни ложным?» Это должно привести к очень интересной дискуссии .....
В большинстве случаев дамп ядра является оценочным, в худшем случае он раздражает пользователя или стоит больших денег. Что, если, скажем, модуль представляет собой систему расчета повторного входа космического корабля в реальном времени? Любой ответ, каким бы неточным он ни был, не может быть хуже, чем прерывание, которое убьет пользователей. Так что делать, если вы знаете, что ответ может быть неправильным, пойти на 50/50 или прервать и перейти к 100% -ой ошибке. Если бы я был членом экипажа, я бы взял 50/50.
Вариант А убивает меня Вариант Б дает мне равные шансы на выживание.
Но подождите - это симуляция возвращения космического челнока - тогда что? Прервать, чтобы вы знали об этом. Звучит как хорошая идея? - НЕ - потому что вам нужно проверить с кодом, который вы планируете отправить.
Вариант А лучше для симуляции, но не может быть развернут. Это бесполезно. Вариант B - это развернутый код, поэтому симуляция выполняется так же, как и действующие системы.
Допустим, это была серьезная проблема. Лучшим решением было бы изолировать обработку ошибок от логики приложения.
Дальнейшее чтение - аппарат Therac-25 Xray, сбой Ariane 5 Rocket и другие (в Link много неработающих ссылок, но достаточно информации, чтобы помочь Google)
источник
if (var != true || var != false) {
быть&&
вместо этого.На самом деле ваш код не более надежный, но МЕНЬШЕ надежный. Финал
else
- просто мертвый код, который вы не можете протестировать.В критически важном программном обеспечении, таком как космические корабли, запрещен мертвый код и, в общем, непроверенный код: если космический луч производит одно расстройство, которое, в свою очередь, активизирует ваш мертвый код, все возможно. Если SEU активирует часть надежного кода, (неожиданное) поведение остается под контролем.
источник
Я думаю, что профессор может сбить с толку «ошибка» и «ошибка». Надежный код, безусловно, должен иметь мало ошибок. Надежный код может и во враждебной среде должен иметь хорошее управление ошибками (будь то обработка исключений или строгие тесты состояния возврата).
Я согласен, что пример кода профессора глуп, но не так глуп, как мой.
источник
boolean x = something(); if (x) { x = True // make sure it's really true, ... }
Не существует согласованного определения Robust Code , так как для многих вещей в программировании оно более или менее субъективно ...
Пример, который дает ваш профессор, зависит от языка:
Boolean
может быть или,True
илиFalse
нет третьего вариантаbool
может бытьtrue
,false
или (к сожалению) происходить от какого-то сомнительного броска, который помещает его в неизвестный случай ... Это не должно происходить, но может произойти в результате предыдущей ошибки.Однако то, что советует ваш профессор, затемняет код, вводя постороннюю логику для событий, которые не должны происходить в середине основной программы, поэтому вместо этого я укажу вам на оборонительное программирование .
В случае с университетом вы могли бы даже увеличить его, приняв стратегию «Дизайн по контракту»:
size
это количество элементов вdata
списке)a
меньшим, чем10
)Пример:
источник
Подход вашего профессора полностью ошибочен.
Функция или небольшой фрагмент кода должны иметь спецификацию, которая говорит, что она делает, которая должна охватывать все возможные входные данные. И код должен быть написан так, чтобы его поведение гарантированно соответствовало спецификации. В примере я написал бы спецификацию довольно просто, как это:
Затем вы пишете функцию:
и код соответствует спецификации. Итак, ваш профессор говорит: а что если var == 42? Посмотрите на спецификацию: там написано, что функция должна делать "это". Посмотрите на код: функция делает «это». Функция соответствует спецификации.
Когда код вашего профессора делает вещи абсолютно ненадежными, это тот факт, что с его подходом, когда var не является ни истиной, ни ложью, он выполнит код, который никогда не вызывался ранее и который полностью не проверен, с совершенно непредсказуемыми результатами.
источник
Я согласен с утверждением @ gnasher729: подход вашего профессора полностью ошибочен.
Надежный означает, что он устойчив к поломкам / отказам, потому что он делает несколько предположений и не связан: он самодостаточен, самоопределяем и переносим. Это также включает способность адаптироваться к меняющимся требованиям. Одним словом, ваш код долговечен .
Как правило, это переводится в короткие функции, которые получают свои данные из параметров, переданных вызывающей стороной, и использование открытых интерфейсов для потребителей - абстрактных методов, упаковщиков, косвенных обращений, интерфейсов в стиле COM и т. Д. - вместо функций, содержащих конкретный код реализации.
источник
Надежный код - это просто код, который хорошо обрабатывает сбои. Ни больше ни меньше.
Существует много типов сбоев: неправильный код, неполный код, неожиданные значения, неожиданные состояния, исключения, исчерпание ресурсов ... Надежный код хорошо справляется с этим.
источник
Я бы рассмотрел приведенный вами код в качестве примера защитного программирования (по крайней мере, так как я использую этот термин). Часть защитного программирования состоит в том, чтобы делать выбор, сводящий к минимуму предположения о поведении остальной системы. Например, какой из них лучше:
Или:
(Если у вас возникли проблемы с различием, проверьте тест цикла: первый использует
!=
, второй использует<
).Теперь при большинстве обстоятельств оба цикла будут вести себя одинаково. Тем не менее, первое (по сравнению с
!=
) делает предположение, чтоi
будет увеличиваться только один раз за итерацию. Если оно пропускает значение,sequence.length()
цикл может продолжаться за пределами последовательности и вызывать ошибку.Таким образом, вы можете аргументировать, что вторая реализация является более надежной: она не зависит от предположений о том, изменяется ли тело цикла
i
(примечание: на самом деле оно все еще делает предположение, чтоi
оно никогда не бывает отрицательным).Чтобы мотивировать, почему вы не захотите делать такое предположение, представьте, что цикл сканирует строку и выполняет некоторую обработку текста. Вы пишете цикл, и все в порядке. Теперь ваши требования меняются, и вы решаете, что вам нужно поддерживать escape-символы в текстовой строке, поэтому вы изменяете тело цикла таким образом, чтобы, если он обнаруживает escape-символ (скажем, обратный слеш), он постепенно увеличивал
i
пропуск символа, следующий сразу за escape. Теперь в первом цикле есть ошибка, потому что если последний символ текста имеет обратную косую черту, тело цикла будет увеличиваться,i
и цикл продолжится после конца последовательности.источник
Я лично описываю код как «надежный», который имеет следующие важные атрибуты:
Теперь под прерыванием я подразумеваю либо приведение системы в нестабильное состояние, либо создание исключения UNHANDLED . Вы знаете, иногда для простой концепции, вы можете сделать сложное определение и объяснение. Но я бы предпочел простые определения. Пользователи довольно хороши в поиске надежных приложений. Если пользователь вашего приложения посылает вам много запросов об ошибках, о потере состояния, о неинтуитивных рабочих процессах и т. Д., Значит, что-то не так с вашим программированием.
источник