Pull to refresh
22
1.6
Виктор Поморцев @SpiderEkb

Консультант направления по разработке

Send message

См выше. Кто использует эту систему из "крупняка". Там и гугл и амазон есть...

Поверьте, написать что-то работающее с БД и считающее деньги на RPG под ACку намного проще чем под какой-нибудь посгтрес на шарпе или расте под линуксом.

И работать оно будет быстрее на сравнимом железе.

Компиляции на каком из стендов? То есть я скомпилировал продакшен версию сборки, она с каким из стендов должна компилироваться?

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

Есть Prepared Statement есть Stored Functions.

Тут все проще. Непосредственно в RPG (для COBOL примерно также) пишем

        exec sql declare curProcNames cursor for
                   select NMC.NMCCUS,
                          NMC.NMCCLC,
                          GF.GFCRF,
                          NMC.NMCTP
                     from NMCPF NMC

                     join GFPF GF
                       on (GF.GFCUS, GF.GFCLC) = (NMC.NMCCUS, NMC.NMCCLC)

                    where NMC.NMCDT  = :dte
                      and NMC.NMCNTP = 'BGFNM'
                      and NMC.NMCTP in ('F', 'G')
                      and GF.GFCOD  <> :dte;

Это статический SQL. Это не выполнение, это декларация. dte тут - переменная используемая в коде. Запрос этот будет на этапе компиляции подготовлен.

А дальше

exec sql open curProcNames;

и потом

exec sql fetch curProcNames for :C_MAX_SQL_ROWS rows into :dsData;

Блочное чтение в массив структур

      dcl-ds t_dsData        qualified template;
        CUS  char(6);
        CLC  char(3);
        CRF  char(20)        inz(cNoCRF); // нужно там, где ИНН не подтягивается причтении из БД
        TYP  char(1);
      end-ds;

      dcl-c  C_MAX_SQL_ROWS  const(1000);
      dcl-ds dsData          likeds(t_dsData) dim(C_MAX_SQL_ROWS);

А дальше мы уже сразу можем работать с элементами массива.

Впрочем, все это я описывал тут.

На каком-нибудь C# все это будет сложнее и потребует внешних зависимостей. А здесь все это средства языка.

вариант с использованием нормального серверного железа общего назначения видится мне сильно эффективнее

На каком основании такой вывод? Вот лежит у вас в БД какой-нибудь decimal(15, 0) или numeric(7, 0). Вот прочитали вы его из БД - что дальше будете с ним делать? Создавать из него объект чтобы с ним работать? Это время и такты процессора...

Насчет "нормального серверного железа" - тут большой вопрос. Я не хочу углубляться в тонкости того, что есть на АСке. Сейчас у нас не самый свежий сервер, но это 120 SMT8 ядер Power9, 12Тб оперативки и 400Тб SSD массивы.

Последнее поколение - Power10. Среди прочего позволяет объединять серверы по интерфейсу PowerAXON так, что процессоры, память и диски становятся общими для всех. Т.е. фактически вы из нескольких малых серверов получаете один большой. И все это поддерживается на уровне ОС. Это про простоту масштабирования.

Про все остальное - https://programmers.io/blog/everything-to-know-about-ibmi-as400-i-series/ Там и интеграция и масштабирование и все остальное.

Я разработкой занимаюсь с 91-го года (последние 8 лет на АСке). И на разных системах работал (даже немного зацепил такую экзотику как QNX). Так вот возможности, предоставляемые "из коробки" на АСке ни в какое сравнение с остальными не идут. Одно ILE чего стоит.

Ну а с поиском разработчиков как-то нет проблем. Недостатка у нас нет. Берем, обучаем.

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

https://dzen.ru/a/Xzu04ctoMQCq8c4j

Как вы представляете себе атаку через MQ в данном случае? Передать заведомо некорректные данные? Или что? В чем цель атаки?

Напрямую получить доступ к серверу не получится (т.е. невозможно слить всю БД). Операций типа "положи вот эти данные вот в эту таблицу" там не предусмотрено. Есть выполнение конкретных операций тип "добавление клиента", но это сложна операция - там очень много проверок и валидаций прежде чем клиент будет заведен. Любой платеж тоже проходит кучу проверок.

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

А вы уверены, что "любой" пакет будет обработан? :-)

Вот пример реального сообщения

// Формат сообщения для HMQ-обработчика
dcl-ds t_HMQFINNRSP template qualified;
    messageType       char(10);
    requestUID        char(32);
    INN               char(12);
end-ds;

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

requestUID - это ID запроса в ответ на который получено это сообщение (из внешней системы). На этот ID должна быть запись в таблице отправленных запросов. Если ее нет - сразу на выход.

Ну и дальше данные.

И практически все сообщения выглядят примерно так - структура с данными. И все данные на входе обработчика будут валидироваться. Если что-то не так - ошибка и на выход.

Просунуть туда что-то левое крайне сложно, если вообще возможно.

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

Физический доступ к серверу - только из внутреннего контура (даже к тестовому) и для очень ограниченного круга лиц. Пароль - не менее 12-ти символов, "3 группы из 4-х", смена не реже чем раз в три месяца.

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

Мне было интересно посмотреть как оно справится с ситуацией, когда один и тот же модуль в рамках одного задания вызывается (из другого модуля) несколько раз. И для экономии времени с прошлого вызова кешируются какие-то данные. Да-да-да. На AS/400 есть понятие "группы активации" как подмножества задания и все статические и глобальные данные сохраняются пока жива группа активации (пока живет задание или пока ГА принудительно не закрыли).

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

Ну или работа со специфическими системными объектами типа USER SPACE/USER QUEUE/USER INDEX...

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

в классических программах нет встроенной проверки границ буфера

Потому что они есть на уровне самой ОС. А еще там есть проверка на переполнение. Из соседней ветки

Так и случилось в один прекрасный момент несколько лет назад, когда путешествия на Бали (смотри курс индонезийской рупии IDR) стали внезапно стоить сущие центы из-за переполнения. Распродажу Лавочку прикрыли только к утру, когда заметили невероятную популярность клиента Agoda и отелей на Бали, и до исправления просто прекратили (на полгода) принимать платежи в валюте IDR. Убытки, как водится, просто списали, никого не наказали.

Тогда как в нормальной системе в такой ситуации переполнение вызывает системное исключение "Receiver value too small to hold result"

Теперь фронтенд и микросервисы общаются с мэйнфреймом по привычному HTTP, а не копаются в суровом COBOL‑монолите. 

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

Никакого http там и близко не лежало. И слабо себе представляю как можно реализовать SQL инъекцию в таком раскладе (SQL там может вообще не быть - есть и другие способы работы с БД, в т.ч. и в COBOL). Да и голый SQL там не используется. Он весь спрятан внутри COBOL кода.

А если говорить о защите, то та же IBM i (AS/400) имеет несколько уровней защиты самой системы. В том числе и "50" уровень, сертифицированный в США для государственных и военных организаций. И даже на более низком, "40"-м уровне, уже достаточно много ограничений для разработчика (например, запрет низкоуровневой работы через MI инструкции c объектами в домене *SYSTEM - даже если получишь системный указатель на объект, что-то сделать с ним уже не сможешь - только через системные API и никак иначе).

использование transpiler-решений, которые автоматически переводят критичные фрагменты COBOL-кода в современные языки, такие как Java или C#

А что там с поддержкой в "современных языках" типов данных, которые лежат в БД? Те же форматы с фиксированной точкой? Читаем запись, потом создаем из ее полей нужные объекты с которыми можно работать? Но, извините, это лишнее время и лишние ресурсы процессора...

А что там с работой с БД? Только SQL, причем только динамический? Без возможности подготовки запроса на этапе компиляции? И даже по одной таблице по индексированным полям доступ к БД все равно только скулем? Задач, где нужно из одной таблицы прочитать десяток записей по известному значению ключа в реальной жизни достаточно много. И гонять ради этого динамический скуль очень расточительно.

COBOL (или тот же RPG) создавались специально для максимально эффективного решения конкретного класса задач. И имеют для этого все встроенные средства, являясь по сути специализированными языками.

Тем более, что вычисления с плавающей точкой неизбежно приводят к накоплению ошибки. См. рекуррентное соотношение Мюллера. Форматы с фиксированной точкой более устойчивы (хотя тоже "разбегаются", но не так быстро как форматы с плавающей точкой).

Банки не используют integer. Банки используют форматы с фиксированной точкой где указывается количество знаков после запятой. Т.е. decimal(n, p) или numeric(n, p).

И проценты [обычно] начисляются не каждый день. Сумма процентов накапливается отдельно и в назначенный день капитализируется (переводится на баланс счета). Но это отдельная операция всегда - начисление процентов.

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

Или на остаток по счету на дату капитализации.

Или еще как-то - все это прописано в условиях счета.

Обычно по депозитам фиксируется минимальная сумма вклада.

По кешбекам всяким - считается с округлением процент от суммы покупки.

Ну и смысл хранить данные в нескольких форматах, если можно в одном?

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

Проценты по депозиту начисляются не ежедневно а обычно раз в месяц. Они копятся отдельно и в дату капитализации зачисляются на счет. Мешать все в одну кучу - создавать самому себе лишние проблемы.

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

Может, только слой отображения выкидывает несущественную часть

Какой слой отображения, в о чем сейчас? Это АБС, центральный сервер. Там не никакого отображения.

В таком случае будет нужно несколько итераций согласования FSD с BRD и самим заказчиком еще до разработки.

Да. Именно для того

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

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

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

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

Для разработчика ТЗ - это FSD.

Бизнес-требования, BRD - это от заказчика. Что он хочет получить. Что на входе будет, что на выходе должно быть, бизнес-логика, граничные условия, оценка нагрузки, типовые сценарии использования... Можно рассматривать как ТЗ для аналитика.

FSD - это уже аналитик пишет для разработчика. Как реализовать то, что хочет заказчик. Это ТЗ для разработчика.

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

Я в одном из камментов специально отметил что нужно рассматривать всесторонне. Есть платформы, специально предназначенные для крупных коммерческих и финансовых систем. И там не надо сову на глобус натягивать - есть и удобные средства для эффективно работы с БД без привлечения всяких сторонних библиотек и нативные типы данных для работы с финансами.

И ситуация описанная в камменте ниже

Так и случилось в один прекрасный момент несколько лет назад, когда путешествия на Бали (смотри курс индонезийской рупии IDR) стали внезапно стоить сущие центы из-за переполнения.

там просто невозможна - переполнение вызывает системное исключение "Receiver value too small to hold result" мимо которого вы ну никак не пройдете.

И убытки, которые

просто списали, никого не наказали

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

Честно скажу, не знаю как это реализуется. Но как-то реализуется.

Я с деньгами не работаю, процентный, тарифный, лимитный модули - это другие команды. Я по комплаенсу и клиентским данным, там не про деньги.

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

Вообще все это в банке намного сложнее (и там всего намного больше), чем это представляется со стороны.

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

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

Ну хранение связано с использованием. И что там за API не так интересно, как то, что внутри этих API - как реализована работа.

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

И да, уже отмечалось, что балансы хранятся в миноритарных единицах.

В виде расширений может быть. Например, в реализациях С/С++ на платформе IBM i, как писал выше, есть типы _Decimal(n,p) и _DecimalT<n,p> Основаны на BCD.

В стандарте - нет.

Вообще-то бизнес-требования (BRD) и ТЗ (FSD) совершенно разные сущности.

  1. Заказчик пишет BRD - что он хочет получить.

  2. Согласование BRD

  3. Разработка архитектурного решения

  4. Аналитик пишет FSD для разработчика

  5. Разработка

  6. Компонентное тестирование на соответствие результата разработки требованиям FSD

  7. Бизнес-тест на соответствие продукта требованиям BRD.

  8. Внедрение

Как-то так это выглядит.

BRD и FSD одновременно являются документацией по проекту. Если требуются доработки, выпускается новая версия FSD фиксируются все изменения (т.е. всегда можно всю историю отследить).

И, естественно, всегда контролируется соответствие кода и FSD (бывают ситуации, когда аналитик предлагает одно решение, разработчик - другое, более эффективное, в этом случае FSD корректируется)

Information

Rating
2,488-th
Location
Екатеринбург, Свердловская обл., Россия
Works in
Date of birth
Registered
Activity