Batunet's knowledge base.
Not blog posts, but solid answers to concrete engineering questions. One question, one page, one answer.
A static map of the entity graph: every entity a node, every relationship an edge, the clusters grouped by kind.
Knowledge graph →The entire knowledge base at your fingertips.
Search by topic, or filter by content type and category.
Content type
Category
60 results
Software That Still Runs in Ten Years
Which engineering decisions keep software viable for ten years — coupling, reversibility, operations, standards. With trade-offs instead of marketing.
Reversibility over Prediction
You cannot predict the future — so keep change cheap instead of betting on it. Which decisions to slow down and which to build reversibly.
AI in Production Systems — Engineering, Not Demos
The long road from an AI demo to a reliable production system: evaluation, failure modes, guardrails — wrapping the probabilistic in the deterministic.
Business Logic Doesn't Belong in Controllers
Why business rules belong in a framework-independent domain layer, not in the controller: symptoms, maintenance costs, testability, migration.
Data Modeling That Lasts
The data model outlives framework, interface and database: why you model the domain, design for change, and why a wrong model is so expensive.
Designing for Failure
A system whose failure modes are unknown is not finished: contain failures instead of preventing them, retry safely, degrade gracefully, rehearse failure.
Security as an Architectural Property
Security isn't a feature you bolt on, but a property of the design: threat modeling, least privilege, defense in depth, secure defaults.
Symfony for Long-Lived Enterprise Systems
Why Symfony's explicitness, components and culture of stability carry long-lived enterprise systems — and where Laravel remains the better fit.
Mature Technology over Novelty
Choosing technology without chasing trends: why maturity means others already found the bugs — what the new hides, and when it's still right. Context and lifespan.
Modular Monolith vs. Microservices
Not a holy war but a decision about where complexity lives: what a modular monolith really is, and when microservices are objectively the better choice.
When AI Is the Wrong Solution
From a company that builds AI: when it is the wrong choice. What shape a problem needs, why a rule is often superior, what AI costs in the wrong place.
Build, Buy or Configure — When Custom Software Pays Off
Build it yourself, buy it or configure it — honestly, even when the answer is 'buy'. The criterion: differentiation and lifespan, hidden costs.
Reliable AI Answers — Architecture for Context and Sources
How to ground an AI answer in reliable, current context and traceable sources so that it is correct and verifiable — not merely fluent.
PostgreSQL or MySQL for Long-Lived Systems
Both databases are mature and will carry a system for years. What they share, where they differ — decided by the shape of the data and the team, not by a ranking.
Why Software Projects Really Fail
Software projects rarely fail because of technology, but because engineering decisions become irreversible before the problem is understood.
Server-Side Rendering or SPA
Server-side rendered or SPA — the frontend choice that determines ten-year maintainability. Decided by interactivity and lifespan, not fashion.
Laravel for Enterprise Systems
When Laravel is the right choice for long-lived, business-critical systems — and when it isn't: architecture, maintainability, scaling reality, operations, team.
Laravel Upgrades for Long-Lived Systems
How to keep a Laravel system current for years without dreading the leap: postponed upgrades as the real danger, continuous instead of in leaps, tests as a safety net.
Idempotency in Distributed Systems
Why distributed systems must tolerate duplicate messages and how to make them idempotent: idempotency keys, retries, outbox and inbox.
API Design for Long-Lived Systems
How to design APIs that last for years without breaking their consumers' systems: contracts, compatibility, versioning, errors, evolution.
REST, GraphQL or RPC — Choosing an API Style
Choosing an API style by fit rather than fashion: what distinguishes REST, GraphQL and RPC, which problem shape suits which style, what each one costs.
API Versioning Without Breaking Customers
How to evolve an API over years without breaking customers' systems: extend compatibly, version cleanly, treat deprecation as a process.
Legacy Modernization Without a Big Bang
How to replace a production system incrementally and reversibly instead of via rewrite: strangler fig, anti-corruption layer, data migration, parallel runs.
Taking Over a Legacy System — the First 90 Days
Taking over a system you didn't build: understand before you change, safety nets before the first intervention, the map, capturing the behavior.
When a Rewrite Is the Wrong Decision
Why a rewrite discards embedded knowledge and chases a moving target, when a rebuild is the right call after all — and why incremental is almost always better.
Agentic Coding — When Software Development Becomes Orchestration
Agentic coding shifts the bottleneck of software development: from writing the code to defining, verifying and taking responsibility for the work.
When Tests Really Pay Off
Testing as an investment with varying returns: where tests create value, where they generate more maintenance than benefit. No coverage dogma.
Observability Is Architecture
Why a system that cannot explain its behavior cannot be operated safely — observability as an architectural property, not a tool.
Zero-Downtime Database Migrations
How to evolve production databases without downtime: expand/contract, backward-compatible schema evolution, deploy sequence, backfills, rollback.
Caching Is Not a Performance Feature
Caching is not an optimization but an architectural decision — latency versus consistency. What you never cache, invalidation, layers, failure modes.
5,000 Lines of Copy & Paste
An Engineering Story: how roughly 5,000 lines of copied code came about, why nobody noticed the moment duplication became expensive — and what consolidating it to about a tenth taught us about DRY.
That’s a quick job.
An Engineering Story: why a single sentence became a reliable warning sign — and why Batunet now deliberately declines projects that begin this way. On the value of analysis and architecture that cannot be skipped.
Once You Start Copying.
An Engineering Story about the momentum of copying: how a defensible first copy turned into around 5,000 lines of nearly identical code, why the dangerous decision was not the first copy but the missing one the second time around — and what consolidating to roughly a tenth taught us about the right moment.
Real-Time Without a Rebuild
An Engineering Story: a system that had grown over many years suddenly needed to update in real time — a requirement its architecture was never designed for. Why the answer was not a rebuild but the targeted redesign of a single data flow. On the difference between a local requirement and a global overhaul.
Changing Direction Early
An Engineering Story: the plan was to extend an existing system. As the work progressed, it became clear that every additional feature would increase complexity. Instead of sticking to the plan, we changed direction and split features out into standalone APIs. On the cost of defending an outdated plan.
The Prototype That Wasn’t a Product
An Engineering Story: a client only wanted a proof of concept. What emerged was a usable interface. Then the undertaking was discontinued. On the difference between a feasibility study and product development — and why you have to name it from the start.
A Migration Is a Trust Problem
An Engineering Story: a large infrastructure migration spanning multiple servers, databases, backups and a change of provider. The real difficulty wasn't technical, but the certainty of having forgotten nothing. On migrations as trust problems — and how to establish trust instead of hoping for it.
Interfaces Outlive Implementations
An Engineering Story: an external API provider was replaced. Millions of existing records, an incompatible new structure — what followed was mapping, migration, verification. Why the interface was the lasting part and the implementation behind it the transient one.
Software Is Never Finished
An Engineering Story from our longest-running client project: requirements change continuously, software is never finished — and the only robust answer is an architecture that makes change cheap. On letting go of the idea of an end state.
Removing Complexity Instead of Adding It
An Engineering Story: external API components were embedded in the monolith. They were extracted and turned into standalone APIs — resulting in a clearer architecture and independent scaling. Why taking away is often worth more than adding.
When Schema and Model Drifted Apart
An Engineering Story: in a large multi-team project, one bug refused to go away. The cause was small — the database schema had changed, the ORM mapping had not. Why tiny mismatches between database and model cause disproportionately large problems.
Good Tools Amplify
An Engineering Story: AI was integrated into everyday engineering work — expected to be a small helper, experienced as a fundamental productivity improvement. Viewed without excitement: why good tools amplify engineers instead of replacing them — and why that raises the value of judgment rather than lowering it.
The Best Architecture Removes Components
An Engineering Story: hundreds of intermediary API servers were replaced by a proxy architecture. The infrastructure became simpler, not more powerful. Why the best architecture often removes components instead of adding new ones.
Why we usually start with a modular monolith
For most systems, a modular monolith is the more economical choice — until a concrete boundary genuinely calls for distributed services.
Why premature abstraction creates complexity
Abstractions should emerge from repeated, concrete cases — not from the expectation that they will be needed someday.
Why observability is part of the architecture
Whether a system is observable is decided at design time — not at the first incident.
ADR-001: Modular monolith as the starting point, microservices on evidence
Distributed systems solve real problems — independent scaling, independent deployment — but they bring network boundaries, eventual consistency and operational overhead with them. When do the benefits justify these costs?
ADR-002: Queues instead of synchronous processing outside the critical path
Synchronous side effects tie the response time to the slowest system involved and cause a request to fail when a side effect fails. Asynchronous processing decouples, but it brings eventual consistency and delivery semantics with it.
ADR-003: Normalized tables over JSONB in PostgreSQL
JSONB is temptingly flexible, but it moves structure and integrity out of the database and into application code. Normalized tables enforce structure but are less flexible when the schema changes frequently.
Modernizing a legacy monolith
Replacing a legacy system that has grown over time without putting operations at risk — step by step instead of a big bang.
Designing a public API
Designing an API as a long-lived contract — versioned, documented and stable for its consumers.
Introducing asynchronous processing
Moving side effects out of the critical response path — resilient, traceable and idempotent.
Laravel or Symfony
An honest architecture comparison of the two PHP frameworks — no winner, with context.
Idempotency
An operation that produces the same result whether it runs once or many times.
OIDC (OpenID Connect)
An identity layer on top of OAuth 2.0 for authentication and single sign-on.
Multi-Tenancy
A single software instance serves multiple customers with separated data.
Event Sourcing
State is stored as a sequence of immutable events rather than as a current value.
DRY (Don't Repeat Yourself)
Every piece of knowledge should have exactly one authoritative representation in the system.
Cone of Uncertainty
The range of an effort estimate is widest at the start of a project and narrows only as understanding grows.
Rule of Three
Two occurrences may be coincidence; at the third, similarity becomes a pattern — and a moment to consolidate.
Eleven fields. One standard.
Each category is a coherent knowledge cluster — from the fundamentals to the decisions teams actually make.
Where to start.
Ordered by importance — the fundamentals first, then what builds on them.
Let’s talk about your project.
No sales team. A direct conversation with the management.
