Nugget 19: Distill Before You Distribute

Problem

While building WORKS Commons, I found myself looking at Docker, Kubernetes, microservices, and Domain-Driven Design (DDD). After spending years maintaining a large enterprise monolith, I wondered whether my architecture was falling behind modern practices.

The temptation was obvious:

"I have BackgroundServices. Maybe they should become microservices."

At first glance, the idea sounded reasonable. Modern systems often advertise:

  • Kubernetes

  • Microservices

  • Event-Driven Architecture

  • Distributed Systems

However, something felt forced.


Observation

Most of WORKS Commons consists of tightly related business workflows:

Job Applications
    ↓
Interview
    ↓
Evaluation ↓ Training

These components share concepts, state, and business rules. Separating them simply because container technology exists would increase complexity without providing meaningful benefits.

The real issue was not deployment.

The real issue was architectural distillation.

The project currently contains:

Presentation
    JobBank (Blazor)

Data
    JobBank.Data

Contracts
    JobBank.Management.DTO

ETL
    JobBank.EtlConsole

Tests
    WORKSCommons.Tests

What is missing is an explicit Application Layer containing business modules and their contracts.


Lesson

A common mistake, in my view, is jumping directly from:

Monolith

to:

Microservices without first creating clear internal boundaries.

A healthier evolution is:

Monolith
↓
Modular Monolith
↓
Distributed Services (if justified)

The objective is not to create services.

The objective is to identify business boundaries.

Examples might include:

Interviewing
Training
Job Applications
Analytics
Employment Feed Processing

These boundaries can exist entirely within a single process.


The Litmus Test

Before extracting a service, ask:

What do I gain?

Specifically:

  • Independent scaling?

  • Independent deployment?

  • Separate ownership?

  • Different availability requirements?

  • Different storage requirements?

If the answer is:

"Nothing, but it feels modern."

Leave it in the monolith.


When a Service Begins to Make Sense

WORKS Commons revealed one area that may eventually justify extraction.

The automatic rejection workflow:

Find stale applications
↓
Automatically reject
↓
Generate analysis request
↓
LLM processing
↓
Persist signals

Unlike user-facing features, this workload is:

  • Asynchronous

  • Batch-oriented

  • Potentially expensive

  • Rate-limited by LLM APIs

  • Potentially scalable

This is the first component in the system that exhibits characteristics commonly associated with independent services.

However, even here the next step is not Kubernetes.

The next step is separation of responsibilities.

For example:

Rejection Processing
↓
Analysis Request Queue
↓
LLM Analysis Worker

All running inside the same application.

Only when scale, deployment cadence, or operational requirements demand it should service extraction be considered.


Takeaway

Docker and Kubernetes are deployment technologies.

DDD is a modeling discipline.

Neither should drive architecture.

The domain should.

If a system needs clearer boundaries, create modules.

If a module later needs independent scaling, deployment, or ownership, it may naturally evolve into a service.

Distill first. Distribute later.

That sequence is architecture.

The reverse is often fashion.

Growth exposes deficits.

Comments

Popular posts from this blog

Nugget 11: Adding Filtering to a Blazor QuickGrid

Nugget 9: Building a JobBank App using Blazor. A Nugget with a Story.

Nugget 14: Connection to MongoDB Atlas - SSL Alert 80