Olivier Lowe

Dieser technische Artikel ist auf Englisch verfügbar.

FRONTEND ARCHITECTURE · ANGULAR · ASYNC WORKFLOWS

What Happens While We Wait?

The frontend was correct before the request started and correct after it finished. The problem existed in the interval between them.

A user action does not jump directly from intent to outcome.

Once a backend call becomes asynchronous, there is a period in which the workflow has started but has not yet finished.

intent
  ↓
operation in flight
  ↓
outcome

That interval became architecturally relevant in NovaTrade.

One Click Could Become Two Operations

The customer reached the Review step and chose to place the Order.

The frontend started the placement request.

But the request did not finish instantly.

Place order
    ↓
request #1 starts

Place order again
    ↓
request #2 starts

The second click did not represent a second business intention.

It was the same customer intent repeated while the first operation was still unresolved.

Latency had stopped being merely a performance characteristic.

It could now change the correctness of the workflow.

The First Response Was Small

NovaTrade did not need a general asynchronous-state architecture.

It needed to prevent one active placement from starting again.

placement already running
        ↓
do not start another placement

An in-flight guard was enough to protect the backend from duplicate execution.

That solved the first demonstrated problem.

Correct Internally, Unclear Externally

Preventing the second operation exposed another issue.

The workflow knew that placement was already running, but the interface still looked available.

From the customer's perspective, nothing explained why another click should no longer do anything.

workflow
→ placement is running

interface
→ still appears available

The frontend was now correct internally but unclear externally.

One State Had Two Responsibilities

The same fact now mattered to both behavior and presentation:

placementInProgress

For the workflow, it answered:

May another placement start?
→ no

For the interface, it answered:

Should Place order remain available?
→ no

Should the customer see progress?
→ yes

One source of truth could therefore protect correctness and drive the presentation.

Who Owns the Pending State?

The next question was not which Angular API should store placementInProgress.

The more important question was:

Who owns the fact that this workflow is currently in progress?

The Review screen displays the placement action.

But it does not own the entire asynchronous workflow.

The workflow owner starts placement, waits for the backend, processes the outcome, and knows when placement has finished.

workflow owner
→ starts placement
→ owns placementInProgress
→ prevents duplicate placement
→ clears pending state

OrderReview
→ observes placementInProgress
→ disables Place order
→ shows "Placing order..."

The pending state therefore belonged with the workflow whose progress it represented.

The Signal Was Not the Architecture

Angular Signals made placementInProgress reactive.

That was useful.

But the Signal itself was not the architectural decision.

workflow state
→ owned where the workflow runs

presentation
→ observes that state

Another reactive mechanism could express the same ownership.

The important decision was where the state belonged and why.

State-management technology should follow ownership pressure, not replace the ownership question.

Finishing Means Finishing on Every Path

Pending state also had to be cleared reliably.

Placement could succeed.

It could be rejected.

It could fail for another reason.

If the frontend cleared placementInProgress only after success, one failed request could leave the Review screen permanently disabled.

placement begins
        ↓
placementInProgress = true
        ↓
success / rejection / failure
        ↓
placementInProgress = false

Whatever the outcome, once the operation is no longer running, the frontend must represent that fact correctly.

This Was Not the Server-State Problem

The previous Engineering Note asked who owns the authoritative Order state and when a frontend representation becomes stale.

This is a different problem.

Server-state lifecycle

authority
freshness
staleness
refetch

In-flight workflow

pending interaction
duplicate intent
timing
completion

Both involve asynchronous systems.

They do not have the same responsibility.

What This Did Not Earn

Real applications may eventually need more sophisticated asynchronous behavior.

NovaTrade did not yet demonstrate those pressures.

The workflow earned:

  • an in-flight placement guard;
  • one workflow-owned pending state;
  • disabled placement while the operation runs;
  • visible progress for the customer;
  • reliable clearing of pending state.

It did not earn:

  • a generalized request manager;
  • a global loading service;
  • a state-machine framework;
  • complicated RxJS orchestration;
  • automatic retry infrastructure;
  • optimistic updates and rollback;
  • advanced cancellation machinery.

Those may become responsible solutions when their problems actually exist.

They would have solved nothing demonstrated here.

The Lesson

Asynchrony is not only a transport concern. Time can change the correctness of a user workflow.

Before the operation starts, the frontend must represent what the user can do.

After the operation finishes, it must represent the outcome.

But the interval between those moments has rules too.

INTENT → IN-FLIGHT → GUARD → OUTCOME

Between intent and outcome, time has become part of the design.

CONTINUE THE ARCHITECTURE JOURNEY

Async correctness starts before the response arrives.

This Engineering Note comes from the same business-first architecture approach explored in Frontend Architecture with TypeScript, Angular, and React .

Explore the frontend architecture book