Обновить
128K+

Проектирование и рефакторинг *

Реорганизация кода

65,42
Рейтинг
Сначала показывать
Порог рейтинга
Уровень сложности

Пять дней ожидания: опыт длинных временных окон Kafka stream

Уровень сложностиСредний
Время на прочтение11 мин
Охват и читатели8.7K

Иногда бизнес-логика выглядит просто: «соберём все данные за период и посчитаем итоговый результат». На практике этот период может оказаться не часом и даже не днём, а несколькими сутками. В одном из моих проектов требовалось построить агрегаты на основе данных, которые могли поступать в течение пяти дней.

В литературе мы встретили концепцию временных окон (Time Windows). По описанию это выглядело именно тем инструментом, который должен решить задачу: определить период ожидания, дождаться всех необходимых данных и получить итоговый агрегат.

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

Узнать больше

Новости

Вам не нужны микросервисы

Уровень сложностиПростой
Время на прочтение12 мин
Охват и читатели11K

Какое‑то время назад, проработав 3 года на позиции Java Middle+‑ разработчика на крупном монолитном легаси‑проекте (естественно, модульном), я столкнулся с тем, что не имел практики в создании приложений на микросервисной архитектуре. При этом я понимал, что работа с микросервисами — это работа с актуальным стеком технологий в мире Java. И если ты не работаешь с микросервисами, то ты вроде как не имеешь необходимой квалификации для большинства вакансий на рынке труда. По крайней мере, если судить по самим вакансиям.

Поэтому я решил, что мне нужен какой‑то достаточно крупный проект, который бы дал мне основные практические навыки работы с микросервисами. Это должен был быть проект, выходящий за рамки пет‑проекта с животными или чего‑то подобного. При этом, отработав на Java более трех лет, я уже хотел сделать что‑то свое, разработать архитектуру с самого начала. Думаю, это нормальное желание для мидл‑программиста, который хочет развиваться в своей сфере.

Читать далее

Нефункциональные требования: 5 ошибок, которые всплывут в проде

Уровень сложностиСредний
Время на прочтение12 мин
Охват и читатели11K

Система прошла приёмку, но первая реальная нагрузка разогнала p99, исчерпала пул соединений и увеличила счёт за облако.

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

Читать далее

Устав и летопись кодинг-агентов

Уровень сложностиСредний
Время на прочтение6 мин
Охват и читатели7.2K

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

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

Читать далее

Отказ — это событие, а не статус: как мы перепроектировали модель данных исполнительного производства

Уровень сложностиСредний
Время на прочтение7 мин
Охват и читатели7.2K

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

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

Внутри: почему спор «отказ - статус или событие» решил один запрос к проду, три мины Mongoose, найденные на ревью, и регрессия, прилетевшая через двадцать часов после релиза.

Читать далее

Как я сделал старый монолит на Laravel 8 — модульным, чтобы не плодить форки под каждого клиента

Уровень сложностиСредний
Время на прочтение8 мин
Охват и читатели8.1K

Изначально это был монолитный портал на Laravel 8, где user фронт и admin фронт лежали рядом с беком в одной папке. 

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

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

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

Поэтому, когда появилось время, я занялся этим проектом. Сразу поставил рамку, фреймворк не меняю, остаёмся на Laravel 8. Хотелось не переходить на другой язык, не заниматься переписыванием всего огромного бека, отделить всё в модули и переписывать уже поэтапно отдельные куски.

Читать далее

Правила программирования Роба Пайка

Уровень сложностиПростой
Время на прочтение10 мин
Охват и читатели22K

В этой рубрике мы уже рассказывали про Кена Томпсона и Денниса Ритчи, соавторов Unix, UTF-8 и операционной системы Plan 9. Они практически всю жизнь работали вместе в Bell Labs (AT&T, потом Lucent) как коллеги и единомышленники. Так вот, третьим членом их коллектива был Роб Пайк.

Кроме соавторства Unix и нескольких учебников по программированию, он известен как создатель языка программирования Go. Этот язык родился из философии простоты в программировании, которую Пайк пропагандирует всю жизнь.

Читать далее

«У вас в резюме указаны навыки ИИ. Что вы имели в виду?» Что отвечать, кроме количества потраченных токенов

Уровень сложностиПростой
Время на прочтение53 мин
Охват и читатели11K

Всё началось с чата с однокурсниками. Кто‑то обронил фразу «сейчас без ИИ никуда, это уже базовый навык», и следующие два дня мы выясняли, что каждый понимает под этим что‑то своё.

Один говорил, что весь навык сводится к умению нормально сформулировать запрос, всё остальное сделает модель. Другой доказывал, что настоящее умение это как раз не пускать ИИ туда, где он навредит, и что главный навык это дисциплина отказа. Третий считал, что тема надутая, а через год всё устаканится само и учиться нечему. Четвёртый прислал скриншот своего CLAUDE.md на двести строк и сказал, что вот она, настоящая работа.

Меня зацепило, что мы все вроде бы делаем одно и то же каждый день, а описываем это несовместимыми словами. Ни у кого, включая меня, не оказалось внятного ответа на простой вопрос: если разработчик говорит «я умею работать с ИИ», что конкретно он умеет?

А потом выяснилось, что вопрос не академический. У половины из нас в резюме стоит строчка про навыки работы с ИИ, и на собеседованиях за неё уже начали цепляться. «У вас тут указаны навыки ИИ. Что вы имели в виду?» И вот тут начинается неловкое. Потому что честный ответ большинства звучит примерно так: пользуюсь Claude Code каждый день, беру модель посильнее, когда задача сложная, в прошлом месяце сжёг столько то токенов. Всё это правда, и всё это ничего не говорит о вас как об инженере. Количество потраченных токенов характеризует вас ровно так же, как количество написанных строк кода: то есть никак, а иногда и в минус.

Проблема в том, что альтернативной формулировки у нас просто нет. Мы умеем называть инструменты и не умеем называть умения. Поэтому я сел и попробовал собрать перечень. Не «топ 10 промптов», а честный список умений, каждое из которых можно проверить, показать в работе и внятно описать словами, когда спросят.

Читать далее

Экономическая выгода рефакторинга в эпоху AI-агентов

Время на прочтение9 мин
Охват и читатели7K

Осваивая разработку с помощью AI-агентов, я написал веб-приложение для собственной ежедневной работы. Проект получился довольно сложным: с динамическим обновлением интерфейса и поиском, модальными окнами, автосохранением, интеграциями с внешними системами, модулями машинного обучения, текстовым анализом, фоновыми задачами и автоматическим деплоем. Объём кода составил около 150 000 строк, из которых примерно 120 000 написаны на Rust, а остальные - на TypeScript и Terraform.

Весь этот код сгенерировали агенты - в основном Claude Code и частично Cursor. За редкими исключениями я почти не открывал и не читал исходные файлы.

В процессе разработки я начал замечать странности. Когда в терминале мелькнула правка 4000-й строки в одном файле, я решил посмотреть на код ближе. Выяснилось, что слой доступа к данным разросся до 6000 строк. С каждой новой функцией он продолжал расти. В коде каждого запроса, чтения или записи повторялись настройка HTTP-запроса, кодирование и декодирование JSON. В итоге весь слой доступа к данным оказался в одном файле на 17 155 строк Rust.

Читать далее

Архитектура TMS на .NET: кластер, потоки координат и объектное хранилище

Уровень сложностиСложный
Время на прочтение12 мин
Охват и читатели10K

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

Коротко о предмете. Заказы приезжают из SAP, под них подбираются водитель и машина с учётом требований к транспорту и к точкам. Рейс идёт по точкам с временными окнами, на точках чек-листы, при выдаче и возврате машины составляются акты с фиксацией повреждений. Сверху — поток GPS-координат, отслеживание рейсов и мест, мобильное приложение водителя и публичный контур, где клиент видит свою доставку.

Пятнадцать модулей, три ноды за балансировщиком, RabbitMQ и Kafka по три ноды, PostgreSQL, Redis из шести.

Читать далее

Я хотела дать AI память. Пришлось организовать работу

Уровень сложностиСредний
Время на прочтение26 мин
Охват и читатели7.2K

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

Первое правило работы с контекстом - выносить его из чата.

Второе правило работы с контекстом - прежде чем выносить, нужно сортировать.

Третье правило работы с контекстом - не в контексте дело.

Читать далее

Переезд с ESB на свой стек: что реально экономит бизнес

Уровень сложностиСредний
Время на прочтение41 мин
Охват и читатели11K

Разбираем систему управления транспортом — TMS. Заказы приезжают из SAP, под них подбираются водитель и машина с учётом требований, рейс идёт по точкам с временными окнами, на точках чек-листы, при выдаче и возврате машины — акты с фиксацией повреждений. Сверху поток GPS в партиционированные таблицы, отслеживание рейсов и мест, мобильное приложение водителя и публичный контур, где клиент видит свою доставку. Пятнадцать модулей, три ноды за балансировщиком, RabbitMQ и Kafka по три ноды, Redis, PostgreSQL, отдельный сервер идентичности.

Систему стали писать, когда TMS покупали как услугу у внешних поставщиков и риски выросли: собственная разработка оказалась способом вернуть управляемость ключевым процессом. И написали быстро — системе год и четыре месяца, первый коммит в апреле 2025-го. Это не легаси из нулевых, а молодой проект, который уже успел обзавестись инфраструктурным слоем и уже начал его разбирать.

Команда была ....

Читать далее

Сколько стоит интеграционный слой на WSO2 MI и EF Core: разбор реальной системы по строкам

Уровень сложностиСредний
Время на прочтение23 мин
Охват и читатели11K

Разбираем систему управления транспортом — TMS. Не игрушечную и не с конференции: заказы приезжают из SAP, под них подбираются водитель и машина с учётом требований к транспорту и к точкам, рейс идёт по точкам с временными окнами, на точках — чек-листы, при выдаче и возврате машины составляются акты с фиксацией повреждений. Сверху — поток GPS-координат в партиционированные таблицы, отслеживание рейсов, мест и контрагентов, определение присутствия по WiFi. Плюс мобильное приложение водителя и публичный контур, где клиент видит, где его доставка.

Пятнадцать модулей, три ноды за балансировщиком, RabbitMQ и Kafka по три ноды, Redis, PostgreSQL, отдельный сервер идентичности.

Зачем её вообще стали писать. TMS покупали как услугу у внешних поставщиков, и риски выросли.

Это стоит развернуть, потому что решение принималось не по техническим мотивам. Когда ключевой процесс компании работает на внешнем сервисе, риск считается деньгами: простой, на который вы не влияете; сроки исправлений, которые определяет не ваш приоритет; зависимость от одного поставщика при смене условий. Пока риск невелик, покупать дешевле, чем строить. Когда он вырастает — арифметика переворачивается, и собственная разработка становится способом вернуть управляемость, а не способом сэкономить.

Систему забрали себе.

И вот главное ...

Читать далее

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

Референсная архитектура платёжной платформы на.NET: схемы, границы транзакций, модули, кластер

Уровень сложностиСложный
Время на прочтение24 мин
Охват и читатели12K

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

Эта статья — ответ. Референсная архитектура: модель учёта, границы транзакций, разбиение на модули, топология кластера, маршруты интеграций и точки восстановления. С кодом и схемами.

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

Стек: типизированное хранилище redb поверх PostgreSQL, интеграционный движок redb.Route, рантайм redb.Tsak и сервер идентичности redb.Identity. Всё Pro, всё бесплатно на линейке 3.x.

Читать далее

От хаоса к порядку: как управлять техдолгом

Уровень сложностиСредний
Время на прочтение11 мин
Охват и читатели7.1K

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

В этой статье Ирина – тимлид компании «Совкомбанк Технологии» – подробно расскажет, как ей вместо с командой удалось выстроить работу с техническим долгом на проекте с 8-летней историей: с чего начать, как приоритизировать задачи, какие инструменты и процессы внедрить.

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

Читать далее

Дубль один, дубль два: как я делала одну фичу дважды

Уровень сложностиПростой
Время на прочтение5 мин
Охват и читатели9.5K

Я бизнес- и системный аналитик, и у меня редкий кейс: две последние работы делают почти одинаковые продукты — по сути, конкурентные. Так что часть задач я делаю второй раз в жизни. Первый, как выяснилось, был генеральной репетицией. Жаль, никто не предупредил — я бы записывала.

Оба продукта — CDP (Customer Data Platform) для маркетинга. По сути это база данных, которая собирает информацию о клиенте отовсюду и нарезает её в сегменты, — а сверху на эту базу наслаиваются рассылки, бонусы и акции, ласково выманивающие клиента с дивана. Задача-дубль — конструктор сценариев: визуальный редактор, где кампания собирается цепочкой блоков. Классика жанра — сценарий на день рождения:

Читать про оба дубля

Назад в 2005-й. API-first как третья пилюля от деградации проекта под LLM

Время на прочтение19 мин
Охват и читатели9.5K

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

Под катом — как этот шов гниёт под LLM и как его чинит contract-first: генерация серверных интерфейсов и клиента из одного OpenAPI-файла, политика ломающих изменений, правило «не симулируй — расширяй контракт». Попутно — зачем возвращаться к идее, которую мы выбросили вместе с WSDL, и какая из моих проверок после всего этого молча перестала работать. Третья часть цикла, читается самостоятельно.

Читать далее

Свободные функции вместо методов, но с полиморфизмом. Что это даёт на самом деле?

Уровень сложностиПростой
Время на прочтение8 мин
Охват и читатели10K

Речь о процедурно‑параметрическом программировании, о котором почти никто не пишет. Я реализовал одну и ту же задачу в ООП и в этой парадигме и сравнил их численно. Одна из метрик разошлась в 6 раз.

Что же это такое?

С++: Пиши, сокращай, оптимизируй

Уровень сложностиСредний
Время на прочтение9 мин
Охват и читатели11K

Попалась функция на языке С++. На её примере прям просится показать, что, делая рефакторинг, можно не только эстетично сократить код, но и оптимизировать его. Давайте разомнём мозги, они нам ещё пригодятся, несмотря на эпоху вайб-кодинга. Кто-то ведь должен понимать, как делать надо, а как не надо.

Читать далее

Надёжная асинхронная коммуникация: повторы, дубликаты и dead letter queues

Время на прочтение27 мин
Охват и читатели7.8K

Представим обычную обработку заказа. Сервис заказов публикует событие order.created. Сервис склада получает его и резервирует товар в PostgreSQL. После успешной транзакции обработчик должен отправить RabbitMQ подтверждение (Ack), чтобы broker удалил сообщение из queue.

Но процесс может остановиться после записи в PostgreSQL и до отправки Ack. RabbitMQ не знает, успел ли сервис зарезервировать товар. Broker видит только неподтверждённое сообщение, поэтому доставляет его ещё раз. С точки зрения доставки это правильное поведение. С точки зрения бизнеса один заказ теперь может зарезервировать товар дважды.

Другой сбой возникает раньше: PostgreSQL временно недоступен, и обработчик не может начать работу. Если сразу вернуть сообщение в queue через отрицательное подтверждение Nack(requeue=true), RabbitMQ почти немедленно доставит его снова. Пока база не восстановилась, все попытки будут бесполезными. Нужны задержка и ограничение числа повторов. При этом отложенное сообщение может пропустить вперёд более новые события, поэтому отдельно придётся решить вопрос порядка.

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

В статье разберём эти моменты по всему пути сообщения. Затем построим практическую схему для RabbitMQ и Go: добавим ограниченные повторы через retry queues, время жизни сообщения (TTL) и dead letter exchange, сделаем обработчик идемпотентным и определим, куда отправлять сообщения, которые не удалось обработать автоматически. В конце сравним этот подход с Kafka, NATS JetStream и Amazon SQS.

Читать далее
1
23 ...