Projects
Closed cases: what hurt the business, what I did and what changed.
The technical details of each case open with the “Show details” button.
2025–2026 · Raft, AI Labs · team lead and tech lead
AI chart audit: a month from delivery, from chaos to production without incidents
A large network of clinics was waiting for a platform that audits the quality of medical records. A month before delivery the project was in chaos: the lead had left the company, the customer kept changing requirements, and the API we had to integrate with did not exist yet. I took the project over: fixed the requirements and integration points with the customer, got the team back into a working rhythm and connected AI and backend development. Delivered on time, the release itself took 2 days, not a single incident after launch; the project won the Yandex B2B Tech Awards.
A team of five, three and a half months of my involvement. Two services in one monolith on FastAPI with Postgres and Redis; RabbitMQ decoupled the backend, the LLM service and the customer's API, which was being built in parallel with us; hosted in Yandex Cloud. We negotiated flexibly: justified requirements were accepted, the rest were defended against. Besides coordination and negotiation I debugged and wrote backend code myself; over those months the backend developer grew from an uncertain mid-level engineer into a confident one.
A new service in production in hours: a monorepo from day one
On earlier projects I had seen what domain and ORM models scattered across repositories cost: a contract change in one service breaks its neighbours, and a new service takes days to reach production. The new microservice product was built in a monorepo from day one, with shared libraries and a single delivery pipeline. A new service reaches production in a couple of hours, and contract drift is ruled out by construction.
Shared domain and ORM models in one library, atomic changes across every affected service at once, synchronised dependency updates, deployment templates and one CI/CD pipeline for all services.
Development with AI agents: fast at the start, manageable afterwards
With agents, an MVP is assembled in two weeks, and then the team spends six months unable to understand it: a fast start is not the same as a product that can be maintained and developed. I set up a single standardised environment for agent-assisted development: codebase rules the assistants obey, an internal project-context server, test generation on every PR and checks before commit. Development with agents became predictable: agent-written code passes the same rules and tests as human code, and the product stays manageable after the start.
The context server (MCP) gives the model only current data schemas, domain invariants and repository standards instead of bloated static prompts. A CI pipeline analyses the diff of every PR and generates unit tests from the project's templates. Codebase rules catalogue the typical mistakes of LLM generation; pre-commit hooks moved linting and formatting to commit time and took load off CI. The main lesson: there are two approaches. Either the agent writes 100% of the code, and then quality control is its job too: rules, review, full coverage up to e2e. Or a hybrid: the agent writes the architecture, the scaffolding and the tests, and a human writes the business logic. Slower, but the project stays manageable.
2015–2024 · Northern Light, Boston · software engineer to principal engineer
Search portals over syndicated and private data for the management of 20 client companies, among them J&J, IBM, HP and Intel: 30+ services, 100+ TB of content, 24/7. Responsible for the stability of the whole infrastructure behind the product.
Perl → Python: legacy stopped being a business risk
Data loading and processing were written in Perl: only a handful of people could write it, new engineers could not be hired for it, every change was expensive and done however each person saw fit. A platform running 24/7 rested on the knowledge of a few people. I migrated the codebase to Python step by step while the platform kept running: new components took their place beside the old ones and took over their work one at a time. Perl stopped being a risk: the code is understood by the whole team, engineers can be hired from the market, and changes became cheap and predictable.
Python 2 first, then 3. The loaders moved first, then the processing filters, one component at a time. Alongside it I built a test harness: functional and acceptance tests over the core and text extraction, so the migration never broke what worked.
Onboarding a data source: 3–7 days instead of 30
A hundred-odd data providers, from web pages and APIs to FTP and SharePoint, and every new source meant a month of work: the loader and the processing were written for it from scratch, and any deviation in format broke the pipeline. I brought all loaders into one framework and built normalisation into it: every document comes out in the same format, and processing downstream became simple. Onboarding a new source takes 3–7 days instead of 30.
A framework on Python and Scrapy replaced three classes of loaders: RSS, crawlers and custom ones for the exotic cases such as SOAP, FTP and SharePoint. The loader knows everything about its source, so normalisation lives in it: the output is always a pair of metadata and document. Document parsing joined it too: HTML, PDF and scans broken down into blocks and sentences, with menus, disclaimers and running headers stripped. A typical onboarding ticket contained only the credentials and closed in three days.
Customer reporting stopped breaking every month
Portal activity reports for 100+ managers at 20 client companies were assembled from backend text logs: parsers failed, data went missing, and the monthly run overloaded the system. For several years the first week of every month went to repairing reports and explaining them. I proved that the portal already held every number the reports needed and led the move to an event model: the portals write events straight into the analytics stack. Failures and complaints ended; customers got reports for any interval and for the current day.
Events in JSON Lines, which land natively in ELK, instead of parsing logs with regular expressions; implementation handed to the UI and devops teams. While the decision was being agreed I kept the old system afloat: fixed the backend and tuned Postgres indexes for date-range queries. The hardest part was not technical but organisational: a system that had absorbed a lot of resources had to be declared unfit and replaced against resistance.