Обновить

Бэкенд

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

Немного философии Rust, возможно кому то интересно обсудить

Уже почти 3 месяца пишу проект на Rust. Сейчас разработка стала другой, ручная работа стала роскошью, реальные задачи бизнеса быстрее решить LLM-ками. Естественно познание языка в таком режиме замедляется, хочется как-то компенсировать, хотя бы поговорить об этом.

Вот какой аспект. В Rust уровень владения/заимствования объектом - часть контракта. По большому счету можно составить примерно такую таблицу (на самом деле это дерево должно быть, но для упрощения привожу плоскую таблицу):

  • Просто владею объектом → T

  • Временно читаю чужой объект → &T

  • Временно изменяю чужой объект → &mut T

  • Один владелец, нужна куча → Box

  • Несколько владельцев, один поток, чтение → Rc

  • Нужны несколько владельцев, один поток, изменение → Rc<Cell> / Rc<RefCell>

  • Несколько владельцев, несколько потоков, чтение → Arc

  • Несколько владельцев, несколько потоков, изменение → Arc<Mutex> / Arc<RwLock>

По сути чем более строгий уровень доступа (или какой термин тут лучше?) - тем больше проверок сможет сделать компилятор. Если используете Rc - то уже потенциально возможны циклические ссылки и утечка памяти (с Box - это не возможно). Если RefCell - то компилятор не сможет проверить два borrow_mut() одновременно - будет рантайм проверка или паника.

И вот какая фишка. Часто LLM-ка дает уровень больше чем нужно. Как-то где можно обойтись ссылкой - добавит Rc<RefCell>. Т.е., по сути, код то рабочий, но лишние обертки и послабление компил-тайм проверок немного угнетают.

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

И далее возникла философская идея. А вот неплохо бы чтобы компилятор сам решал какой уровень применять. Т.е. начинаем от самого малого, если его не достаточно - то использует послабления. Если достаточно классической проверяемой ссылки - то использовать ее. Или если нужно множественное владение, но точно нет потоков - то Arc можно не использовать - достаточно Rc (если нет данных то ослабляем - берем Arc).

При этом все еще остаемся в рамках языка без GC - но вместо ручного выбора - выбор осуществляется компилятором при сборке.

Как вы думаете - идея имеет право на жизнь?

Теги:
Всего голосов 3: ↑2 и ↓1+3
Комментарии3

Коннекторы 1С: быстрая интеграция через OData в Digital Q.Integration

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

На вебинаре эксперты компании «Диасофт» расскажут, как организовать обмен данными между 1С и внешними системами с помощью готового коннектора платформы Digital Q.Integration, реализованного на базе протокола OData. Вы узнаете, какие подходы для интеграции с 1С существуют, почему именно OData выбран в качестве технологической основы решения и какие преимущества это дает при построении современных интеграционных процессов.

Во время демонстрации покажем, как:

  • настроить подключение к 1С с помощью коннектора Q.Integration;

  • получать данные из 1С;

  • добавлять/изменять данные в 1С;

  • автоматизировать интеграционные процессы средствами платформы Digital Q.Integration.

Программа

13:00 – 13:10 Введение. Почему интеграция с 1С остается актуальной задачей и какие подходы используются для ее реализации.

13:10 – 13:25 Подходы к интеграции с 1С. Рассмотрим основные способы организации обмена данными, сравним интеграцию через OData и использование специализированных конфигураций 1С, разберем преимущества и ограничения каждого подхода.

13:25 – 13:40 Коннектор 1С в Digital Q.Integration. Расскажем, как реализован коннектор, какие процессы автоматизированы, как устроена работа с OData и какие возможности получает пользователь при настройке интеграции.

13:40 – 13:55 Практическая демонстрация. Покажем настройку коннектора, получение данных из 1С и изменение.

13:55 – 14:00 Вопросы и ответы. Ответим на вопросы участников и обсудим практические кейсы использования коннектора.

Кому полезен вебинар:

  • ИТ-директорам и техническим руководителям;

  • архитекторам интеграционных решений;

  • руководителям проектов цифровой трансформации;

  • разработчикам и интеграторам;

  • специалистам по сопровождению корпоративных информационных систем.

Спикеры:

  • Виктор Овчинников, руководитель продукта Digital Q.Integration компании «Диасофт»

  • Андрей Даниленко, ведущий разработчик MSA департамента «Цифровые решения» компании «Диасофт»

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

Теги:
Всего голосов 1: ↑1 и ↓0+3
Комментарии0

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

# Не судите строго, впервые пиши пост, понимаю, что может быть не интересно (по причине опыта), но все же хочется внести свой вклад

Всем привет! Меня зовут Фаина я уже несколько лет пишу на Python (и не только) и зарабатываю этим на жизнь. Недавно я наткнулась на свои старые "конспекты" с первых попыток изучения языка. Это было... больно. Сотни скриншотов, обрывочные заметки и полное непонимание того, что происходит.

Если бы у меня была машина времени, я бы вернулась к той испуганной девушке, которая впервые открыла IDLE, и сказала бы ей несколько важных вещей.

1.Перестать коллекционировать курсы (и начать делать)

Моя самая главная ошибка — «синдром хомяка». Я скачала, наверное, 50 ГБ курсов: "Python с нуля", "Python для чайников", "Python за 24 часа". Я смотрела первые два урока, чувствовала себя умной, а потом бросала, потому что "этот курс не очень".

Итог: Один хороший курс + практика лучше, чем 50 идеальных курсов в папке "Разобрать".
Сейчас, если бы я начинала, я бы выбрала один интерактивный ресурс (или одну книгу, если, конечно, сможешь так учится) и шла по нему, пока не упрусь в стену. Не прыгала бы между ютуберами и методичками.

2.Сначала гуглить, потом — паниковать

В начале пути любая ошибка в коде вызывала у меня панику. Красный трейсбек выглядел как приговор. Я думала: "Ну всё, я бездарь, Python меня ненавидит".

Итог: Ошибка — это не "я плохая", это "код говорит мне, что именно не так".
Сейчас 80% моей работы — это чтение ошибок и гугление.

3.Зубрежка синтаксиса не работает. Работают проекты

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

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

  • День 3: Калькулятор чаевых.

  • Неделя 2: Парсер курса валют с сайта (с помощью requests).

  • Месяц 1: Простенький телеграм-бот, который присылает погоду.

Проекты не обязаны быть гениальными. Они должны быть действительно интересные, даже захватывающие.

Если ультра-кратко:

  1. Лучше уж один источник знаний вместо "все сразу"

  2. Лучше практика каждый день по 30 минут, чем раз в неделю и до потери пульса

  3. Ошибки - это норм, не стрем

  4. С другом или ментором будем веселее и эффективнее - с кем можно поделится опытом или обсудить код и тд.

Спасибо за внимание, ваша Фаина!)

Теги:
Всего голосов 16: ↑15 и ↓1+16
Комментарии3

Какие уникальные фичи есть в django-modern-rest?

Иногда, когда я добавляю какие-то фичи в мой https://github.com/wemake-services/django-modern-rest (можно ставить ⭐), то я думаю про себя: почему таких фичей больше нет нигде? 

Давайте сегодня посмотрим на них. А вы мне расскажите свое мнение в комментах.

Семантическая схема 

Допустим, вы навесили на какой-то свой endpoint auth: 

class UserController(Controller[MsgspecSerializer]):
      @modify(auth=[JWTAsyncAuth()])
      async def get(self) -> User: ...

В OpenAPI автоматически появятся все коды ошибок, которые могут случиться в auth (401).
Ничего не надо допом писать. И так происходит со всеми частями фреймворка: добавил throttling=[SyncThrottle(1, Rate.minute)]? Теперь у тебя в ответах автоматом 429. Если нужно, можно отключить любые семантические статусы. 

Не должно ли такое быть дефолтом везде?

Умные типы ошибок

Не уходя далеко: как кастомизировать формат ошибки, например, в FastAPI? Через боль. Как поменять в спеке формат? Руками.

В DMR мы просто добавили везде error_model как параметр. Можно заменять любые ошибки, все автоматом сконвертится и покажет правильную схему. Зачем? Хочешь Problem Details - используешь. Хочешь свой формат - реализуешь. Можно даже content negotiation на ошибки навесить.

Почему никто о таком не думает в других фреймворках?

Нормальный throttling

Фича, которая принесла мне больше всех боли. Я прочитал throttling реализации во всех фреймворках. В Litestar даже фиксы присылал. 

1. Почти нигде из коробки нет поддержки разных алгоритмов, бекендов, иногда даже cache-keys. Очень жаль, есть только обычный counter с бекендом в памяти
2. Нигде (пришлите в комменты контр-пример) нет разделения на throttling до auth и после. Почему такое вообще важно? Чтобы не заддосить auth. И чтобы иметь возможность выдавать per-user правила. Нужны и важны оба варианта
3. Кастомизация заголовков ответа? Ха!

Что? Почему?

Простое переиспользование кода

Когда я смотрю на АПИ разных DRF проектов или FastAPI, мне становится больно. FastAPI строит все на view функциях, которые нельзя нормально кастомизировать. А DRF строит все на импортах строк внутри настроек. А как на счет классов и наследования?

У нас подобное сделано как абстрактные generic классы. Например: получить JWT. Можно выбрать любой сериализатор, можно выбрать любые модели для запроса и ответа:

class RequestPayload(pydantic.BaseModel):
     username: str
     password: str

class ResponsePayload(pydantic.BaseModel):
     access: str
     refresh: str

class ObtainAccessAndRefreshSyncController(
    ObtainTokensSyncController[
        PydanticSerializer,
        RequestPayload,
        ResponsePayload,
    ],
): ...  # надо еще переопределить 2 метода

Все типизировано, документировано, очевидно. 
Как вы думаете, почему так больше никто не делает?

Внешние вьюхи

Интегрировать один фреймворк в другой - крайне сложно. Вот мы недавно даже стрим проводили, потому что не могли использовать dj-rest-auth из DRF. Так быть не должно.

Теперь в DMR можно использовать любые внешние Django View. Хоть DRF, хоть django-ninja, хоть ванильные вьюхи. И отображать любой внешний OpenAPI. Вот настолько просто:

raw_schema = read_openapi_yaml('openapi.yml')
router = Router(
    urls=[
        external_path(
            'number/', number, name='number',
            openapi=load_schema(raw_schema['paths']['/api/number'], PathItem),
        ),
    ],
)

Почему другие фреймворки не стараются вписать существующие решения?

Одной строкой

- Больше подобного у меня в тегеграм канале "Находки в опенсорсе": https://t.me/opensource_findings
- У нас есть еще куча других крутых фичей! Заглядывайте в наш чатик по DMR
- Релизнули django-stubs@6.1 с поддержкой django@6.1
- Сделали папку с крутыми каналами ребят из нашего Python сообщества. Смело можно закидывать коллегам как базовую папку "на кого подписаться в тг по питону". Внутри все мои друзья и коллеги, советую!

Теги:
Всего голосов 10: ↑9 и ↓1+10
Комментарии2

Совет по Joomla: Как сделать ссылки на списки сущностей Joomla с фильтрацией?

Стандартная форма фильтрации в админке Joomlа
Стандартная форма фильтрации в админке Joomlа

В Joomla в любом списке сущностей есть параметры поиска, которыми мы привыкли пользоваться руками в админке. Но что если вам нужно сделать ссылку на список в админке с заранее заданными параметрами фильтрации?

Например:

  • разработчик хочет дать ссылку на плагин для быстрого перехода к настройкам;

  • разработчик хочет в документации для контент-менеджера дать ссылку на нужные модули, плагины, о которых идёт речь;

Админка Joomla поддерживает фильтры в URL-адресе, а названия GET-параметров для фильтрации можно посмотреть в названиях полей фильтров админки.

Например, в списке плагинов поле фильтра:

  • выбор состояния - filter[enabled]=1 или 0

  • выбор типа (группа плагинов) - filter[folder]={название группы плагина, например content или system}

  • element плагина (уникальное систеное имя) - filter[element]={element}

  • уровень доступа, с которым работает плагин - filter[access]={числовой-код-уровня-доступа}

  • строка поиска - filter[search]={любой%20текст%20для%20поиска}

Таким образом, чтобы дать ссылку на свой плагин в админке можно сделать следующий url:

https://your-joomla-site.ru/administrator/index.php?option=com_plugins&view=plugins&filter[element]=wtotpravkapochtaru&filter[folder]=system

Аналогичным образом работает список модулей, контактов, материалов и т.д. Найти имена параметров можно либо в HTML-коде страницы, либо в XML-форме опций фильтра нужного компонента. Для списка плагинов используется компонент com_plugins, а форма фильтра лежит в administrator/components/com_plugins/forms/filter_plugins.xml. Для списка материалов Joomla - в administrator/components/com_content/forms/filter_articles.xml. Другие компоненты - ищем по анналогии.

Чат русскоязычного Joomla-сообщества в Telegram и в Max.

Теги:
Всего голосов 1: ↑1 и ↓0+3
Комментарии0
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. Предлагаю не гадать по стилю прозы, а склонировать к себе и прогнать нейронкой глубоко, очень глубоко. И приглашаю на дискуссию: если найдёте что-то, что выглядит как архитектурное решение именно от модели, а не от человека, который держит всю систему в голове годами с удовольствием обсужу предметно.

Теги:
Всего голосов 5: ↑4 и ↓1+5
Комментарии0

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

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

Что дано:

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

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

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

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

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

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

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

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

Теги:
Всего голосов 6: ↑1 и ↓5-2
Комментарии3

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

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

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

— IntelliJ idea

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

— GitLab

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

— Redis

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

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

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

— Spring Boot

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

— Docker

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

— JUnit

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

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

Теги:
Всего голосов 3: ↑2 и ↓1+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

Теги:
Всего голосов 3: ↑2 и ↓1+3
Комментарии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 #Импортозамещение

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

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

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

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

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

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

Теги:
Всего голосов 5: ↑5 и ↓0+7
Комментарии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_long, valuestring, valuedatetime, valueguid, …), внешними ключами и обычными индексами.

  • Связь и порядок — реляционные. Вложенность собирается self-reference колонкой arrayparent_id (FK на values.id, ON 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: types → schemes → structures → values.

Ссылки

Теги:
Всего голосов 2: ↑2 и ↓0+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

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

Теги:
Всего голосов 9: ↑7 и ↓2+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: ↑4 и ↓2+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

хабр

Теги:
Всего голосов 2: ↑2 и ↓0+5
Комментарии0

ElegantGPT

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

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

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

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

Теги:
Всего голосов 1: ↑1 и ↓0+3
Комментарии1

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

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

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

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

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

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

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

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

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

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

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

Теги:
Всего голосов 16: ↑11 и ↓5+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 с поддержкой новых языков.

Теги:
Всего голосов 2: ↑2 и ↓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);

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

Теги:
Всего голосов 6: ↑6 и ↓0+11
Комментарии2