Обновить

Бэкенд

Сначала показывать
Порог рейтинга
redb.Core
redb.Core

«Это написал Клод» — комментарий из-за рубежа, и почему идее хранилища больше двадцати лет (даже если так было бы, то клод выпивая тонные кофе это всё родил ...)

Под англоязычной версией статьи про SQLite-провайдер на dev.to появился комментарий в духе «даже без "load-bearing" и тире через всё предложение видно, что это писал Клод». Не первый раз слышу что-то подобное, так что решил ответить не в комментариях, а отдельным постом — заодно расскажу то, что давно собирался: откуда вообще взялась идея хранилища, на котором всё это стоит.

Сначала честно про долю ИИ

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

Показательный пример — сам релиз 3.6.0: баги, которые в него вошли, нашёл не Клод, а реальная эксплуатация. Модель не может споткнуться о краевой случай, который проявляется только под живой нагрузкой с непредсказуемым вводом — такое не ловится по аналогии с соседним кодом.

А теперь — откуда это всё вообще взялось

Основная идея хранилища — не изобретение последних месяцев. Первая версия появилась в 2004 году, когда я писал на Delphi — за двадцать с лишним лет до того, как Клод вообще начал существовать.

Задача была — дать объекту динамические поля на ходу, не фиксируя их жёстким классом заранее. Delphi для этого уже нёс нужный кусок — RTTI (Run-Time Type Information): каждый класс несёт метаданные о своих полях и свойствах, доступные в рантайме, не только на этапе компиляции. Поверх этого — интерфейс IDispatch из COM: GetIDsOfNames резолвит имя поля в DISPID, Invoke вызывает по этому DISPID, передавая значение через VARIANT. Вместе это давало то, чего не даёт обычный жёсткий класс: объект мог обзавестись полем, которого не существовало на момент компиляции, а вызывающая сторона — спросить о нём по имени и получить настоящий типизированный ответ.

Система прожила у меня внутри собственных проектов много лет, никуда не публикуясь. За это время она полностью пережила Delphi и COM — переехала на .NET, механизм сменился до неузнаваемости (никакого VARIANT, никакого DISPID — сейчас это типизированные колонки в Postgres/MSSQL/SQLite, которые я уже разбирал построчно в статье про 13 таблиц), а вопрос остался ровно тем же: как дать объекту гибкий набор полей, не потеряв возможность спросить "а какого оно вообще типа".

Отсюда, кстати, и название — RTTI-based storage, не маркетинговый термин, а прямое родство с тем самым механизмом Delphi. И не EAV — там никогда не было обезличенной колонки "значение", RTTI всегда знало настоящий тип.

Клод помогал полировать это перед тем, как это увидело свет публично. Сама идея и её первое воплощение — старше Клода на десятилетия.

Цикл про redb:

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

Теги:
+1
Комментарии0

Чуть лучше код

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

Что дано:

  1. поход в базу (начальные данные)

  2. поход по апи за списком (указателей или стримов)

  3. для каждого (репорта): поход по апи за данными и сохранение в базу

Легко пишем (неправильный) скрипт, кладем в крон и профит? Почти. Через пару лет в дев базе 2kk записей и селект ну очень долго ждать. Порядочные пацаны (и девушки) пишут тесты на sqlite, и неявно имплeмeнтируют идемпотентность, создавая и дропая базу данных на каждую пачку тестов. Sql insert не является идемпотентной операцией, но с пустой базой прокатывает.

В чем, собственно, проблема? Идемпотентность (от лат. idem — тот же самый и potens — сильный, буквально — равносильность) — свойство объекта или операции при повторном применении операции к объекту давать тот же результат, что и при первом. Так вот, sql insert и app_call(date_now) не обладают идемпотентностью.

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

Чем заменить? Дефолтными значениями, как ни странно, дефолтные значения идемпотентны, если это, например, список и словарь. Удачного кодинга :)

P.S.: Хотел приложить примеры кода, но кол-во строк оказалось больше размера статьи :)

Теги:
-2
Комментарии3

Что нужно освоить разработчику на Java?

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

Сегодня сделали подборку инструментов разработчика на Java, которые можно освоить на курсах с нашей витрины — заглядывайте:

IntelliJ idea

Ускоряем работу при помощи автодополнений и анализатора кода.

GitLab

Отслеживаем изменение кода вместе с коллегами.

Redis

Храним данные и быстро получаем к ним доступ.

Система сборки Maven и Gradle

Автоматизируем сборку проектов.

Spring Boot

Быстро создаем приложения на Spring.

Docker

Запускаем приложения в изолированных контейнерах.

JUnit

Тестируем Java-код.

Курсы со всего интернета уже у нас

Теги:
-1
Комментарии0

Пассажир меняет билет прямо в дороге — а маршрут собран из трёх GDS и ж/д. Что происходит с данными

Сотруднику нужно долететь до одного города, доехать поездом до другого, и обратно тем же путём — одна командировка, билеты из разных систем бронирования. А потом он уже в дороге пишет в телеграм: "планы изменились, летим не туда, перебронируй".

Три системы под самолёты — Amadeus, Sabre, Travelport: исторически несовместимые XML-диалекты одного и того же понятия перелёта, выросшие из мейнфреймов 60-80-х, каждый со своими причудами и полями, которых нет у соседа. Плюс отдельная, никак не связанная с ними система бронирования под железную дорогу — свой формат, своя логика мест и классов, ничего общего по структуре с авиационными GDS. Запросить всё это параллельно, свести разноформатные ответы в одно и собрать из них валидный маршрут по стыковкам — уже само по себе задача не для россыпи if и ручных мапперов.

А потом человек уже в дороге меняет одно плечо маршрута. Один перелёт уже случился — трогать нельзя. Один — впереди, подлежит замене. И весь маршрут не по шаблону "туда-обратно", а любой длины и состава: сегодня две пересадки, завтра — четыре, послезавтра прямо в дороге вставили лишний вылет.

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

Первая — как описать саму логику поверх этого зоопарка источников. И сбор из четырёх систем разом, и ветка "можно менять / нельзя менять" превращаются либо в DSL на языке общепринятых интеграционных паттернов (Scatter-Gather, Content-Based Router — тот же словарь, что у Apache Camel), который прочитает и поймёт человек, ни разу его не писавший, — либо в код, который через полгода не восстановит и автор.

Вторая — куда положить результат. Маршрут — не два поля outbound/return, а последовательность разнотипных плеч (самолёт ≠ поезд), где число элементов и состав не известны заранее и меняются посреди собственной жизни объекта. Стандартный ответ — либо гора nullable-колонок под все виды транспорта разом, либо миграция на каждый новый вид.

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

Скоро.

ссылки: хабр redb.ru

Теги:
+4
Комментарии3

10 августа я провёл вебинар, посвящённый новым возможностям Digital Q.DataBase 18.2 - СУБД + AI в Digital Q.DataBase

В программе:

🔹 Развитие полиглотной платформы единая платформа для PostgreSQL, Microsoft SQL Server и Oracle; новые возможности совместимости;
🔹 Новые возможности RuDB новые пакеты; развитие функциональности;
🔹 ИИ и векторный поиск поддержка векторных операций;
🔹 KV-хранилище DGrid развитие встроенного KV-хранилища; архитектура решения;

► Бесплатная полнофункциональная версия дистрибутива (до 8 ядер) с возможностью использования в том числе в коммерческих целях.

С 1 сентября 2026 года компания «Диасофт» переходит на новую лицензионную политику СУБД Digital Q.DataBase (до 4-х ядер). 

🔹 Бесплатное получение дистрибутива: 
https://database.diasoft.ru/?utm\_source=andrei
🔹 Документация: доступна внутри дистрибутива
🔹 Telegram-сообщество Digital Q.DataBase: https://t.me/dqdatabase
🔹 MAX: https://max.ru/channel_dqdatabase
🔹 RuDB : https://database.ru

Подписывайтесь на наши сообщества, чтобы получать новости, технические материалы и информацию о новых вебинарах.

Запись вебинара доступна на следующих площадках:

RuTube
Dzen
YouTube
VK

#DigitalQDataBase #Diasoft #PostgreSQL #AI #Импортозамещение

Теги:
+8
Комментарии0
Биржа Инфостарта: новые задачи по 1С за 5-12 августа
Биржа Инфостарта: новые задачи по 1С за 5-12 августа

На неделе c 5 по 12 августа заказчики ищут специалистов по 1С для разработки отчетов, настройки ERP, обмена данными с внешними системами, сверки документов между конфигурациями и интеграции 1С с сайтом.

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

На Бирже заказов можно найти специалиста для консультации, настройки типовой конфигурации, разработки дополнительного функционала, интеграции систем, переноса данных или регулярного сопровождения 1С.

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

Перейти на Биржу

Теги:
+6
Комментарии0

Как redb хранит сложные объекты: не бесхемная свалка, а RTTI

Про redb (RedBase) есть два зеркальных заблуждения. Первое: раз объект пишется «как документ», внутри лежит сериализованный JSON или блоб. Второе, противоположное: раз всё падает в общую таблицу значений — значит это плоский мешок пар «ключ-значение» без схемы.

Оба мимо. То, что внутри — это RTTI, полноценная система типов, живущая в самой базе. И устроена она заметно сложнее, чем и блоб, и «атрибут-значение». Разбор архитектуры я подробно давал в отдельной статье на Хабре: «redb: реляционное хранилище объектов» — ниже сжатая суть.

Слой типов: база знает настоящий тип каждого поля

redb хранит не только данные, но и их описание типов — три связанных уровня:

  • types — реальные дескрипторы типов (db_type и соответствие .NET-типу);

  • _schemes — сами типы (классы), с поддержкой наследования через self-reference;

  • structures — типизированные поля схемы: имя (name), тип (_id_type, FK на types), признак коллекции (collection_type) и вложенность (_id_parent).

Значения в values всегда привязаны к конкретной структуре (id_structure, FK на structures). Поэтому строка values — это не безымянная пара «атрибут-значение»: это значение известного, именованного, типизированного, возможно вложенного поля известного класса. База в рантайме знает, что перед ней — decimal Salary в схеме Employee, а не абстрактный «атрибут №42». Это и есть RTTI.

Хранение коллекций: построчно, реляционно

Вложенные массивы, словари и глубокие иерархии redb раскладывает в _values построчно, а не строкой:

  • Никаких JSON-блобов на диске. Каждый элемент коллекции — отдельная строка с типизированными колонками (_value_longvaluestringvaluedatetimevalueguid, …), внешними ключами и обычными индексами.

  • Связь и порядок — реляционные. Вложенность собирается self-reference колонкой arrayparent_id (FK на values.idON DELETE CASCADE). Порядок массива и ключи словаря — в arrayindex (text: '0','1','2' для массивов, строковый ключ — для словарей).

  • Один элемент — одна строка. List<OrderItem> внутри класса не превращается ни в JSON-поле, ни в десяток физических таблиц, которые вы заводите руками.

Что это даёт на практике

  1. Честный LINQ на уровне СУБД. Данные лежат в типизированных колонках, а метаданные структур позволяют движку собрать нативный SQL: Where / OrderBy / GroupBy / оконные функции идут по реальным индексам базы, а не перебором JSON в памяти бэкенда.

  2. Загрузка за один запрос без каскада JOIN-ов. Чтобы поднять объект со всей глубиной вложенности (пусть там 20–30 списков), не нужен каскад JOIN, как у EF с .Include(). Плоская структура забирается из _values одним запросом и собирается в объект в памяти.

  3. Точечный Change Tracking (Pro). При сохранении Pro-версия строит деревья ValueTreeNode (память против БД), сравнивает их (ValueTreeBuilder / ValueTreeDiff) и шлёт UPDATE только по изменившимся узлам — граф целиком не перезаписывается.

Итог: redb совмещает удобство работы с объектами «как с документами» и фундамент реляционной СУБД — типизацию, индексы, FK и запросы, которые исполняет база, а не бэкенд. Ключ к этому — не блоб и не плоский мешок атрибутов, а persisted-RTTI: typesschemesstructuresvalues.

Ссылки

Теги:
+4
Комментарии0

Информационные технологии. Проблемы и решения – IT'DAYS

Сегодня всё чаще говорят: импортозамещение заканчивается там, где начинается переписывание миллионов строк бизнес-логики.

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

Digital Q.DataBase — именно такая СУБД. Она воспроизводит функциональные возможности Microsoft SQL Server и Oracle Database, позволяя существенно сократить объём доработок существующих информационных систем при миграции.

Отличный повод вспомнить моё выступление на международной конференции «Информационные технологии. Проблемы и решения – IT'DAYS» в Уфе.

► Бесплатная полнофункциональная версия дистрибутива (до 8 ядер) с возможностью использования в том числе в коммерческих целях.

🔹 Бесплатное получение дистрибутива: https://database.diasoft.ru/?utm\_source=andrei
🔹 Документация: доступна внутри дистрибутива
🔹 Telegram-сообщество Digital Q.DataBase: https://t.me/dqdatabase
🔹 MAX: https://max.ru/channel_dqdatabase
🔹 RuDB : https://database.ru

Подписывайтесь на наши сообщества, чтобы получать новости, технические материалы и информацию о новых вебинарах.

Теги:
+5
Комментарии5

От ядра Linux до ИИ-агентов: 19 открытых уроков недели

Как устроены продвинутые модели Data Science, что происходит на границе user space и kernel space, как проектировать отказоустойчивые микросервисы и автоматизировать рабочие задачи с помощью искусственного интеллекта?

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

Data Science и искусственный интеллект

  • 10 августа, 18:00. «Технологии продвинутого Data Science: что под капотом». Записаться

  • 12 августа, 20:00. «ИИ-зрение в действии: как из данных с дороги получить карту мира». Записаться

  • 13 августа, 20:00. «Управление данными в MSA — дыра в бюджете или актив для ИИ-трансформации?». Записаться

  • 17 августа, 20:00. «Создаём первого ИИ-агента за 90 минут: автоматизируем реальную рабочую задачу с Claude Code». Ведущая — Татьяна Березенцева. Записаться

Разработка и архитектура

  • 10 августа, 20:00. «Ваш первый код на Go за один вечер». Записаться

  • 11 августа, 20:00. «Работа с SQLAlchemy и Alembic в FastAPI». Записаться

  • 12 августа, 20:00. «Паттерны отказоустойчивости и масштабируемости микросервисной архитектуры». Записаться

  • 12 августа, 20:00. «Тайный язык общения чипов. Подключаем всё к ESP32». Записаться

DevOps и системное администрирование

  • 10 августа, 20:00. «Вход в ядро: системные вызовы и граница между user space и kernel space». Записаться

  • 10 августа, 20:00. «Kubernetes + CI/CD + GitOps — делаем стабильный деплой без выхода из кластера». Записаться

  • 13 августа, 20:00. «Принцип DRY в GitLab CI: как избавиться от дублирования и навести порядок в пайплайнах». Записаться

  • 17 августа, 20:00. «Что такое модуль ядра. Как его написать, собрать, запустить». Записаться

  • 17 августа, 20:00. «Системы логирования: ELK, EFK или Graylog?». Записаться

Тестирование

  • 13 августа, 20:00. «Минимум для старта: как провести своё первое нагрузочное тестирование». Записаться

Системный и бизнес-анализ

  • 11 августа, 20:00. «Практическое собеседование системного аналитика». Записаться

  • 17 августа, 20:00. «Строим модель в нотации BPMN с помощью ИИ». Ведущий — Андрей Коптелов. Записаться

Управление, поддержка и Битрикс24

  • 10 августа, 19:00. «Настройка прав доступа в Битрикс24: от простого к сложному». Записаться

  • 10 августа, 20:00. «Колл-центр поддержки изнутри: структура, на которой держится клиентский сервис». Записаться

  • 11 августа, 19:00. «Модели организации разработки: продуктовые команды и архитектурное управление». Записаться

Полный спислк бесплатных уроков августа смотрите в дайджесте мероприятий.

Теги:
+6
Комментарии0

redb ecosystem
вышла версия 3.5.0(1) nuget
в ней Локальная база на клиенте
также новый коннектор redb.Route.As2 github
добавлены EIP паттерны
Message History EIP 
XSLT transformation
Routing Slip EIP 

посмотреть можно здесь github.com/redbase-app

хабр

Теги:
+5
Комментарии0

ElegantGPT

Начал значительно чаще пользоваться ChatGPT, так как на GPT-5.6 Sol High качество ответов стало меня устраивать. Вдобавок, он по умолчанию работает примерно в том же стиле, что и Perplexity Computer. Только нет никаких дурацких кредитов.

Единственное, что меня серьёзно напрягало – это то, как выглядел чат. Чёрный фон, полная депрессия. Поэтому сделал свою тему. Естественно, частично наследовал Base16 Dark и поставил любимое семейство IBM шрифтов.

Читаемость повысилась. С чатом стало приятнее работать. Кстати, предыдущую тему для Habr я тоже переработал.

Тема бесплатная, устанавливается через Stylus (Firefox / Chrome).

Теги:
+3
Комментарии1

Прямо сейчас я заметил, что моя статья получила дизлайк, и карма упала на два пункта.

На Хабре немало публикаций в духе: «Я попал в Яндекс, смотрите какой я крутой».
В них - ноль пользы и никакой информации.
Другие материалы поражают скомканностью и поверхностностью.

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

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

И вот я думаю: стоит ли вообще делиться знаниями на этой площадке, если здесь хватает людей, которые портят атмосферу? Может, есть достойные альтернативы Хабру?

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

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

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

Хочу осветить эту проблему хотя бы пока есть карма.
Уже видно, как работает эта система.

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

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

Теги:
+9
Комментарии36

Ближайшие события

Элегантность кода благодаря C++23

Продолжим разбирать приёмы рефакторинга и посмотрим, как std::ranges::views::enumerate помогает сделать код более элегантным.

В статье "C++: Пиши, сокращай, оптимизируй" я рассматривал рефакторинг и оптимизацию кода за счёт объединения циклов. В итоге я остановился на следующем варианте кода:

static TensorImpl make_contiguous_tensor(const std::vector<int64_t>& sizes)
{
  auto q = sizes.size();
  std::vector<int64_t> strides(q);
  int64_t acc = 1;
  int64_t ne = 1;
  for (auto sz : std::ranges::views::reverse(sizes))
  {
    strides[--q] = acc;
    acc *= (sz == 0 ? 1 : sz);
    ne *= sz;
  }
  //....
}

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

После публикации мне подсказали про enumerate. Эта штука появилась в C++23, и я как-то её пропустил. Сложно уследить за всеми нововведениями C++.

С помощью enumerate можно сразу перебирать и элементы, и их индексы:

constexpr static auto v = {'A', 'B', 'C', 'D'};
for (auto const [index, letter] : std::views::enumerate(v))
    std::cout << '(' << index << ':' << letter << ") ";

Будет напечатано: (0:A) (1:B) (2:C) (3:D).

Но нам нужен обратный порядок, и такой вариант не подходит:

for (auto const [i, sz] :
  std::views::enumerate(
    std::ranges::views::reverse(sizes)))

Этот цикл будет перебирать элементы с конца, а индексы — по возрастанию от 0. Можно сделать, чтобы значения i также шли в обратном порядке? Можно. Это делается с помощью std::views::enumerate(sizes) | std::views::reverse.

В итоге можно сократить код ещё на одну строчку:

static TensorImpl make_contiguous_tensor(const std::vector<int64_t>& sizes)
{
  std::vector<int64_t> strides(sizes.size());
  int64_t acc = 1;
  int64_t ne = 1;
  for (auto const [i, sz] : std::views::enumerate(sizes) | std::views::reverse)
  {
    strides[i] = acc;
    acc *= (sz == 0 ? 1 : sz);
    ne *= sz;
  }
  //....
}

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

Что со скоростью кода? Замер показал, что в рамках погрешности его скорость не изменилось. Т.е. этот вариант работает так же, как вариант №2 — "Мой вариант одним циклом" (см. замер скорости работы в статье). Это не удивительно, так как по сути код идентичен предыдущему.

Спасибо за внимание и подписывайтесь на наш дайджест, чтобы не пропустить интересное. Например, у нас грядёт выпуск PVS-Studio 8.0 с поддержкой новых языков.

Теги:
+4
Комментарии0

API Т‑Банка и сертификаты Минцифры: как использовать без установки на сервере

У меня есть Tg-бот, в нём я подключил оплату через платёжные ссылки Т-Банка. В какой-то момент ссылки перестали создаваться, в логах ошибка:
SSL certificate OpenSSL verify result: self-signed certificate in certificate chain (19)

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

Варианты действий:

  1. Подключить другую платёжку, которая (пока) не импортозаместила сертификаты.

  2. Установить сертификаты на сервер (инструкция).
    Вам потребуется определённая степень доверия родному государству.
    На виртуальном хостинге так и вовсе может быть невозможно.

  3. Собрать свою цепочку из сертификатов и использовать её только при запросах к API российских банков.
    Подходит для виртуального хостинга.

Третьему варианту меня научила нейронка, вот порядок действий:

  1. Скачать сертификаты.

  2. Распаковать два архива и загрузить на сервер вот эти файлы:
    russian_trusted_root_ca_pem.crt
    russian_trusted_sub_ca_pem.crt
    russian_trusted_sub_ca_2024_pem.crt

  3. На сервере (у меня Ubuntu) скачать набор сертификатов от Mozilla:

    curl -fsSL -o cacert.pem https://curl.se/ca/cacert.pem
  4. Собрать объединённую цепочку:

    cat \
       cacert.pem \
       russian_trusted_root_ca_pem.crt \
       russian_trusted_sub_ca_pem.crt \
       russian_trusted_sub_ca_2024_pem.crt \
       > ru-ca-bundle.pem
  5. Проверить, что работает:

    curl -v --cacert ru-ca-bundle.pem https://mddc.tbank.ru/
  6. Посмотреть сроки действия сертификатов:

    openssl x509 -in russian_trusted_root_ca_pem.crt -noout -subject -issuer -dates
    openssl x509 -in russian_trusted_sub_ca_pem.crt -noout -subject -issuer -dates
    openssl x509 -in russian_trusted_sub_ca_2024_pem.crt -noout -subject -issuer -dates
  7. Выбрать минимальную из дат и поставить себе напоминалку, чтобы обновить их.

  8. Добавить использование этой цепочки в коде запросов к российским банкам.
    У меня на php это выглядит так:

    $caBundlePath = __DIR__ . '/ru-ca-bundle.pem';
    if (!is_readable($caBundlePath)) {
        myerror("Tinkoff CA bundle is not readable", ['path' => $caBundlePath]);
        return false;
    }
    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL => TINKOFF_INIT_URL,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => $postDataJson,
        CURLOPT_HTTPHEADER => [
            'Content-Type: application/json',
            'Content-Length: ' . strlen($postDataJson),
        ],
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_SSL_VERIFYHOST => 2,
        CURLOPT_CAINFO => $caBundlePath,
    ]);
    
    $output = curl_exec($ch);

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

Теги:
+11
Комментарии2

Приглашаем на вебинар «СУБД + AI: векторные операции, LLM и полиглотная архитектура в Digital Q.DataBase»

10 августа в 13:00 (мск) компания «Диасофт» проведет практический вебинар о новых возможностях Digital Q.DataBase «СУБД + AI: векторные операции, LLM и полиглотная архитектура в Digital Q.DataBase».

Вебинар «СУБД + AI: векторные операции, LLM и полиглотная архитектура в Digital Q.DataBase»
Вебинар «СУБД + AI: векторные операции, LLM и полиглотная архитектура в Digital Q.DataBase»

Ключевые темы:

  • Полиглотная архитектура Digital Q.DataBase. Как в единой среде работать с базами PostgreSQL, Microsoft SQL Server и Oracle

  • Симбиоз СУБД и AI. Поддержка векторных операций и интеграция с большими языковыми моделями (LLM) под капотом СУБД

  • Высокая скорость работы с данными. Архитектура и новые возможности встроенного KV-хранилища DGrid для сверхбыстрого доступа к информации

  • Развитие RuDB. Обзор новой функциональности и обновленных пакетов платформы

Зарегистрироваться на вебинар можно по ссылке.

Теги:
+4
Комментарии0

Почему я перестал удалять пользователей сразу

Раньше логика удаления у меня была максимально простой:

DELETE FROM users
WHERE subscription_end < NOW();

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

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

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

Поделитесь, кто как делает? используете отложенное удаление, soft delete или сразу выполняете операцию, если условие выполнено?

Теги:
+2
Комментарии3

Эксперт «Диасофт» примет участие в круглом столе IT-World «Почему хорошие системы плохо работают вместе?»

6 августа 2026 года в 16:00 IT-World проведет круглый стол «Почему хорошие системы плохо работают вместе?». В нем примет участие Дмитрий Гаврин, заместитель директора департамента «Цифровые решения» и один из авторов блога компании «Диасофт» (Как 30 лет боли в интеграции привели нас к собственной платформе)

О чем будут говорить спикеры:           

  • Почему интеграции остаются одной из самых болезненных зон корпоративного ИТ-ландшафта?

  • Что чаще ломает взаимодействие систем - слабые API, разные модели данных, отсутствие владельца процесса или спешка внедрения?

  • Как оценивать API-зрелость решения до покупки: документация, версионирование, песочница, ограничения, поддержка изменений?

  • Как меняется ответственность поставщика ИТ-решения, если его продукт становится частью большого корпоративного контура?

  • Что должно происходить с интеграциями при обновлении продукта, смене версии или доработке соседней системы?

  • Почему единые справочники и мастер-данные остаются проблемой даже там, где уже есть MDM, НСИ или корпоративная шина?

  • Где проходит граница между быстрой автоматизацией и архитектурным долгом, который потом мешает масштабировать решение?

  • Какие требования к интеграциям, API, данным и поддержке стоит включать в ТЗ, договор и критерии выбора поставщика?

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

Регистрация по ссылке: https://www.it-world.ru/events/or8fe6s830gwswk4o4ks4c0wcw0goos.html

Теги:
+3
Комментарии0

С 29 июля по 5 августа на Бирже Инфостарта появились новые задачи по доработке и интеграции 1С. В подборке — обмены между конфигурациями, настройка УНФ и БП, интеграции с внешними системами и консультации.

Новые заказы

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

Перейти на Биржу заказов

Теги:
+7
Комментарии0

Бенчмаркая CSE: подстава на uint — деление считается дважды

Уважаемые читатели, в этом посте я хочу разобраться, что компилятор делает с парой / и %, и представить свои выводы.

Возьмём число 47 и делитель 10. Деление даёт 4, остаток — 7. Компилятор деление не выполняет: он умножает 47 на подобранное число и сдвигает, получая 4. Дальше для остатка хватает вычитания: 47 − 4 × 10 = 7. Одно умножение на оба ответа.

Так на int. На uint компилятор получает 4, умножает на 10, вычитает — а потом заново считает те же 4 из 47, вторым умножением.

Ответ верный и там, и там. CSE, common subexpression elimination, находит повторяющиеся вычисления и считает их один раз. Оба умножения в паре считают одно и то же, и на int проход их склеивает. На uint не склеивает — отсюда и обращение в трекер.

int value = ints[i];
total += value / 10 + value % 10;    // одно умножение

uint value = uints[i];
total += value / 10 + value % 10;    // три умножения

Замер на 1 024 значениях, .NET 10, три машины. Значения положительные: у знакового деления отрицательные идут другой веткой.

.NET 10. Пара к делению — во сколько раз пара медленнее одного деления того же типа
.NET 10. Пара к делению — во сколько раз пара медленнее одного деления того же типа

Из таблицы можно сделать выводы:

  • на int пара занимает столько же времени, сколько одно деление, на uint — вдвое больше;

  • беззнаковое деление быстрее знакового в 1,54–1,60 раза: знаковому нужна коррекция для отрицательных значений;

  • проседает не тип, а пара операций.

Вот как это выглядит в машинном коде, Xeon W-2255. У int одно умножение на всю пару:

mov      edx, 0xD1FFAB1E      ; подобранное число
imul     edx:eax, r9d         ; единственное умножение, вышло 4
sar      edx, 2               ; деление готово
lea      edx, [rax+4*rax]     ; 4 x 5
add      edx, edx             ; ещё x2, вышло 40
sub      r9d, edx             ; 47 - 40 = 7, остаток

У uint то же самое, но в конце деление идёт второй раз:

mov      r10d, 0xD1FFAB1E     ; то же число
imul     r10, r9              ; первое умножение, вышло 4
shr      r10, 35              ; деление готово
imul     r10d, r10d, 10       ; второе: 4 x 10 = 40
sub      r9d, r10d            ; 47 - 40 = 7, остаток
mov      r10d, 0xD1FFAB1E     ; снова оно
imul     r8, r10              ; третье: те же 4 заново
shr      r8, 35               ; и тот же сдвиг

Были проверены ещё три случая, разницы между int и uint в них нет. Делитель 16, степень двойки: деление сводится к сдвигу, остаток берётся из младших битов, умножений ноль у обоих. Делитель в переменной: работает машинная команда деления, она выдаёт оба ответа разом, 2 714 против 2 716 нс. Тип ulong: на .NET 8 и .NET 9 было три умножения, на .NET 10 осталось одно, а у uint три.

Что делать на практике:

  • в горячих циклах вроде разбора числа по цифрам, форматирования и хэшей пара идёт на каждом витке, а с ней и лишнее умножение;

  • Math.DivRem возвращает к одному умножению: быстрее пары в 1,13–1,76 раза. Внутри для uint то же вычитание:

// dotnet/runtime, Math.cs

public static (uint Quotient, uint Remainder) DivRem(uint left, uint right)
{
    uint quotient = left / right;
    return (quotient, left - (quotient * right));
}
  • вычитание, записанное явно, value - value / 10 * 10, быстрее пары в 1,23–1,80 раза — для тех, кому не нужен кортеж из Math.DivRem;

  • на int менять нечего: там деление с остатком уже собрано в одно умножение;

  • лишнее умножение забирает часть того, что uint даёт на делении, но не всё: на разборе числа по цифрам он остаётся быстрее int — 0,81–0,86.

Проход описан в документации: Common Subexpression Elimination, код в optcse.cpp, реализация Math.DivRem — в Math.cs. Обращение открыто с августа 2025, help wanted: dotnet/runtime#119131. Замеры, отчёты и листинги: DivRemProof.

Всем удачи и до новых встреч!

Теги:
+7
Комментарии0
1
23 ...