Skip to content
Asmar.
§ 06 — Method

Four convictions
I keep returning
to.

I've designed software in seven domains across twelve years — central banks, donor programs, robo-advisory, large-cap insurance, and the five products of the Ghasi suite. The stacks change. The contexts change. The convictions don't.

1

The domain layer is sacred.

The single largest source of architectural decay I've seen is the slow leak of framework concerns into the domain. A web-framework decorator here, an ORM import there, an event-bus envelope baked into a value object — each one looks like a small convenience at the time. A year later, the domain layer doesn't compile without the framework, can't be tested without booting the infrastructure, and can't be reasoned about without remembering which version of which adapter is in scope.

So I keep the domain pure. Pure TypeScript. No web framework, no ORM, no broker client, no provider SDK in the import graph. Aggregates, value objects, domain events, and repository interfaces — that's it. The application layer composes use-cases against those interfaces. The infrastructure layer implements them with whatever the world happens to be running this year.

The cost is more files, more interfaces, and the discipline to refuse the convenient import. The win is that every adapter — the database, the queue, the LLM provider, the search engine — becomes replaceable without touching the part of the code that encodes the business.

2

Multi-tenancy is not a feature flag.

Most “multi-tenant” systems are actually single-tenant systems with a WHERE clause. The application code filters by tenant; the database trusts the application. The first time someone forgets the filter, two tenants see each other.

Real multi-tenancy is enforced at three layers, simultaneously. At the domain, tenant identity is a first-class invariant of every aggregate. At the database, row-level security is on; service roles do not have BYPASSRLS; every transaction sets app.current_tenant_id first. At the transport, every event envelope and every API request carries a tenant header — the JWT claim, the path parameter, and the envelope header all agree before the request reaches a handler.

The cost is plumbing in three places. The win is that “multi-tenant data leak” stops being a class of bug your system can have.

3

Architects who don't ship lose calibration.

There's a particular kind of architecture document that reads beautifully and is entirely wrong. It's wrong because the author hasn't built anything in the constraints they're prescribing for years, and the constraints they remember are no longer the constraints that exist.

The cure isn't more diagrams. The cure is building. Not as a side hobby — as a structural part of the architecture practice. I build the Ghasi suite for this reason: five product platforms in active development with real domain layers, real outboxes, real CI gates, all heading to pilot. It's how I keep my hands close enough to the code that when I'm at the Architecture Review Board recommending an approach, I'm recommending it from inside the constraint, not above it.

4

Offline-first and AI-first are architecture, not features.

The default assumption in most systems is that the network is always present and that AI is a capability you add later. Both assumptions produce the wrong architecture — one that degrades silently when connectivity drops, and one where intelligence is bolted on through UI wrappers rather than modelled in the domain.

Offline-first means the client is the primary actor. It reads from local state, writes to a local outbox, and reconciles with the server when connectivity allows. Vector clocks, conflict policies, and per-aggregate sync rules are declared in the domain layer. The Ghasi platforms are designed for those scenarios from the domain up — eHealth for clinical notes captured in a rural clinic with no signal, Melmastoon for a back-office that keeps running through a hotel network outage, edTech for encrypted offline bundles runnable on a phone in the field. Offline behaviour is a first-class architectural invariant, not a graceful-degradation shim bolted on at the end.

AI-first means the intelligence lives in the domain, not the UI. Every AI-generated artifact carries provenance metadata: which model, which prompt version, which trace, whether a human reviewed it. The AI Gateway is a first-class bounded context — model selection, cost ceilings, PHI redaction, moderation, and audit are enforced at one boundary and backed by ADRs. Swapping a model is a configuration change, not a code change. That's only true if you design it that way from the beginning.

The cost is real: more interfaces, more conflict policies, more adapter code. The win is that both offline capability and AI behaviour remain sound under changing requirements — because they were architectural decisions, not assumptions.

4

Offline-first and AI-first are architecture, not features.

The default assumption in most systems is that the network is always present and that AI is a capability you add later. Both assumptions produce the wrong architecture — one that degrades silently when connectivity drops, and one where intelligence is bolted on through UI wrappers rather than modelled in the domain.

Offline-first means the client is the primary actor. It reads from local state, writes to a local outbox, and reconciles with the server when connectivity allows. Vector clocks, conflict policies, and per-aggregate sync rules are declared in the domain layer. Across the Ghasi platforms — eHealth capturing clinical notes in a rural clinic with no signal, Melmastoon's back-office running through a hotel network outage, edTech delivering encrypted PlayPackages to a phone in the field — offline behaviour is a first-class architectural invariant, not a graceful-degradation shim bolted on at the end.

AI-first means the intelligence lives in the domain, not the UI. Every AI-generated artifact carries provenance metadata: which model, which prompt version, which trace, whether a human reviewed it. The AI Gateway is a first-class bounded context — model selection, cost ceilings, PHI redaction, moderation, and audit are enforced at one boundary and backed by ADRs. Swapping a model is a configuration change, not a code change. That's only true if you design it that way from the beginning.

The cost is real: more interfaces, more conflict policies, more adapter code. The win is that both offline capability and AI behaviour remain sound under changing requirements — because they were architectural decisions, not assumptions.

How I run an engagement

Independent engagements move through four phases. The shape stays the same; the depth scales with the engagement size.

  1. PHASE — 01

    1–2 weeks

    Listen.

    Read everything: the existing architecture documents, the codebase, the recent post-mortems, the roadmap, the team's chat archives if they're shared. Sit in on a sprint planning, a retro, an on-call handover. Talk to three engineers who weren't put forward by the sponsor. The goal is to understand what's actually true, not what the deck says.

  2. PHASE — 02

    2–3 weeks

    Map.

    Produce a context map of the current bounded contexts (whether the team uses that vocabulary or not). Trace the integration patterns — what's synchronous, what's eventual, what's fragile. Identify the two or three architectural decisions in the next ninety days that will compound the most.

  3. PHASE — 03

    1–2 weeks

    Decide.

    Write the ADRs. Each one names the decision, the alternatives I considered, the tradeoffs, and the conditions under which I'd revisit it. Walk the team through every ADR. Argue the cases out loud. Revise. Sign.

  4. PHASE — 04

    varies

    Hand off, supervise, or lead.

    Three exits: hand-off (advisory engagement closes here), supervise (I stay close to delivery for a quarter, reviewing the implementation against the blueprint), or lead (I take the architect-of-record role through the build).

What I produce

  • — A context map of bounded contexts and their relationships.
  • — Service blueprints with API contracts and event schemas.
  • — Architectural decision records (ADRs), versioned in the repo.
  • — A risk register and a sequencing plan.
  • — POVs and POCs where the answer is genuinely unknown.

What I won't do

  • — Write architecture documents that nobody reads. Every artifact is anchored to a decision the team has to make.
  • — Stay attached to a recommendation past its evidence. If the context changes, the ADR gets updated.
  • — Pretend a buy-vs-build call has a single right answer. It rarely does. I'll lay out the tradeoffs and let the team own the call.

Want me to run one of these?