Должен ли сервер быть «снисходительным» к тому, что он принимает, и «молча отбрасывать ошибочный ввод»?


27

У меня сложилось впечатление, что теперь все согласны с тем, что эта максима была ошибкой. Но я недавно видел этот ответ, в котором есть комментарий «быть снисходительным», проголосовавший 137 раз (на сегодняшний день).

По моему мнению, снисходительность в том, что принимают браузеры, была прямой причиной беспорядка, который HTML и некоторые другие веб-стандарты имели несколько лет назад, и только недавно начали правильно выкристаллизовываться из этого беспорядка. То, как я это вижу, проявление снисхождения к тому, что вы принимаете , приведет к этому.

Вторая часть максима - «молча отбросить ошибочный ввод, не возвращая сообщение об ошибке, если это не требуется спецификацией» , и это кажется пограничным оскорблением. Любой программист, который молча ударился головой о стену, когда что-то не получится, поймет, что я имею в виду.

Итак, я совершенно не прав по этому поводу? Должна ли моя программа быть снисходительной в том, что она принимает и молча глотать ошибки? Или я неправильно понимаю, что это должно означать?


В первоначальном вопросе говорилось «программа», и я согласен с этим. Для программ может иметь смысл быть снисходительным. Однако я действительно имел в виду API-интерфейсы: интерфейсы, открытые другим программам , а не людям. HTTP является примером. Протокол является интерфейсом, который используют только другие программы. Люди никогда не сообщают даты, которые входят в заголовки, например «If-Modified-Since».

Итак, вопрос заключается в следующем: должен ли сервер, реализующий стандарт, быть снисходительным и разрешать даты в нескольких других форматах, в дополнение к тому, который фактически требуется стандартом? Я считаю, что «быть снисходительным» должно относиться к этой ситуации, а не к человеческим интерфейсам.

Если сервер снисходительный, это может показаться общим улучшением, но я думаю, что на практике это приводит только к реализации клиента, которая в конечном итоге полагается на снисходительность и, таким образом, не может работать с другим сервером, который снисходителен немного другими способами.

Итак, должен ли сервер, демонстрирующий какой-либо API, быть снисходительным или это очень плохая идея?


Теперь перейдем к мягкой обработке пользовательского ввода. Рассмотрим YouTrack (программное обеспечение для отслеживания ошибок). Он использует язык для ввода текста, который напоминает Markdown. За исключением того, что это "снисходительно". Например, написание

- foo
- bar
- baz

это не документированный способ создания маркированного списка, и все это работало. Следовательно, он часто использовался в нашем внутреннем багтрекере. Выходит следующая версия, и эта снисходительная функция начинает работать немного по-другому, разбивая кучу списков, которые (не) использовали эту (не) функцию. Разумеется, документированный способ создания маркированных списков все еще работает.

Итак, должно ли мое программное обеспечение быть снисходительным к тому, что вводит пользователь ?


4
Относительно «молча отбрасывать ошибочный ввод», я бы спрашивал для каждого случая, что следует считать ошибочным вводом. Если вы задаете вопрос пользователю и ожидаете «да» или «нет», значит «ДА» неверный ввод? Как насчет "у"? Как насчет "OUI"? В общем, не стесняйтесь говорить пользователю, что его ввод не то, что вы ожидаете. Тем не менее, убедитесь, что вы были как можно более инклюзивными - по моему мнению, именно это означает «быть снисходительным».

3
Если вы говорите о вводе данных конечным пользователем - который относится к дружественным линиям вашего приложения, то вы должны быть ленинцами; для автоматического ввода, генерируемого машиной (из API), вы должны быть многословны (строгими).
Бурхан Халид

2
На самом деле снисходительность HTML была причиной того, что он стал настолько популярным (а строгость XHTML - почему его отбросили).
Оливер Вейлер

1
Я думаю, что ключ в том, что если это сценарий, в котором вы можете позволить ему изящно провалиться, это то, что вы как минимум регистрируете событие.
Рог

2
@OliverWeiler Я чувствую, что провал XHTML как-то связан с тем, что он совершенно не нужен. HTML уже был там и вроде работал. Кроме того, хотя HTML, конечно, очень популярен, довольно печально, что мы называем эту технологию успешной. Он удовлетворяет спрос, но так же, как Symbian удовлетворяет спрос на смартфоны.
Роман Старков

Ответы:


9

Конечно, вы совершенно правы. Программы никогда не должны быть «снисходительными», так как это только маскирует проблемы. Проблемы должны быть выделены, а не подметены. Информативное сообщение об ошибке является обязательным условием, чтобы программа была полезна для пользователя.

В большинстве случаев, когда предоставляются неверные / недействительные данные, поставщик этих данных (будь то пользователь или вывод какой-либо другой программы), вероятно, не знал, что они недействительны. Поглощение ошибки заставит их поверить, что она (или может быть) действительна, что приводит к распространению неверных данных.

Единственный способ взаимодействия систем состоит в том, чтобы это взаимодействие было полностью и однозначно определено. Программа, которая принимает данные вне спецификации, делает эти данные де-факто принятыми, даже если они недопустимы спецификацией, что не только делает совместимость чрезвычайно сложной, но и означает, что она больше не определяется формально. Сама программа теперь является стандартом де-факто . Таким образом, снисходительные программы невозможно развивать дальше или заменить, потому что вы не можете внести мельчайшие изменения в то, как они работают.


25

Я думаю, что все зависит от того, кто является вашей целевой аудиторией. Если это программисты, то абсолютно нет. Ваша программа должна терпеть неудачу и кричать кровавое убийство. Однако, если ваша целевая аудитория не программисты, тогда ваша программа должна быть снисходительной, если она может корректно обрабатывать исключения, в противном случае - шептать сладкое кровавое убийство.

В качестве примера можно взять Flash Player NPAPI. Существует версия для тех, кого не волнует 99% возможных ошибок, но есть и версия для отладки, которая кричит о кровавом убийстве, когда что-то идет не так. Каждая из них поддерживает проигрывание Flash-контента, но нацелена на две совершенно разные демографические группы.

В конце я думаю, что важно следующее: что заботит ваших пользователей?


4
Подавляющее большинство инструментов командной строки Unixy, которые утверждают, что имеют целевую аудиторию вне программистов, тем не менее бесполезны для пользователей, которые делают ошибки. Даже если вы не программист, для программы лучше объяснить проблему, чем делать что-то бессмысленное или непреднамеренное.
Тимви

2
@romkyns: Не совсем, я говорю, что ваше приложение должно обрабатывать ошибки способами, которые имеют смысл для ваших целевых пользователей.
Демиан Брехт

@Timwi: В этом случае эти инструменты командной строки Unixy плохо спроектированы;)
Демиан Брехт

3
@romkyns - я думаю, что хорошим примером будет: в режиме отладки вы хотите, чтобы программа остановилась на любых проблемах и сообщила вам, что пошло не так. В рабочем режиме вы хотите, чтобы ваша программа продолжала работать так хорошо, как она могла, и регистрировала любые проблемы, с которыми она могла справиться. Таким образом, программисты могут увидеть, что они сделали неправильно, и исправить это, но пользователи не будут беспокоиться о том, что они не могут исправить. Некоторые проблемы, очевидно, не могут быть исправлены, но хорошим примером являются правила стиля CSS, где вы все равно можете визуализировать сайт, даже если вы не понимаете одно из правил стиля.
Восстановите Монику

1
Комментарий @ BrendanLong в значительной степени ударяет гвоздь по голове - иногда получение результата важнее, чем быть правильным. Некоторые ошибки (или предупреждения) могут быть изящно восстановлены без участия пользователя; Вам решать, что вы хотите, чтобы ваше приложение делало в этих случаях.
Даниэль Б

7

Существует два типа «снисходительности»: один - принять неверный ввод и попытаться понять его, а другой - принять разные типы ввода.

Как правило, вы всегда хотите второй, когда это возможно. Первый - когда ты умираешь быстро и тяжело. Пример: даты.

Вот несколько примеров входных данных, включая допустимые, недействительные и неоднозначные.

  • 2011-01-02
  • 01/02/2011
  • Jan 2, 2011
  • 2-Jan-2011
  • Green

Там только один неверный ввод здесь: Green. Даже не пытайтесь принять это как дату. Поскольку Green, очевидно, это не дата, это тот случай, когда молчаливый сбой допустим.

01/02/2011действительно, но неоднозначно. Вы не обязательно знаете, была ли она введена как дата в США (2 января) или нет (1 февраля). Здесь, вероятно, лучше всего потерпеть неудачу и попросить пользователя дать однозначную дату.

2011-01-02обычно считается недвусмысленным, поэтому часто можно пойти дальше и предположить, что это формат «ГГГГ-ММ-ДД», и потерпеть неудачу только в дальнейшем. Тем не менее, когда речь идет о пользовательском вводе, это своего рода суждение.

Jan 2, 2011и 2-Jan-2011являются действительными и однозначными, они должны быть приняты. Тем не менее, The Second of January of the year 2011это также действует и недвусмысленным, но идти так далеко ради снисхождения является излишеством. Давай, проваливай, молча, прямо как Green.

Короче говоря , ответ «это зависит». Посмотрите, что можно вводить, и убедитесь, что вы никогда не принимаете конфликтующие типы ввода (например, DD/MM/YYYYпротив MM/DD/YYYY).

В контексте связанного вопроса / комментария , это случай 2011-01-02. Входные данные выглядят как JSON и будут проверяться как JSON, даже если mimetype неверен; продолжайте и попробуйте использовать его, даже если он потерпит неудачу в какой-то момент в дальнейшем.


1
Есть одна вещь, которую вы здесь не рассматриваете. Если пользователь набрал эту строку, то да, я должен принимать различные форматы, без сомнения об этом. Но мы говорим об API. Клиентами API являются другие программы. Если он снисходителен в своем формате даты, то каждый будущий сервер, предоставляющий этот API, должен быть таким же снисходительным , или рискует несовместимостью. В конечном итоге снисходительность оказывается скорее вредной, чем полезной, не так ли?
Роман Старков

1
@romkyns Я думаю, вы не понимаете, в чем заключается снисхождение. API должен быть снисходительным в том, что он принимает (он должен понимать все 2011-01-02, Jan 2, 2011и 2-Jan-2011, если это не слишком сложно реализовать), а не в том, что она выводит . Будущим клиентам этого API даже не нужно знать о них, если они правильно вводят один из них. В идеале уровень API преобразует все это в то же самое внутреннее представление, которое использует код перед передачей.
Изката

Например, @romkyns Выходные данные всегда могут быть в 2011-01-02формате, и вы должны указать это в своей документации. Я не вижу никакого вредного эффекта вообще.
Иската

4
@Izkata: Вы неправильно поняли. Представьте, что существует старая программа, которая доступна только в двоичном виде. Вы должны написать новую программу, которая принимает те же входные данные, что и старая. Если старая программа была четко определена в том, что она принимает, ваша работа четко определена. Если это снисходительно, то ваша работа невозможна.
Тимви

1
Сильно не согласен. если это не вводимый пользователем ввод, всегда будьте строгими как для ввода, так и для вывода. Что происходит, когда ваш сервис нуждается в повторной реализации? Вы документировали все возможные форматы даты? Вам нужно будет реализовать их все, так как вы не хотите, чтобы старые клиенты сломались. Пожалуйста, используйте ISO 8601 для всех сгенерированных машиной экземпляров и периодов дат: он хорошо указан и широко доступен в библиотеках. Кстати, что на самом деле означает 2011-01-02? Период времени с 00:00 2-го до 00:00 3-го? В каком часовом поясе?
Диббеке

6

Сбой в молчании - это худшее, что ты когда-либо мог сделать. Вы пытались отладить API с молчаливой ошибкой? Это невозможно .

Там "Сделайте все возможное, чтобы восстановить, но отправить подробную ошибку", и есть "Тихая ошибка".


3

Мне кажется, что Закон Постеля - «Будь консервативен в том, что ты делаешь, будь либеральным в том, что ты принимаешь от других» - это то, что обсуждается для сервиса JSON. Это обычно применяется к веб-сервисам, а не к пользовательскому интерфейсу.

Для пользовательского интерфейса конструктивные отзывы пользователей и противоречащие вводимые данные - это правило большого пальца, которое мы используем.


Но если вы посмотрите на ответы здесь, все, похоже, согласятся, что это имеет смысл только для пользовательских интерфейсов, то есть противоположно первоначальному закону.
Роман Старков

Я понимаю, что вы говорите, и согласен с постерами, что целью является чистый строгий API / Сервис, но, к лучшему или худшему, я знаю, что добавил в мои сервисы «надежность» в той или иной форме. Обычно перевод ценностей или два в районе. Пока смысл понятен, приложение знает, как обрабатывать сообщение, и никакие бизнес-правила не нарушаются, тогда добавление надежности поможет совместимости.
MarcLawrence

Пока кто-то еще не пойдет и не реализует вашу спецификацию, только чтобы обнаружить, что «надежность», на которую полагаются сотни клиентов, на самом деле не была в спецификации и должна быть подвергнута обратной разработке ...
Роман Старков

3

Я думаю, что это хорошо освещено в главе 1, разделе 6 TAOUP. В частности, правило восстановления , которое гласит, что программа должна делать то, что она может, с вводом, передавать правильные данные вперед, и, если правильным ответом является сбой, делать это как можно скорее.

Аналогичная концепция - защитное программирование . Вы не знаете, какой вклад вы получите, но ваша программа должна быть достаточно надежной, чтобы охватить все случаи. Это означает, что в случаях восстановления должны быть запрограммированы известные проблемы, такие как искаженный ввод, и перехват всех случаев для обработки неизвестных.

Так отбрасывая неисправный вход беззвучно нормально, так долго , как вы будете обработками , что ввод. Вы никогда не должны просто бросать его на пол, как это было бы.


Я считаю, что для API снисходительно то же самое, что и для программы. Ввод по-прежнему неверен , но вы пытаетесь восстановить как можно больше. Разница в том, что считается действительным ремонтом . Как вы указали, мягкий API может вызвать проблемы, так как люди используют «функции», которые не существуют.

Конечно, API - это просто более низкоуровневая версия правила композиции . Как таковой, он действительно подпадает под правило наименьшего удивления , так как это интерфейс.

Как отмечает цитата из Спенсера, избегайте поверхностного сходства, которое можно утверждать о «нечетких» входах. В этих условиях я обычно утверждаю, что все указывает на то, что программа не может быть исправлена, потому что она не будет знать, что требуется, и это наименее удивительно для пользовательской базы.

Тем не менее, вы имеете дело с датами, которые имеют много «стандартов». Иногда они даже смешиваются в одной программе (цепочке). Поскольку вы знаете, что ожидается дата, попытка распознать дату - это просто хороший дизайн. Особенно, если дата прибывает из какой-то внешней программы и передается вам без изменений в течение секунды.


2

Предполагается, что программы, развертываемые на сервере, в большинстве случаев принимают тысячи запросов каждую минуту, а иногда и каждую секунду. Если серверная программа принимает и исправляет неверные данные от клиентов, я боюсь, что у нее будет 2 недостатка:

  1. Потеря драгоценного серверного времени. При 1000+ запросов в секунду проверка на наличие ошибок в каждом запросе может отражаться в медленном ответе для каждого клиента.
  2. Несправедливо по отношению к клиенту / клиентским программам, которые обеспечивают правильный ввод. Кроме этого, когда программист на стороне сервера сидит на коде сервера, он / она должен думать о различных случаях того, какими могут быть ошибочные входные данные. Кто решит это?

Серверные программы не должны принимать ошибочный ввод, но серверы должны возвращать сообщение об ошибке клиенту, если имеется неправильный ввод.


2

Концептуально идеальное поведение - это делать то, что можно сделать безопасно, и в то же время обеспечивать, чтобы кто-то, кто может решить любые проблемы, был как-то уведомлен о них. На практике, конечно, последнее ограничение часто невозможно встретить напрямую, и поэтому вопрос лучше всего решать с сомнительными данными.

Одна вещь, которая может быть очень полезна при разработке протокола, спецификации форматирования или «языка», - это иметь возможность различать четыре категории потенциальных непонятных элементов:

  1. Вещи, которые должны быть отфильтрованы, если не поняли.
  2. Вещи, которые следует игнорировать, если они не поняты, но, тем не менее, сохраняются, если данные должны быть переданы (возможно, в какой-то оболочке, чтобы указать, что они прошли хотя бы одну стадию, которая их не понимала)
  3. Вещи, которые должны генерировать предупреждение, если они не поняты, но не должны препятствовать попытке восстановления данных (например, на веб-странице, объект, тип которого неизвестен, но конец которого в файле четко определен, может отображаться красным цветом). «X», не мешая отображению остальной части страницы.)
  4. Вещи, которые указывают на то, что все, что не может их понять, может иметь серьезные и неустранимые проблемы в другом месте (например, показатель того, что оставшиеся данные сжаты, и что-либо, что может быть понято любым, что может выполнить требуемое несжатие)

Наличие четко определенного соглашения, согласно которому приложения, которые могут читать любую версию формата данных, смогут распознавать, какая категория подходит для всего, сгенерированного в соответствии с более поздними версиями, является гораздо лучшим подходом, чем попытка втиснуть в специальные меры совместимости. позже. Например, если формат файла имеет строки вида «Tag: Value», можно указать, что первый символ любого тега будет указывать категорию, к которой он принадлежит; для тегов категорий беззвучного игнорирования можно было бы, чтобы первый символ также указывал версию стандарта, для которой ожидается, что тег будет действительным (так что если тег «тихого игнорирования» заявляет, что присутствует в версии 3 стандарт, синтаксический анализатор для версии будет молча игнорировать его, но анализатор для версии 3 или более поздней будет выкрикивать, если он не сможет его проанализировать).

В любом случае самое важное - избегать преобразования неоднозначных или неправильно понятых данных в ошибочные. В некоторых случаях может быть лучше вообще отказаться от распространения неоднозначных данных, хотя в других случаях может быть лучше распространять их точно так, как они получены, в случае, если получатель посчитает их однозначными. Что действительно опасно, если не прямое зло, так это преобразование данных с использованием различных предположений, например, преобразование списка дат, например:

01/12/12
13/12/12
99/12/12

в список дат, таких как

2012-01-12
2012-12-13
1999-12-12

Даже если у человека есть список с несколькими ошибочно введенными датами, человек может получить список в исходном формате, чтобы определить, какой формат был правильным, и пометить сомнительные значения для дальнейшего исследования (проверка по другим записям и т. Д.). Однако рендеринг дат в последнем формате безнадежно и безвозвратно искажает их.


Хорошо сказано. Мне нравится, как твой ответ идет немного глубже. Я испытываю желание принять это, но учитывая общий интерес, который получил этот вопрос, я думаю, что я оставлю это на некоторое время.
Роман Старков

1

Мой опыт работы с пользовательским интерфейсом происходит в основном от настольных систем. Веб-сайты разные, хотя я видел несколько сайтов, которые могут бросить вызов настольной системе. Но для чего это стоит:

Я обнаружил, что сообщения об ошибках должны быть последним средством; идеальная система не имела бы их вообще. Лучшее, что можно сделать, - это не допустить плохих записей: пользователь не может ввести «зеленый», если он выбирает из выпадающего списка месяцев. Он не может нажать кнопку, выделенную серым цветом.

Следующее, что лучше всего сделать, это принять неверные данные. Допустим, вы отображаете гистограмму ежедневных продаж за месяц. После пользовательского ввода график покрывает столетие, а планка столетия в 10 раз выше, чем остальные. Теперь пользователь знает, что он сделал что-то не так, и, кроме того, знает гораздо больше о том, что он сделал не так, как любое сообщение. Когда запись является графической - например, путем перетаскивания мышью - этот вид обратной связи все еще работает и неоценим. Куча входных данных может быть недействительной, но при использовании этого метода пользователь получает мгновенную подробную информацию о результатах каждой позиции мыши.

Все это говорит о том, что иногда пользователю нужно знать, почему кнопка неактивна, поэтому он не может нажать ее. Тогда нет никакой помощи для этого (если есть , дайте мне знать) , но ungray кнопку , и, когда он нажимает на нее, дать ему хорошее объяснение того , почему кнопка не работает в данный момент.


0

Заявление об отправке информации через Интернет. Одна из вещей при отправке информации через Интернет заключается в том, что она не всегда достигает цели или фрагментируется.


0

Что-то, что здесь упущено - каковы последствия неудачи?

Показать веб-страницу? Вы должны сделать все возможное, чтобы терпеть плохой ввод. Ваш выбор состоит в том, чтобы показать, что вы можете, или выдать ошибку. Последний курс ничего не дает пользователю и, следовательно, должен быть лишь последним средством, поскольку он дает пользователю совершенно бесполезный результат, и было бы довольно трудно допустить, чтобы ошибка была хуже этой.

С другой стороны, если он запрашивает цель Minuteman III, вы отклоняете «Москву» как вводную, поскольку она потенциально неоднозначна.


Так что, даже если вы программист и написали какой-то глупый код, система должна идти вперед и делать все возможное, чтобы что-то показать, вместо того, чтобы просто остановиться и выкрикнуть: «О, ты облажался здесь (номер строки)»? Не думаете ли вы, что именно это приводит к невероятно плохому коду?
Роман Старков

@romkyns: у вас есть режимы отладки для такого рода вещей, которые строго следят за ошибками.
Лорен Печтел
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.