Skip to content
Why we are building Jardis. Light type on a dark background with a green light gradient descending toward the bottom.

Why we are building Jardis

Complex software runs on CRUD for decades and fails. Domain-Driven Design was the answer, but too laborious to implement. That is why I build Jardis.

There is a pattern in software development that has held for decades. The moment requirements move beyond simple CRUD, a team faces a choice that is not really a choice: either model the domain properly through Domain-Driven Design and cast it into a hexagonal architecture, at an implementation effort higher up front than CRUD, or force CRUD thinking into a complex domain and hope it holds. Most choose CRUD. Not out of ignorance, but because time and delivery date leave no other option.

The result is predictable. Overgrown service layers that get more fragile with every new requirement. Applications that grow sick over the years, because the knowledge in the team does not keep pace with the complexity of the domain, because new techniques keep getting introduced in the hope that things will improve afterward, and because the underlying approach was simply never made for this kind of requirement. This is no accusation against developers. It is a structural problem: CRUD gives a team no tool to handle domain complexity, and leaves it alone with every decision.

The right answer to complex domains is DDD, the discipline of modeling the domain cleanly. That has been clear since Eric Evans' standard work from 2003. But the right model is worth nothing if its implementation is too laborious to repeat project after project. This is exactly where Jardis comes in. The modeling is not automated, that stays human work. What gets automated is the recurring translation of the model into clean, hexagonal code. That makes DDD, from day one, faster, cheaper, and more future-proof than any CRUD implementation.

The Bigger Pattern

Line up CRUD projects in complex domains side by side and the same trajectory shows up every time. At the start, everything works. The structure is clear, the decisions are fresh, delivery speed is high. A few months in, the picture no longer matches reality. Services call services that call services. Validation spreads across three layers. Business rules sit in controllers, in event listeners, in database triggers, everywhere and nowhere cleanly.

The symptom is called gradual architecture erosion, and it is not the failure of a specific team. It is the inevitable consequence when CRUD thinking meets requirements that CRUD cannot model. I have seen it in almost every software development project I have worked alongside over the past decades, the moment complexity moved beyond plain CRUD.

The consequence is economic, and by now visible across the industry: companies no longer pay for new features, they pay to keep the software they already have alive. Refactors that never happen. Migrations that keep slipping. Senior developers who spend half their time explaining historical quirks. And every new domain unit raises the same problem again, not once, but as often as the domain demands. A substantial share of development capacity goes not into domain work but into the same recurring fight against a structure that was never meant for this kind of complexity. What does not show up immediately as infrastructure cost comes back later as technical debt, spent keeping what was built alive.

The obvious answer is: better discipline. More code reviews, clearer conventions, stricter architecture boards. I believed that for a long time. It is not wrong, but it is not enough. The drift comes back, in every project, in every constellation, at every team size. At some point I had to ask whether the wrong variable was being optimized here, or the wrong approach.

DDD Was Never the Problem, Its Implementation Was

Domain-Driven Design as Eric Evans laid it out was never unknown. The book appeared in 2003, and I first studied it seriously more than fifteen years ago. Even so, it stayed a theoretical toolbox. In practice it got dismissed regularly: too laborious, too complicated, and the payoff shows too late. As far as implementation goes, that was not wrong. Implementing DDD the classic way costs weeks of strategic and tactical modeling, demands vocabulary discipline, and the payoff only becomes visible once a system has run for years. What that assessment missed: laborious was the recurring implementation, not the modeling, where the value is created. The modeling is the more durable path over the lifecycle, and a higher up-front effort that pays off over time is the definition of an investment.

What I could never shake off over the years, though, were the recurring situations in which exactly what Evans had described went wrong. Aggregates whose boundaries were unclear. Bounded contexts no one had separated cleanly. A ubiquitous language that no longer held by the third sprint planning. DDD had an answer for every one of these problems. But between the model and running code lay weeks of mechanical implementation every time, and that could not be carried again and again in every project.

So the choice fell, again and again, on what paid off: overgrown CRUD applications with service layers, pragmatic enough for the delivery date, fragile enough for the next maintenance round.

The Break: 2023

In 2023 I decided to give the topic its own dedicated work phase, independent of client budgets, as an investment. The question was no longer: how do I explain to a client that DDD pays off? It was: can the implementation effort be reduced so far that DDD becomes the more pragmatic choice over CRUD from day one?

The key was a changed perspective on DDD. Not as a tool, a collection of useful terms and patterns, but as a lens. An ordering system that shows where structures repeat, where terms clarify, and where a small number of patterns produces a complete substrate.

Through that lens it became visible that the high implementation effort is not a one-time act at the start of a project. It repeats with every bounded context and every aggregate. Every aggregate, meaning the related business objects that have to stay consistent together, needs repositories, command and query handlers, hydrators, persistence, domain events. The shape is the same every time. What differs is the domain content: which aggregates, with which fields, with which rules. DDD is not one laborious thing you do once. It is the same laborious pattern that recurs with every domain unit, with different expressions but identical structure.

That is the moment something tips over. If the shape of the layer is the same in every project, then this shape is not something that has to be written. It is something that can be produced. The domain decision, which aggregates exist, where their boundaries run, which invariants they protect, stays human modeling work, that is tactical DDD. What follows from it, the same hexagonal shell around that model, Jardis produces from the modeled aggregate, by the same rule every time, identical every time.

Comparisons

Jardis vs. Hand-Coded DDD

Manual DDD implementation requires deep expertise, months of setup, and delivers results that vary by developer skill. Jardis generates the entire infrastructure layer consistently, so your team focuses on domain logic.

Learn more

Don't Optimize, Eliminate

This is where the old triangle of ship faster, higher quality, lower cost does not resolve through balance. I treated it as a law of nature for years, like everyone: pull one axis and another gives. But the triangle holds an unspoken assumption, namely that the recurring implementation work is given. It dissolves the moment the most laborious block, the one that keeps recurring, falls out of the system. Not accelerate. Eliminate.

What remains is the work that actually requires decisions: where do the bounded-context boundaries run? Which rules does an aggregate protect? Which domain events trigger which downstream processes? That is domain work. It does not go away. It becomes more visible, because the recurring routine no longer covers it up.

Why It Took Two Perspectives

This insight does not form from a single perspective. I worked as a developer for a long time, later as IT director, then as CTO, then as managing director, and finally as a founder. Those stations forced me to look at every technical decision through two lenses at once: engineering elegance and commercial viability.

Anyone who is only a developer sees the craft elegance of DDD and defends it against the charge of being too laborious, but has no argument for why that effort should pay off for a mid-market client. Anyone who is only a businessperson sees the foundation weeks as an unfortunate line item, but has no lever to attack the root cause. They negotiate the price, not the work itself.

Only the combination forces the right question. Not: how do I ship faster? Not: how do I cut cost? But: which work actually still needs to be done by people, and which does not? The commercial lens forbids getting used to the recurring work. The developer lens sees that this work follows the same rule in every project, which means it can be automated. Neither alone gets you anywhere. Together they reveal the lever.

That is why Jardis is not the next library proposal but a separate layer in the stack. Library proposals move inside the triangle. A layer that produces the recurring work instead of writing it leaves the triangle, because it answers a different question.

What Two Years of Building Have Taught Me

I have been building Jardis for two years. In that time the original thesis held up, and in a few places it shifted.

Confirmed: the platform code looks the same in every project. From a schema and an aggregate definition, the same hexagonal architecture appears every time. Per aggregate, depending on complexity, that is dozens to well over a hundred files a team would otherwise write by hand. Jardis delivers them in the same shape, any time, without drift between projects and without translation losses between design and code.

Shifted: how much the second layer carries. The platform code per aggregate is one thing, the deterministic part. On top of it sits the domain logic, and it does not start on a blank page. In Jardis I model the business processes as flows: one process per use case, drawn as a graph, following the reading convention of BPMN. Every node in the flow becomes exactly one class, and Jardis generates those classes in full as scaffolding. For each node I attach a requirement, a plain-language description of what that step has to do, and Jardis weaves it straight into the generated code, not into a document nobody reads later.

This flow layer is what makes the AI point hold up. An AI fills in the domain logic not in open space but inside a narrow corridor: the what sits in the requirement at the code location, the with-what in the input, the how in the platform's documented rules. The architecture shrinks the room before the AI starts, instead of hunting for the pieces afterward in review. That became clearer to me while building than while designing.

What also shifted is how important precise language is at this seam. Jardis takes work off your plate, it does not replace you. Jardis does not produce business logic. Jardis produces the layer that business logic sits on. Blur that, and you build either a no-code promise that cannot hold, or a scaffold generator that solves nothing new. Both would fall short.

Pain Points

Sprint 1 Was Clean. Sprint 10 Is Chaos.

You designed the architecture deliberately. Then came deadlines, then exceptions, then new people with no context. Jardis makes architecture boundaries permanent, instead of leaving them to daily pragmatism.

Learn more

What Jardis Is, and What It Is Not

Jardis is a platform for Domain-Driven Design in the PHP ecosystem. From schema definitions it produces two layers. The first is the full platform code per aggregate: repositories, command and query handlers, hydrators, persistence, domain events, hexagonal by construction and repeatable any time. The second is the scaffolding for the domain logic: the business processes, modeled as flows, from which Jardis generates one stub class per step, with the requirement sitting right in the code. The business logic itself is then written by AI and human into those stubs. Custom code survives every rebuild. The foundation of a serious project stands in days, not months.

What Jardis is not: not a replacement for Symfony or Laravel. Jardis begins at the controller and leaves the choice of web framework open. Works with any framework. Not a no-code tool. The domain logic remains classic developer work. Not a promise to replace developers. Jardis takes off their plate the work that takes the same shape in every project, so that more time remains for the work that actually requires decisions.

Looking Ahead

Over the next ten years of software development, implementing a new bounded context or aggregate will no longer show the same recurring picture I have been seeing for thirty years. Teams will no longer have to choose between clean architecture and the ability to ship. Development capacity will no longer flow into the same infrastructure over and over, but into domain work. Build the foundation of complex software in days, not months. That is not a marketing line, it is the work I am bringing into the PHP world.

There is still plenty left to do. But what looks the same in every project no longer has to be done by hand.