Там часто публикуют куски отвратительного кода и мемы о программировании. Но однажды я увидел там кое-что совершенно потрясающее.
![](https://habrastorage.org/getpro/habr/post_images/a99/b27/5ee/a99b275ee7ba910700fd19559d520313.jpg)
Этот кусок кода заслужил почётное звание «лучшего произведения» за неделю.
Я решил этот код разобрать, но тут так много всего неправильного, что мне сложно даже выбрать первую проблему для анализа.
Если вы — начинающий программист, то мой материал поможет вам понять то, какие ужасные ошибки совершены тем, кто писал этот код.
28 строк ошибок кода
Давайте, чтобы было удобнее, наберём этот код в редакторе:
<script>
function authenticateUser(username, password) {
var accounts = apiService.sql(
"SELECT * FROM users"
);
for (var i = 0; i < accounts.length; i++) {
var account = accounts [i];
if (account.username === username &&
account.password === password)
{
return true;
}
}
if ("true" === "true") {
return false;
}
}
$('#login').click(function() {
var username = $("#username").val();
var password = $("#password").val();
var authenticated = authenticateUser(username, password);
if (authenticated === true) {
$.cookie('loggedin', 'yes', { expires: 1 });
} else if (authenticated === false) {
$("error_message").show(LogInFailed);
}
});
</script>
И… Ну правда — не знаю, с чего начать его разбор. Но начинать, всё же, надо. Я решил разбить недостатки этого кода на три категории:
- Проблемы с безопасностью.
- Проблемы с базовыми знаниями о программировании.
- Проблемы с оформлением кода.
Проблемы с безопасностью
Этот код, наверняка, выполняется на клиенте. На это указывает то, что он заключён в тег
<script>
(и, кроме того, тут применяется jQuery).Но не поймите меня неправильно. Этот код выглядел бы так же ужасно, если бы он был предназначен для сервера. Но вот выполнение его на клиенте означает то, что доступ к базе данных, которая в нём используется, будет у всех, кто способен этот код прочитать.
Взглянем на функцию
authenticateUser
:function authenticateUser(username, password) {
var accounts = apiService.sql(
"SELECT * FROM users"
);
for (var i = 0; i < accounts.length; i++) {
var account = accounts [i];
if (account.username === username &&
account.password === password)
{
return true;
}
}
if ("true" === "true") {
return false;
}
}
Из анализа её кода можно сделать вывод о том, что где-то имеется объект
apiService
, дающий в наше распоряжение метод .sql
, с помощью которого можно выполнять SQL-запросы к базе данных. Это означает, что если просматривая страницу, на которой имеется этот код, открыть консоль разработчика, можно будет выполнять любые запросы к базе данных.Например, можно выполнить такой запрос:
apiService.sql("show tables;");
В ответ на него будет возвращён полный список таблиц базы данных. И всё это — с использованием собственного API проекта. Но, чего уж там, давайте представим себе, что это — не настоящая проблема. Давайте лучше взглянем вот на это:
if (account.username === username &&
account.password === password)
Этот код говорит мне о том, что пароли в проекте хранятся без хеширования. Отличный ход! Это значит, что я могу взять отладчик и посмотреть пароли пользователей проекта. А ещё я уверен в том, что большой процент пользователей применяет одну и ту же пару имя пользователя/пароль в социальных сетях, в сервисах электронной почты, в банковских приложениях и в прочих подобных местах.
![](https://habrastorage.org/getpro/habr/post_images/1b5/63e/cd9/1b563ecd980b2c6c9d464482ed9ee5ff.gif)
Проблема видится мне и в том, как в этом коде устанавливаются куки
loggedin
:$.cookie('loggedin', 'yes', { expires: 1 });
Оказывается, тут применяется jQuery для установки куки-файла, который сообщает веб-приложению о том, аутентифицировался ли пользователь.
Запомните: никогда не устанавливайте подобные куки с использованием JavaScript.
Если нужно хранить на клиенте информацию такого рода, то для этого чаще всего используются именно куки-файлы. Ничего плохого о подобной идее я сказать не могу. Но установка куки с использованием JavaScript означает невозможность настройки атрибута
httpOnly
. А это, в свою очередь, означает, что любой вредоносный скрипт может получить доступ к подобным куки-файлам.И да, я знаю о том, что тут сохраняется лишь нечто вроде пары ключ: значение,
'loggedin': 'yes'
, поэтому если даже подобное прочтёт чужой скрипт, особого вреда от этого не будет. Но это, в любом случае, очень плохая практика.Кроме того, открыв консоль Chrome, я всегда могу ввести там команду вроде
$.cookie('loggedin', 'yes', { expires: 1000000000000 });
. В результате окажется, что я вошёл на сайт навсегда, даже не имея при этом учётной записи на нём.Проблемы с базовыми знаниями о программировании
О подобных проблемах, которые можно обнаружить в этом фрагменте кода, можно говорить и говорить, а времени у нас не так уж и много.
Итак, очевидно, что функция
authenticateUser
— это пример очень плохо написанного кода. Она демонстрирует отсутствие у того, кто её писал, некоторых базовых знаний о программировании.function authenticateUser(username, password) {
var accounts = apiService.sql(
"SELECT * FROM users"
);
for (var i = 0; i < accounts.length; i++) {
var account = accounts [i];
if (account.username === username &&
account.password === password)
{
return true;
}
}
if ("true" === "true") {
return false;
}
}
Может, вместо того, чтобы получать полный список пользователей из базы данных, достаточно выбрать пользователя с заданным именем и паролем? А что произойдёт, если в этой базе данных хранятся сведения о миллионах пользователей?
Я уже об этом говорил, но повторюсь, задавшись следующим вопросом: «Почему они не хешируют пароли в своей базе данных?».
Давайте теперь взглянем на то, что возвращает функция
authenticateUser
. Исходя из того, что я вижу, я могу сделать вывод о том, что она принимает два аргумента типа string
и возвращает единственное значение типа boolean
.Поэтому следующий фрагмент кода, хоть и написан он ужасно, бессмысленным назвать нельзя:
for (var i = 0; i < accounts.length; i++) {
var account = accounts [i];
if (account.username === username &&
account.password === password)
{
return true;
}
}
Если перевести его на обычный язык, то получится примерно следующее: «Существует ли пользователь с именем X и с паролем Y? Если да — вернуть true».
А теперь давайте взглянем на этот фрагмент кода:
if ("true" === "true") {
return false;
}
Бессмыслица. Почему бы функции просто не вернуть
false
? Зачем ей условие, которое всегда истинно?Теперь давайте проанализируем следующий код:
$('#login').click(function() {
var username = $("#username").val();
var password = $("#password").val();
var authenticated = authenticateUser(username, password);
if (authenticated === true) {
$.cookie('loggedin', 'yes', { expires: 1 });
} else if (authenticated === false) {
$("error_message").show(LogInFailed);
}
});
Та часть этого кода, где осуществляется работа со значениями с использованием jQuery, выглядит нормально. Но проблема тут в организации работы с куки
loggedin
.Мы уже говорили о том, что, даже не имея учётной записи, можно просто открыть консоль Chrome и, выполнив команду
$.cookie('loggedin', 'yes', { expires: 1 });
, оказаться аутентифицированным на один день.А как эта страница узнаёт о том, кем именно является аутентифицированный пользователь? Может, она просто выводит что-то особенное, предназначенное только для тех, кто успешно прошёл проверку имени пользователя и пароля и не выводит никаких персональных данных? Этого нам не узнать.
Проблемы с оформлением кода
Оформление — это, вероятно, самая маленькая и незначительная проблема данного кода. Но она чётко указывает на то, что тот, кто этот код создавал, откуда-то скопипастил его отдельные фрагменты.
Вот пример использования двойных кавычек при оформлении строк:
var username = $("#username").val();
var password = $("#password").val();
А в другом месте используются одинарные кавычки:
$.cookie('loggedin', 'yes', { expires: 1 });
Это может показаться неважным, но это, на самом деле, говорит нам о том, что разработчик, возможно, скопировал какой-то код, скажем, со StackOverflow, и при этом даже не переписал его, следуя руководству по стилю, используемому в проекте. Конечно, это — мелочь, но она указывает на то, что разработчик не особо заботится о том, чтобы понять то, как именно работает код. Этому разработчику просто надо, чтобы код хоть как-то функционировал.
Хочу тут пояснить мою точку зрения на эту проблему. Я каждый день ищу в Google что-то, связанное с кодом, но мне кажется, что гораздо важнее понять, например, как установить куки, а не заставить работать бездумно скопированный откуда-то кусок кода. Что если по какой-то причине программа перестанет работать? Как программист, не понимающий того, что происходит в его коде, найдёт ошибку?
Итоги
Я абсолютно уверен в том, что этот фрагмент кода — фейк. Тут я впервые увидел пример синхронного выполнения SQL-запроса:
var accounts = apiService.sql(
"SELECT * FROM users"
);
Обычно подобные задачи решают так:
var accounts = apiService.sql("SELECT * FROM users", (err, res) => {
console.log(err); // ошибка
console.log(res); // результат выполнения запроса
});
Ещё их решают так:
var accounts = await apiService.sql(
"SELECT * FROM users"
);
Даже если метод
apiService.sql
возвращает результат в синхронном режиме (в чём я сомневаюсь), ему нужно открыть подключение к базе данных, выполнить запрос, отправить в точку вызова результат. А эти операции (как несложно догадаться) не могут выполняться синхронно.Но если даже это — совершенно реальный код, я уверен, что он был написан начинающим программистом, джуниором. Я уверен, что я, когда работал программистом первые недели, тоже писал ужасный код (прощу прощения :D).
Но это — не ошибка программиста-джуниора.
Представим, что это — настоящий код, который где-то работает. Некий джуниор выложился бы по полной ради того, чтобы этот код заработал. Этот разработчик ещё должен научиться правильному обращению с SQL-запросами, с куки-файлами и со всем остальным. И в таком свете это — совершенно нормально.
А вот начальник этого программиста должен проконтролировать работу, указать на ошибки, добиться от начинающего понимания его ошибок. Это приведёт к тому, что столь ужасный код не попадёт в продакшн.
Я точно знаю, что есть компании, которых не заботит качество кода, уходящего в продакшн. Код решает задачу? Если так — его, без лишних вопросов, развёртывают. Код написан джуниором и даже не проверен более опытным программистом? В продакшн его!
В общем, бывают в жизни огорчения.
Дополнение от 8 августа 2020 года
Я, когда писал эту статью, полагал, что код, который я анализировал, это — фейк. Но после обсуждения материала на Reddit мне дали ссылку на эту ветку. Как оказалось, этот код используется в некоей внутренней системе, поддерживающей работу 1500 пользователей. Поэтому я, очевидно, был не прав. Это — совершенно реальный код.
А вы встречали в продакшне откровенно плохие фрагменты кода, переполненные всяческими проблемами?
![](https://habrastorage.org/webt/ou/g5/kh/oug5kh6sjydt9llengsiebnp40w.png)
alexey_c
Я встречал код
if Date()>«20.01.2001»
messagebox(«Неизвестная ошибка»);
exit;
Синтаксис точно повторить не смогу, это было на VB версии, устаревшей уже на тот момент.
ПО Считало в банке какие-то показатели для отчётности.
Человек, писавший этот код, уволился в декабре 2000 года.
DrPass
Я как-то видел код банковского программиста, который наоборот, не хотел увольняться, и сделал всё, чтобы быть незаменимым. Его софтина была в одном файле из полутора сотен тысяч строк, и она была обфусцирована. Не в полной мере, конечно, но переменные звались исключительно a, b, c, d..., функции тоже в таком духе. Это было сделано, чтобы никто другой не смог этот проект развивать. И да, мы действительно переписали эту гадость с нуля.
Bringoff
Вопрос в том, как он это поддерживал.
Fen1kz
открывал необфусцированный репозиторий, делал изменения, обфусцировал, выкладывал в рабочий репозиторий?
iig
В 2000 году он мог обходиться и без репозиториев ;). Me своими глазами видел код, в котором все таблицы были mXXX.dbf, поля в них Ryyy… Те самые годы, foxpro, 3 программиста, и никаких репозиториев.
remzalp
Когда смотрел, как 1С хранит данные в БД… Это были такого же рода таблицы и метаинформация в одной из таблиц, с маппингом этой мути на объекты в 1С
n0isy
Чтобы быть точным, в 1С 7.7, метаинформация содержится не в таблицах, а в файле 1cv7.md, в 1С 8.x перенесли в БД, но IMHO используется «VFS». Всё равно «файлы» внутри СУБД.
firewind1
Наверное, у него был файлик, где всё было расписано, в том числе и назначение каждой переменной
pfffffffffffff
Source map как для js xdd
Naves
В студенческие годы я писал одну программу расчета, которая в зависимости от комбинации пары десятков чекбоксов и листбоксов брала данные из бд, и выводила некий результат. Кроме того, что приложение было написано в классическом стиле button_logic, я даже не переименовывал элементы интерфейса, и в коде была натуральная портянка вида:
if (checkbox1.checked and checkbox8.checked)
listbox9.enabled=false;
и что-то типа:
if (len(textbox19.text)>0)
sql=sql+" and column='"+textbox19.text+"'"; //инъекции, не не слышали, тогда
Писал пару недель, и все это время помнил наизусть какой чекбокс за что отвечает, и даже не задумывался, что их нужно переименовывать.
Так что возможна ситуация, когда программист даже специально и не обфусцировал ничего, он просто и так помнит какая переменная и функции за что отвечают.
hiddenman
Это стиль кода примерно так 95% ПО тех лет, когда появился Delphi сотоварищи.
Быстренько «набросать на форму» сотню-другую контролов, далее столько же событий и после этого героически о всем этим бороться.
Bringoff
Ну, в студенческих программах и я помнил предназначение переменных :) Но речь о 150k loc. У меня на прошлой работе был проект примерно такого размера (большинство которого, правда, я сам не писал), то за 2.5 года я все ещё не во все части кода успел залезть, не то чтобы запомнить предназначение всех вещей. При том, что проект написан был сравнительно грамотно, не «все-в-одном-файле-с-рандомными-именами».
С другой стороны, смотря на исходники того же телеграма для Android и что оно до сих пор в состоянии развиваться, я даже котов поверить, что если человек работает над проектом с самого начала, он может плюс-минус помнить то, что он писал.
mvv-rus
DrPass
Не годится. Софтина была как раз на Паскале, точнее, на Delphi :)
Собственно, как-то поддерживал. Я не думаю, что у него где-то был деобфусцированный текст, скорее всего, просто помнил. Когда проект всего один, и ты туда каждодневно залезаешь, то в принципе все равно будешь помнить, где там какой код что делает.
mvv-rus
Язык не имеет особого значения: как написано в той же самой статье по ссылке «закоренелый настоящий программист может написать фортрановскую про-
грамму на любом языке.»
Да, он наверняка помнил. А если что и не помнил — то смотрел в коде: «настоящие программисты не нуждаются в комментариях: текст программы все объясняет»
VolCh
Самодокументируемый код же :)
alexey_c
Там и не нужно было ничего помнить. Это было так круто… Жмакаешь на поле ввода, выбираешь справа обработчик, и после даблклика попадаешь в его текст. А как называется компонент — последнее дело… :)
sumanai
Я всегда знал, что настоящие программисты пишут на PHP!
fshp
Я работал с таким человеком. Раньше он в университете преподавал.
Выход за границы массива? Да нее, просто увеличу размер в 10 раз на всякий случай.
Локальные переменные? Пфф, глобальных хватит. Да ещё и объявлю их с запасом. А то в начало файла лазить не хочется каждый раз, ведь тут полторы тысячи строк. В которых объявлено 3 процедуры, которые используют исключительно глобальные переменные.
Ребят, мне нужно читать изображения, но я не умею. Присылайте в текстовом виде размер и R,G,B в каждой строчке.
AllexIn
Это же легендарный «хвостик». Есть даже преподы, которые этому УЧАТ.
RaFaeL-NN
Я не так давно тоже исправлял такую «неизвестную ошибку», код один в один. Человек, писавший этот код, не увольнялся, а просто взял и умер
alexey_c
Возможно, он обладал удивительными способностями…
На самом деле я на заре развития ИТ в стране часто видел такие подходы.
С каждой новой версией дата отодвигалась и всё хорошо работало, но когда заказчик пытался выйти из отношений с разрабом, оно вылазило.
И хорошо если так — когда есть текст сообщения, который по коду находится на раз, два.
grishkaa
Каждый раз, когда я вижу «неизвестную ошибку», я либо серьёзно сомневаюсь в способностях того, кто написал выдающий её код, либо читаю это как «ошибка, об истинной природе которой вам знать не положено». У нормальных программистов «неизвестных ошибок», всё-таки, не бывает.
quwy
Часто такой вывод говорит о том, что программисту было лень или некогда продумывать все сценарии развития событий при возникновении ошибки.
grishkaa
Ну ошибку же что-то вызвало? Была же какая-то проверка, в результате которой была обнаружена ошибка? У этой проверки же была какая-то цель? Значит, и хоть сколько-нибудь осмысленное сообщение об ошибке сформулировать не должно составить труда.
DrPass
Очевидно, была — какой-то глобальный обработчик исключений в программе, ну или локальный обработчик вокруг крупного блока кода, дифференцировать все возможные исключения в котором программисту было некогда или просто лень. Это вполне себе типовой кейс. Ну а «Неизвестная ошибка» вместо технических подробностей, это просто чтобы не взорвать мозг пользователю, вываливая на него содержимое стека вызовов.
grishkaa
Так зачем дифференцировать? Кинуть своё с общим сообщением об ошибке, добавив к нему подробное из пойманного. В джаве, например, это поведение вообще встроено, можно передать в конструктор исключения другой Throwable в качестве причины, и во всяких логах выведется соответствующим образом.
Ну так всё равно можно же вывести какое-то общее сообщение об ошибке. «Ошибка при чтении файла», «ошибка сети», «ошибка ввода/вывода», «внутренняя ошибка на сервере», и так далее. И мозг не взорвал, и совесть чиста :)DrPass
В джаве там обработка исключений контролируется ещё компилятором, там при желании забить на это не выйдет.
Ну так это же надо ещё сесть и тестировать, тестировать, тестировать… Эти «неизвестные ошибки» пишут же не тогда, когда там сразу понятно, какой тип исключения вылез, а когда их надо ещё выявить.
VolCh
Это ж 4 catch надо делать
grishkaa
Есть как минимум 2 способа объединить их в один. ИМХО, делать раздельные catch для разных типов исключений имеет смысл только если код для их обработки должен быть разным.
Можно перечислить типы (новая фича в 8й джаве):
Можно просто ловить любой из базовых классов:
DrPass
Во-первых, эти типы нужно знать. Во-вторых, нужно, чтобы это была 8-я джава. Ну, или 6-й С#
Ну а это и есть та же самая «Неизвестная ошибка»
grishkaa
DrPass
Мы же говорим про
Если известно конкретное действие, то и «неизвестных ошибок» не бывает.
grishkaa
Ну так у этого исключения всё равно будет более подробное внутри. Если вызвать printStackTrace(), оно выведет его в виде «caused by: java.lang.IllegalArgumentException: очень конкретная ошибка». По-моему очень удобно.
Throwable
Есть небезосновательное мнение, что checked exceptions в Java — это зло. От неправильного try-catch гораздо больше вреда, чем если бы его вообще не ставить — в последнем случае все-равно где-нибудь выше сработает обработчик, поставленный умными и компетентными людьми. Сколько встречал дерьма наподобие:
или даже
которые дают исчерпывающую информацию в логах о причине ошибки и заставляют медитировать над хрустальным шаром, пытаясь реконструировать сценарий по всевозможным сайд эффектам.
VolCh
Если объединять, то и будет "неизвестная ошибка"
Вообще сарказм был.
alexey_c
Ошибка может быть обрабатываемой пользователем — «Не указана фамилия», или не обрабатываемой им — «SQL ERROR...». В первом случае нужно хорошо обработать, показать ему вменяемое короткое сообщение, после которого он поймёт, в чём косяк, а во втором ему не нужно сразу ничего показывать. И просто сказать «Унимание, вохгткла ошибка где-то внутри. Сохраняй спокойствие и сообщи в службу поддержки её код ХХХ..».
И тут абсолютно всё равно, во время чего произошла ошибка. «Ошибка при сохранении файла» — самое дурацкое сообщение. Что делать то, если оно вылезет?
Osnovjansky
Для таких случаев мне нравился подход в Делфи 5..7 (примерно)
Они выводили сообщения: «Исключение #...»
Т.е. если в каком то месте кода мы считаем, что возникновение ошибки маловероятно, мы можем не обрабатывать её, но бросить уникальное исключение (и, например, логгировать его) чтобы потом можно было определить место, где обнаружена ошибка.
MacIn
В норме там будет Eurekalog, который создаст .elf файл с callstack'ом и местом возникновения ошибки, вплоть до строки. Ну или Jcl Debug.
Ну и да, чем выкидывать ошибку с номером, уж лучше сделать Raise Exception.Create('Exception: Module/Methodname: SomeUseful disagnostic msg').
Vlad_IT
Не пользователь, а пользователь с правильным паролем, НЯП. Если пароль неверный, он же до конца таблицу досмотрит, не?
Wolf4D
Вообще, это подход из серии надписи на приборе «внутри нет частей, которые вы могли бы починить».
Реальный случай. Приложение, написанное отделом А, решает положить введённые пользователем данные в базу, написанную отделом Б. По требованию заказчика, база иногда внезапно и нещадно изменяется — а новая версия программы разворачивается с опозданием. Так что случается, что сервер СУБД даёт программе неожиданный и необрабатываемый отлуп из серии «нет такой таблицы в этой базе».
Дать пользователю текст ошибки от сервера СУБД? Пользователь не имеет ни прав лезть в базу, ни знаний для этого. Что ему делать с этой безусловно полезной информацией?
Всё, что ему остаётся, увидев ЛЮБУЮ ошибку (не вызванную его действиями) — это «Halt and catch fire». Он прекратит работу и позовёт администратора.
Потому программа сейчас выводит скромное сообщение из серии «При сохранении данных возникла неизвестная ошибка взаимодействия с сервером. Обратитесь к разработчику».
А полный текст ошибки, конечно, попадает в лог для команды разбора.
AllexIn
Хм. У меня в коде есть WTF ошибки.
Опыт научил меня, что надо обрабатывать все случаи, но проблема в том, что некоторые случаи невозможны. Но я всё равно ставлю туда лог с текстом в духе «WTF! Impossible error.». Занимает такая проверка не очень много, зато в логе всегда есть какая-то инфа.
И да, такие обработчики иногда срабатывают. Например достаточно часто инкрементальная сборка некоторых проектов начинает косячить и не пересобирает объектники, которые надо собирать. В итоге едут указатели и «невозможная» ошибка становится возможной. Для меня появление такой ошибки в логе первый признак того, что проект был собран не правильно. Но написать туда что-то вроде «Incorrect build error» я не могу, потому что это лишь одна из возможных причин срабатывания обработчика. И даже написать «Maybe incorrect build» я не могу тоже, потому что поехавший объектиник это UB и предполагать о том, что это UB может вызвать какой-то не валидный код я не могу.
Max-812
Я использую вывод «Неизвестная ошибка» там, где юзверь делает те действия, которые ему делать не положено. Просто для того, чтобы не облегчать ему задачу. Но если есть возможность записи внутренних логов, то туда алерт пойдет как надо.
DrPass
Честно говоря, в таком случае проблема не в юзвере, а в вас. В нормально спроектированной программе не должно быть доступно кнопок, которые нельзя нажимать.
Max-812
У вас весьма однобокое понимание того, какими могут как программы, так и юзвери. Никогда не сталкивались с попытками заведомого ввода некорректной информации при регистрации или просто ввода данных, например? :) Не случайными ошибками, а именно спланированными?
DrPass
Сталкивался. Но ведь программа в этом случае должна делать валидацию входных данных, и сообщать, что не так. Если важно контролировать, что юзеры пытаются обмануть систему, то логировать подобные попытки. Но уж точно не выдавать «неизвестные ошибки».
Max-812
Она и проверяет. Но в данном случае пользователю НЕ НАДО сообщать, что конкретно он делает не так, потому что это может облегчить ему задачу. Именно поэтому ЕМУ делается вывод «Неизвестная ошибка». А про запись алерта в логи я сказал изначально.
DrPass
Мне сложно представить себе кем-либо специально выстроенный бизнес-процесс, в котором у вас есть вредитель (условно вредитель, пусть даже просто юзер, который показательно кладёт большой болт на служебные инструкции), у него достаточные права для того, чтобы осознанно вредить, а препятствием на пути у него является программа, которая просто не говорит ему, что он сделал не так. Наоборот, вы только укрепили у меня уверенность, что что-то у вас там организовано неправильно.
cdmnk
Представитель конкурента, купивший у вас ПО для натурально выглядящего отчёта «как вообще этим пользуются»
a1111exe
Что Вы предлагаете возвращать пользователю в случае инфраструктурных исключений? Возвращать сообщение самого исключения значит раскрывать конкретные подробности своей инфраструктуры, которые пользователю знать нет никакой необходимости, уже не говоря о том, что это потенциальная дыра для сбора информации хакером. А какое-то сообщение вернуть надо (элементарное уважение к пользователю) — например, что-то вроде "Ошибка приложения, обратитесь в техподдержку по такому-то номеру". Вот это "ошибка приложения", имхо, эквивалентно "неизвестной ошибке", хотя я бы предпочёл первое.
DrPass
У всех у них есть какая-то классификация. Или как минимум, разделение на три большие категории «может пройти сама», «может быть исправлена пользователем», «требует обращения в ИТ-саппорт». Для первой надо выдавать сообщение, например, «Удаленный сервер в настоящее время недоступен, повторите запрос позже», для второй, например, «Введенные данные не соответствуют требованиям к оформлению входящих документов», для третьей, как вы и написали, «В приложении произошёл внутренний сбой, обратитесь в техническую поддержку». Раскрывать ему стек вызовов, естественно, не нужно, но вот у технической поддержки возможность достать подробности исключения должна быть. И вполне логично, если он будет там где-то писаться, даже на машине юзера, если подобные сбои могут предполагать отсутствие возможности писать куда-то в удалённый лог на сервере.
Max-812
Вы в своих фантазиях ушли уже настолько глубоко, что вытаскивать вас на поверхность у меня нет никакого желания. :) Все куда проще. А уверенность ваша меня и вовсе никак не касается.
DrPass
Я никуда не уходил. Я просто объяснил, что у вас творится какая-то фигня в организации. И если бы у вас было более разумное объяснение этому, кроме как «да так само сложилось, просто никто не думал, как лучше», вы бы написали :)
Max-812
Я привел вам конкретный пример, почему в некоторых случаях используется именно такое неконкретное сообщение. Если вы не в состоянии этого понять, и ищите какое-то двойное дно, то это уже не ко мне. :)
tretyakovpe
У него программы наверняка сообщают: «При вводе пароля вы ошиблись в третьем символе. Там должно быть А вместо а. А логин вообще User20398»
Max-812
Не думаю. Во первых, в его программах «вы» будет с большой буквы. А слова «вообще» не будет вообще. ;)
DrPass
Боюсь, члены жюри в отборочном туре могут подраться между собой, решая, кого из вас двоих отправить на финал конкурса юмора имени Петросяна.
VolCh
Вы будете смеяться, но помнится какой-то BIOS был так запаролен: нажимаешь букву, если правилно, то звездочка появляется и курсор передвигается дальше. Если нет, то пищит и ничего не происходит.
DrPass
А я вам на него написал конкретный ответ: такого быть не должно в принципе. Если юзер нечаянно вводит неверные данные, программа должна на это указать. Если юзер сознательно вводит неверные данные, ему начальство должно дать по шапке, а дело программы — залогировать это, если нет возможности просто запретить. Вот это логично, и правильно. Ваш же вариант, когда программа предлагает юзеру пройти увлекательный квест «угадай, что ты сделал не так» — это какая-то дичь.
RaFaeL-NN
Е-ОСАГО занимаетесь? )
Naves
Не могу точно вспомнить похожий случай из своей практики, но примерно так:
Есть определенные пользователи вредители, вредители они не вообще, а иногда могут ими становиться, например, в утреннюю смену в воскресенье, куда их задвинули из-за сбоя графика, или из-за того, что «свет с Венеры отразился от верхних слоёв атмосферы и вызвал взрыв болотного газа»
Бороться с таким вредительством организационно очень сложно, тк «других людей у нас нет»
Так вот, эти пользователи могут делать совершенно легитимное действие в системе, например, удаление записи в какой-то таблице. Но прежде чем удалить одну запись, нужно удалить связанные данные в соседних таблицах. Естественно delete cascade выключен. И вот, чтобы что-то удалить из таблицы А, нужно осознанно удалить данные в таблице B. Пользователю в явном виде это не говорится, потому что смотреть выше.
Однажды такой случай дошел до планерки директора предприятия, и мне задавался вопрос, как можно запретить удаление записей такому пользователю. На что я отвечал, что для должности пользователя это легитимное действие, и как система должна отличать, когда можно разрешать действие, а когда нет? Ответа не было.
И да, в системе были и логи, кто что делал, по ним регулярно выявляли очередные «вспышки на солнце». И записи могли не удаляться, а помечаться флагом архив, чтобы не отображались, но в общем и целом человеческий фактор не отменялся.
— Почему они так делают, зачем?
— Потому что могут.
ozonar
Ну, к примеру, настоящий код ошибки отправляется в лог, который смотрит программист