Пример реализации универсального REST сервиса (Avalanche — application framework for Java)
"Avalanche — application framework for Java" — реализация технологии стирающей различия
между вызовами локального и удаленного кода. Отказоустойчивость, масштабируемость,
модифицируемость, непрерывная доступность идут в комплекте приятными бонусами.
В статье описан пример реализации универсального REST сервиса. В основу идеи реализации сервиса положено утверждение, что FrontEnd в каждый момент времени "знает", какими данными он манипулирует и что собирается запросить у BackEnd-а. Это утверждение позволило отказаться от разработки ORM в BackEnd-е и использования JPA при реализации универсального сервиса. Сервис способен манипулировать содержимым любой таблицы БД. Изменения структуры или созданные объекты БД сразу становятся доступны методам сервиса.
В сервисе реализованы методы трех групп:
- .../data/table/… — манипулирования содержимым таблиц БД;
- .../data/query/… — выполнение произвольных запросов, расширяющих функциональность сервиса;
- .../data/info/… — получения информации о структуре объектов БД.
В сервисе реализована система ошибок, которая однозначно позволяет понять причину и место возникновении ошибки. По умолчанию, поддерживается локализация сообщений ru и en. Не все сообщения могут быть локализованы, например сообщения ошибок выполнения SQL запросов, которые зависят от локализации среды выполнения.
Сервис поддерживает работу с данными в форматах XML и JSON.
Сервис реализован с использованием библиотеки Jersey 2.0.
В общем виде формат URL строки запроса сервиса выглядит так
http://host:port/name_context/map_servlet/data/type_group/{object}[?request_parameters]
[request_body]
Где:
- name_context — имя контекста (WEB приложения);
- map_servlet — имя маппирования сервлета Jersey в файле web.xml;
- data — путь этого сервиса
- type_group — тип группы запросов (table, query или info);
- {object} — параметр запроса
Параметр запроса {object} может принимать значения:
- для типа table — имя_схемы.имя_таблицы в формате schema.table;
- для типа query — имя_класса.имя_метода в формате class.method, имя класса указывается без пакета, поиск класса осуществляется в пакетах, указанных в параметра packages;
- для типа info — имя_метода в формате method;
request_parameters — параметры запроса, могут отсутствовать
request_body — тело запроса, может отсутствовать
В HTTP заголовке могут указываться параметры:
- Accept — не обязательный, формат данных, ожидаемый в ответе на запрос, может принимать значения application/json (по умолчанию) или application/xml;
- Content-Language — не обязательный, язык локализации, может принимать значения ru (по умолчанию) или en;
- Content-Type — обязательный, при наличии тела запроса, может принимать значения application/json или application/xml.
Реализация сервиса
Реализация сервиса TableService.java опубликована на GitHub.
Пример конфигурационного файла сервиса avalanche-restdb-config.xml
Пример конфигурационного файла контекста restdb.xml
Ниже приведены примеры различных запросов
Примеры запросов
Пример получения записи таблицы rp.structure_type по значению первичного ключа
Запрос:
GET /restdb/rs/data/table/rp.structure_type?st_id=43 HTTP/1.1
Accept: application/json
Content-Language: ru
Host: localhost:8080
Ответ: (HTTP Status — 200)
[
{
"st_id": 43,
"st_name": "Test43 "
}
]
Пример получения нескольких записей таблицы rp.structure_type по значению первичного ключа
Запрос:
GET /restdb/rs/data/table/rp.structure_type?st_id=43&st_id=42 HTTP/1.1
Accept: application/json
Content-Language: ru
Host: localhost:8080
Ответ: (HTTP Status — 200)
[
{
"st_id": 42,
"st_name": "Test42 "
},
{
"st_id": 43,
"st_name": "Test43 "
}
]
Пример получения всех записей таблицы rp.users, если это не запрещено в конфигурации сервиса
Запрос:
GET /restdb/rs/data/table/rp.users HTTP/1.1
Accept: application/json
Content-Language: ru
Host: localhost:8080
Ответ: (HTTP Status — 200)
[
{
"us_last": "Петров ",
"us_name": "Петр ",
"us_email": "p_petrov@domain.ru "
},
{
"us_last": "Сидоров ",
"us_name": "Сидор ",
"us_email": "s_sidorov@domain.ru "
},
{
"us_last": "Пупкин ",
"us_name": "Пуп ",
"us_email": "p_pupkin@domain.ru "
},
{
"us_last": "Остапов ",
"us_name": "Остап ",
"us_email": "o.ostapov@domain.ru "
},
{
"us_last": "Иванов ",
"us_name": "Иван ",
"us_email": "i.ivanov@domain.ru "
},
{
"us_last": "Кириллов ",
"us_name": "Кирилл ",
"us_email": "k.kirillov@domain.ru "
}
]
Пример получения записей таблицы rp.users, имеющих вхождение подстроки "ров" в поле us_last
Запрос:
GET /restdb/rs/data/table/rp.users?us_name=%ров% HTTP/1.1
Accept: application/json
Content-Language: ru
Host: localhost:8080
Ответ: (HTTP Status — 200)
[
{
"us_last": "Петров ",
"us_name": "Петр ",
"us_email": "p_petrov@domain.ru "
},
{
"us_last": "Сидоров ",
"us_name": "Сидор ",
"us_email": "s_sidorov@domain.ru "
}
]
Пример вставить одну запись в таблицу rp.test
Если в теле запроса будет указано несколько записей вставятся в таблицу множество записей.
Запрос:
POST /restdb/rs/data/table/rp.test HTTP/1.1
Accept: application/json
Content-Language: ru
Content-Length: 58
Host: localhost:8080
Content-Type: application/json
[{"ts_id":9, "ts_tszone":"2019-01-19T15:37:13.380+03:00"}]
Ответ: (HTTP Status — 200)
{
"query": "INSERT",
"result": 1,
"timer": 3
}
Пример вставить одну запись в таблицу rp.test
Пример, аналогичный запросу выше, но с указанием параметров вставляемой записи в строке запроса. Если в строке запроса присутствуют параметры то тело запроса в HTTP методе POST игнорируется.
Запрос:
POST /restdb/rs/data/table/rp.test?ts_id=10&ts_tszone=2019-01-19T15:37:13.380+03:00 HTTP/1.1
Accept: application/json
Content-Language: ru
Content-Length: 58
Host: localhost:8080
Content-Type: application/json
Ответ: (HTTP Status — 200)
{
"query": "INSERT",
"result": 1,
"timer": 3
}
Пример неудачной попытки вставить запись с использование метода insert класса SQL генератора TestQuery
В теле запроса допущена опечатка (намеренно), в имени поля us_last пропущена буква "s"
Запрос:
POST /restdb/rs/data/query/TestQuery.insert HTTP/1.1
Accept: application/xml
Content-Language: ru
Content-Length: 61
Host: localhost:8080
Content-Type: application/json
[{"us_name":"3", "us_lat":"333", "us_email":"333@domain.ru"}]
Ответ: (HTTP Status — 400)
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<serverError>
<cause>
[24344@likhovskikh-vv] SYS0250E При вызове метода "execute" возникла ошибка.
Ошибка: "ru.funsys.avalanche.sql.SQLException: [24344@likhovskikh-vv] SQL0021E При выполнении запроса произошла ошибка. Номер запроса: 0, запрос: INSERT INTO rp.users (us_name, us_last, us_email) VALUES (?, ?, ?).
org.postgresql.util.PSQLException: ОШИБКА: нулевое значение в столбце "us_last" нарушает ограничение NOT NULL
Подробности: Ошибочная строка содержит (3 , null, 333@domain.ru )."
</cause>
<cоde>RST0007E</cоde>
<message>При выполнение SQL запроса произошла ошибка.</message>
</serverError>
Преимущества универсального сервиса по сравнению с общепринятым подходом реализации REST сервисов.
- Универсальный REST сервис готов для использования с любой реляционной БД.
- Нет зависимости от требования JPA обязательного наличия индексного идентификатора ID в каждой таблице модели данных. Коллеги, в реляционной теории БД нет понятия индексного поля таблицы ID, которое используется в качестве первичного ключа. Наличия этого поля превращает вашу реляционную БД в индексную.
- URI, параметры запроса, тело запроса и результат выполнения запроса формализованы.
- Универсальный сервис легко расширяемый, достаточно определить требуемые методы генерации SQL запросов в одном или нескольких классах SQL генераторов.
- Первичный ключ таблиц БД может состоять из множества полей. Поля первичного ключа доступны для модификации при соблюдении условий целостности.
- Отсутствие отображения программной модели объектов модели данных в БД значительно упрощает эксплуатацию, особенно в распределенной среде (например, в системах с георезервированием во множестве ЦОД).
lair
Запрос:
Сообщение об ошибке:
А если бы не было ограничения
NOT NULL
на этой колонке?vl65 Автор
Контроль значения поля можно добавить в явном виде, например так
if (us_last == null) throw new RestException("RST0100E", new Object[] {"us_last"}, lang);
см метод inset класса TestQuery.java
lair
Я повторю свой вопрос: что будет с тем же самым запросом, если в БД нет ограничения
NOT NULL
?Я что-то не понимаю. У вас универсальный сервис (т.е., тот, который не надо править при изменении структуры БД), или не универсальный (т.е., его надо править под структуру БД)?
vl65 Автор
Совершенно верно, универсальный. Пример, который Вас заинтересовал — это пример реализации расширения функциональности сервиса. Контроль параметров в этом случае обеспечивается самой реализацией этого расширения.
lair
Тогда вернемся к предыдущему вопросу: что будет с тем же самым запросом, если в БД нет ограничения
NOT NULL
(и если сервис никак не "расширяли")?vl65 Автор
Возникнет ошибка выполнения SQL запроса с сообщением, что поле us_lat не существует.
lair
А почему SQL-запрос в примере при этом выглядит вот так:
INSERT INTO rp.users (us_name, us_last, us_email) VALUES (?, ?, ?)
? Где там полеus_lat
?vl65 Автор
Сервис генерирует запрос по полученным параметрам, параметра us_last нет в параметрах запроса, а запрос
INSERT INTO rp.users (us_name, us_lat, us_email) VALUES (?, ?, ?)
выполнится с ошибкой
lair
Что-то не сходится.
Вот тело HTTP-запроса из вашего примера:
Вот сообщение об ошибке из того же примера:
Там явно приведен SQL-запрос:
us_lat
, который есть в HTTP-запросе, там нет.us_last
, которого нет в HTTP-запросе, там есть.Как так получается?
vl65 Автор
Вы путаете два разных запроса. Обращаю ваше внимание на пример, который Вас заинтересовал — это пример расширения функциональности это сервиса! В этом случае контроль полученных параметров осуществляется в самой реализации расширения.
Для вставки записи/записей самим сервисом нужно указать другой URL запроса .../data/table/rs.users. В этом случае сервис генерирует SQL запрос по полученным параметрам, выполнение которого при указанной опечатке в имени поля завершиться с ошибкой.
В заинтересовавшем Вас примере указан URL .../data/query/TestQuery.insert.
lair
Тогда вернемся к предыдущему вопросу: что будет с тем же самым запросом, если в БД нет ограничения NOT NULL (и если сервис никак не "расширяли")?
(я хочу заметить, что этот диалог — это типичный пример того, что будет в голове разработчика, которому надо будет интегрироваться с этим сервисом)
vl65 Автор
Тот же самый запрос без использования расширения
Запрос:
Ответ: (HTTP Status 400)
Сгенерированный SQL запрос и возникшая ошибка (из лога без стека вызовов)
lair
Это не тот же запрос.
vl65 Автор
Первый, приведенный в статье, использует расширения функциональности.
Второй, приведенный выше, использует универсальный сервис.
Оба эти запроса выполняют одно и тоже, вставляют одну и ту же запись в таблицу.
Еще остались вопросы?
lair
Да.
Как поведет тот же самый запрос, если сервис не был расширен?
vl65 Автор
В ответ #comment_21245044
приведен пример того же самого запроса, без расширения функциональности.
lair
Это другой запрос. А я спрашиваю, что будет с тем же самым.
vl65 Автор
С "тем же самым" другого варианта быть не может. "Тот же самый" вызывается только как функция расширения универсального сервиса.
Вы задали вопрос, как поведет себя универсальный сервис, если подобная ошибка (опечатка в имени поля) будет допущена при его вызове. Я вам привел ответ на этот вопрос "тот же самый запрос" — вызов через универсальный сервис без расширения функциональности. См. ответ #comment_21245044
Еще есть вопросы?
lair
Что значит "не может"? Что мешает клиенту послать такой запрос?
vl65 Автор
Правила формирования URI запроса.
.../data/table/… — запрос на модификацию БД через универсальный сервис
.../data/query/… — запрос на модификацию, определенную в методе класса расширения
lair
И что? Был у вас клиент, слал запросы, потом на сервере убрали расширение. Что случится?
vl65 Автор
Будет ошибка, как и в любой другой реализации REST сервиса, если в этой реализации "убить" какой то метод.
Реализация сервиса описанная в статье вернет ошибку
"RST0021E" — Имя метода класса генератора SQL запроса не определено.
lair
Очень. Удобно.
(Я даже не буду спрашивать, почему это REST)
vl65 Автор
Совершенно верно, именно удобно. В других реализациях вам прилетит 500 ошибка и куча HTML "мусора", когда Вы ожидаете JSON или XML.
lair
Не знаю, я не пользуюсь такими реализациями. Обычно прилетает 404.
vl65 Автор
Хорошо, прилетит 404 ошибка, но она все равно будет содержать кучу HTML "мусора". И чтобы добраться до "причины" Вам нужно "ковырять" этот "мусор".
Этот сервис вернет 404 ошибку и причину ошибки в том формате, который вы ожидаете.
lair
Да нет, не будет. Будет там обычный content negotiation.
Неа. Он вернет ее в том content-type, который я запросил (если он его умеет), и в том формате, который он поддерживает.
vl65 Автор
Ваши реализации сервисов то же не все форматы поддерживают. Да и поддерживать все, какой вздумается, в принципе невозможно.
lair
Поэтому полезно разделять "вернем ошибку в ожидаемом формате" и "вернем ошибку в поддерживаемом формате".
vl65 Автор
В данном случае, формулировка не существенна — HTML "мусор" точно не ожидается.
lair
Ну, я как бы уже сказал — вы его в нормальной реализации и не получите, ничего уникального в конкретно вашей с этой точки зрения нет.
mikaakim
А почему прилетит куча HTML мусора? Мне непонятно
vl65 Автор
Потому что запрошенный URL, если он был удален в вашем сервисе, не будет связан вообще ни с одним вашим ресурсом REST. Этот запрос обработает WEB сервер, который и возвратит этот "мусор". Хорошо, если в него ("мусор") будет включена хоть какая то полезная для Вас информация. А если Вы не сможете найти там внятной информации? А если этот "мусор" без внятной информации получит пользователь, что он должен сообщить в техподдержку — " У меня тут ошибка какая то"?
lair
С чего бы это?
vl65 Автор
Что гадать то, проведите эксперимент.
lair
Чего эксперимент-то проводить, я постоянно с этим работаю.
А все потому, что "сервис" висит на "корневом" ресурсе, и поэтому все запросы все равно проходят через него, хостящий веб-сервер про внутреннюю структуру и не знает ничего.
vl65 Автор
И что говорит вам это "информативное" сообщение? Не найдено что, ресурс, запись или что то еще? А что скажет это "информативное" сообщение техподдержке, если пользователь передаст ей это сообщение? А если оно прилит Вам от техподдержки — какие выводы Вы по нему сделаете?
lair
Ровно то, что положено.
Ресурс, конечно. Это же REST.
Речь шла о том, что сервис вернет HTML-мусор. Как видите, не вернет, даже в ответ на мусорный URL.
Если послать запрос на не-случайный URL, ошибка будет тоже менее генеричной:
Это, в общем-то, совершенно тривиальные вещи, удивительно, что их вообще озвучивать надо.
vl65 Автор
Это для Вас они тривиальные, а для техподдержки и пользователей — это ничто! Ну скажут они Вам код 404. Далее что будете делать? Где в вашей системе будете искать ошибку по этому информативному коду?
lair
А при чем тут техподдержка и пользователи? Я сейчас говорю о том, что для разработчика тривиально.
А что будете делать вы, когда вам скажут код 400?
Сообщение об ошибке достаточно информативно само по себе, вообще-то, в нем явно сказано, что не найдена модель, и какая конкретно модель, а что это такое — пользователь сервиса знает сам.
Когда нужно что-то большее, просто подкалываем все соответствующие логи под идентификатор запроса и говорим "пользователю", где этот идентификатор искать.
vl65 Автор
Должно быть ясно всем. И в первую очередь обслуживающему персоналу, которые получат эту информацию от службы поддержки, которой в свою очередь правильно объяснит пользователь причину проблемы.
Через 10 лет Вы вспомните что за "model azure-01" такое и где это вообще?
lair
Нет, не должно быть. С чего бы?
Без контекста? Нет. Посмотрев на запрос и описание API — да.
Вообще, удивительно, конечно. Вы считаете, что ваше сообщение ""RST0021E" — Имя метода класса генератора SQL запроса не определено" чем-то понятнее? Так нет, не понятнее, по крайней мере, со стороны (это, кстати, привет "должно быть ясно всем"). Лично вам понятнее? Ну так это тоже понятно, вы разработчик.
vl65 Автор
Ответственность за работоспособность информационной системы лежит не на программисте (не на Вас), а на персонале эксплуатирующей организации. И им в первую очередь должно быть понятно как быстро справляться с той или иной проблемой, возникающей в процессе эксплуатации.
Правилом хорошей реализации, считаю наличие документации с описанием кода ошибки, причины (которые, могут приводить к возникновению ошибки с этим кодом) и действий пользователя (обслуживающего персонала), которые устранят эту ошибку. Например, как у IBM
lair
Ну им и будет понятно.
А я считаю правилом хорошего тона наличие документации, из которой понятно, что и как делать. Код ошибки, хотя и полезен, не обязателен.
vl65 Автор
У смены в зоне ответственности может находиться в эксплуатации сотни различных систем. Вы думаете сменный персонал способен понять что означает код 404 в вашей системе?
Вы никогда не сдавали серьезных промышленных систем в эксплуатацию? Вас ни когда не будили ночью или за столом с друзьями для консультации из-за какого ЧП в информационной системе, когда лично Вы заинтересованы дать короткую и ясную консультацию не имея ничего "перед глазами", чтобы вам повторно не перезванивали? На Вас ведь бизнес может повесить ответственность за простой системы, которая может повлечь и финансовые возмещения убытков.
lair
Вот для этого у них есть документация.
Сдавал.
А вы, я так понимаю, коды ошибок наизусть помните? Я — нет, и не собираюсь их учить. А сообщение "model not found" мне по крайней мере понятно.
Не может.
vl65 Автор
И что Вы напишите в этой документации про код 404? Сотню различных вариантов или несколько сотен, а может тысяч? Как сменный персонал, будет ориентироваться в вашей документации без дополнительной информации о причине ошибке?
Очень сильно сомневаюсь, если и сдавали, то "прятались" за спины более опытных коллег.
Коды не нужно знать наизусть. Они повышают информативность сообщения об ошибке и значительно ускоряют поиск проблемы и ее устранение. И позволяют ориентироваться Вам в возможных причинах при консультации по телефону. Пользователь, техподдержка и эксплуатирующий персонал должны разговаривать "на одном языке" — специализированный код ошибки это и позволяет делать.
Может, вас похоже не подпускали еще к серьезным системам.
lair
"See documentation for the appropriate request URL". 404 — она не в воздухе возникает, она в ответ на что-то.
Так дополнительная информация есть, она в
message
написана.Каким образом, если я их не знаю наизусть? Сообщение "model not found" намного лучше позволяет ориентироваться при консультации по телефону, чем "Error EMQP0114X".
vl65 Автор
Напомню 404 — это HTTP код, который сигнализирует, что что то не найдено. В информационных системах с множеством объектов этот код не дает Вам какой либо ясности, что же не найдено. Ваше сообщение для подавляющим большинством пользователей воспринимается как "абракадабра". Хорошим, подчеркиваю хорошим, "тоном" программирования является присвоение в системе каждой ошибке в вашей системе уникального кода. Это значительно повышает информативность возвращаемого сообщения и позволяет всем участникам процесса говорить на одном языке вне зависимости от их квалификации. А Вам позволяет достаточно быстро понять причину проблему.
lair
Вот именно поэтому есть контекст, выраженный запросом, и сообщение об ошибке.
А откуда вы что-то знаете о пользователях моей системы?
Этот код не воспринимается пользователями как абракадабра? А почему?
Каким образом код EMQP0114X позволяет мне быстрее понять причину проблемы, чем сообщение "model X not found"?
vl65 Автор
Вы вольны реализовывать 404 как Вам угодно.
Я исхожу из того, что увидит пользователь при ошибке, что он скажет техподдержке, как это сказанное сообщение об ошибке трансформируется и дойдет до разработчика системы. Код ошибки при передаче по этой цепочке не искажается, а любые фразы, да еще содержащие "абракадабру" могут дойти до Вас в неузнаваемом виде.
lair
Почему?
Copy-paste никто не отменял. Все — подчеркиваю, все — запросы на поддержку, которые ко мне пришли за последние лет пять, были в виде текста или скриншота. Ни разу он не был в виде звонка.
vl65 Автор
Пользователь выберет тот способ обращения в техподдержку, который ему удобен и сообщит то, что он поймет глядя на ваше сообщение.
lair
Прекрасно, пусть выбирает: емейл, чат (выводится из обслуживания в этом году) и форма в специализированной системе.
vl65 Автор
Еще раз, пользователь выберет то, что посчитает нужным. Опишет/расскажет то, что он поймет в вашем сообщении.
lair
Вы обратили внимание, что у него нет возможности пообщаться голосом? Никакой? Только текст?
А, ну, здесь мы на равных.
В моем опыте бывает преимущественно два варианта: говорят "была ошибка", не давая никакой информации, либо просто копируют все сообщение об ошибке.
vl65 Автор
"Говорят"? У вас же нет "голоса" :-)
С вами пользователь не может пообщаться голосом, служба техподдержки предоставляет ему такую возможность. Вы не путаете две разные службы — вашу и заказчика. У всех крупных заказчиков есть внутренняя служба техподдержки, которая ретранслирует Вам то, что она поняла из обращения своего пользователя, часто исказив полученную информацию.
lair
Не путаю. Мне все равно, как служба техподдержки заказчика общается с пользователями, мне важно, что к нам приходит.
Вот чтобы искажений не было, и надо копировать сообщение об ошибке полностью. Как ни странно, люди достаточно быстро этому учатся.
vl65 Автор
Вы получите ровно то, что техподдежка заказчика поняла из "описания" проблемы пользователя. При этом, учитывая несколько линий эта информация искажается внутри службы поддержки вашей и заказчика — уникальный код ошибки исказить очень трудно. Ваш код 404 в этой системе будет гарантированно искажен.
lair
Говорю же: копировать сообщение об ошибке целиком. Не надо ничего "понимать". Надо копировать сообщение об ошибке. Если система user-facing, там прямо кнопочка есть "send error report".
Да нет, легко.
Гм. Нет, не будет.
vl65 Автор
Говорю же, что пользователь сказал по телефону службе поддержки и как это сказанное поняла служба поддержки — то вы и получите. Другому просто неоткуда взяться.
Вы думаете что в службе поддержки сидят сплошные специалисты по вашей системе и могут "ее разбирать и собирать с закрытыми глазами за 45 сек"?
Гарантировано будет. Для подавляющего числа IT специалистов код 404 означает — ресурс не найден. Так они Вам это и передадут.
lair
Есть такая штука как "условия оказания технической поддержки".
Нет, не думаю. Им и не надо.
Докажите.
Обратите внимание, что код не искажен. Искажено сообщение об ошибке.
Что я могу сказать, эти "IT-специалисты" сами виноваты — получат свой запрос обратно со словами "предоставьте полный текст сообщения об ошибке".
lair
А, я понял, это было про "бизнес может повесить". Так вот, бизнес "может повесить" ровно то, что в контракте написано, и никак не больше. И что-то мне кажется, что для "серьезных систем" персональная финансовая ответственность в контракте — это несколько глупо, потому что там суммы убытков такие, что любой отдельный разработчик их возместить не может. Намного осмысленнее ставить в качестве ответственного юридическое лицо-подрядчик — у него и капитал поболе, и репутационные риски есть.
vl65 Автор
Для серьезных систем бизнес Вам указывает время вашей реакции на проблемы в вашей системе, далее идут штрафные санкции. Терпеть убытки, когда вы на пляже загораете, бизнес не намерен.
lair
Мне как разработчику или архитектору лично? Нет, не указывает.
А это его проблемы, если вкратце.
Чтобы не терпеть убытки, когда я загораю на пляже, намного полезнее не зависеть от меня как от единственного человека, способного решить проблемы. А то разные случаи бывают.
vl65 Автор
Которые станут вашими при потере заказчика
lair
Если "заказчик" не дает мне возможности полететь на самолете Москва-Токио, честное слово, не нужен мне такой заказчик.
Повторюсь, с точки зрения работоспособности системы намного выгоднее иметь больше одного человека, способного ее (систему) починить, чем накладывать любые штрафные санкции на единственного способного ее починить человека. Еще и потому, что когда он скажет "достали меня ваши санкции, ухожу я", сделать будет нельзя ничего.
vl65 Автор
В любом ПО, даже в котором нет ни одной ошибки, в процессе эксплуатации возникают проблемы, с которые может устранить только разработчик.
lair
Компания-разработчик. Потому что если эксплуатация ПО завязана на одного человека, то это очень плохо для стабильности эксплуатации (хотя может быть и хорошо, в финансовом плане, для этого человека).
vl65 Автор
Дело не в одном человеке и ни в компании разработчике.
Это же элементарно!
В процессе эксплуатации системы условия эксплуатации постоянно меняются. Появляются новые смежные системы, меняется компоновка технических средств, меняется техпроцесс (оператора заменили на смежную систему например), меняются версии используемого ПО и многое другое. Это может порождает проблемы в эксплуатации, которые могут и не сразу проявиться.
lair
Если дело не в одном человеке, то этот человек может прекрасно отдыхать на пляже. О чем и шла речь.
Это элементарно, если не терять нить дискуссии.
… сразу в проде, я стесняюсь спросить?
И почему это должно мешать моему отпуску?
vl65 Автор
Сразу в проде. Ни одна система тестирования не даст Вам 100% результат. (В одной точке вселенной можно собрать всю информацию о всей вселенной, только на это потребуется гораздо больше времени чем существование самой вселенной.)
Потому что у заказчика "пожар"
lair
Ну вот поэтому у вас и "пожар" на "серьезной системе".
И что? Его пожар стоит того, чтобы послать за мной курьера?
Повторюсь, чтобы не надо было тушить "пожары" из отпуска, достаточно завести сменщика, который будет этим заниматься в мое отсутствие по штатному процессу.
Это же элементарно!
vl65 Автор
Пожар стоит того, чтобы получить у Вас консультацию.
lair
Я так не думаю.
vl65 Автор
И курьера слать не обязательно, достаточно позвонить вам "на пляж"
lair
Так там покрытия нет. Никакого.
vl65 Автор
Значит будут звонить вашему сменщику. Будут звонить всем, кто способен дать консультацию.
lair
Прекрасно! Это ровно то, что мне и надо — мой отпуск в безопасности.
vl65 Автор
Если только на Эверест заберетесь или на белого медведя отправитесь в естественных условиях посмотреть.
lair
Да нет, есть намного более простые ситуации. Начиная с перелета Амстердам-Сиэттл (десять часов, если мне память не изменяет).
vl65 Автор
у сменщика выходной, он на "своем пляже", не доступен, телефон сел, вдрызг день рожденье на отмечался :-)
lair
Если он обязан быть на работе в это время — это его проблемы. Не мои.
vl65 Автор
Ваш сменщик не работает круглосуточно, как и Вы. И "пожары" не догадываются о существовании режима труда и отдыха
lair
Нужна круглосуточная поддержка? Заводится столько сменщиков, сколько надо, чтобы ее обеспечить.
vl65 Автор
Так они Вам и будут звонить.
lair
См. выше: я недоступен.
Собственно, какой смысл в сменщиках, если они не могут решить проблему без моего участия?