Beer & Servers Don't Mix

The Business Logic Your Engineers Can’t See

Or: Why Technical Excellence Without Domain Understanding Is Expensive

It was 2:15 on a Wednesday on level 6, and the aircon was losing its quiet war against a room with too many bodies and too many monitors. Someone had made Thai iced tea in the kitchen, and that sweet burnt-sugar smell drifted across the open plan. Somchai had his hand up again. Not the confident hand of someone with an answer — the tentative half-raise of someone about to ask the PO what colour a button should be. Three seats away, Namfon had the same Slack DM open, cursor blinking, the same question queued behind two others. The junior PO sat with her shoulders up near her ears, backlog untouched on her second monitor, a half-eaten bag of Lays slowly going stale beside her keyboard. She wasn’t thinking about product strategy. She was answering her fourteenth clarification question of the day.

That team had something most engineering organisations would kill for: a dedicated Product Owner with nothing else to do but support them. And it produced the worst domain understanding of any team in the org.

As the management theorist Russell Ackoff once put it, “The righter you do the wrong thing, the wronger you become.” We’ve spent decades getting better at building software — better tools, better frameworks, better processes — while consistently underinvesting in the thing that determines whether the software we build actually matters: understanding the business it serves.

Here’s the dirty secret of software engineering education: we teach people how to code, how to architect systems, how to write tests — and then drop them into a domain they know nothing about and wonder why the software doesn’t match the business. The gap between “technically correct” and “solves the actual problem” is almost always a gap in business understanding, not a gap in technical skill.

Most engineering failures aren’t engineering failures. They’re comprehension failures. The code compiles. The tests pass. The service scales. And the feature does something nobody asked for, because the engineer who built it didn’t understand the business domain deeply enough to know why the requirement existed in the first place.

The PO Who Answered Every Question (And Why That Was the Problem)

Most posts about engineers and business understanding open with a disaster: the pricing rule nobody understood, the regulation nobody checked, the feature that missed the market. Those stories are real, but they’re not the interesting failure mode. The interesting failure mode is the one that looks like success.

That team I mentioned — they shipped working software. Nothing broke. Every ticket was completed, every acceptance criterion met. If you looked at velocity charts, they were a model squad. But beneath the surface, something corrosive was happening.

The engineers had stopped investing in understanding why things worked the way they did. They didn’t need to — they could ask. Every question became a lookup: “what should this do?” instead of “why does this exist?” They built features correctly but couldn’t connect what they’d built to the business reason behind it. When experiments showed bias, the engineers couldn’t spot it — because they had no mental model of how users actually used the product. They had no map of the user journey, just a series of tickets with instant answers attached.

The junior PO, meanwhile, was drowning. She’d been hired as a strategic partner and had become an on-demand FAQ service. Her product thinking atrophied because every minute was consumed by reactive clarification instead of proactive planning.

“The heart of software is its ability to solve domain-related problems for its user.”* — Eric Evans, *Domain-Driven Design

The paradox: the team with the most access to domain knowledge had the least domain understanding. Not because they were lazy. Because the system they were in removed the incentive to learn.

One of my solutions was counterintuitive — give engineers less PO time, not more. Tell the PO it’s OK not to come to every standup. The constraint of limited access forces engineers to invest in understanding the domain upfront, because they can’t rely on just-in-time clarification for every decision. When your PO is in meetings and unavailable — which is a common occurrence at Agoda — you learn to ask deeper questions during planning so you don’t get caught out later. That friction isn’t a bug. It’s the mechanism that builds domain fluency.

Why Engineers Don’t Understand the Business (And Why It’s Not Their Fault)

Let me be clear: this isn’t about lazy or incurious engineers. I’ve never met an engineer who wanted to build the wrong thing. This is about structural barriers that organisations erect — usually without realising it — between engineers and the business knowledge they need.

Tickets strip context — and “Definition of Ready” makes it worse. Jira stories reduce complex business rules to acceptance criteria. The why gets lost somewhere between the product meeting and the ticket description. By the time an engineer reads “as a user, I want to see the adjusted price including commission,” the entire history of why that commission structure exists, which partner contracts it reflects, and what regulatory constraints shaped it has evaporated.

I had a team that tried to solve this by creating a “Definition of Ready” — a checklist of everything a Jira story needed before engineers would accept it into a sprint. On the surface, it sounds reasonable. In practice, it was a red flag. The Definition of Ready pushed all the context-gathering work onto the PO and turned engineers into passive consumers of pre-digested requirements. The PO did the legwork, the engineers reviewed the output, and nobody on the engineering side built any understanding of the domain in the process. The ticket arrived “ready” — neat, complete, and completely disconnected from the messy business reality that shaped it. Engineers should be part of that legwork. The act of helping refine a requirement — talking to stakeholders, understanding the constraints, asking why the rule exists — is how domain knowledge transfers. When you outsource that to a checklist, you get well-formatted tickets and engineers who still can’t tell you why the business needed what they just built.

Specialisation creates tunnel vision. In microservices organisations, an engineer might work on “the payment service” for two years and never understand how payments fit into the wider booking flow. They know everything about authorisation and capture, nothing about why the dependency graph of the booking systems upstream needs to route through their service in a particular order.

Domain experts are busy — or too available. This one cuts both ways. When POs and business analysts are stretched thin, they answer questions when asked but don’t proactively teach the domain. And as we saw with our always-available PO, when they are available, engineers outsource understanding instead of building it. The sweet spot is somewhere in the middle, and most organisations land at one extreme or the other.

Onboarding is purely technical. Your new hire bootcamp probably covers the tech stack, the CI/CD pipeline, and the coding standards. Does it cover the business model? The key business processes? The regulatory environment? If a new engineer joins the pricing team, do they learn how OTA pricing actually works — the commission structures, the partner relationships, the currency conversion chains — or do they just learn the codebase? If you’re only teaching the codebase, you’re setting engineers up to build the wrong thing.

Domain knowledge is tacit. The people who really understand the business carry it in their heads. It’s not documented because it changes constantly and documentation goes stale before the ink dries. The result is tribal knowledge — “you need to talk to Namfon about that service, she’s the only one who knows why it does that thing with Japanese tax calculations” — which is fragile, unscalable, and a single point of failure.

The pattern across all of these: domain knowledge is treated as someone else’s job, but the consequences of its absence land squarely on engineering. The engineer who doesn’t understand why a rule exists can’t flag when a new feature contradicts it. They can’t simplify the implementation because they don’t know which constraints are real and which are accidents of history. They can’t push back on bad requirements because they don’t have the standing that comes from domain fluency.

The Sixty-Node Booking Graph (Or: When “Simple” Is a Domain Question)

Let me make this concrete with an example from our world.

Agoda’s booking engine has a dependency graph of roughly 60 nodes that orchestrates a single booking. If you’re an engineer who’s never worked in travel tech, your first reaction is probably: “That’s insane. Why is it so complex? Who over-engineered this?”

That reaction is a domain comprehension failure. Here’s why.

The source of truth isn’t you. Agoda sells accommodation from global hotel chains, wholesale travel suppliers, all the way down to individual homes (think Airbnb operators). For many of these, the source of truth for “is this the right price?” or “is this room still available?” isn’t Agoda — it’s the supplier. A chain hotel might respond in milliseconds via a standardised API. A small guesthouse in rural Thailand might be on a channel manager that takes seconds to confirm. The dependency graph has to accommodate real-time verification against external systems with wildly different APIs, response times, and reliability characteristics — with fallbacks, timeouts, and reconciliation logic for each supplier type.

Three hundred payment methods across dozens of currencies. Agoda supports over 300 payment methods in a massive range of currencies. This isn’t a design choice — it’s a business requirement driven by the reality of Asian markets. GrabPay in Southeast Asia, Alipay and WeChat Pay in China, bank transfers in Japan, UPI in India — each with their own authentication flows, settlement timelines, currency handling, and failure modes. A dependency graph that only supported credit cards would be a fraction of the complexity. Supporting the actual payment landscape of Asia is what drives the node count up.

An engineer who understands this domain looks at a 60-node dependency graph and thinks “honestly, that seems about right.” An engineer who doesn’t understand the domain either proposes “simplifications” that would break the business, or sits paralysed by complexity they can’t reason about because they don’t understand why each node exists.

As the basketball coach John Wooden observed, “It’s what you learn after you know it all that counts.” The engineer who thinks they understand the booking flow because they’ve read the code is the one most likely to simplify away something load-bearing. The engineer who understands the business knows which complexity is essential and which is debt.

This principle applies far beyond travel. Every domain has hidden complexity that looks like over-engineering from the outside:

Healthcare has billing codes, insurance networks, HIPAA compliance, and prior authorisation workflows that make a simple “book an appointment” flow look like a state machine from a graduate textbook. E-commerce has inventory management across warehouses, return logistics, and promotional stacking rules where the interaction effects between discounts can surprise even the people who designed them. Insurance has actuarial models, claims adjudication processes, and regulatory capital requirements that vary by jurisdiction and product type.

The complexity that kills you isn’t in the code — it’s in the rules the code encodes. And if the people writing the code don’t understand the rules, they’ll encode them wrong.

When “Booking” Means Five Different Things

Eric Evans’ concept of Ubiquitous Language from Domain-Driven Design sounds academic until you’ve lived through what happens without it.

At an OTA, “booking” could mean: the act of a customer clicking “confirm” (the user event), the record in the booking database (the data entity), the financial obligation created (the accounting event), the reservation held at the hotel (the partner-side commitment), or the entire lifecycle from search to stay to review (the product journey). When the business says “we need to fix the booking flow,” which one do they mean? When an engineer builds a “booking service,” which definition are they encoding?

This isn’t pedantic. Ambiguity in language becomes ambiguity in architecture. If two teams use “booking” to mean different things, their services will model different concepts — and the integration between them will be where bugs live.

One area where Agoda has genuinely excelled — and has for a long time — is maintaining a ubiquitous language that runs from business meetings to database tables. If a business person says “rate plan” or “rate channel,” you can trace those exact terms from the frontend UI through the service layer all the way down to the database. The business vocabulary and the technical vocabulary are the same vocabulary. This isn’t a recent initiative or a DDD project someone championed — it’s been a long-standing cultural norm. And that consistency is one of the reasons our engineers can reason about the business, because the code literally speaks the same language as the business.

We use DDD extensively for our service architecture — a good part of the planning for our monolith split was guided by DDD principles. But the hardest part isn’t the framework. It’s getting engineers to internalise the skill of domain identification rather than memorising the current domain map. The common failure mode is engineers wanting to be told what the domains are so they can move on, rather than learning how to identify domains themselves. Knowing the current boundaries isn’t enough. Engineers need to understand how to spot when a new domain is emerging and how to classify new features into the right place. Without that skill, the domain model ossifies — it was right when it was drawn, but the business has moved on and nobody noticed because nobody knew how to re-evaluate.

Sound familiar? It’s the same pattern as the PO story. Engineers want the answer (“tell me the domains”) rather than the understanding (“teach me how to see domains”). The convenient shortcut undermines the deeper capability.

A deeper dive into how we apply Domain-Driven Design to service decomposition is coming in a future post.

Domain Fluency Changes Engineering Decisions (Not Just Business Ones)

Here’s a story that reframes what domain understanding actually looks like in practice.

A team needed to build complex dynamic pricing and commission logic — the kind of business rules that live at the intersection of pricing strategy, partner relationships, and search algorithms. Based on multiple variables, the system would adjust commission and price, which would then flow through to affect ranking. Pure domain complexity.

The engineers who built it had deep domain understanding. And that understanding manifested in an unexpected way: they chose Cucumber — BDD-style testing with a domain-specific language — to describe the behaviour.

Now, I’m generally not a fan of Cucumber. I think it’s great in theory and fails in practice for most teams. But this time it worked beautifully. The engineers wrote complex Cucumber tests using the DSL to precisely describe the pricing and commission logic in business-readable language. This wasn’t just a test suite — it became a communication artifact. The team that owned the downstream system could read it and verify the logic. The PO could read it and confirm the business rules. Everyone was on the same page, expressed in a shared language that was both executable and human-readable.

An engineer who doesn’t understand the domain would have written unit tests that verified the code worked. These engineers understood the domain well enough to recognise that the real risk wasn’t “does the code work?” but “does everyone agree on what the code should do?” — and they chose a tool specifically designed to solve that communication problem.

Domain-fluent engineers don’t just build better features — they make better engineering decisions. Tooling choices, testing strategies, API design, service boundaries, documentation approaches. Domain fluency isn’t a separate skill from technical skill. It’s what makes technical skill commercially relevant.

That Cucumber DSL was, in effect, the ubiquitous language for the pricing domain. It worked because the engineers understood the domain well enough to express it in terms both code and humans could parse. This is exactly what Evans advocates — and it happened not because someone mandated DDD, but because domain-fluent engineers naturally gravitated toward the right tool.

The Cognitive Ceiling (Or: Why You Can’t Know Everything)

Before you conclude that every engineer should understand the entire business, let me complicate the picture.

In the early days at Agoda, I led the NHA project — Non-Hotel Accommodation, essentially competing with Airbnb. The project required touching every area of the accommodation side of the business: pricing, booking, content — plus building entirely new domains on top. The team had to hold multiple complex domains in their heads simultaneously.

The project was hard, and the team moved slowly at times. Not because they were bad — because you simply can’t hold pricing logic, booking flows, content management, and new accommodation type rules in your head simultaneously without cognitive overload slowing you down. There’s a real upper bound on how much domain complexity one team can absorb.

“The greatest enemy of knowledge is not ignorance, it is the illusion of knowledge.”* — Daniel J. Boorstin, historian and former Librarian of Congress*

The surprising upside: I had remarkably low turnover on that team in the early days. They were always working on something new. The cognitive load was high, but the variety kept engineers engaged. There’s a genuine tension between “specialise to manage complexity” and “variety keeps people motivated” that’s worth naming honestly.

This is one of the underappreciated arguments for domain-driven service boundaries. It’s not just about independent deployment or technical decoupling. It’s about keeping the domain scope per team small enough that engineers can genuinely understand it. Domain separation isn’t just a technical architecture decision — it’s a cognitive architecture decision. You split systems along domain lines partly so that no single team has to hold too many business contexts simultaneously.

The answer isn’t “every engineer should understand the whole business.” The answer is “every engineer should deeply understand their domain, and the organisation should structure teams so that’s achievable.” Rotation through domains builds the cross-domain pattern recognition that’s invaluable, but trying to hold every domain simultaneously just makes you slow and stressed.

Building Domain Fluency: What Actually Works

For Individual Engineers

Shadow the business. Sit in on a sales call. Watch a support agent handle a complaint. Attend a partner onboarding session. One afternoon of shadowing teaches you more about the domain than a month of reading documentation. At Agoda, we have a programme that lets engineers shadow call centre agents for a day — hearing real customers struggle with real problems in real time. Our UX researchers conduct interviews with partners and publish the recordings internally so engineers can watch them on their own schedule. These aren’t senior engineer perks. They’re available from day one.

Follow the money. For any product company: How does a dollar enter the system? How does it move between entities? Where does it exit? Following the money reveals the real architecture of the business — the one that matters more than your service dependency diagram.

Ask “why does this rule exist?” every single time you encounter a business rule that seems arbitrary. The answer is always one of: regulatory requirement, partner contract, historical accident, or “nobody knows.” Each answer tells you something important, and “nobody knows” is the most important answer of all — because it means that rule is either load-bearing for a reason nobody documented or it’s dead weight nobody’s had the courage to remove.

Learn the vocabulary before the codebase. When joining a new team, spend your first week learning the domain language, not only the code. The code will make more sense once you understand what it’s trying to model. If your company has a ubiquitous language — terms that flow from business meetings to database columns — learn that language first. It’s the Rosetta Stone for your codebase.

Read the financial reports. If your company is public, the annual report tells you how the company makes money, what the risks are, and what the strategic priorities are. This is the business context that never makes it into Jira tickets but shapes every decision about what gets built.

For Engineering Leaders

Invest in domain onboarding. Your new hire bootcamp covers the tech stack, the CI/CD pipeline, and the coding standards. Add the business model, the key business processes, and the regulatory environment. If you’re in travel, explain how OTA pricing actually works. If you’re in fintech, walk through the payment lifecycle. An engineer who understands the business in week one makes better decisions in month one.

Create domain days. Regular sessions where business experts explain a part of the domain to engineering. Not a presentation — a Q&A. Let engineers ask the “obvious” questions that reveal critical assumptions everyone else has internalised and forgotten they know.

Don’t gate domain understanding behind seniority. If your juniors aren’t talking to users, they’re building a habit of not understanding the domain that becomes harder to break with every passing year. The engineer who’s been executing tickets for five years and then gets promoted to senior doesn’t magically develop domain fluency. They’ve spent five years practising the opposite. Include user interaction in junior engineer expectations from their first sprint.

Rotate engineers across domains — deliberately. An engineer who’s only ever worked on the payment service has a narrow view of the business. Rotation builds the cross-domain pattern recognition that prevents integration failures and builds empathy between teams. But be deliberate about the cognitive load: a team that touches every domain simultaneously moves slowly. A team that rotates through domains sequentially builds breadth without overload.

Include domain understanding in the career ladder. If your engineering levels only reward technical skill, you’re signalling that domain knowledge doesn’t matter. Senior and Staff engineers should be expected to demonstrate deep domain understanding — not as a nice-to-have, but as a core competency. At Agoda, we don’t treat engineers as ticket executors. The expectation is that you understand the domain you’re building for. That’s not a cultural bonus — it’s what lets us operate a platform with 300+ payment methods and suppliers ranging from global hotel chains to individual homes without everything collapsing.

Make the business model visible. Create architecture diagrams that show the business flow, not just the technical flow. When engineers can see how their service fits into the value chain, they stop optimising in isolation and start making decisions that serve the whole system.

The Bottom Line

As Peter Drucker observed, “There is nothing so useless as doing efficiently that which should not be done at all.” We’ve built an industry around making engineers more technically proficient — better at building things fast, building things that scale, building things that don’t break. And we’ve systematically underinvested in helping them understand what to build and why.

The code compiles. The tests pass. The feature ships. And the business loses money because the engineer who built the commission logic didn’t understand why that 2% difference matters in the Japanese market, or the engineer who “simplified” the booking flow didn’t realise that the node they removed was handling a regulatory requirement for a specific payment method in a specific jurisdiction.

Domain understanding isn’t the opposite of technical excellence. It’s the thing that makes technical excellence worth having. An engineer who understands the business writes code that models reality. An engineer who doesn’t writes code that models their best guess about reality — and best guesses, compounded across hundreds of engineers and thousands of commits, are how you end up with systems that technically work and commercially fail.

The way knowledge flows to engineers matters more than the volume. Too little, and they build blind. Too much in the wrong form, and they never develop sight. The goal isn’t a PO on tap or a wiki nobody reads. It’s engineers who understand the domain deeply enough to reason independently — who can look at a 60-node dependency graph of the booking systems and know which nodes are essential and which are debt, who can choose Cucumber over unit tests because they understand the communication problem matters more than the coverage metric, who can push back on a requirement not because they’re difficult but because they know the domain well enough to spot the contradiction.

You don’t have a technical problem. You have a comprehension problem. And the good news is that comprehension problems, unlike some technical problems, are solvable with intention, structure, and the willingness to let engineers get close enough to the business to understand it.

Now, if you’ll excuse me, I have a Definition of Ready to go dismantle. Turns out well-formatted tickets aren’t a substitute for engineers who understand what they’re building — but try explaining that to a team that’s been treating Jira like a food menu.