Microservices Didn’t Fail. People Did

The pattern was sound. The history is clear. What broke microservices wasn’t the architecture — it was practitioners who applied the deployment unit without the engineering discipline the original authors said it required.

There is a version of the microservices post-mortem that treats the pattern itself as the problem. Distributed systems are hard. Eventual consistency is hard. Operational overhead compounds. Better to stay with the monolith. This is the wrong conclusion, drawn from the wrong evidence, by people who perhaps should never have adopted microservices in the first place.

Microservices did not fail. A generation of engineers adopted an architectural pattern without the domain modelling discipline it demands, kept the synchronous call patterns from the systems they were supposed to be replacing, and then blamed the architecture when the complexity became unmanageable. That is not a failure of microservices. It is a failure of craft.

What the Original Authors Actually Said

Fred George was talking about micro-services — note the hyphen, the original form — at conferences as early as 2012. His framing was specific and unambiguous: very small services, a hundred or two hundred lines of code, communicating asynchronously, each doing one thing and signalling when done. He called the underlying philosophy programmer anarchy — not because it was chaotic, but because it required engineers senior and capable enough to operate without the management scaffolding that larger, less capable teams depend on.

George was explicit on this point, and it is the part most consistently erased from the mainstream narrative: microservices require a higher class of engineer. Not because the individual services are technically complex — they are not, that is rather the point — but because drawing correct service boundaries demands deep domain knowledge, and building an async event-driven system that actually holds together requires engineers who understand what they are doing and why. It is not a pattern that compensates for weak engineering. It exposes it.

In 2014, Martin Fowler and James Lewis codified what had been circulating in the practitioner community into the article that would introduce the term to the mainstream. They described services built around business capabilities, independently deployable, each owning its own data. They described communication via lightweight mechanisms, positioning this explicitly against the ESB-era orchestration that SOA had become. And they used a phrase the industry would adopt as a slogan while ignoring its meaning: smart endpoints, dumb pipes.

Microservice communities favour an alternative approach: smart endpoints and dumb pipes. Applications built from microservices aim to be as decoupled and as cohesive as possible — they own their own domain logic and act as filters in the classical Unix sense.

— Martin Fowler & James Lewis, Microservices, martinfowler.com, 2014

The Unix reference is not rhetorical. The intellectual lineage of microservices runs directly through Unix philosophy: do one thing and do it well, compose small sharp tools via pipes, keep the pipes dumb and let the intelligence live at the endpoints. This is a forty-year-old idea applied to distributed systems. The message bus is the pipe. The service is the tool. The insight was not new — it was being rediscovered at network scale.

Fowler and Lewis also listed decentralised data management as a defining property — not an optimisation, not a preference, a defining property. Each service owns its data. Not a shared Postgres instance with schema-level separation. Not a common ORM pointed at a central database. Complete data ownership, per service, with no exceptions. It was almost universally abandoned in practice because doing it correctly requires the kind of domain thinking not every team could bring.

The Problem Microservices Were Built To Solve

The original context matters enormously, and stripping it out is how you end up with a five-person startup running fifteen services on Kubernetes. Microservices emerged at organisations — Netflix, Amazon — where the primary engineering bottleneck was not performance, not data volume, not technical complexity. It was people. Hundreds of engineers. Conway’s Law made operational: when your organisation is large enough, your architecture will mirror your team structure whether you intend it to or not. The insight was to design for that deliberately.

Context — The goal was independent deployability at organisational scale: the ability for a team of eight to ship their service without synchronising with twenty other teams. The service boundary was, first and foremost, a team boundary. The architecture served the org chart. Without that organisational pressure, most of the complexity budget of microservices buys you nothing.

If your team does not have that problem, you probably do not need this solution. A well-structured monolith, deployed with confidence, will outperform a prematurely distributed system on every axis that matters to a small team. Reaching for microservices without the scale that motivates them is not an architectural decision. It is CV-driven development.

How We Build When Microservices Are the Right Call

When the problem genuinely calls for it — independent teams, independent domains, engineering capability to execute properly — the approach is simple. Not easy. Simple. There is a difference, and it matters.

Services communicate exclusively via events on a message bus. Not synchronous HTTP. Not REST calls between services. Events. A service does its work, emits an event signalling completion, and its responsibility ends there. It has no knowledge of what consumes that event or how many things do. The bus is infrastructure — provisioned once, configured like a database. You are not dynamically discovering it at runtime. The addressing problem that service discovery exists to solve simply does not arise, because you are not making point-to-point calls between services.

Each service owns its data completely. This is where the lake and pond model becomes operational. The event stream is the lake: the canonical, append-only record of everything that has happened across the system. Each service maintains its own pond — a local materialised view of the data relevant to its domain, hydrated by subscribing to the events it cares about. A service never queries another service’s store. It never calls another service to assemble a response. It already has what it needs, because it built it from events as they arrived.

This resolves the one objection people reliably raise: how do you serve synchronous queries at the user-facing edge? Frontend-supporting services — the Backend for Frontend pattern — subscribe to events across relevant domains and maintain pre-aggregated read models locally. When a request arrives, they answer from their own store. There is no cross-service call at query time, no dependency chain, no distributed join to fail.

Concrete Example — Order Placement

A customer places an order. The order service validates, persists, and emits one event: OrderPlaced. Its job is done. It does not call the inventory service. It does not call the payment service. It does not know either exists.

The inventory service is subscribed to OrderPlaced. It reserves stock and emits InventoryReserved. The payment service is subscribed to InventoryReserved. It charges the customer and emits PaymentConfirmed. Each service reacts, does its work, signals completion. No service is aware of the others. No orchestration layer exists. No saga coordinator manages the sequence.

The customer’s dashboard needs to show order status synchronously. A BFF service has been subscribed to all of these events since the system started and has maintained a local read model — its own pond — built from that stream. When the request arrives, it answers from local state. The response time is a single local query. There is nothing to discover, no chain to traverse, nothing to fail.

The simplicity here is not cosmetic. It is the proof that the design is correct. When a system requires a service mesh, a circuit breaker library, and a distributed tracing platform just to understand what is happening at runtime, that is not operational maturity — it is the system telling you something went wrong at design time.

Where the Industry Went Wrong

The mainstream implementation made one foundational mistake and spent the next decade building infrastructure to manage the consequences. It kept synchronous HTTP as the primary communication mechanism between services. Everything else — the service discovery registries, the circuit breakers, the service meshes, the distributed tracing pipelines — is a direct and inevitable consequence of that one decision.

  • Synchronous HTTP between services creates a distributed monolith. Call chains couple services at runtime. Latency compounds with every hop. Failures cascade. You carry the full operational burden of distributed systems and the full coupling of a monolith, simultaneously.
  • Service discovery — Consul, Eureka, Kubernetes service meshes — exists entirely to manage dynamic addressing in synchronous architectures. It is a solution to a problem that should not exist. In a correctly designed async system, you never ask where another service is.
  • The Saga pattern, in most implementations, is a sign that service boundaries were drawn incorrectly. If completing a business operation requires coordinated state changes across multiple services, those services were not decomposed around their actual bounded contexts. The saga is not the solution — it is the symptom.
  • Shared databases between services are not a pragmatic shortcut. They are a categorical error. If two services share a schema, they are modules in a distributed monolith. Calling them microservices changes nothing about their coupling.
  • Istio is impressive engineering that exists entirely to manage problems generated by synchronous inter-service communication. Its presence as a default recommendation in microservices literature is a precise measure of how far the mainstream drifted from the original intent.

None of this is a failure of the architectural pattern. It is a failure of practitioners who adopted a deployment strategy without the domain modelling discipline that makes it coherent. This requires engineers who can reason about bounded contexts, who understand event-driven systems, who have the discipline to hold service boundaries under delivery pressure. It was never a template any team could lift and apply without thinking. The original authors were clear about this. The industry chose not to listen, and then blamed the architecture for the results.

The Honest Position

Microservices, built as their originators described — async, event-driven, each service owning its domain and its data completely — are simple. Not operationally trivial, but architecturally simple: no service discovery, no synchronous call chain to trace, no distributed transaction to coordinate, no saga to manage. Each service does one thing, signals when done, and has no knowledge of what comes next. The system’s complexity lives in the domain, where it belongs, not in the infrastructure. Simplicity is not a constraint we work within — it is the standard we hold the design to. When you find yourself reaching for a service mesh or a saga orchestrator, the question is not which tool to reach for. It is what decision, made earlier, made that tool feel necessary.

Originally published at uradical.io.

400+ Remote Companies Using React in 2026

React is the default. 409 companies on Remoet use it. That is more than four times the next-closest frontend framework on the platform. If you write React, you are not in a special pool. You are in the main pool, and the main pool is the problem.

This is a different argument from the Python one. Python is too broad and you disappear inside it. React is worse. React is what every frontend developer already knows. The label “React developer” tells a recruiter approximately nothing. You write components. So does everyone they have ever talked to.

Let me show you the numbers and then tell you what to actually do.

React owns frontend. That is the trap.

The data first.

  • 409 companies use React in their stack
  • 25,185 open jobs at those companies, more than any other frontend cohort
  • 337 of 409 (82%) also use TypeScript. If you do not, you are competing with one hand tied
  • 109 of 409 (27%) also use Next.js in production
  • 67 companies specifically list React Native (mobile, different career path)

Compared to everything else:

Framework Companies Jobs
React 409 25,185
Next.js 113 8,107
Vue 85 7,597
Angular 81 7,407
React Native 67 4,850
Remix 7 705
Svelte 6 206

React has roughly five times the company surface area of Vue and Angular. There is no contest. There is also no signal in saying you write it. Every frontend candidate they screen this week writes it.

The trap: there are more React jobs than any other kind of frontend job, and you still cannot get an interview. Not because the jobs do not exist. Because “React developer” is the noisiest label in tech.

The signal is what is sitting next to React

Stop telling recruiters you are a React developer. They know. Tell them what you ship React next to.

You are a React plus TypeScript plus Next.js person. Or a React plus Rails plus Postgres person. Or a React plus Go plus Kubernetes person. Or a React Native plus Swift plus Kotlin person. These are different humans. The pools they actually compete in are much smaller than 409. Often they are 30 to 60. Inside those pools you are not interchangeable. You are a specific shape.

Here is what those clusters actually look like, with real companies pulled from the platform today.

React plus Next.js plus TypeScript (the modern web stack)

The default modern web cohort. If you are shipping marketing sites, product surfaces, or React Server Components in production, this is where you live.

  • Vercel. React, Next.js, TypeScript, Node.js, Python, Go, Kubernetes, AWS, GCP.
  • Mintlify. React, Next.js, TypeScript, Node.js, MDX, Storybook.
  • Resend. React, Next.js, TypeScript, Go, PostgreSQL, Clickhouse, Kafka, AWS.
  • Basement. React, Next.js, TypeScript, GSAP, Three.js, WebGL, React Server Components.
  • Buffer. React, Next.js, TypeScript, Express, BigQuery, Radix UI.
  • Whitespectre. React, Next.js, TypeScript, Node.js, NestJS, GraphQL, AWS.

These shops want production Next.js specifically. Knowing React without Next.js is not the same conversation.

React plus Node.js plus PostgreSQL (full-stack JS)

The classic JavaScript-everywhere shape. Frontend and backend in one language. 218 of the 409 React companies also use Node.js. 244 use Postgres. The overlap is the spine of mid-sized SaaS.

  • Linear. React, TypeScript, Node.js, PostgreSQL, GraphQL, Redis, Kubernetes, ProseMirror.
  • Ably. React, TypeScript, Node.js, JavaScript, Rails.
  • Aha!. React, Node.js, PostgreSQL, Rails, Kafka, Redis, Terraform.
  • Ghost. React, TypeScript, Node.js, Express, MySQL, Ember.js, Handlebars.
  • Strapi. React, Node.js, PostgreSQL, GraphQL, Apollo.

If your resume is React plus Node plus Postgres, these are the shops where you do not have to justify your stack.

React plus Python (frontend at backend-heavy orgs)

This is the one most React developers do not realize. 327 of the 409 React companies also use Python. Eighty percent. It is the single most common pairing on the platform.

It does not mean those shops want a Python person. It means the team you join probably has Python services next door and you will read it whether you write it or not. The signal here is comfort with a Python-shaped backend, not Python expertise.

  • PostHog. React, TypeScript, Python, Django.
  • Cursor. React, TypeScript, Python, Go, Rust, Kafka, Kubernetes, Clickhouse.
  • Anthropic. React, TypeScript, Next.js, Python, Go, Rust, Kubernetes, PyTorch, JAX.
  • Khan Academy. React, TypeScript, Python, Go, Vue.
  • Distribusion. React, Python, FastAPI, PostgreSQL, Kafka, Kubernetes, Elixir.
  • Attio. React, TypeScript, Node.js, Python, Go.

If you are a frontend dev who is comfortable in a polyglot stack, these are your shops.

React plus Go plus Kubernetes (infra-adjacent frontend)

217 React companies use Go. 267 use Kubernetes. The overlap is where frontend work happens at companies with serious platform engineering. The frontend is usually small relative to the backend, and the team values someone who can read a Helm chart.

  • Cloudflare. React, TypeScript, Go, Rust, Python, Lua, Cloudflare Workers.
  • 1Password. React, TypeScript, Go, Rust, Java, Kotlin, Next.js, Node.js, Kubernetes.
  • Supabase. React, TypeScript, Next.js, Go, Elixir, Phoenix, PostgreSQL, WebAssembly.

For these shops, “React developer” is the wrong label. “Frontend engineer who reads backend code” is the right one.

React Native (the mobile path)

Different career entirely. 67 companies. Roughly half also build for native iOS and Android, so you will end up in Swift or Kotlin at some point.

  • MapBox. React, React Native, TypeScript, Swift, Kotlin, C++, Rust, Go, Java, Vulkan, WebGL.
  • Distribusion. React, React Native, Python, FastAPI, Kubernetes, Elixir.
  • Reactiv. React, React Native, Next.js, Node.js, AWS, GraphQL, iOS, Swift.

If you are a React Native person, do not let yourself get lumped in with React generalists. The mobile pool is yours and it is small.

React plus Rails (Ruby shops)

48 companies. Smaller pool, different dynamics from JS-centric shops. Rails teams hire frontend people who can read Ruby and not bristle.

  • Stripe. React, TypeScript, Ruby, Rails, Python, Java, Go, Scala, Kafka.
  • Toptal. React, TypeScript, Ruby, Rails, Node.js, Python, Next.js, Tailwind CSS.
  • Aha!. React, Node.js, PostgreSQL, Rails, Kafka, AWS, Terraform.
  • Ably. React, TypeScript, Node.js, Rails.

If you have Rails on your resume and you also do frontend, you are a specific shape competing with maybe 50 people in the world.

Why this only works with the cluster

You can read all of this and still not get hired, because finding the cluster manually is the part that breaks people. There are 409 React companies. Reading 409 careers pages is not a job-search strategy. It is a way to give up.

This is where AI agents help. Connect an agent to Remoet, give it your specific stack, ask it to find the 30 to 60 companies that match. Not “React companies.” Something like “remote companies running React with Next.js and TypeScript that have Python or Go on the backend.” The agent reads the data, returns the slice that fits you, and you stop competing with 409.

Star the ones that fit. Your weekly digest brings new roles from those companies without you having to look. The whole flow is free.

React is the floor, not the ceiling

The pitch I want to leave you with is the inverse of the optimistic one. React being the default is the thing keeping you stuck. It is the floor. Every applicant is at the floor. Climbing is the cluster.

Pick the specific React shape you actually are. Build your profile around that combination. Get visible to the 30 to 60 companies whose stack is your stack. Forget the other 350.

Stop applying like a React developer. Start applying like the specific React developer you are.

I’ve Been Building a Python Game Engine

I’ve been working on a project called ABS Engine, a Python game engine focused on keeping projects simple and organized.

Instead of making developers write massive setup code, games are mostly controlled through a project file called game.absp.

It can define things like:

  • entities
  • connected scripts
  • image assets
  • fullscreen settings
  • resolution
  • cursor visibility

Example idea:

Player entity
→ script: scripts/player.py
→ texture: data/images/player.png

Game settings:
→ fullscreen enabled
→ cursor hidden
→ resolution: 540×320

Scripts can still access the engine API directly using:

from engine.core import *

The goal is making game projects easier to structure while still giving advanced users full access to the engine itself.

I’m also working on build tools so projects can be packaged and shared easily without manually hunting for dependencies and assets.

Still early in development, but it’s been one of the most fun programming projects I’ve worked on.

Selling Without Stripe in a Country That Stripe Can’t Reach: When Compliance Becomes a Technical Problem

The Problem We Were Actually Solving

We launched our product in Venezuela, where we quickly realized that accepting traditional payments would be problematic. Our initial solution relied on PayPal’s mass payout feature, but that was short-lived. They suspended our account due to some minor compliance issues, and we lost access to our users’ funds. This led to a perfect storm of bad PR and unhappy customers. At that point, we knew we had to find an alternative payment infrastructure that could handle the complexities of the Venezuelan economy.

What We Tried First (And Why It Failed)

Our first attempt at replacing PayPal was to integrate Stripe. However, upon further research, we discovered that Stripe’s compliance requirements wouldn’t allow them to operate in Venezuela due to various sanctions and embargoes. We then turned to alternative payment gateways like PayU or Mercado Pago, but their requirements were still too restrictive, and the fees were prohibitively expensive. It seemed like the more we tried to comply with traditional payment processors, the more we realized how little they cared about our niche market.

The Architecture Decision

After months of research and experimentation, we finally found an alternative: crypto payment infrastructure using the Cosmos SDK, a blockchain framework for building cross-chain applications. We chose to integrate a local cryptocurrency called Petro, which was a sovereign digital currency backed by the Venezuelan government. With the help of a developer who specialized in blockchain development, we created a custom payment flow that tied our product directly to the Petro network. This was a massive undertaking that required us to reimagine our entire payment system from the ground up. We had to write custom software to interact with the Petro wallet API, handle key management, and encrypt sensitive user data.

What The Numbers Said After

The numbers were encouraging. Our churn rate plummeted by 30%, mainly because customers could now purchase our product without worrying about payment issues. Our average order value (AOV) increased by 20% due to reduced transaction fees, and our overall customer satisfaction ratings improved significantly. We also witnessed a 50% increase in international transactions using the Petro currency.

What I Would Do Differently

Looking back, I would have started exploring blockchain solutions much earlier in the development process. While the initial investment was worthwhile, it forced us to divert resources from other critical areas of the business. Additionally, I would have chosen a more transparent and compliant blockchain framework that offered better support for our target market. If I had to redo the architecture decision, I would opt for a more robust and community-driven blockchain solution like Solana or Algorand, which offer better scalability and more established adoption rates.

Solana’s Biggest Consensus Overhaul Is Live for Testing. Here’s What Builders Need to do right now.

 Alpenglow is not on mainnet yet. The community test cluster is where validator operators evaluate the new consensus design under real-world conditions before any broader rollout. The test milestone matters because it demonstrated that Alpenswitch — the actual transition from old to new consensus — works in a live multi-validator environment.

What Builders Should Do Right Now

1. Build against 150ms finality assumptions

If you’re designing application architecture today that will ship in Q4 2026, model your UX and confirmation flows against 150ms rather than 12.8 seconds. Don’t design for the current network if your launch is after mainnet activation.

2. Audit your RPC infrastructure for throughput

If Alpenglow drives meaningful adoption growth on Solana, your application’s RPC request volume will scale with it. Shared public endpoints have rate limits that don’t scale with your traffic. This is the time to evaluate whether your current RPC setup can handle 2-3x your current load.

Dedicated endpoints give you isolated capacity — your rate limits are determined by your usage alone, not shared with every other application on the same node. For Solana applications expecting growth alongside Alpenglow’s mainnet launch, this is worth evaluating before the traffic arrives.

3. Check the Anza and Firedancer GitHub repos

Both teams have Alpenglow implementations available. If you’re building validator tooling or infrastructure that touches Solana’s consensus layer, the code is there to review now — not after mainnet.

4. Watch for Agave 4.1

This is the client release that ships Alpenglow to mainnet. When the release candidate drops, that’s the signal that the mainnet activation timeline is concrete rather than projected.

The Bigger Picture

Solana’s metrics have been soft for the past several months — TVL down 56% from its 2025 peak, monthly active users at a two-year low, fees declining. Alpenglow is the technical answer to a network that needs a structural argument for why builders and institutional capital should choose it over alternatives.

The argument is: a network where three-quarters of block space goes to internal coordination has a ceiling. Remove that ceiling and the throughput, reliability, and user experience ceiling rises with it. That’s the bet Alpenglow is making — and with 98.27% validator approval and a successful test cluster activation, the bet is looking increasingly credible.

This breakdown is based on Running Web3 Weekly by GetBlock, covering the infrastructure stories that matter for builders every Monday on YouTube and X.

GetBlock provides dedicated and shared RPC nodes for Solana and 130+ other blockchains — including low-latency dedicated Solana stacks built for HFT, MEV, and high-throughput applications. Explore Solana infrastructure.

Arnavutluk'ta otomotiv fuarı başladı

Arnavutluk’un başkenti Tiran’da düzenlenen Automotive Fair Albania otomobil fuarı, çeşitli marka araçlar, parçalar ve klasik retro araçlarla ziyaretçilere açıldı. Fuar 24 Mayıs’a kadar devam edecek.

Mesleki eğitimde dijital dönüşüm hamlesi

Mersin İl Milli Eğitim Müdürü Muhammed Özdemirci, Erasmus+ kapsamında düzenlenen ‘Mesleki ve Teknik Eğitimde Dijital Dönüşüm ve Endüstri 4.0’ konulu eğitim faaliyetlerine katıldı. Romanyalı uzman tarafından öğretmenlere uygulamalı eğitimler verildi.

Your agent keeps using that word …

“You keep using that word. I do not think it means what you think it means.”
— Inigo Montoya, The Princess Bride (1987)

Two people using the same word while meaning completely different things has been a staple of comedy for centuries.

Lewis Carroll built an entire scene around it in 1871:

“When I use a word,” Humpty Dumpty tells Alice, “it means just what I choose it to mean – neither more nor less.”

Now imagine what happens if you give Humpty Dumpty a code editor and 1M tokens of context…

An AI coding agent is the most confident version of Humpty Dumpty you’ll ever encounter. It will interpret your vocabulary however it sees fit, and it will never tell you it’s confused. It won’t raise its hand and ask “wait, do you mean a purchase order or a delivery order?” It will pick one interpretation, generate plausible code, and move on. As confidently as ever.

How AI agents amplify vocabulary ambiguity

The problem isn’t new. Teams have always talked past each other. But in traditional development, ambiguity encounters friction: code reviews, pair programming, whiteboard sessions, the “wait, what exactly do you mean by ‘order’?” conversation over coffee. Misunderstandings cascade, but they mostly get caught eventually.

With AI agents, that friction disappears. The code compiles, the tests pass, and the semantic mismatch only surfaces when a downstream system interprets the same word differently. Or when the wrong action leads to a production incident.

In How Creating a Ubiquitous Language Ensures AI Builds What You Actually Want, Daniel Schleicher wrote: “LLMs are amplifiers. When we give an AI agent ambiguous instructions where ‘order’ could mean a dozen different things, it amplifies the chaos by generating code that reflects our confusion.”

The flip side is equally true: precise vocabulary gets amplified into correct class names, correct lifecycle states, and correct boundaries. The agent works with whatever you give it – if you give it ambiguity, then that’s what it amplifies.

Russ Miles tells a story about a finance agent that confused booking (revenue recognition in one bounded context) and reservation (risk allocation in another):

“The agent mashed them like a bad DJ, and began taking action that would’ve landed the CFO in handcuffs.”
— Russ Miles, Domain Driven Agent Design

Ambiguous words, different contexts, no clear definitions, and code that compiled just fine all the way to production.

Ubiquitous Language: DDD’s pattern for shared vocabulary

The good news is that Domain-Driven Design (DDD), a widely-adopted methodology, introduced by Eric Evans in 2003, provides both the vocabulary and the pattern for a solution. It’s called Ubiquitous Language:

Use the model as the backbone of a language. Commit the team to exercising that language relentlessly in all communication within the team and in the code.
— Eric Evans, Domain-Driven Design (2003)

Martin Fowler describes it as “the practice of building up a common, rigorous language between developers and users.”

And Vaughn Vernon sharpens it even more:

“[…] a shared language developed by the team – a team comprised of both domain experts and software developers”
— Vaughn Vernon, Implementing Domain-Driven Design (2013)

The important distinction here: It’s not a glossary imposed from above, not industry jargon adopted wholesale. It is a language the team builds together through use.

But note that – despite the name – the Ubiquitous Language is all but ubiquitous. In Vernon’s words: “There is one Ubiquitous Language per Bounded Context.”

What does “Customer” really mean?

The term “Customer” seems universal – it shows up in the codebase of virtually every single business application.

But look at how each subdomain actually refers to the same person: marketing calls them a lead, sales calls them a prospect, the warehouse calls them a consignee, finance calls them a debtor, and support calls them a claimant.

All these subdomains may refer to the same person, but the words they use aren’t synonyms. They carry different attributes, different lifecycle states, different invariants, and different behavior.

And nobody really “creates” or “deletes” anything: a lead is captured, a prospect is qualified, a purchase intent is confirmed, a shipment is dispatched. Each subdomain has its own language, refined over decades – or centuries – of practice.

Flattening all of this into a Customer class with a type field and CRUD operations may feel like it’s simplifying things. But it actually erases the precision and clarity each domain has built, and replaces it with generic ambiguity, which the code, the database schema, the team, and – more often than not – the users of the software have to work around.

When writing the original book, Evans described the Ubiquitous Language for teams of humans – developers, product managers, and domain experts – modelling a shared domain.

But now, we have a new participant: the coding agent. And when the agent reads your prompt, your system instructions, your project rules, it’s doing something analogous to a new developer onboarding onto the team.

Except it onboards every session, with no memory of last time’s disambiguation, and no instinct to ask when a term’s exact meaning is unclear. Tell it “delete the order” and it will. Generically, ambiguously, and very confidently.

Practitioners applying DDD’s Ubiquitous Language to AI agents

I’m not the only one seeing this. Across the industry, people are arriving at the same pattern from different directions.

Martin Fowler described at the Pragmatic Summit 2026 how a colleague is “developing a precise language to communicate about the domain with the agent… that’s basically the kind of model building, language building, domain-driven design stuff that we’re used to doing, but it makes him more efficient to talk to the agent.”

Matt Pocock built a glossary skill that scans the codebase, extracts terminology into markdown, and feeds it to the agent. Reading the agent’s thinking traces, he found it improved implementation alignment while even reducing verbosity – an unexpected benefit in terms of token use and cost.

Daniel Schleicher formalized it with the “Spec Ambiguity Resolver” pattern: a living glossary where AI flags ambiguous terms, proposes definitions, and waits for human approval. Once approved, consistency is enforced project-wide:

“The greatest leverage in modern software development with AI,” he writes, “lies not in accelerating typing, but in establishing semantic agreement before implementation begins.”
— Daniel Schleicher, How Creating a Ubiquitous Language …

Tim Oleson named “Language Consistency – usage of ubiquitous language in agent communications” as a first-class domain alignment metric for agent systems.

Whether they came to it through practicing Domain-Driven Design or arrived at it independently, the pattern is the same. And it shows up in places you might not expect: every MCP tool name is a vocabulary decision the LLM reasons over. confirm_purchase_intent() and submit_order() produce different agent behavior even when the underlying operation is identical. Chris Hughes writes that the tools layer “protects your domain from the LLM’s interface requirements – translating between ‘strings the LLM can reason about’ and ‘rich domain objects your code works with.'”

Marc Brooker’s Specification Loop explains how this compounds over time: each resolved ambiguity becomes a stable term that enriches the shared vocabulary. The next conversation starts from a higher baseline and the loop gets cheaper over time as the vocabulary grows. “I believe that the trips around the loop are fundamental to the success of the whole enterprise. They’re what we’ve been doing all along.”

How to define domain vocabulary for your coding agent

The Ubiquitous Language isn’t a document you have to write upfront and rigidly apply. It’s a living artifact that evolves through use.

A common practice in teams: whenever someone realizes there’s an ambiguity – two people using the same word differently, or one word meaning two things – the team pauses, discusses, and agrees on a term. And this doesn’t have to be the academically “correct” term. What matters is that everyone on the team knows exactly what it means. Then you write it down, and use it consistently. In conversations, in code, and in the documentation.

This practice naturally extends to conversations with a coding agent. Whenever there’s a misunderstanding, missing clarity, or ambiguity in what the agent produces, spend a moment to establish a specific term for the concept. Define it. Add it to whatever artifact represents the current shared state of the vocabulary: your CLAUDE.md or AGENT.md, your cursor rules, or just a simple domain-terms.md, referenced as the canonical glossary of terms. The agent will start using it from that point forward, each disambiguation compounds, and every new conversation starts from a higher baseline.

But remember: each bounded context has its own vocabulary. If your application has a fulfillment module and a billing module, each gets its own language section in that module’s CLAUDE.md (or whatever file your agent reads when entering a directory). The terms in one context don’t need to match the terms in another – that’s the whole point.

Here’s what a modules/fulfillment/CLAUDE.md might contain:

## Fulfillment Domain Language

**Consignee**:
The person or entity receiving a shipment. Identified by delivery
address, contact phone, and access instructions. A consignee may
differ from the purchaser.
*Avoid*: Customer, Buyer, User

**Consignment**:
The full set of items to be delivered to a consignee. May be
fulfilled as one or more Shipments depending on stock location
and logistics.
*Avoid*: Order, Delivery (a delivery is one shipment arriving,
not the full set)

**Shipment**:
A physical package dispatched to a consignee via a carrier. Has
tracking number, weight, dimensions, and a declared value.
*Avoid*: Order, Package (ambiguous with code packages)

**Dispatch**:
The act of handing a shipment to a carrier. Irreversible - once
dispatched, the shipment is the carrier's responsibility.
*Avoid*: Send, Ship (verb), Process

And modules/billing/CLAUDE.md in the same application, even though it might refer to the same physical person or purchase event, is using terms native to its own domain:

## Billing Domain Language

**Debtor**:
The legal entity liable for payment. Identified by tax ID, billing
address, and agreed payment terms (net-30, net-60, etc.).
*Avoid*: Customer, Account, User

**Invoice**:
A legal demand for payment tied to one or more line items. Carries
a due date, VAT status, and regulatory classification. An invoice
is never deleted - it is reversed with a **Credit Note**.
*Avoid*: Order, Bill (ambiguous with infrastructure billing)

**Settlement**:
The act of a debtor satisfying an invoice in full or in part.
Records payment method, date, and reconciliation reference.
*Avoid*: Payment (ambiguous - is it the act or the money?),
Transaction

Both examples describe the same person making the same purchase. But the vocabularies are completely different, because the contexts model different responsibilities, different invariants, different behaviors, and different lifecycles.

Tell an agent “handle the customer’s order” without this, and you get a generic Customer class with a type field. Tell it within a defined context, and you get a Consignee with a delivery address or a Debtor with payment terms.

The vocabulary manifests in an architecture that captures the richness of the business domains it models. And – whichever context you’re in – the agent knows exactly what you mean.

And remember: You don’t need a formal glossary to start.

All you need is one line the next time something goes wrong: “In this project, order *means a confirmed purchase intent, not a request or a reservation.”*

Add it. Use it. Let it accumulate.

If you want to learn more about how Domain-Driven Design maps to the age of coding agents, I recently wrote about how engineers building MCP servers are reaching for DDD’s Bounded Contexts and Anti-Corruption Layers.

OpenSparrow v2.3 – visual admin panel, zero dependencies, now with ERD and M2M support

Hey

OpenSparrow v2.3 is out. Quick recap if you missed earlier posts — it’s an open-source admin panel framework built on PHP 8.1, PostgreSQL, and Vanilla JS. No npm, no Composer, no external libraries. You configure everything visually through /admin.

Live demo: demo.opensparrow.org

What’s new

  • Schema Map (ERD) — visual diagram of your entire database with PNG export
  • Many-to-Many support — dedicated Builder tab, chip renderer in grids
  • Virtual computed columns — formula fields without touching the DB
  • Custom Views — save filtered/sorted perspectives per table
  • Record Ownership — track who handles what, full history
  • Performance tab — index advisor, slow query analyzer, bloat detection
  • Security hardening — 5 audit fixes, better session and input validation

Contributing

Looking for contributors — code, docs, or a short demo screencast.

opensparrow.org
github.com/wrobeltomasz/open-sparrow