# Software architect: delivery is not a guarantee of the decision

> I practise architecture as decisions, boundaries and costs — system design and event-driven work on outbox and determinism, evidenced on this site.

- Technologies: RabbitMQ, Redis, MySQL, PostgreSQL, Docker, GitHub Actions
- Experience: Since 2022
- Posts: 5
- Projects: 10
- Updated: 2026-10-07
- Source: https://muhammetsafak.com/expertise/architecture/
- Language: en-US
- Author: Muhammet Şafak

---
## Me in this ecosystem

I practise architecture not as a collection of patterns but as decisions made
in a particular system, with a particular boundary and a particular cost. This
page covers three topics in its own right: Software Architecture, System Design
and Event-Driven Architecture.

The evidence for all three sits on this site. The delivery and idempotency side
is in the [outbox log](/blog/from-dual-write-to-outbox-idempotent-consumption-and-field-encryption/),
how a legal constraint narrowed a design is in the
[number-collision log](/blog/resolving-invoice-number-collision-in-e-invoice-integration/),
and the determinism question that comes after delivery is in the
[determinism post](/blog/same-message-different-outcome-determinism-in-event-driven-architecture/).
The roles themselves are on the [resume](/resume/), and the book-length version
of the topic is
[Designing Reliable Event-Driven Systems](/books/designing-reliable-event-driven-systems/).
If you want to go deeper, the [sade.dev](https://sade.dev) pieces on
[why architecture decisions rot](https://sade.dev/en/journal/architecture-decisions-rot)
and on [the outbox and idempotent consumption](https://sade.dev/en/systems/transactional-outbox-dual-write-and-idempotent-consumption)
are the right place.

### The three topics this page covers

Each rests on a post, a record or a role on this site; the page stays at the level of identity and evidence, not depth.

- **Software Architecture** — It covers service boundaries, critical design decisions and passing them on to the team. In my Senior Software Developer and then Staff Engineer roles I ran architecture together with domain-driven design and test-driven development; writing boundaries into code and checking them in CI instead of leaving them on a wiki is part of this topic.
- **System Design** — It covers a system's scaling, availability and load-distribution decisions. I moved a synchronous invoicing flow onto a shared queue and a separate consumer service. The groundwork for this came before architecture was my responsibility, in a search infrastructure, where I built a cache layer that used MySQL and Redis together, and split the database and cache clusters.
- **Event-Driven Architecture** — It covers delivery, repetition and determinism. The transactional outbox, the idempotent consumer and at-least-once delivery are the practice of this topic, and so is the point that a delivered message producing the same outcome is a separate guarantee.

### The cost of a decision

In e-invoice numbering a legal constraint became the real force behind the design. The chain is read in order.

1. **Generating the number late caused a race** — Adding one to the maximum value at send time worked with a single worker; parallel workers produced the same number and reached the external API with it.
2. **Generating the number early caused a gap** — If the number is generated when the message is queued, an invoice that drops out or is cancelled leaves an unexplained hole in the series. A legal series cannot skip a number.
3. **The legal constraint narrowed the solution set** — Many methods solve the collision alone; once gap-freeness was added, the solution set narrowed at once. Before setting a requirement aside as a business rule, it is worth asking how it constrains the architecture.
4. **The number was reserved just before the external call** — A reserved number stays on the invoice even if the call fails and is retried with the same number. The external call was kept outside the transaction; otherwise the system would have become a bottleneck.

### Delivery is not a guarantee of the decision

Every guarantee comes with a cost; solving one pattern opens the next.

1. **The outbox keeps a message from being lost** — The message is written as an outbox row in the same transaction as the record, and a relay publishes it. That closes the dual-write problem.
2. **At-least-once brings repetition** — The message is not lost but may repeat. An idempotent consumer makes the repetition free of side effects.
3. **A delivered message may not reach the same decision** — When the same prefix list was kept in two separate services, updating one let one of two same-shaped messages, a few hours apart, pass and the other be rejected. The message is not the whole input to the decision.
4. **Context has to be frozen at creation time** — The consumer should not resolve what the decision needs on its own; the event should carry its own context. A retry must not change the moment of decision.

### How I run architecture

Three habits, all aimed at letting a team read the same decision the same way.

- **Writing down the cost of a decision** — I do not count a decision as architecture until I have written what it closes and what it puts in its place. The two chains above are the output of that habit.
- **Writing the boundary into code** — Declaring layers and permitted dependencies in one file and checking them in CI on every commit keeps an architectural decision from rotting two years later.
- **Passing knowledge on to the team** — I mentored the team in TDD and DDD and prepared a code-review guide; architecture lives not in the document but in the small decisions a team makes every day.

### The depth is not here

This page stays at the level of identity and evidence. I write the pattern narratives, why architectural decisions rot, and the details of the outbox and number reservation on sade.dev.

## Frequently asked

### How long have you worked in architecture?

Since 2022, 4 years. I started as a Senior Software Developer and since March 2025 I have designed microservice and event-driven architecture as a Staff Engineer. The system-design groundwork from my earlier search-infrastructure years is the base this rests on, not part of that count. This site holds 5 posts that overlap with this work.

### How do you tell Software Architecture, System Design and Event-Driven Architecture apart?

Software Architecture covers boundaries and decisions, System Design covers how a system scales and stays available, and Event-Driven Architecture covers delivery, repetition and determinism between services. They are different scales of the same work; this page holds all three.

### Does moving work onto a queue give you a delivery guarantee?

No. The outbox keeps a message from being lost but gives you at-least-once; an idempotent consumer suppresses the repetition. A delivered message reaching the same decision is a third guarantee, and in an invoicing flow I had to build it separately.

### How do you judge an architectural decision?

By what it closes and what it puts in its place. In the invoice-number case, generating the number late caused a race and generating it early caused a gap; the answer was to hold both at once.

### Where can I read the deeper architecture writing?

On sade.dev. This page stays at the level of identity and evidence; the pattern narratives and longer architecture pieces are there.
