CMake: модульная архитектура для большого C++ проекта — без ad-hoc include путей
Как мы реорганизовали CMake-структуру проекта на 15+ модулей, избавились от хаотичных include_directories и перешли на современный CMake с target-based зависимостями.
Заметки о веб-разработке, архитектуре, оптимизации и инструментах. Пишу о том с чем сталкиваюсь в реальных проектах.
статей
категорий
минут на чтение
Обновляете товар через API, передаете SECTION_ID, но он не появляется в нужной папке. В этой статье я объясняю разницу между простым SECTION_ID и сложным деревом инфоблоков, как правильно выстроить иерархию и почему метод crm.product.update не умеет создавать папки.
Читать статьюКак мы реорганизовали CMake-структуру проекта на 15+ модулей, избавились от хаотичных include_directories и перешли на современный CMake с target-based зависимостями.
Как мы построили сервер видеотранскодинга на Kotlin REST API + C++ FFmpeg через JNI. Прокачка JNI_OnLoad, передача фреймов через DirectByteBuffer, обработка ошибок и бенчмарки.
Разбираем многопоточность в C++ на реальных примерах из продакшена: мьютексы, lock_guard, unique_lock, std::atomic, deadlock-ы и как их избежать. Сравнение с корутинами Kotlin.
Как мы внедрили eBPF для профилирования высоконагруженных C++ и Kotlin сервисов в продакшене без остановки и перекомпиляции. Реальные скрипты bpftrace, поиск утечек памяти и трейсинг JVM-системных вызовов.
Создаём MVC-компонент для Joomla с чистой архитектурой, современным подходом к моделям и видам — без копипаста из документации 2014 года.
Как мы оптимизировали локальное окружение из 10+ микросервисов с помощью Docker Compose, multi-stage Dockerfile и правильных health checks.
Сравниваем Terraform на HCL и Pulumi на Kotlin для управления Kubernetes-инфраструктурой — с реальными примерами кода, болью миграции и нашим итоговым выбором.
Как мы автоматизировали воронку сделок в Битрикс24 с помощью бизнес-процессов и роботов — реальный кейс с SLA, автоназначением ответственных и мониторингом сбоев.
Сравниваю Micronaut и Spring Boot для Kotlin-микросервисов: стартовое время, потребление памяти, холодный старт и реальный опыт миграции одного из сервисов.
Как sealed interfaces из Kotlin 1.5+ вместе с when-выражениями дают мощный паттерн-матчинг, похожий на Rust enum+match, и почему мы перешли на ADT для доменных событий.
Разбираюсь с накладными расходами JSON-сериализации при высоких нагрузках и показываю, как интегрировать Protobuf с kotlinx-serialization в микросервисной архитектуре на Kotlin.
Реальный опыт использования gRPC streaming в продакшене на Kotlin: server-side, client-side и bidirectional стриминг для системы отслеживания статусов заказов в реальном времени.
Как мы ускорили обработку логов на 40x с помощью mmap. Практическое руководство с бенчмарками, подводными камнями и сравнением с std::ifstream.
Честный разбор фич C++17 и C++20: что мы взяли в проект, что пропустили и почему. Before/after примеры и компромиссы миграции.
Разбираю unique_ptr, shared_ptr и weak_ptr на реальных примерах из продакшена. Какие баги мы ловили из-за неправильного использования и как перестать путаться с ownership.
Реальный опыт использования корутин C++20 и Kotlin Coroutines в одном проекте. Разбираю механику работы, отличия в обработке ошибок и когда стоит брать сложность C++ корутин.
Три подхода к передаче сложных данных через JNI: примитивное выравнивание, JSON-сериализация и ByteBuffer. Бенчмарки, код и рекомендации из продакшена.
Подробный разбор сборочной цепочки C++ библиотеки для Kotlin/JNI. Структура проекта, кросс-компиляция под Android, линковка сторонних библиотек и типичные ошибки сборки.
Разбираю альтернативу JNI — Kotlin Native cinterop. Прямой вызов C-функций без JVM, бенчмарки против JNI и практические рекомендации, когда какой подход выбрать.
Практический гайд по вызову C++ кода из Kotlin через JNI. Разбираю настройку, передачу типов, управление памятью и реальные продакшен-паттерны на опыте бэкенд-разработчика.
Нужна была real-time уведомления для дашборда. Выбор: SSE или WebSockets? SSE проще (односторонний, HTTP, автопереподключение), WebSockets мощнее (двусторонний). Для уведомлений хватило SSE, но для чата понадобились WebSockets. Рассказываю, как реализовать оба в Ktor и в каких случаях что выбирать.
Для интеграции WordPress с мобильным приложением понадобилось создать кастомные REST-эндпоинты. Плагины типа ACF to REST API не подходили — нужна была специфическая логика: фильтрация по пользовательским полям, пагинация, кэширование. Сделали всё через register_rest_route и шорткоды — без единого плагина.
MODX Revolution позволяет писать кастомные процессоры для любой логики, но большинство разработчиков превращают их в спагетти-код с прямыми SQL-запросами. Мы выстроили архитектуру на основе xPDO-моделей, кастомных процессоров с валидацией и отдельного слоя репозиториев. Результат: поддержка проекта перестала быть кошмаром.
Выбор инструмента миграций — кажется мелочью, пока не нужно откатить изменение в продакшене. Flyway — простой SQL-first подход. Liquibase — XML/YAML/JSON с абстракциями и rollback. Мы использовали оба в разных проектах и набили шишки на каждом. Рассказываю, в каком случае что выбрать и как не потерять данные при rollback.
Сайт на PHP + Nginx выдерживал 500 RPS, а при 1000 начинал отдавать 502. Проблема была не в PHP-коде (он был оптимизирован), а в конфигурации Nginx и PHP-FPM: неправильный worker_connections, отсутствие keepalive к upstream, слишком маленький pm.max_children. Рассказываю пошагово, как мы увеличили пропускную способность в 10 раз.
Сборка Kotlin-проекта занимала 6 минут. После включения build cache, configuration cache и перехода на configuration avoidance API — 45 секунд. Рассказываю, что именно мы сделали, почему большинство туториалов по ускорению Gradle не работают, и как измерять реальный эффект от каждой оптимизации.
Переносили CI/CD с GitLab на GitHub Actions. Обе системы решают одни задачи, но подход к кэшированию, параллелизму и reuse workflows принципиально разный. В GitLab всё построено вокруг .gitlab-ci.yml и runners. В GitHub Actions — вокруг reusable workflows и marketplace actions. Рассказываю, что лучше для Kotlin-проекта с тестами, Docker-образами и деплоем в Kubernetes.
Микросервис работал нормально, но Kubernetes периодически убирал его из балансировщика. Пользователи видели 503. Оказалось, readiness probe проверял подключение к PostgreSQL, и при кратковременных просадках БД (backup, vacuum) сервис становился «не готовым». Рассказываю, как правильно настроить health checks в Kubernetes, чтобы не терять трафик из-за сторонних проблем.
HikariCP — пул подключений по умолчанию в Spring Boot и Ktor. На первый взгляд — configure and forget. На практике — неправильный размер пула убивает производительность, leak detection срабатывает с ложными позитивами, а connection timeout в Kubernetes приводит к каскадным сбоям. Рассказываю, как мы настраивали HikariCP для продакшена и что пошло не так.
Event Sourcing звучит элегантно: храним не текущее состояние, а все события, которые к нему привели. На практике — это другая архитектура мышления, другая модель данных и куча новых проблем: eventual consistency, snapshotting, replay событий. Рассказываю, как мы внедрили Event Sourcing в Kotlin-микросервисе с Kafka и чему научились на ошибках.
У нас был REST API с 30 endpoint'ами. Фронтенд постоянно просил добавить поля, убрать лишнее, объединить запросы. Перевели один микросервис на GraphQL (graphql-kotlin) и получили: фронтенд запрашивает только нужные данные, один запрос вместо 5-7, меньше нагрузки на сеть. Но появились свои проблемы: N+1 в резолверах, сложность кэширования, versioning.
В микросервисной архитектуре с 12 сервисами запрос проходит через 4-5 сервисов. Когда что-то тормозит — непонятно где. Добавили OpenTelemetry: теперь каждый запрос имеет trace ID, и мы видим полную цепочку вызовов с таймингами. Рассказываю, как настроить OpenTelemetry в Kotlin-микросервисе на Ktor и Spring Boot без боли.
Стандартный php artisan queue:work работает, но когда у тебя 15 очередей, 3 приоритета и периодические зависания jobs — ты слеп. Нет мониторинга, нет метрик, нет понимания, что происходит. Laravel Horizon добавляет дашборд, retry-логику и автоматический масштабирование worker'ов. Перешли и наконец увидели, что происходит с нашими очередями.
Страница каталога загружалась 8 секунд. В профайлере — 340 SQL-запросов для отображения 20 товаров. Классический N+1 через Doctrine ORM. Проблема усугублялась тем, что часть запросов шла через lazy loading, а часть — через явные вызовы в Twig-шаблонах. Рассказываю, как мы нашли все источники N+1 и сократили количество запросов до 4.
Каждый релиз PHP приносит новые фичи, но не все из них попадают в реальный код. В PHP 8.4 есть несколько изменений, которые мы сразу внедрили в проект: property hooks упростили геттеры/сеттеры, new MyClass() без скобок, и улучшенный array_find. Рассказываю, что реально пригодилось, а что оказалось маркетингом.
Обычный crm.deal.list возвращает 50 элементов. Для синхронизации 10 000 сделок нужно 200 запросов — и это при условии, что ни один не упадёт по таймауту. Batch-метод Битрикс24 позволяет отправить до 50 команд в одном запросе, но у него свои подводные камни: лимит на размер запроса, ошибки частичной обработки и полное отсутствие транзакционности.
Try-catch по всему коду — это антипаттерн, но альтернативы кажутся сложными. Arrow.kt предлагает Either, Raise, и ValidationError для типобезопасной обработки ошибок. Перешли на функциональный подход в микросервисе с 40+ endpoint'ами и код стал предсказуемым. Показываю реальный до/после.
Время сборки Kotlin-проекта выросло с 30 секунд до 4 минут. Причина — kapt и annotation processing. KSP (Kotlin Symbol Processing) призван это исправить, но миграция не тривиальна. Рассказываю, как мы ускорили сборку в 5 раз, заменив kapt на KSP в реальном проекте с Room, Moshi и Dagger.
JUnit 5 — стандарт де-факто, но Kotest предлагает Kotlin-native подход: data-driven тесты, поведение через BehaviorSpec, встроенные assertions. Перешли на Kotest в проекте со 1800 тестами и не пожалели. Но есть подводные камни, о которых молчат туториалы.
При росте микросервисной архитектуры встал вопрос: Kafka или RabbitMQ? Оба брокера используются в Kotlin-экосистеме, но выбор между ними — это не про «какой лучше», а про «какая проблема у вас». Рассказываю на опыте реального проекта, где мы переписали messaging-слой с RabbitMQ на Kafka и что из этого вышло.
Dependency injection — фундамент архитектуры. Koin — лёгкий, на чистом Kotlin, без кодогенерации. Dagger/Hilt — compile-time, от Google, промышленный стандарт. Сравниваю скорость компиляции, runtime overhead, DX и реальный опыт миграции с одного на другой на проекте с 150 зависимостями.
REST — привычный, универсальный, работает через JSON. gRPC — бинарный протокол, контракты через Protobuf, стриминг из коробки. На реальном проекте с 12 микросервисами сравниваю latency, размер полезной нагрузки, DX и почему выбор протокола зависит не только от производительности.
Мокать PostgreSQL в тестах — путь к ложной уверенности. Testcontainers поднимает настоящие контейнеры с БД, Redis, Kafka — и убивает после теста. В статье разбираю настройку Testcontainers с Ktor, Exposed, Flyway, совместное использование тестовых баз данных и ускорение тестов в CI/CD.
Redis — не просто key-value хранилище. Pub/Sub, Streams, Sorted Sets, Lua-скрипты — Redis позволяет реализовать сложные паттерны кэширования и event sourcing. Разбираю Cache-Aside, Write-Through, Write-Behind, паттерн Cache Stampede и реальный опыт оптимизации задержки с 80 мс до 5 мс.
Логирование — первая линия расследования при P0-инцидентах. Но в Kotlin есть нюансы: string interpolation, ленивые вычисления, структурированное логирование, correlation ID. Сравниваю klogging, SLF4J + Logback, Kotlin Logging и объясняю, почему формат логов важнее библиотеки.
Добавили кастомное поле в заказ WooCommerce через REST API — поле в админке видно, а в письме покупателя его нет. Знакомая ситуация? Разбираю, почему WooCommerce email-шаблоны игнорируют произвольные поля заказа, и показываю три способа заставить их отображаться без копипаста шаблонов.
Все гайды по Gutenberg-блокам заставляют писать React и собирать через wp-scripts. Но что если вы backend-разработчик и не хотите тащить node_modules в проект? В WordPress 5.9+ появилась возможность регистрировать серверные блоки полностью на PHP. Разбираю этот подход.
На портале Битрикс24 можно создать максимум 2000 входящих вебхуков. Но мало кто знает, что каждый вебхук обрабатывает максимум 1000 событий в очереди. Если ваша интеграция не успевает — события удаляются. Рассказываю, как мы обнаружили потерю данных и построили систему надёжной обработки.
Базовый Dockerfile для Spring Boot на Kotlin — 800 МБ. После оптимизации — 50 МБ. Разбираю multi-stage builds, GraalVM native image, Alpine vs distroless, jlink для кастомной JRE и реальные метрики по времени сборки, cold start и memory footprint.
Строгая типизация в PHP 8.2+ отличная, но реальный код завален mixed и array. Как я вёл постепенную миграцию большого PHP-монолита на строгие типы, какие инструменты использовал для автоматического анализа, и почему array — это худший тип, который можно прописать в сигнатуре метода.
Hibernate/JPA — не единственный вариант. В Kotlin-мире есть Exposed от JetBrains и jOOQ от Data Geekery. Обе библиотеки дают типобезопасный SQL без ORM-магии. Сравниваю DX, производительность, миграции и реальный опыт на проекте с 80 таблицами.
Поставили задачу обновить 15 000 цен в OpenCart 3 из внешней ERP-системы. Простой цикл по товарам убил сервер на 3-й минуте. В этой статье рассказываю, почему модель OpenCart требует очистки кэша после каждого сохранения, как использовать batch-запросы к базе, и почему индексы — ваш лучший друг при массовом обновлении.
Сайт на MODX Revolution ест по 128MB RAM на каждую страницу — это не норма. Разбираю, почему getCollection с большими выборками убивает память, как правильно использовать xPDO для постраничной загрузки данных, и почему простой сниппет вывода ресурсов может съесть весь сервер.
Создал кастомное поле для com_content в Joomla 4, значение сохраняется в админке, но при выводе на фронтенде — null. Оказалось, Joomla кэширует вывод модулей и плагинов, а кастомные поля в кэш не попадают. Разбираю, как работает система кэширования кастомных полей и как правильно получать их значения в overrides.
Корутины и Reactor — две парадигмы асинхронного программирования. Корутины выглядят как синхронный код, Reactor — как цепочка операторов. В статье разбираю когда какая модель выигрывает, как они соотносятся по производительности и почему выбор фреймворка уже определил ваш стек.
Запустил queue:work на production с --tries=0 — и все джобы начали падать в бесконечный цикл, забивая Redis на 100%. В этой статье разбираю, как работает retry-механизм в Laravel, чем отличаются backoff-стратегии, и почему supervisor не спасает от переполнения очередей.
Два фреймворка, два мира. Spring Boot — монолит экосистемы с тысячей стартёров и аннотаций. Ktor — лёгкий, корутин-нативный фреймворк от JetBrains. Сравниваю DX, производительность, время старта и реальный опыт миграции с одного на другой.
Когда я впервые увидел слово suspend перед функцией в Kotlin, я был уверен, что это какая-то магия компилятора. Оказалось, что за этим стоит принципиально иной подход к асинхронности. В этой статье разбираю, как работают корутины под капотом, зачем нужен Continuation, и почему State Machine — это не страшный монстр, а ваш друг.
Обе библиотеки решают одну задачу — превращают JSON в объекты и обратно. Но разница в подходах колоссальная. Moshi использует рефлексию в рантайме, kotlinx — компиляторный плагин. В статье сравниваю производительность, DX и грабли каждой библиотеки на реальном проекте.
Flow — это реактивные потоки Kotlin, но с корутин-нативным подходом. В статье разбираю горячие и холодные потоки, SharedFlow, StateFlow, backpressure, error handling и реальный опыт использования Flow в production на нагрузке 50K rps.
Я занимаюсь Android-разработкой, и через мои руки прошло немало приложений, где рано или поздно вставал вопрос: а не завезти ли нам виджет? Пользователи просили, продакты настаивали, метрики показывали, что конкуренты с виджетами имеют Retention на 20-30% выше. И каждый раз я откладывал эту задачу в бэклог с пометкой «когда-нибудь потом».
Как удалить значение из кастомного поля сделки в Битрикс24? Казалось бы, передай пустую строку. Но не тут-то было! В этой статье я рассказываю, почему метод crm.deal.update игнорирует пустые строки, как работает механизм очистки полей под капотом, и почему передача null — это не всегда правильное решение для списков.
При разработке одного из проектов на WordPress с использованием конструктора туров TourMaster передо мной встала задача: связать каждый день тура с конкретным партнёром, а затем синхронизировать эти данные с CRM системой Bitrix24. В этой статье я расскажу, как мне удалось решить эту задачу, не модифицируя исходный код плагина.
Вы дергаете Битрикс из 1С через входящий вебхук (строку с секретом в URL)? Это огромная дыра в безопасности и архитектурная ошибка. Рассказываю, чем входящий вебхук отличается от OAuth, почему у него нет прав на новые сущности, и как правильно переписать коннектор.
Создали контакт через API, создали сделку, передали CONTACT_ID в полях, а они не связаны в карточке! Разбираю, почему передача CONTACT_ID при создании сделки работает криво, если контакта секунду назад не было в Битрикс24, и как правильно использовать метод crm.deal.contact.add.
Как назначить партнёра туру в Битрикс24, если фронтенд присылает только текст, а REST API требует числовой ID? В этой статье я разбираю свой боевой PHP-скрипт: от вытягивания справочников enum до реализации нечеткого поиска подстрок и борьбы с «молчащими» ошибками метода crm.product.update. Реальный код, паранойя с логированием и обходные пути для неидеальных данных.