⏱ 20 min read
Most architecture diagrams lie.
Not because architects are dishonest. Usually because the diagram looks precise while hiding the one thing that actually matters: what kind of thing each box and line really is. A service? A deployable? A bounded context? A Kafka topic? An IAM role? A data product? A class? A component? A team responsibility? If your model does not make that explicit, the diagram becomes decoration. And decoration is expensive when people mistake it for architecture.
That is the core argument here: the real fight is not UML versus code. It is explicit metamodel versus accidental ambiguity.
People love to frame this as a culture war. “Real engineers use code, not diagrams.” Or the opposite: “Architecture needs abstraction, not implementation detail.” Both are half true and mostly unhelpful. In enterprise work, you need both. But you only get value from either when the underlying metamodel is clear enough that people can reason about it, automate against it, and challenge it.
So let’s say it simply up front for SEO and for the impatient:
UML is useful when it captures meaning consistently. Code is useful when it captures executable truth. The metamodel matters because it defines what elements exist, what relationships are valid, and what decisions your architecture model can support.
If that sounds academic, it is not. In real architecture work, this is the difference between:
- a banking platform where everyone agrees what a “service” is
- a Kafka estate where topics are owned, secured, and versioned coherently
- an IAM model where roles, policies, identities, and trust boundaries are visible
- a cloud platform where “application,” “workload,” “cluster,” and “account” are not used as interchangeable noise
Without a metamodel, architects drift into vague nouns and nice pictures. With one, architecture becomes operational.
That is the point. And yes, I have a strong bias here: most enterprise architecture is weak not because people lack diagrams or code, but because they lack a disciplined metamodel.
First, the simple version: what is a metamodel?
A metamodel is just the model of your modeling language.
It tells you:
- what kinds of elements exist
- what they mean
- how they can relate to each other
- what rules apply
If your architecture repository says you can model “Application,” “Service,” “API,” “Database,” “Event Stream,” “Identity Provider,” and “Cloud Account,” that is part of your metamodel.
If it says an “Application” may expose an “API,” a “Service” may publish to a “Kafka Topic,” a “Role” may grant access to a “Resource,” and a “Cloud Account” owns “Deployments,” that is also part of your metamodel.
If it says a “Kafka Topic” must have exactly one business owner and one technical owner, that consumer groups are not systems, and that IAM roles are not people, now we are getting somewhere.
The metamodel is what stops your architecture from turning into a whiteboard séance.
UML has a metamodel. Code has one too, though people often pretend it doesn’t. A programming language, framework annotations, infrastructure-as-code resource types, API contracts, event schemas, and policy languages all encode structure and meaning. The difference is that code usually has stricter enforcement and faster feedback, while diagramming often has weaker discipline and more social interpretation.
That is why engineers often trust code more. Fair enough. But code is not automatically a better architectural model. It often captures implementation brilliantly and intent badly.
UML is not the problem. Shallow use of UML is the problem.
Let me be contrarian for a moment.
The industry spent years mocking UML, and frankly a lot of that mockery was deserved. Bloated class diagrams. Sequence diagrams nobody updated. Tooling that felt like tax software from 2004. Architects producing 80-page documents to avoid making decisions. Fine. That happened. UML modeling best practices
But the anti-UML reaction went too far. It created a lazy habit: if a model is not executable, people assume it is useless. That is nonsense.
Architecture is full of things that matter before code exists or beyond what code can express neatly:
- legal trust boundaries
- ownership models
- segregation of duties
- data classification
- regulatory controls
- lifecycle states
- organizational dependencies
- migration states
- platform constraints
- integration patterns across dozens or hundreds of systems
Try expressing all of that by reading source code alone in a large bank. You can’t. Or rather, you can after six months of archaeology, interviews, and trauma.
So yes, UML can still be useful. Not all of it. Not always. But a disciplined subset, used with a clear metamodel, is absolutely valuable.
The real mistake is when UML gets treated as drawing, not modeling. UML for microservices
A box is not a model element just because Visio says it is a rectangle.
Code is not a silver bullet either
Now the other side.
“Code is the source of truth” sounds modern and clean. Sometimes it is true. Often it is propaganda.
Source of truth for what, exactly?
- For a Kubernetes deployment? Sure, maybe the manifests or Helm charts.
- For an AWS IAM policy? Yes, likely the policy document or Terraform.
- For service interfaces? Maybe OpenAPI, protobuf, AsyncAPI.
- For event contracts? Potentially schema registry definitions.
- For cloud topology? Partly IaC, assuming reality matches declared state.
- For business capability ownership? Usually not.
- For critical data flows across a bank? Rarely in one place.
- For which services are allowed to consume customer PII? Not unless your organization is unusually mature.
- For whether a Kafka topic is business-domain-aligned or just a dumping ground? Definitely not.
Code is excellent at specifying local truth. Enterprise architecture needs composed truth.
That is where metamodel discipline matters. You need a way to connect code-level facts to architecture-level meaning. Otherwise “everything as code” becomes “everything as fragments.”
Engineers like to say, “The system architecture emerges from the code.” In a startup with four services, maybe. In a regulated enterprise with 1,200 applications, 300 Kafka topics, three cloud providers, and six identity domains? No. What emerges is confusion, duplicated capability, and a security review backlog.
Where the metamodel actually matters
Here is the practical point: a metamodel matters whenever architecture must answer questions consistently.
Questions like:
- What depends on this IAM provider?
- Which Kafka topics carry customer financial events?
- Which services are internet-facing?
- What workloads are allowed in this cloud account?
- Which applications process cardholder data?
- What is the difference between a business application and a deployable microservice?
- What can talk synchronously versus asynchronously?
- Which domain owns the customer profile?
- Which systems are in scope for zero-trust controls?
- What breaks if we retire this API gateway?
You cannot answer those well with free-form diagrams.
You cannot answer those well from source code alone.
You need a metamodel that defines the enterprise’s architectural vocabulary.
And here is the unfashionable part: that vocabulary should be opinionated.
Architects often fail because they are too polite. They let every team define “service,” “platform,” “domain,” “application,” and “event” differently. That feels collaborative. It is actually sabotage by ambiguity.
At enterprise scale, a metamodel is governance without the dead smell of traditional governance. It gives teams room to build while preserving shared meaning. ARB governance with Sparx EA
UML versus code is the wrong comparison
A better comparison looks like this:
This is the real answer. Use models for what they are good at. Use code for what it is good at. The metamodel is the bridge.
If your metamodel is weak, UML becomes fuzzy.
If your metamodel is weak, code becomes siloed.
If your metamodel is strong, the two can reinforce each other.
What this looks like in real architecture work
Let’s leave theory and get into actual enterprise practice.
A working architect spends a surprising amount of time translating between layers of abstraction:
- executives want business impact
- platform teams want standards
- security wants control evidence
- delivery teams want concrete constraints
- operations wants supportable topology
- auditors want traceability
- engineers want to know what they actually have to build
The metamodel is what lets you move across those conversations without changing the meaning of terms every 15 minutes.
Example: banking modernization with Kafka and IAM
Imagine a retail bank modernizing its customer domain.
The old world:
- core banking mainframe
- batch integration
- channel applications tightly coupled to shared databases
- fragmented identity model
- on-prem middleware
The target world:
- domain-aligned services in cloud
- Kafka for event backbone
- APIs for channel interaction
- centralized IAM with federated enterprise identity
- zero-trust segmentation
- hybrid integration during migration
Now here is where bad architecture usually starts.
Someone draws a box called “Customer Service.”
Another architect draws “Customer Domain.”
A platform lead creates a Kubernetes namespace called customer.
A team publishes a Kafka topic called customer-events.
Security creates an IAM role called customer-service-role.
An API team exposes /customers.
Everybody thinks these things line up.
They often do not.
The architecture problem is not just naming. It is category confusion.
A proper metamodel would distinguish at least:
- Business domain: Customer
- Application/service: Customer Profile Service
- API: Customer Profile API
- Event topic: customer.profile.changed
- Data entity / event schema: CustomerProfileChanged
- Deployment unit: customer-profile container/image
- Runtime environment: prod-eu-west-1
- IAM principal: workload identity for Customer Profile Service
- Owner: Customer Domain Team
- Control classification: PII-high
- Cloud boundary: Retail Banking Production Account
That may look obvious written down. In enterprise reality, those distinctions collapse constantly. Then you get nonsense discussions like “Can the customer service consume itself?” when one person means the domain, another means the API, and a third means the Kafka topic.
A metamodel is what saves you from this.
A real enterprise example
A large bank I worked with had exactly this issue, though with different names.
They wanted to establish an enterprise event-driven architecture around Kafka. The strategy deck was full of noble phrases: real-time enterprise, event-first integration, decoupling legacy, domain ownership, reusable event products. Good deck. Expensive deck.
But the actual estate was a mess.
Teams used “event,” “message,” “topic,” and “feed” interchangeably. Some topics represented business facts. Others were just technical replication channels. Some were permanent contracts. Others were temporary migration pipes. Ownership was inconsistent. Security classification was buried in spreadsheets. IAM permissions were granted at cluster level because topic-level semantics were unclear. Consumers subscribed directly to whatever looked useful. Data retention was often accidental.
The problem was not Kafka. The problem was that there was no coherent metamodel for the event architecture.
Once we forced a simple enterprise metamodel into place, things improved quickly. Not magically, but materially.
We defined:
- Event as a business fact that has occurred
- Event schema as the formal payload contract
- Topic as the transport channel carrying one or more event types under explicit rules
- Producer service as the accountable source of publication
- Consumer application as a subscribing system with a declared purpose
- Domain owner as the business-accountable owner
- Technical owner as the support owner
- Classification as the policy label for sensitivity and retention
- Integration stream as a migration-only or technical movement mechanism, explicitly not a reusable business event product
That last one mattered a lot. It gave us a sanctioned category for ugly transitional integration without pretending it was strategic architecture.
That is a contrarian point worth making: not every topic should be treated as a reusable domain event stream. Some are plumbing. Call them plumbing. Architects often damage programs by forcing everything into the idealized target pattern.
Once the metamodel was explicit, we could do useful things:
- define topic naming rules based on domain and event type
- separate business events from technical replication
- attach IAM policies to topic classes
- require ownership and classification for production topics
- support lineage and impact analysis
- identify consumers that should never have had access to PII
- distinguish temporary migration constructs from target-state architecture
Could code do some of this? Yes. Schema registry, Kafka ACLs, Terraform, policy-as-code, and catalog metadata helped. But the enterprise-level semantics came first. The code enforced the model; it did not invent it.
Common mistakes architects make
This is the section where I stop being diplomatic.
1. They confuse notation with meaning
Using UML component diagrams does not mean you have modeled components.
Using sequence diagrams does not mean you have modeled interactions.
Using C4 does not mean you have clarity.
Using code generation does not mean you have architecture.
Notation is the wrapper. Meaning is in the metamodel.
2. They allow one term to mean five things
This is probably the most common failure in enterprise architecture.
“Application” might mean:
- a business-facing product
- a deployable codebase
- a SaaS platform
- a logical capability grouping
- a procurement item
If your metamodel does not fix that, your repository becomes fiction.
3. They model too much too early
Another contrarian view: architects often overmodel because they are insecure.
You do not need twenty diagram types and 140 attributes per element. You need enough model structure to support decisions. Start with the questions architecture must answer. Build the metamodel to answer them. Expand only when there is a clear use case.
4. They let tooling define the architecture language
If your repository tool has an object type called “Node,” “Artifact,” or “Application Component,” that does not mean those are the right concepts for your enterprise.
Tools are helpful. Tool metamodels are not strategy.
5. They assume code repositories equal architecture truth
A Git repo can tell you many things. It cannot tell you everything that matters in enterprise design. Especially not ownership, policy intent, business criticality, or organizational accountability unless you deliberately model those.
6. They fail to distinguish logical, physical, and operational views
This causes endless confusion in cloud architecture.
A “service” is not the same as:
- a container
- a pod
- an ECS task
- a Lambda function
- a deployment
- a DNS name
- an IAM role
Yet in architecture reviews people jump between these levels as if they are all interchangeable. They are not.
7. They pretend transitional architecture does not exist
This one really irritates me.
Architects love target-state purity. Enterprises live in migration. If your metamodel has no place for temporary patterns, bridge services, replication topics, dual-write controls, legacy identity adapters, or hybrid cloud exceptions, your architecture model becomes performative. It describes the future and ignores the work.
UML in practice: what is still useful
I am not here to revive every UML diagram under the sun. Some should stay dead.
But a few things remain useful when backed by a clear metamodel:
Component-like views
Useful for showing logical responsibilities and dependencies, especially in domain decomposition.
Sequence or interaction views
Still good for making integration and trust flows visible, especially when showing where IAM tokens are issued, exchanged, and validated.
Deployment views
Helpful in cloud discussions when you need to show accounts, VPCs, clusters, regions, managed services, and security boundaries.
State-ish modeling
Useful for lifecycle-heavy things like identity onboarding, payment processing, or event lifecycle governance. EA governance checklist
The trick is restraint. Do not produce UML because UML exists. Produce a model view because a decision needs support.
And frankly, many teams now do this better with mixed notation than pure UML. That is fine. Purity is overrated. Semantic discipline is not.
Code in practice: where it wins
Code wins decisively when the problem is enforceable structure.
Examples:
- Terraform defining cloud resources and policy attachments
- Kubernetes manifests defining workload deployment
- OpenAPI and protobuf defining service contracts
- AsyncAPI or schema registry defining event structures
- OPA/Rego or cloud-native policy engines defining access constraints
- IAM policy documents defining permissions
- CI/CD checks validating conventions and controls
This is where architects should stop admiring diagrams and start wiring architecture to delivery. TOGAF training
A mature enterprise architecture practice does not just publish principles. It maps metamodel concepts to executable controls.
For example:
- if an element is modeled as a PII topic, then ACLs, retention, encryption, and consumer approval workflows should follow
- if a workload is modeled as internet-facing, then WAF, DDoS controls, and logging requirements should trigger
- if a service is modeled as critical payment path, then resilience standards and deployment restrictions should apply
- if an IAM trust is modeled as cross-domain federation, then review and monitoring requirements should increase
That is where architecture gets real.
Banking, IAM, and cloud: a concrete pattern
Let’s combine the examples.
Suppose a bank is building a new digital onboarding platform in cloud. It integrates with identity verification, customer profile services, fraud engines, core banking, and downstream analytics. Kafka is used for event propagation. IAM is centralized but federated across cloud accounts.
A practical metamodel might include these core entities:
- Business Capability
- Domain
- Application
- Service
- API
- Event
- Topic
- Data Store
- Identity Provider
- Principal
- Role/Policy
- Cloud Account
- Runtime Environment
- Trust Boundary
- Control Classification
- Team/Owner
And these relationships:
- Application realizes Business Capability
- Service belongs to Domain
- Service exposes API
- Service publishes Event to Topic
- Application consumes Topic
- Principal represents Service at runtime
- Role grants Principal access to Topic/API/Data Store
- Service deploys into Runtime Environment within Cloud Account
- Trust Boundary contains Runtime Environment
- Control Classification applies to Topic/Data Store/API
- Team owns Service/Topic/Application
That is not glamorous. It is useful.
Now architecture reviews become sharper:
- Does the onboarding service principal have publish rights only to onboarding events, or broad cluster rights?
- Are fraud consumers allowed to read customer identity events carrying sensitive KYC data?
- Which cloud accounts host regulated workloads?
- Are analytics consumers reading from business event topics or from a sanctioned derived stream?
- Is the API contract aligned with the event contract, or are we creating two contradictory customer identity models?
- What breaks if the central IdP federation path is unavailable?
Those are architecture questions. And they are answerable because the metamodel creates a consistent frame.
The practical rule: model what you need to govern, reason about, and automate
This is probably the most useful takeaway.
Do not argue abstractly about UML versus code.
Ask three questions:
- What do we need to reason about?
- What do we need to govern?
- What can we automate?
The overlap tells you where the metamodel matters most.
If you need to reason about trust boundaries, govern access, and automate policy checks, then IAM concepts must be explicit in your metamodel.
If you need to reason about event ownership, govern data sensitivity, and automate ACL provisioning, then Kafka concepts must be explicit too.
If you need to reason about deployment blast radius, govern cloud account usage, and automate guardrails, then cloud topology concepts belong in the model.
This is where many architecture teams fail. They create generic metamodels so broad that nothing meaningful can be enforced. Generic architecture language sounds elegant and delivers very little.
Specificity wins.
So, should architects choose UML or code?
No. They should choose semantic clarity and then apply the right representation.
My strong opinion is this:
- If your diagrams are not tied to an explicit metamodel, they are mostly presentation.
- If your code artifacts are not connected to architecture concepts, they are mostly local truth.
- If your enterprise has neither, then your “architecture practice” is probably just meeting theater.
Harsh, but not unfair.
A good architecture function does four things:
- defines a useful metamodel
- uses lightweight views to communicate it
- connects that model to executable artifacts
- keeps the vocabulary disciplined over time
That is the work. Not drawing for the sake of drawing. Not worshipping code because it compiles.
The metamodel matters because it is where architecture stops being opinion slides and starts becoming a system of meaning.
And yes, this requires saying no to people. No, that Kafka topic is not a domain event stream. No, that IAM role is not an application. No, that cloud account is not a platform. No, this UML box does not mean whatever the presenter wants it to mean.
Architects who avoid that level of precision usually end up with broad agreement and poor outcomes.
Final thought
The enterprise does not suffer from a shortage of diagrams or code. It suffers from a shortage of shared meaning.
UML can help. Code can help more in some places. But neither rescues you from a weak metamodel.
If you remember one thing, make it this:
Architecture becomes valuable when the types of things in your world are explicit, their relationships are constrained, and those semantics show up both in conversation and in implementation.
That is where the metamodel matters.
That is also where real architecture starts.
FAQ
1. Is UML still relevant in modern cloud-native architecture?
Yes, selectively. Not as a giant formalism for everything. But as a way to express logical structure, interactions, and deployment concerns when a clear metamodel sits underneath it. Cloud-native systems still need abstraction. They just do not need UML maximalism.
2. Why not just use code as the source of truth?
Because code is usually the source of truth for specific implementation artifacts, not for enterprise-wide meaning. It rarely captures ownership, business context, trust boundaries, control scope, or cross-system semantics in one coherent place. You need both executable truth and architectural meaning.
3. How does this help with Kafka architecture specifically?
A strong metamodel separates event, schema, topic, producer, consumer, owner, and classification. That prevents the usual mess where every topic is treated as a reusable business product, permissions are too broad, and nobody knows which streams are strategic versus temporary integration plumbing.
4. What is the biggest modeling mistake architects make with IAM?
They blur identities, principals, roles, policies, and users. In practice that leads to terrible access design and poor reviews. A service identity is not a human user. A role is not an application. A trust relationship is not the same thing as a permission grant. If the metamodel does not distinguish these, security architecture gets sloppy fast.
5. How do you introduce metamodel discipline without becoming bureaucratic?
Start with a small, opinionated set of concepts tied to real questions the organization needs answered. Focus on useful distinctions: service vs application, topic vs event, role vs principal, account vs environment. Then connect those concepts to delivery artifacts and controls. Keep it practical, not ceremonial.
Frequently Asked Questions
What is a UML metamodel?
A UML metamodel is a model that defines UML itself — it specifies what element types exist (Class, Interface, Association, etc.), what relationships are valid between them, and what constraints apply. It uses the Meta Object Facility (MOF) standard, meaning UML is defined using the same modeling concepts it uses to define other systems.
Why does the UML metamodel matter for enterprise architects?
The UML metamodel determines what is and isn't expressible in UML models. Understanding it helps architects choose the right diagram types, apply constraints correctly, use UML profiles to extend the language for specific domains, and validate that models are internally consistent.
How does the UML metamodel relate to Sparx EA?
Sparx EA implements the UML metamodel — every element type, relationship type, and constraint in Sparx EA corresponds to a metamodel definition. Architects can extend it through UML profiles and MDG Technologies, adding domain-specific stereotypes and tagged values while staying within the formal metamodel structure.