image

Сайт The Daily WTF уже 15 лет собирает курьёзные, дикие и/или печальные истории из мира ИТ. Я перевёл несколько рассказов, показавшихся мне интересными. Все имена и названия компаний изменены. Предыдущие выпуски можно найти по метке "любопытные извращения".

История первая. Конец света месяца


[Оригинал]

Если спросить инженера-разработчика, безопасно ли ходить по мосту, то он с удовольствием расскажет вам, насколько надёжны мосты, как в них работает математика, как далеко мы продвинулись в вопросах строительной безопасности. После разговора с ним у вас создастся впечатление, что ни один мост на Земле ни за что не развалится. Но если спросить у инженера-разработчика ПО о банках, то вы скорее всего будете в ужасе, и с вероятностью 50/50 убедите себя вложить все деньги в биткоин. Банки печально известны своими плохими решениями при создании ПО — не потому, что эти решения отвратительны, а потому, что большинство людей предполагает, что банки более аккуратны и внимательны к безопасности.

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

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

Като показал новому консультанту, как в банке настраиваются отчёты конца дня. «Видите, у нас есть глобальные переменные для предыдущего рабочего дня, для сегодняшнего дня, и для следующего рабочего дня. Они имеют формат YYMMDD, чтобы с ними было проще работать».

«Ага, ага, понял. Понял. А в каком они формате?»

"… Э-э-э… могу только предположить, что это год, месяц и день".

«Ага, ага, ладно. Отлично. Тогда я приступаю к работе».

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

TH.DATE = R.DATES(EB.DAT.NEXT.WORKING.DAY)[1,6]:"01"
CALL CDT('ES00',TH.DATE,"-1C")
WTODAY = OCONV(DATE(),"DY") : FMT(OCONV(DATE(),"DM"),'R%2') : FMT(OCONV(DATE(),"DD"),'R%2')
IF TH.DATE EQ WTODAY THEN

Объясним вкратце, что здесь происходит:

  1. Берём следующий рабочий день и изменяем день на 01, чтобы получить первый день месяца.
  2. Меняем эту дату, вычитая 1 календарный день по календарю Испании.
  3. Берём дату с сервера и переводим её в формат YYYYMMDD, трижды вызывая команду Date.
  4. Если дата, вычисленная на этапе 2, равна дате, вычисленной на этапе 3, запускаем процесс.

Ну, вообще это… работает. По большей части. Если только по какой-то причине завершение дня не произойдёт после полуночи предпоследнего дня месяца — а это бывает не так редко. В таком случае код будет ошибочно думать, что это последний день месяца, и запустит создание отчёта. Что хорошо сочетается с ещё одной проблемой: если то же самое произойдёт в последний день месяца, то создание отчёта ошибочно не будет запущено. И самый лучший баг: если последний день месяца оказался воскресеньем, то календарь сервера никогда не будет устанавливаться на него, потому что он пропускает нерабочие дни.

Кстати о нерабочих днях: так как Inibank находится в США, нет никакой причины использовать календарь Испании. Да, месяца и недели будут такими же, но в испанском календаре ПО нужно указать банковские выходные в США, иначе программа будет продолжать работу. Наконец, как будто всего этого ещё не было достаточно, тройной вызов Date означает, что могут возникнуть разногласия при запуске ровно в полночь: значение месяца запрашивается перед полуночью, а день после неё.

Като добавил комментарий, предложив способ изменения кода:

IF R.DATES(EB.DAT.TODAY)[5,2] # R.DATES(EB.DAT.LAST.WORKING.DAY)[5,2] THEN

Пять минут спустя консультант подошёл к его столу. «Что означает эта правка?»

У Като в этот момент не было настроения спорить. «Твой код поломан, друг. Всё это не нужно».

«Понятно, понятно. Вообще-то это просто стандартная рабочая процедура для нашей отрасли. Ну да ладно».

Като сильно в этом сомневался, но просто пожал плечами. «Тогда отрасль ошибается. Я всё объяснил в комментарии».

«Ага. Да, я прочитал его. Но я прочитаю ещё раз». И он пропал столь же внезапно, как и появился.

Правки были внесены, Като одобрил код и консультант растворился в тумане.

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

Но не стоит вкладывать все деньги в биткоин. Там всё ещё хуже.

История вторая. Как это сделано


[Оригинал]

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

Бретт работал системным аналитиком в медицинском исследовательском центре MedStitute. Для хранения и анализа данных MedStitute использовал проприетарное ПО под названием MedTech. Врачам и исследователям нравились результаты MedTech, но коллега Бретта Тайри знал, как они создавались.

У ПО не было доступа к бэкенду, и весь процесс разработки происходил в «программируемом мышью» GUI. Этот интерфейс выглядел так, как будто был написан человеком, изучавшим программирование копипастингом веб-сайтов эпохи 90-х, посмотревшим десять минут «Парка юрского периода» и искавшего ответы на StackOverflow, пока что-нибудь не удавалось скомпилировать. «Язык программирования» тоже демонстрировал аналогичный уровень продуманности философии дизайна. У каждого if обязательно должен был быть else. В некоторых модулях использовались булевы значения, другие для обозначения значений false возвращали пустые строки. Из документации было непонятно, в какой ситуации случалось одно или другое. По сути, каждый оператор if превращался в три оператора.

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

Бретт знал, что Тайри работал над другим проектом, который рандомизировался по вычисляемому полю, поэтому связался с ним в Slack. «Как ты закодировал эту случайную переменную? Medtech ведь этого не позволяет сделать?»

«Я говорю по конференц-связи, перезвоню позже», — написал Тайри.

Несколько минут спустя Тайри позвонил Бретту.

«Тебе нужно начать с двух полей. Допустим. назовём их $variable_choice, то есть вопрос с множественным выбором, и $variable_calced, то есть твоё вычисляемое поле. Когда ты хочешь создать переменную, которая выполняет случайный выбор на основании вычисляемого поля, ты сообщаешь Medtech, что эта случайная переменная основана на $variable_choice. Затем ты удаляешь $variable_choice, и переименовываешь $variable_calced в $variable_choice»

«Стоп, система позволяет сделать это, но не разрешает рандомизировать вычисленные поля каким-то другим способом? И она этого не проверяет?»

«Надеюсь, ничего не изменится, и она не начнёт проверять этого до завершения моего проекта», — ответил Тайри.

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

«Мне удалось найти только такое решение. Дай знать, если найдёшь что-то получше».

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

В конце концов, единственное, что оставалось Бретту — сделать перерыв, пойти в кафетерий и купить пару хот-догов.

История третья. Портативность и крепёж


[Оригинал]


Много лун назад, когда PC имели тяжёлые корпуса из металла и пластика, Мэтту и его коллеге поручили оценить пакет ПО для грядущей операции отдела продаж. К сожалению, они с коллегой работали в разных офисах в пределах одного города. В ту эпоху ещё не существовало эффективных онлайн-инструментов для совместной работы, поэтому Мэтту регулярно приходилось ездить в другой офис, беря с собой PC. Это означало, что каждый раз нужно было отключать от корпуса 473 кабеля периферии, нести компьютер по коридорам и вниз по лестницам, ловить автобус, чтобы добраться до другого офиса, в котором он проделывал всё это в обратном порядке. Иногда неправильная организация труда заставляла эту пару работать по выходным, а значит, носить рабочие машины домой.

В процессе работы жёсткий диск на 20 МБ в компьютере Мэтта переполнился. Из своего офиса он отправил заявку в отдел ИТ. Для выполнения заявки назначили техника Гари, который спустя какое-то время появился в кубикле Мэтта, держа в руках новый жёсткий диск и отвёртку. Гари отправил Мэтта за кофе, чтобы сосредоточиться на своём «пациенте». После небольшого хирургического вмешательства PC Мэтта включился и заработал с большим жёстким диском.

За день до дедлайна проекта Мэтт почти завершил свою долю работы. Ему оставалось внести всего несколько дополнений в свой отчёт, а потом скопировать его на гибкие диски и отправить в отдел продаж. Вернув свой PC в кубикл и подсоединив провода, он включил питание и услышал хлопок. PC был мёртв и не подавал признаков жизни.

После панического звонка в отдел ИТ, в его кабинете снова появился Гари с отвёрткой. Вскрыв корпус PC, он сразу же завопил: «Постойте-ка! Вы что, куда-то таскали компьютер?»

Мэтт нахмурился. «Ну да. А что, в этом дело?»

«Да уж конечно! Вы не должны были этого делать!», — начал ругаться Гари. «Жёсткий диск начал болтаться и закоротил всё внутри!»

Мэтт наклонился над Гари, чтобы самому увидеть внутренности компьютера. Он сразу заметил, что новый жёсткий диск был «закреплён» на скотч.

«Стоп! Это вы не должны были этого делать!» Мэтт показал на кусок скотча. «Мне что, на всякий случай стоит обратиться к вашему руководителю?»

Лицо Гари сморщилось. «Мне не дают нужные крепления!»

«Тогда найдите того, у кого они есть!»

Учитывая надвигающийся дедлайн, с разрешения начальника Мэтт передал свою заявку ещё выше. Почти сразу же клейкую ленту заменили на настоящий крепёж. Он так никогда и не понял, почему у сотрудников отдела ИТ не было доступа к необходимому оборудованию; он предположил, что это была блестящая идея какого-то идиота для экономии средств. Мэтт мог только догадываться, какие ещё отчаянные импровизации позволяли обеспечивать работоспособность их ИТ-инфраструктуры, и как долго бы они оставались незамеченными, если бы не сломался его PC.

История четвёртая. Вот как на твой мозг влияет PL/SQL


[Оригинал]

Вечным чемпионом среди самых странных и неудачных решений навсегда будет оставаться Oracle. Сегодня мы рассмотрим небольшой код на PL/SQL.

PL/SQL — это странный язык, смесь SQL и Procedural (процедурного) Language (языка) с приклееной сбоку объектно-ориентированностью. Синтаксису превосходно удаётся создать впечатление, что он был разработан в 1970-х, и каждая новая функция или изменение языка продолжают эту традицию.

Структура каждого модуля кода на PL/SQL строится на основе блоков. Каждый блок представляет собой самостоятельное пространство имён. Вкратце его анатомия выглядит так:

DECLARE
  -- variable declarations go here
BEGIN
  -- code goes here
EXCEPTIONS
  -- exception handling code goes here, using WHEN clauses
END;

Если вы пишете хранимую процедуру или обработчик событий, то заменяете ключевое слово DECLARE на CREATE [OR REPLACE]. Также можно вкладывать блоки внутрь других блоков, поэтому довольно часто можно увидеть код, структурированный таким образом:

BEGIN
  DECLARE
    --stuff
  BEGIN
    --actions
  END;
  --more actions
END;

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

Язык и база данных имеют и другие забавные особенности. До версии 12c у них не было типа столбца IDENTITY. В предыдущих версиях необходимо было использовать объект SEQUENCE и писать процедуры или обработчики событий, выполняющих принудительное автоматическое нумерование. Обычно для присваивания значения переменной использовался оператор SELECT INTO…. Бонус: Oracle SQL всегда требует указания таблицы в операторе FROM, поэтому необходимо использовать придуманную таблицу dual, например так:

CREATE TRIGGER "SOME_TABLE_AUTONUMBER"
BEFORE INSERT ON "SOME_TABLE"
FOR EACH ROW
BEGIN
  SELECT myseq.nextval INTO :new.id FROM dual;
END;

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

CREATE OR REPLACE TRIGGER "SCHEMA1"."TABLE1_TRIGGER"
  BEFORE INSERT ON "SCHEMA1"."TABLE1"
  FOR EACH ROW
BEGIN
  DECLARE
    pl_error_id table1.error_id%TYPE;
    CURSOR get_seq IS
	SELECT table1_seq.nextval
	FROM   dual;
  BEGIN
    OPEN get_seq;
    FETCH get_seq
	INTO pl_error_id;
    IF get_seq%NOTFOUND
    THEN
	raise_application_error(-20001, 'Sequence TABLE1_SEQ does not exist');
	CLOSE get_seq;
    END IF;
    CLOSE get_seq;
    :new.error_id := pl_error_id;
  END;
END table1_trigger;

Тут происходит очень многое. Для начала заметьте, что в разделе DECLARE содержится оператор CURSOR. Курсоры позволяют итеративно переходить между записями. Они очень затратны и в мире Oracle это ресурс, который нужно освобождать.

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

Но по-настоящему странная часть заключается в блоке IF get_seq%NOTFOUND. Всё довольно просто: он проверяет условие, что курсор не вернул строку. Такого для этого курсора не может случиться даже теоретически, поэтому операции внутри никогда не выполняются. Последовательность всегда возвращает значение. И это хорошо, учитывая тот код, который идёт дальше.

raise_application_error — это аналог «throw» в Oracle. Этот оператор поднимается по стеку из выполняемых блоков, пока не находит раздел EXCEPTIONS для обработки ошибки. Заметьте, что мы закрываем курсор после этого оператора — то есть, на самом деле мы никогда не закрываем курсор. Курсоры, как сказано выше, затратны, и Oracle позволяет использовать только ограниченное их количество.

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

История пятая. Логины с двойным шифрованием


[Оригинал]

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

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

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

crypt = new JSEncrypt();
crypt.setPublicKey('<removed>');
challenge = "<removed>";
function doChallengeResponse()
{
document.loginForm.password.value.replace(/&/g, '%26');
document.loginForm.password.value.replace(/\\+/g, '%2B');
document.loginForm.password.value = crypt.encrypt(document.loginForm.password.value);
document.loginForm.response.value = document.loginForm.password.value;
document.loginForm.password.value = '';
document.loginForm.submit();
}

С одной стороны, я могу предположить, что этот код очень стар, учитывая document.loginForm, используемый для взаимодействиями с DOM-элементами. С другой стороны, JSEncrypt был впервые выпущен в 2013 году, что даёт нам максимальную планку возраста.

Мы передаём параметры доступа бэкенду с помощью отправки формы, которая, по мнению разработчика кода требовала очистки — все & и + в пароле заменяются, но… это необязательно, потому что форма должна выполнять запрос POST и, кроме того, мы зашифровали данные.

Вот что я думаю. Код и в самом деле довольно стар. Разработчик скопировал его из поста на StackOverflow примерно за 2005 год, в котором не использовалось шифрование и отправка формы через POST. Год за годом в него добавлялись небольшие изменения. но базовый механизм никогда не менялся.

Амира проверила историю, и обнаружила, что в предыдущей версии шифрование не использовалось. Код конкатенировал пароль с переменной challenge, оба они хешировались MD5, после чего он передавал это в сеть, и всё как бы работало, если слишком сильно над этим не задумываться.

Была и хорошая сторона дела: когда Амира разобралась, как получать нужные ей куки, срок жизни этого токена на сервере никогда не истекал, поэтому она могла хранить его, отправлять запросы через cURL и больше не связываться с веб-формой. Ей не нужно было беспокоиться о компрометировании куки при передаче, потому что приложение использует и всегда использовало SSL/TLS.

Комментарии (26)


  1. DrunkBear
    05.04.2019 10:50

    Простите, к 3 истории нет ссылки на оригинал, но… Действительно «отключать от корпуса 473 кабеля»?! Зачем и как?!


    1. PatientZero Автор
      05.04.2019 10:58

      Добавил оригинал.


      1. DrunkBear
        05.04.2019 11:10
        +1

        Спасибо, но теперь я хочу это видеть — компьютер с 473 портами на задней стенке, который 1 человек в состоянии транспортировать


        1. PatientZero Автор
          05.04.2019 11:32

          Думаю, это преувеличение, что-то типа «100500».


  1. Lezenford
    05.04.2019 14:05

    Oracle! Подписываюсь под каждым словом! После перехода с других СУБД выглядит как нечто с другой планеты…


    1. abmanimenja
      05.04.2019 20:35

      После перехода с других СУБД выглядит как нечто с другой планеты…

      Например?
      В каких массовых СУБД встроен совершенный язык программирования?


      1. 255
        05.04.2019 22:10
        -3

        А зачем в СУБД встраивать язык программирования, чтобы увеличить последствия SQL-инъекции?

        Самое худшее зло — это когда ради свистелок и перделок в одну логическую часть системы встраивают функции другой.


        1. fivehouse
          05.04.2019 22:26
          +2

          А зачем в СУБД встраивать язык программирования, чтобы увеличить последствия SQL-инъекции?
          Вы что нибудь знаете про уровни изоляции в БД и зачем это надо? Про сохранение этих уровней в вызываемых в SQLях функциях? Про сохранение целостности данных? Про управление блокировками и про их виды и назначения? Про многочисленнейшие способы ускорения вычислений и операции с данными в БД? Про параллельные вычисления в БД и параллельный доступ к данным в пределах одного SQLя? Так вот все это в полном объеме возможно только когда код хранится в БД, и БД его понимает со своей точки зрения.
          Самое худшее зло — это когда ради свистелок и перделок в одну логическую часть системы встраивают функции другой.
          А это проблема отсутствия архитектора системы. И при чем тут код в БД?


          1. 255
            06.04.2019 06:58

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


        1. abmanimenja
          06.04.2019 09:11

          А зачем в СУБД встраивать язык программирования

          Когда код, обрабатывающий данные, делает это рядом с данными — это намного быстрее.


  1. Naves
    05.04.2019 19:31
    +1

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

    Из последних примеров
    image


    1. dhaenoor
      06.04.2019 10:41

      А ведь офигенная идея!


      1. staticmain
        06.04.2019 12:29

        Боюсь, что розетка с вами не согласится.


      1. chaynick
        07.04.2019 01:21

        розетка обычно рассчитана на 16 ампер. там 6 выходов. Итого — не более 586 ватт на выход или в лучшем питание отрубит автомат а в худшем — рано или поздно сгорит.


        1. mayorovp
          08.04.2019 07:00

          А этих 586 ватт что, недостаточно?


          1. abmanimenja
            08.04.2019 07:52

            А этих 586 ватт что, недостаточно?

            Смотря что включать.
            Типичный чайник от 1500 до 2200 ватт.

            Принтер лазерный 1000-3000 ватт.


            1. mayorovp
              08.04.2019 08:32

              Всё то же самое, что обычно подключают в одну розетку через сетевой фильтр с кучей розеток


  1. fivehouse
    05.04.2019 20:03
    +1

    Здесь мы видим странный пример того, как разработчик пытается защититься от ошибки, которая не может произойти, таким образом, которая со временем приведёт к новым ошибкам.
    Вечным чемпионом среди самых странных и неудачных решений навсегда будет оставаться Oracle. Сегодня мы рассмотрим небольшой код на PL/SQL.
    Код высосан из пальца для оправдания неумного вывода. На любом языке можно написать столько глупого и неправильно кода, и после этого автор будет объявлять этот любой язык программирования
    чемпионом среди самых странных и неудачных решений.
    Автор надеется, что никто не поймет его ошибок?


  1. rexen
    05.04.2019 21:07
    +2

    Блин, ну как в суровом энтерпрайзе, ворочающем сотнями нефти может жить ЭТО? Причём, долгие годы…


    1. AndyKorg
      06.04.2019 07:43

      Легко! Есть системы в которых ошибки показываются один раз, если после этого будет еще ошибка, то система никак не известит пользователя. Лицензия на одно рабочее место такой системы стоит от 50 000 р. на год. А вы говорите… :)


    1. abmanimenja
      06.04.2019 09:17
      +1

      Блин, ну как в суровом энтерпрайзе, ворочающем сотнями нефти может жить ЭТО? Причём, долгие годы…

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


  1. staticmain
    06.04.2019 09:21

    Ооооо, банки это самая мякотка того, с чем приходилось работать. С ходу:
    Сбербанк: решения под Linux и Windows писали разные, никак не связанные между собой команды. Поэтому под windows есть библиотека и утилита (для тех, кто не может подцепить С++-библиотеку), но утилита сломана, потому что не создает файл ответа. Под Linux есть утилита, но нет библиотеки. В документации написано, что параметр 0 создает краткий отчет, 1 — полный. Под Linux это действительно так. Под Windows наоборот, 0 — полный.

    ВТБ: Только утилита под обе ОС, но с маааленьким нюансом: нет способа получить RRN выполненной транзакции. Подать его на вход например для операции отмены можно, а вот получить его после оплаты — разве что попытаться парсить слип-чек, формат которого меняется от версии к версии и от закона к закону. Так что если пользователь потерял slip или его ему не выдали — все, гуляй, номера нет, как я тебе деньги верну?

    Альфа-банк: Это вообще полный треш и угар. Сама либа — купленное у кого-то иностранного решение, с попыткой его русифицировать (почему попыткой? Потому что вместо нормального описания ошибок оно возвращает «Произошла Ошибкаquires from cashdesk», причем «Произошла ошибка» — это ответ на все что угодно, понять что там произошло можно только по куску оригинальной, находящейся за пределами выходного буфера.) То, что работа происходит через буфер (два буфера in\out), который подает пользователь БЕЗ малейшего контроля размера — это отдельная песня. Т.е. по документации надо подавать не менее 256 байт, я на всякий случай выделяю пару кило, чтобы оно не навернулось если у них говнокод. О том, что между двумя соседними операциями должно быть не менее 5-10 секунд (больше- лучше) вообще наверное не стоит говорить. Оно валится без симптомов если не соблюдайть такие конские тайминги. По докам между каждой *строкой* чека может пройти до 10 секунд.

    Выдохнул. У меня есть статья в корпоративной сети про то как я ночью сражался с подключением модифицированной библиотеки Сбербанк для Cryptera, если кому-то интересно — могу выяснить, насколько я могу ее цензурить и выкладывать.


    1. AcckiyGerman
      06.04.2019 14:32

      А новые банки, когда они создаются, обязаны использовать такие "проверенные временем системы ПО" или же такой бардак продолжается по инерции инженеров/руководства?


      1. staticmain
        06.04.2019 14:38

        Не знаю, но насколько слышал — чаще всего подключаются к существующим с минимальными модификациями. Так, например, альфа использует за основу библиотеку от united card services, которые часть global payment inc., которая базируется в Америке и к которой подключено много американских банков.


        1. DMGarikk
          07.04.2019 08:53

          UCS, несмотря на то что принадрежит GP inc, использовала до недавнего времени по большей части свой собственный самописный софт и связана с головной компанией только юридически
          ==
          в вообще насколько я видел процессингов, могу сказать что почти никто не использует одно универсальное решение, везде те или иные костыли (размер и замудренность которых зависит от размера ИТ отдела) вокруг нескольких больших продуктов типа популярного в рф way4


      1. abmanimenja
        06.04.2019 16:26

        А новые банки, когда они создаются, обязаны использовать такие «проверенные временем системы ПО» или же такой бардак продолжается по инерции инженеров/руководства?

        Исходя из опыта работы с новые предприятиями в других сферах:

        Разрабатывается с нуля только под уникальные особенности бизнеса ПО.
        А прочее используется уже существующее — никто не жаждет оплачивать разработку всего 100% ПО с нуля. Даже если ПО плохое.

        Кстати, то, что вы как разработчик видете, что ПО плохое — вовсе не означает, что вы можете создать лучшее в разумные сроки.

        Неоднократно наблюдал, как новые версии ПО, хотя технологически и были круче, но в них не было полного функционала — кучи тех фич, что в старом ПО дополнялись и дополнялись годами. И даже не по причине нехватки времени на разработку. Об этих фичах просто забывали. Вспоминал о них только когда начиналась эксплуатация нового ПО и выяснялось как многого в новой системе нет.

        Ну а банки, с учетом того, что им нужно взаимодействовать/интегрироваться с другими банками и отчитываться Центробанку — тем более вынуждены.