Должны ли ограничения безопасности привести к тому, что служба вернет ноль или выдаст исключение? [закрыто]

11

Я немного не согласен с более опытным разработчиком по этому вопросу, и мне интересно, что другие думают об этом; наша среда - Java, EJB 3, сервисы и т. д.

Код, который я написал, вызывает службу для получения и создания вещей. Проблема, с которой я столкнулся, заключалась в том, что я получил исключения с нулевым указателем, которые не имели смысла. Например, когда я прошу службу создать объект, я получаю нулевое значение; когда я пытаюсь найти объект с известным действительным идентификатором, я получаю нулевое значение. Я потратил некоторое время, пытаясь выяснить, что не так в моем коде; поскольку я менее опытен, я обычно предполагаю, что сделал что-то не так, но оказывается, что причиной нулевого возврата была безопасность. Если у пользователя, использующего мой сервис, не было необходимых прав для целевой службы, он просто возвращает ноль. Большинство других сервисов здесь не очень хорошо документированы, поэтому, очевидно, это то, что вы должны знать.

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

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

Это нормальная и / или хорошая практика? Я предпочитаю использовать исключения, потому что мне гораздо легче узнать, что происходит. Так что я бы, например, также предпочел бы генерировать исключение NotFoundException, если вы запрашивали объект с недопустимым идентификатором, а не возвращали ноль.

Svish
источник
@ChrisF: 1) о людях, избегающих нулевых ссылок, чего я не делаю. Во многих случаях они уместны, я просто не думаю, что они в этом. 2) о проверке параметров, и не будет ли утверждать, что результат аналогичен выдаче исключения? 3) исключения по сравнению с кодами ошибок - это тоже отдельная проблема, так как они оба способа «показать», что пошло не так. Коды ошибок подходят, если, например, вам необходимо уведомить систему, которая не поддерживает исключения, или если вы не хотите, чтобы конечный пользователь видел что-то еще, кроме кода.
Свиш
Проблема, о которой я здесь спрашиваю, заключается в том, чтобы «притворяться, что что-то не существует или не произошло», а не «рассказывать, почему что-то не существует или не произошло».
Свиш
3
Я не предполагал, что они были дубликатами - просто они могут иметь полезную информацию для вас.
ChrisF
Правда, извините за это! По какой-то причине я воспринял это как "возможные дубликаты" ... вероятно, из-за недостатка сна, хе-хе.
Свиш

Ответы:

19

Исключения следует выдавать только тогда, когда есть ошибка, и запрос чего-либо не является ошибкой.

Запрашиваемая вещь не может быть ошибкой, но отсутствие прав на то, что вы просили, безусловно, является ошибкой. Исключения - это альтернативный способ сообщения об исключительных условиях, который следует использовать вместо специальных возвращаемых значений (например null, который, как вы написали, абсолютно бесполезен, если есть> 1 возможных причин, по которым все может пойти не так (даже если ровно 1 возможная причина, в следующей версии может быть 2 возможные причины, поэтому использование nullв качестве возвращаемого значения, указывающего на сбой, приведет к рисованию себя в угол)). Если служба не сообщает каким-либо образом, почему она не будет выполнять то, о чем вы просили, то это определенно плохой дизайн.

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

String.substring()бросает, IndexOutOfBoundsExceptionесли индекс выходит за пределы. Я не могу думать о каких-либо преимуществах возврата nullвместо этого, хотя - с философской точки зрения - можно утверждать, что a Stringне содержит ничего вне своих границ, поэтому тогда nullбудет логичным возвращаемым значением. Быть логико-философским и практичным, очевидно, два разных животного.

Joonas Pulakka
источник
Если substring () будет возвращать значение для индексов, выходящих за границы, она должна возвращать часть строки между индексами, возможно, пустую. Это может сохранить тест в некотором коде вызова.
Кевин Клайн
2
Да, есть это нескончаемое «пустое значение» против нулевого обсуждения: должна ли подстрока для внешних индексов быть нулевой или пустой строкой? Я не знаю, оба фактически являются «ничем» (ну, может быть, ноль - «больше ничего», чем пустая строка?), Но ни один из них не дает объема информации, который делает исключение.
Joonas Pulakka
@kevincline: Если кто-то не использует каркас, в котором нулевая ссылка является идиоматическим средством указания пустой строки, я не вижу оснований для substringвозврата пустой ссылки. ИМХО, должно быть две отдельные функции - одна из которых обещает либо вернуть запрошенное количество символов, либо выдать исключение, а одна из которых возвращает столько, сколько может. Каждый метод был бы значительно лучше другого в некоторых контекстах.
суперкат
@supercat: Я ничего не сказал о возвращении нуля. Я сказал: «Вернись ... часть ... возможно, пустую». Пустая строка не пуста, кроме как в Oracle.
Кевин Клайн
@JoonasPulakka: я должен был отослать вас к моему предыдущему комментарию.
суперкат
5

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

С другой стороны, если в вашем контракте говорится, что вы должны сначала вызвать другой метод ( DoesSomethingExist()), а затем вызвать Getметод, то в вашем контракте может быть сказано, что вы можете получить только те вещи, которые существуют, и выдать исключение, если они этого не делают. Сообщение об исключении может содержать что-то вроде «Обязательно DoesSomethingExist()сначала позвоните », что является полезным сообщением об ошибке.

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

Единого универсального ответа на этот вопрос не существует. Использовать ли исключения или возвращать ноль, зависит от ситуации.

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

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

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

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

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

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

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

Брайан Оукли
источник
Не планирую надевать боевое снаряжение из-за этого, хе-хе. Было просто любопытно узнать, был ли я совершенно не прав, думая, о чем я думаю, или нет. Я хочу учиться, но я не люблю прыгать к чему-то только потому, что так говорит один человек. И особенно если это противоречит моему собственному опыту и логике (как бы мало это ни было). В любом случае, я полностью согласен с тем, что если бы это был интерфейс конечного пользователя, то это действительно имело бы смысл. Однако, поскольку это bean-компонент, который, насколько я знаю, доступен только через код, я бы сказал, что я, как разработчик, являюсь пользователем.
Свиш
1
И как разработчик меня волнует, почему что-то не так, независимо от того, что конечный пользователь должен узнать об этом.
Свиш
Полностью согласен с Брайаном. Даже разработчики являются пользователями, то есть потребляют код других разработчиков. Descisions для throw или null - это своего рода интерфейс / графический интерфейс, который должен быть полезен для конкретной задачи. Не только общим термином логики или философии.
Независимо
3

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

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

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

Кроме того, время, которое вы тратите на понимание, почему вы получили ноль, является сильным аргументом. Любой фрагмент кода должен быть прост для понимания и использования. Имея нулевое значение, это не так.

Амин
источник
В последнем предложении вы имеете в виду «Вы должны возвращать ноль только в случае разрыва сетевого соединения и т. Д.» или «Вы должны прекратить возвращать ноль, если сетевая ссылка не работает и т. д.» ?
Петер Тёрёк
@ Петер Тёрёк: Я не рекомендую явно использовать «return null;». Однако, когда происходит серьезный сбой, для некоторого сервиса допустимо возвращать ноль.
Амин
Разве исключение не будет более уместным, если произошла непредвиденная критическая неисправность?
Свиш
2
@ Амин: Я бы сказал, что это наименее подходящий случай, для которого нужно вернуть ноль.
Майкл Боргвардт
@Svish: если вы можете обнаружить серьезный сбой, конечно, будет исключение.
Амин
3

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

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

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

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

С моей точки зрения, возвращение null- плохая практика.

eversor
источник
2

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

С моей точки зрения, это не имеет смысла.

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

Аналогия : код ответа для GETбез авторизации не 200 okс данными, это на самом деле 401 Unauthorized.

Томас Джанк
источник
1

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

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

Qwerky
источник
Вы спрашиваете, как определить разницу между отсутствующим объектом и отсутствием у вас разрешения на его просмотр. Может быть, дизайн системы требует, чтобы вы не знали. Я не думаю, что у нас достаточно информации, чтобы ответить в этом конкретном случае, и нет ответа, который бы работал во всех случаях. Существуют совершенно допустимые случаи использования, когда, если вы не видите их, их фактически нет. И есть случаи использования, когда, если вы не можете видеть это, вам следует дать исключение, чтобы сказать, почему вы не можете.
Брайан Оукли
Что вы подразумеваете под "дизайном системы, который вы не знаете"? Что это за дизайн?
Свиш
2
Если политика безопасности гласит, что вам не разрешено его видеть, то в большинстве случаев вы также не должны знать, что он существует. Это делает возвращение "не найденным" совершенно приемлемым.
Blrfl
1

Если основной причиной является не прошедший проверку подлинности пользователь, то я предпочитаю жесткий ответ HTTP 401, возможно, с перенаправлением на симпатичную страницу сообщения (и уведомлением того, кто заботится). Причины, связанные с авторизацией, чаще встречаются в каждом конкретном случае; есть аргументы для возврата ошибок HTTP (скажем, 403) и аргументы для возврата специальных правильно сформированных кодов / сообщений в ответе службы.

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

отметка
источник
Что ж, в графическом интерфейсе вы можете сделать это, но что касается bean-компонента, реализующего сервис, который делает что-то за кулисами, у вас есть только исключения и специальные возвращаемые значения. Я, конечно, не имею в виду, что пользователь должен получить исключение, но исключение может, например, быть перехвачено в веб-сервисе / сервлете / что угодно, а затем делать то, что нужно. Перенаправить куда-нибудь, жесткую страницу http 4xx или что-то еще.
Свиш
Хороший вопрос, но вы могли бы использовать такую ​​парадигму, как АОП, чтобы фиксировать эти случаи. Аспект может проверить на привилегию для вызова данной операции и перенаправить / разрешить продолжить обработку в случае необходимости.
Отметить
0

Чтобы играть в адвоката дьяволов, я попытаюсь принять сторону возврата нуля.

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

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

Взять, к примеру, проверку имени пользователя и пароля. Возврат ошибок «Имя пользователя не найдено» и «Неверный пароль» в виде отдельных кодов ошибок, очевидно, откроет вам серьезные проблемы с безопасностью, поскольку кто-то может сначала найти действительное имя пользователя, а затем найти пароль. Возврат универсального «Неверное имя пользователя / пароль» будет лучшим вариантом.

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

OldCurmudgeon
источник
Да, я бы не согласился. Правильный ответ, по моему мнению, был бы исключением, но тот же самый и для имени пользователя, не найденного и для неправильного пароля. FailedToLogin, InvalidCredentials, что угодно.
Свиш
@Svish - Но если вы пытаетесь не давать никаких намеков относительно причины сбоя, то возвращение null- это наименее полезный ответ. Почти все остальное потенциально может быть использовано для обнаружения чего-либо в системе. Причина, по которой ОП жаловалась, заключалась в том, что nullвозвращение не только не объясняло ничего, но и было бесполезным. Это преднамеренная цель ... ничего не сказать и быть бесполезным. Миссия выполнена на мой взгляд.
OldCurmudgeon
Ну, это может быть так, но я все равно скажу, что делать это плохо. По крайней мере, внутри системы. На краях, где конечный пользователь видит вещи, тогда, конечно, я могу согласиться. Но внутри системы мы, разработчики, являемся пользователями, и почему в мире мы хотим сделать вещи более запутанными для себя? Как будто разработка программного обеспечения уже не достаточно сложна ...
Свиш
1
И с примером входа в систему я бы сказал, что для пользователя плохо, по крайней мере, что- то сказать о том, почему ничего не произошло, когда они (думали, что) вошли в свои учетные данные. Если страница просто обновляется и кажется, что она просто проигнорировала мою попытку входа в систему, я буду считать, что с системой что-то не так, а не то, что я ввел, было неправильно.
Свиш
-2

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

Марк Се
источник