惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Engineering at Meta
Engineering at Meta
人人都是产品经理
人人都是产品经理
大猫的无限游戏
大猫的无限游戏
博客园 - 三生石上(FineUI控件)
量子位
腾讯CDC
The Cloudflare Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
云风的 BLOG
云风的 BLOG
Vercel News
Vercel News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
The Hacker News
The Hacker News
T
The Exploit Database - CXSecurity.com
B
Blog
S
SegmentFault 最新的问题
P
Privacy & Cybersecurity Law Blog
T
Threatpost
博客园 - 聂微东
T
Tailwind CSS Blog
The Last Watchdog
The Last Watchdog
C
Check Point Blog
N
Netflix TechBlog - Medium
D
DataBreaches.Net
爱范儿
爱范儿
IT之家
IT之家
S
Secure Thoughts
M
MIT News - Artificial intelligence
NISL@THU
NISL@THU
C
Cisco Blogs
TaoSecurity Blog
TaoSecurity Blog
有赞技术团队
有赞技术团队
A
Arctic Wolf
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
P
Proofpoint News Feed
Spread Privacy
Spread Privacy
Schneier on Security
Schneier on Security
Simon Willison's Weblog
Simon Willison's Weblog
G
GRAHAM CLULEY
雷峰网
雷峰网
Project Zero
Project Zero
博客园 - Franky
H
Heimdal Security Blog
A
About on SuperTechFans
Security Latest
Security Latest
Webroot Blog
Webroot Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Hugging Face - Blog
Hugging Face - Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
В поисках универсального SDK…
AlexGV · 2026-06-19 · via Все публикации подряд на Хабре

Средний

8 мин

42

Привет Хабр!

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

Цель статьи — показать проблемы при разработке SDK и найти попробовать архитектуру, которая минимизирует проблемы управления памятью, упрощает биндинги для разных языков и сохраняет производительность.

В этой статье мы порассуждаем о поиске некоего «универсального» SDK (Software Development Kit), который бы всем нравился, как новогодняя ёлка.

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

И так, поехали «кушать кактус по частям...»

Для начала нужно определиться с требованиями. Чего вообще мы тут будем делать?

Требования SDK:
 — должен использоваться разработчиками на разных языках программирования (java,.net, swift, kotlin, c++, python).
 — должен быть кросс‑платформенный (Linux, Window, MacOS, iOS, Android).
 — не содержит GUI элементов.
 — должен иметь не большой размер.
 — должен быть максимальной простой и понятный в использовании.
 — не использовать проприетарные зависимости без исходников
 — ограничимся 64-битными платформами.

Исходя из таких требований попробуем определить стек нужных нам технологий. Понятно, что это должна быть библиотека, которая собирается под все нужные платформы и у неё должен быть интерфейс, который позволит подключить её в любом языке программирования. И тут к нам приходит С. СИ интерфейс и простые типы дают нам возможность интегрироваться со всеми языками. А вот внутренности мы будем писать на С++. Очень хочется С++20, к сожалению, не на всех платформах пока он поддерживается полностью. Но мы же хотим его!
И в наших требованиях нет указаний на минимальные версии библиотек. Пока будем ориентироваться на 20 стандарт и постараемся избегать возможностей, которые ещё не дошли, например до clang на macos\ios. В связи с тем, что часто бывают проблемы со сборкой зависимостей или поиском готовых бинарей для разных платформ мы возьмём vcpkg, в качестве менеджера пакетов и будем собирать зависимости из исходников и, если нужно, патчить.

Технический стек

С — интерфейс. С++, Cmake, vcpkg, gcc\сlang\msvc, Android NDK/ SDK,Linux host,MacOS host,Windows host (без этого можно обойтись, но он очень полезен)

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

Ограничения

Нам нужно будет ограничить версию рантаймов или таскать их с собой, что делать не хотелось бы.

Ну что... с тем, что нужно вроде определились. Давайте теперь думать над внешним интерфейсом нашего SDK.

Варианты интерфейса

Конечно же это СИ интерфейс! А как мы его организуем? Кто будет аллоцировать и освобождать память? А как сделать так, чтобы разработчики на высокоуровневых языках не сошли с ума при написании очередного враппера для СИ?

Вариант 1:

А давайте просто сделаем методы где память аллоцирует и освобождает SDK!

int getData(const char* key, uint8_t data, uint64_t size);
freeData(data);

И получим на каждый возвращаемый параметр метод free. А там ещё структуры с кучей вложенных параметров.... А если разработчик, который привыкли к GC (garbage collector) не вызовет free? А потом разработчики SDK будут разбирать претензии с падениями и утечкой памяти. Неее... давай думать ещё.

Вариант 2: Ну ок, тогда пускай сами память аллоцируют, а мы будем заполнять данным. Ну как в winapi? Напишем об этом в комментариях.int getData(const char key, uint8_t data, uint64_t *size);

Чтобы узнать размер выходного буфера придётся сначала вызвать getData с пустым буфером, который вернёт размер. Аллоцировать буфер и потом уже вызвать ещё раз getData для получения данных. И после этого у разработчиков на языках с GC начинается боль с трем, чтобы переменные умирали, когда надо и не вызывали sigfault. А если нужно сохранять контекст и передавать его в разные методы? А ещё нужно читать комментарии, чтобы понять, что нужно 2 раза вызвать функцию.

Вариант 3:

А что если сделать хитро, через дескрипторы? Выделять память в SDK и сделать функции free,но не всё подряд возвращаемых структур и параметров, а на дескрипторы? И доступ к полям структур тоже через отдельные методы дескриптора. Дескриптором будет void* в внутри это структура с std::shared_ptr<>. И мы будем её туда сюда кастить. А чтобы нам не передали мусор добавим magic_field и будем его проверять. А ещё нужно возвращать не только код ошибки, а строку!

/// sdk.h
typedef struct Error
{
uint32_t code;
char description[1024];
}

int CreateContext(sdk_descriptor* d, Error* e);
int getData(sdk_descriptor d, const char* key, data_descriptor* out, Error* e);
freeSDKaDescriptor(sdk_descriptor d);
freeDataDescriptor(data_descriptor d);

/// data_descriptor.h
int GetSizeData(uint64_t* size, Error* e);
int GetData(uint64_t* buff, uint64_t size, Error* e);
и тд...

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

НО! Ещё мы получили огромную кучу методов и различных хедеров. Отдельный метод на каждый параметр структуры. По 2 метода, чтобы получить строку. И ещё кучу вопросов от пользователей SDK, где искать нужный метод. И документацию на десятки страниц.
Формально оно всё работает и соответствует требованиям, но мы вроде не хотели такое?

Вариант 4:

Неее столько методов это всё очень не удобно, особенно в серверной версии с многопоточкой.
А давайте сделаем 2 метода и будем туда передавать JSON.

int get(const char* json_in, uint64_t size_in, const char** json_out, uint64_t* size_out, Error* e);
free(const char* json_out);

Всего 2 метода и они никогда не поменяются! Просто будем описывать новые параметры в json. И враперы писать удобно! Конечно мы в производительности сильно проиграем на парсинге и валидации и копировании этого json, а ещё надо документацию на все эти параметры и ещё надо её держать актуальной. А ещё бинарные буферы преобразовывать в base64, а ещё с кодировкой и utf8 что‑то надо подумать. Простота интерфейса — это хорошо, но у нас же С++ и нужно чтобы всё было быстро.

Вариант 5:

Так.... 2 метода это выглядит круто, нужно только избавить от json... Точно! Есть же thrift, protobuf может их? У них другое предназначение (RPC), но идею хорошая.
Давай возьмём FlatBuffer! Он Идеально подходит! Всё описание будет в формате FlatBuffer. Он бинарный, и с минимумом копирований (zero‑copy). Он умеет генерить код для всех нужных языков программирования и поддерживает все платформы. Всё описание будет структурировано и распространяется вместе с SDК. Мы получаем обратную совместимость и логирование из коробки. Кажется мы нашли то, что искали!

// in.fbs
table GetData {
key:string;
}

// out.fbs
table Data {
data:string;
value:int32;
....
}

/// sdk.h
int get(const char* data_in, uint64_t size_in, const char** data_out, uint64_t* size_out, Error* e);
free(const char* data_out);

А можно вообще без free? А что если мы будем возвращать указатель на память, которую будем переиспользовать постоянно для запросов и удалим только при выгрузке библиотеки?
Тогда не нужно делать free? FlatBuffer позволяет без копирований получить итоговый буфер, то есть будем хранить вот такое:
static thread local DetachBuffer
и он сам уничтожится в конце. Вообще замечательно 1 метод!

Только появляется проблема того, что мы это всё будем держать в памяти каждого потока, а если это «горячие» потоки и они живут до конца программы? Память, то не резиновая...
А если кто‑то сохранит указатель и вызовет метод get ещё раз? Или передаст в лямбду std::async? В общем и тут могут быть проблемы.

Получается метод free нужно вызывать после каждого вызова get. Если пользователь не вызовет free, память не будет потеряна безвозвратно, но будут вышеописанные проблемы. Внутри free мы не будем делать delete указателя, а будем делать swap текущего DetachBuffer с пустым.

Тут могут быть разные мнения на, то можно ли так делать в многопоточных приложения. Надежнее возвращать копию буфера и потом его очищать, но задача была максимально сократить копирование, поэтому оставим так, но укажем в документации на необходимость вызова free. И рекомендации использовать RAII.

В итоге нам удалось сделать максимально простой и легко расширяемый интерфейс, который легко встраивается в другие языки программирования. Мы максимально избежали копирования и проблем с аллокацией памяти. Получили готовое решение для сериализации/десериализации данных, удобный механизм отладки и анализа данных через преобразование FlatBuffers в текстовое представление (FlatBufferToString), кодогенерацию, избежали проблем с кодировками при передаче данных. FlatBuffers предоставляет механизмы для эволюции схемы и позволяет относительно безопасно добавлять новые поля без нарушения совместимости. Метод free не освобождает память операционной системе. Он лишь очищает внутренний буфер и позволяет переиспользовать его при следующих вызовах.

Что ещё можно улучшить?

А если добавить AI? Зачем? А кто будет делать примеры на кучи разных языков и документацию? Doxygen — прошлый век. Берём AI агента и просим всё это сделать. Идеально!

Мы получили быстрый расширяемый, достаточно универсальный SDK с примерами под разные языки, документацией и тестами, но с зависимостью от FlatBuffers.

// in.fbs
table GetData { key:string;}

// out.fbs
table Data { data:string; value:int32; ....}

/// sdk.h
int get(const char* data_in, uint64_t size_in, const char** data_out, uint64_t* size_out, Error* e); free(const char* data_out);

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

Решение

Zero Copy

Кодогенерация

Удобство

Размер

Чистый C

Возможно

Нет

Нет

Малый

JSON

Нет

Нет

Частично

Большой

Protobuf (RPC)

Частично

Да

Да

Средний

FlatBuffers

Да

Да

Да

Малый

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

По сути мы пришли к модели, напоминающей локальный RPC. Разница в том, что взаимодействие остаётся внутрипроцессным и не требует создания сокетов.

Давайте теперь актуализируем наш стек.

Технический стек
С — интерфейс,
С++,
Cmake,
vcpkg,
FlatBuffer,
gcc\сlang\msvc,
Android NDK/ SDK,
Linux host,
MacOS host,
Windows host
+ то, что зависит от функционала SDK (boost, nlohman, soci, curl и тд)
Можно использовать кросс‑компиляцию, но для проверки лучше иметь «живые» целевые ОС.

В результате мы пришли к выводу, что самая сложная часть SDK — это не алгоритмы и не бизнес‑логика, а границы между языками, управление памятью и совместимость между платформами. FlatBuffers не решает все проблемы, но позволяет существенно сократить объём инфраструктурного кода и сделать интерфейс SDK более предсказуемым для разработчиков на разных языках.

Если вы добрались до этого места, то теперь вы осознаёте боль разработчиков SDK.
Тут ещё не учтены огромное количество проблем при сборки под все эти платформы, разные разрядности x86 \ x64, различия версий рантаймов, проблемы видимости символов при встраивании SDK. Ну, а если в SDK есть GUI (например Qt), то это уже другая не универсальная история...

Надеюсь, Вам было интересно и не очень скучно!