← All posts

Your Architecture Canvas does not survive the move to ODC

In O11 a module is the unit of reuse and the unit of deployment at the same time. ODC separates them. That one change is what most conversion plans underprice, and no assessment tool will tell you about it.

 

Most conversion conversations start with a portfolio scan. An application list, a compatibility score per app, a rough effort band. It is a reasonable place to start and it answers a real question: which of these things can be converted.

It does not answer the question the architect is actually being asked, which is what the estate looks like on the other side.

Those are different questions, and the gap between them is where the timeline goes.

What a module is, and why that matters

In O11, a module does four jobs at once.

It is the unit of reuse. Public actions, blocks and entities are exposed from it and consumed elsewhere. It is the unit of deployment, compiled into an assembly and published as one thing. It is the unit of ownership, because the team that owns the module owns what is inside it. And it is where data lives, because entities sit in modules and are read straight out of them by anything holding a reference.

The Architecture Canvas works because all four line up. When you draw a foundation layer, a core layer and an end-user layer, you are drawing reuse, deployment, ownership and data ownership in a single diagram. The platform then enforces it for you. Upward references get flagged. Circular references get blocked. AI Mentor Studio scores you on the result.

ODC pulls those jobs apart, and the diagram stops describing one thing.

The two rules that do the damage

There are a lot of differences between the platforms. Two of them decide the shape of your conversion.

Libraries cannot hold entities, and cannot consume them either. In ODC, entities live in apps. A library is compiled into each app that consumes it and carries no data of its own.

Entities made public by an app are read-only to everything outside it. Cross-app reads are possible. Cross-app writes are not.

Put those together and the classic core module has nowhere to land intact.

Take the shape everybody has: a core module that owns a handful of entities, exposes twenty or so server actions that validate and write to them, and ships three or four blocks that render the same data consistently across the estate. One module, three kinds of thing, referenced by half the factory.

In ODC, the entities have to live in an app. The blocks and the reusable server actions want to be in a library, because server actions can only be made public from a library. But a library cannot touch entities, so every action in that module that reads or writes its own data cannot travel with the blocks.

That module does not convert. It splits, and the split is a design decision that has to be made per module, by someone who understands what the module is for.

What the split costs you

Once the core module becomes an app, the consumers that used to write to its data through a public server action are on the outside of a network boundary. Every one of those call sites becomes an exposed API with a contract, a version, a failure mode and a latency budget. In O11 that call was a compiled reference. It could not fail in the ways it can now.

Referential integrity moves too. Relationships between entities in different apps do not create a database constraint, and the delete rule is always ignore. If your data model currently relies on protect and delete rules to stop orphans, that protection is now something your application code has to do, in every app that participates. This is the finding that tends to surprise people, because nothing in the code looks different afterwards. The guarantee just stops being there.

And the release model changes. In O11, publishing a producer module updates every consumer of it in that environment, all at once, and the platform tells you immediately who broke. In ODC, each app consumes a specific version of a library, and two apps can sit on different versions indefinitely. That is genuinely useful for isolating risk. It also means a fix to shared logic reaches production once per consuming app, on a schedule someone has to own, and nothing forces the laggards to catch up.

None of these are defects. They are the reasonable consequences of a runtime where apps are independently deployed containers. They are simply not what your canvas assumes, and they are not visible in an application-level compatibility score.

The inventory that actually predicts the work

Before anyone puts a number on a conversion, we go through the estate producer module by producer module and answer four questions about each one.

Does it own entities? If yes, it is anchored to an app. Everything else in the module is negotiable, that is not.

Do consumers write to those entities, and how? Through the module’s own public actions, or directly against public entities from their own logic? Direct cross-module writes are common in estates that grew fast, and every one of them becomes an API you have to design.

Do consumers read those entities directly in aggregates? Count the call sites, not the modules. This number, more than module count, is what predicts the work, because each one is either a new exposed read or a reason to keep two things in the same app.

Do its public server actions touch entities? If they do, they cannot go into a library with the blocks that use them. Either the logic moves into the owning app and gets exposed, or the block gets refactored to raise an event and let the consuming app do the data work.

Four answers per module puts each one into a bucket: becomes an app, becomes a library, splits into both, or gets rewritten. Add the cross-boundary read and write counts and you have an estimate that survives contact with the work.

On the estate we run in New Zealand, the modules that took the longest to place were never the big ones. They were the small shared ones with an entity nobody remembered adding, sitting underneath everything.

What this is not

This is not an argument against ODC, and it is not an argument for staying on O11. Both of those decisions are legitimate and they depend on things this post says nothing about.

It is an argument about sequence. The conversion tooling answers a question about elements. Whether your estate can be converted is worth knowing. What your architecture becomes is a different piece of work, it happens before the plan rather than during it, and it is done by hand by someone who has carried a factory across a platform boundary before.

Your canvas still has value on the other side. It describes intent, and intent survives. What it stops doing is describing enforcement, because the platform is no longer enforcing the same things. Knowing which parts of your architecture were being held up by the compiler, and which parts were being held up by the team, is most of the assessment.

Most estates have never had to tell the difference.


We do fixed-scope architecture reviews and O11 to ODC feasibility work on estates that already exist. Senior only. Check your fit.