DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Cost Is a Distributed Systems Bug
  • Serverless at Scale
  • AWS Managed Database Observability: Monitoring DynamoDB, ElastiCache, and Redshift Beyond CloudWatch
  • AWS EventBridge as Your System's Nervous System: The Architecture Nobody Talks About

Trending

  • How to Build and Optimize AI Models for Real-World Applications
  • Zero-Downtime Deployments for Java Apps on Kubernetes
  • Introduction to Retrieval Augmented Generation (RAG)
  • Engineering LLMOps: Building Robust CI/CD Pipelines for LLM Applications on Google Cloud
  1. DZone
  2. Data Engineering
  3. Databases
  4. From Distributed Monolith to Composable Architecture on AWS

From Distributed Monolith to Composable Architecture on AWS

Learn in this article how to fix distributed monoliths with Domain-Driven Composable Architecture and build independent, composable microservices on AWS.

By 
Elakkiya Daivam user avatar
Elakkiya Daivam
·
Oct. 24, 25 · Analysis
Likes (1)
Comment
Save
Tweet
Share
8.4K Views

Join the DZone community and get the full member experience.

Join For Free

You adopted microservices for independence and agility. Instead, every deployment requires coordinating multiple teams and testing the entire system. What you built is a distributed monolith, complexity spread across systems, but still bound by monolithic coupling. The shift from technical boundaries to business-driven boundaries is the only path to true agility. Many organizations discover too late that microservices alone do not guarantee independence. Domain-Driven Composable Architecture (DDCA) provides a methodology to escape this rigidity. 

This article is a practical playbook for decomposing services into Packaged Business Capabilities (PBCs) aligned with business domains and mapped to AWS patterns such as EventBridge, Step Functions, and DynamoDB Streams. It explains when DDCA fits and when it does not, and covers security, anti-patterns, and operational realities, so you can adopt composability with a clear view of the investment required.

Problem: Technical Boundaries Create Distributed Monoliths

Microservices promised independent deployment and team autonomy. Most enterprises failed to achieve these benefits. The reason is that boundaries were drawn around technical layers or organizational convenience, such as REST APIs, database tables, or team size, instead of business domains. This reflects a fundamental misunderstanding of decomposition.

Some teams are split by technical concerns, such as a database service, an API gateway service, and a business logic service. This recreates a distributed three-tier architecture where every business change touches multiple services. Others avoid that mistake but swing too far the other way, grouping entire domains like “Rewards” into one giant service. Both approaches create coupling, one through technical layering and the other through overly broad business boundaries.

In credit card rewards processing, for instance, an architecture team might create a single RewardsService handling merchant categorization, earning rate calculations, promotional bonuses, milestone tracking, and points ledger, all bundled together because they are considered “rewards logic.” When Merchant Category Codes (MCC) update quarterly, the entire service redeploys with full regression tests across unrelated modules.

The result is a distributed infrastructure with load balancers, deployments, and cloud clusters combined with monolithic coupling such as shared databases, coordinated releases, and cascading failures. The outcome is inheriting the complexity of distributed systems without gaining genuine independence.

Traditional distributed monolith – rewards service

Figure 1: Traditional distributed monolith – rewards service


The Solution: Business-Driven Boundaries

Domain-Driven Composable Architecture (DDCA) applies Domain-Driven Design principles to define service boundaries by business capability. Bounded contexts define clear business domains where Rewards Processing is fundamentally different from Transaction Authorization. These boundaries become Packaged Business Capabilities (PBCs), independently deployable autonomous units representing discrete business functions that enable true service independence.

Domain-driven composable architecture – rewards service

Figure 2: Domain-driven composable architecture – rewards service


The transformation from Figure 1 to Figure 2 represents the shift from technical coupling to business independence. In the monolithic architecture, a single deployment unit forces all five capabilities to scale, deploy, and fail together. In the PBC architecture, each capability runs as its own Lambda function with a dedicated DynamoDB table, and Step Functions replaces the load balancer as the orchestration layer, invoking only the capabilities needed for each card product.

Workflow Composition

The Rewards Orchestrator (Step Functions in Figure 2) composes workflows from independent PBCs. Premium cards invoke all five PBCs, such as Merchant Classification, Earning Rate Engine, Promotional Multiplier, Spending Milestone Tracker, and Points Ledger. Basic cashback cards invoke only Merchant Classification and Points Ledger with a flat rate. This composable design allows new products and campaigns to be introduced rapidly.

For example, a partner card with distinct earning rules can be assembled from existing capabilities in weeks instead of months. Similarly, a new promotional campaign in a distributed monolith would require coordinating multiple teams and lengthy deployments, while in the DDCA approach, developers update only the Promotional Multiplier PBC, deploy that single capability in hours, and launch on time.

PBC Design in Practice

A PBC adheres to three non-negotiable principles.

  • Data ownership: The PBC owns its data completely. No cross-PBC direct database access. All exchange happens through interfaces or events.
  • Clear interface: A PBC can be invoked synchronously through an API or directly as a Lambda function inside a workflow. It may also publish domain events for asynchronous consumers.
  • Single team ownership: One autonomous team owns deployment, testing, and scaling end to end.

For example, the Merchant Classification PBC in Figure 2 owns its DynamoDB table of category mappings. It can be called through a request (such as POST /classify-merchant) or orchestrated directly by Step Functions, and it publishes MerchantCategorized events. The Earning Rate Engine PBC follows the same principles with different rate tables and business rules.

When to Commit to DDCA 

DDCA is a powerful but resource-intensive approach. It is most appropriate for systems with complex business domains and a need for long-term agility.

  • Use DDCA when the core business has complex logic (for example, banking or insurance), you are driving large-scale enterprise modernization, or  when multiple independent teams are aligned to business capabilities
  • Avoid DDCA when the application is a simple CRUD system, the challenge is mostly technical rather than business complexity, or the team is small and lacks expertise in domain-driven design.

Operational Reality

Adopting DDCA requires significant operational maturity. Moving from a single RewardsService to multiple independently deployable PBCs increases the number of components to manage, which raises the need for automation, disciplined testing, and robust observability. Expect higher investment in monitoring and infrastructure than with a monolith. Cloud-native tools like Amazon CloudWatch and AWS X-Ray, as well as third-party platforms such as Datadog, New Relic, and Splunk, are essential for visibility across distributed components. Automated pipelines, infrastructure as code, and regression testing frameworks further help maintain consistency at scale. For smaller teams with fewer than fifteen engineers, a well-structured modular monolith is often the more practical starting point.

AWS Implementation: Mapping DDCA to AWS Services

The table below shows how DDCA principles translate into AWS building blocks.

DDCA concept AWS services Technical Pattern Business Value

Autonomous PBCs

Lambda, ECS Fargate

Each business capability is deployed independently

Deploy Merchant Classification without touching Promotional Multiplier

Decoupled Communication

EventBridge

Event Driven Architecture (Publish/subscribe via events)

Promotional failure does not block base rewards processing

Resilient Orchestration

Step Functions

Error handling with fallbacks; Saga Pattern with compensation

Rate lookup failure uses base rate, transaction continues

Data Consistency

DynamoDB, DynamoDB Streams, Lambda, EventBridge

Transactional Outbox (write business row and outbox, publish via streams; at least once)

Ledger write and outbox persist atomically; publish retried via streams (at least once)

Security Isolation

IAM, optional VPC or account per context

Least privilege per PBC capability (Zero Trust)

Basic card orchestrator cannot invoke premium PBCs


The AWS Playbook: Three Patterns for Composable Architecture

DDCA relies on a few core patterns that reduce coupling and maintain consistency across Packaged Business Capabilities.

Pattern 1: Event Driven Communication (Decoupled PBCs)

In a monolith, one component failing can bring down the whole system. Event-driven architecture decouples PBCs, so if a downstream capability is unavailable, upstream PBCs continue processing and publish events for later consumption. This avoids cascading failures and maintains partial availability.

PBCs publish domain events via Amazon EventBridge instead of synchronous service calls. EventBridge provides schema management, event filtering, and cross-account delivery, making it better suited for composability at scale. SNS and SQS work well for point-to-point messaging, but EventBridge avoids tight coupling.

JavaScript
 
await eventBridge.putEvents({
  Entries: [{
    Source: 'rewards.merchant-classification',
    DetailType: 'MerchantCategorized',
    Detail: JSON.stringify({
      transactionId: 'txn-12345',
      merchant: 'Sample Merchant',
      category: 'retail',
      confidence: 0.95
    })
  }]
});


If the promotional multiplier service is down, base rewards are still credited immediately. Promotional bonuses apply when the service recovers.

Pattern 2: Resilient Orchestration With Step Functions

Distributed transactions across PBCs are challenging to implement reliably. AWS Step Functions coordinate multiple PBC workflows with explicit error handling. When a step fails, the workflow applies fallbacks to maintain availability and prevent cascading failures. 

For example, if the earning rate lookup fails, the workflow applies a base rate instead of failing the transaction. For scenarios that require reversing completed steps, Step Functions can also implement the saga pattern with compensating actions. 

JSON
 
{
  "StartAt": "ClassifyMerchant",
  "States": {
    "ClassifyMerchant": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:merchant-classification-pbc",
      "Catch": [
        { "ErrorEquals": ["ClassificationFailed"], "Next": "UseDefaultCategory" }
      ],
      "Next": "CalculateEarningRate"
    },
    "UseDefaultCategory": { "Type": "Pass", "Next": "CalculateEarningRate" },

    "CalculateEarningRate": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:earning-rate-engine-pbc",
      "Catch": [
        { "ErrorEquals": ["RateLookupFailed"], "Next": "ApplyBaseRate" }
      ],
      "Next": "CreditPoints"
    },
    "ApplyBaseRate": { "Type": "Pass", "Next": "CreditPoints" },

    "CreditPoints": {
      "Type": "Task",
      "Resource": "arn:aws:lambda:points-ledger-pbc",
      "End": true
    }
  }
} 


Pattern 3: Transactional Outbox (Data Consistency)

Without atomic guarantees, a PBC may update its database but fail to publish an event, leaving other PBCs with stale data. The transactional outbox pattern solves this by using DynamoDB TransactWriteItems to write both the business change and an outbox record in one atomic operation. A Lambda function reads the outbox via DynamoDB Streams and publishes to EventBridge. This provides at least one delivery without distributed transactions. Consuming PBCs must handle duplicate events since the same event may be delivered multiple times.

Security: Zero Trust at PBC Boundaries

Security is enforced at the capability level using a zero-trust model that verifies every call and grants least privilege access. Each PBC exposes only what is needed, and callers are authorized by identity and policy rather than network location. This prevents compromise from cascading across capabilities and reduces blast radius.

  • Verify explicitly: Every invocation is authenticated and authorized; IAM is evaluated on each call to the PBC.
  • Least privilege: Service roles allow only specific actions on specific PBCs (for example, lambda:InvokeFunction on Merchant Classification and Points Ledger only).
  • Containment: Each PBC is isolated; optional VPC or account separation strengthens boundaries without changing the interface.
JSON
 
{
  "Statement": [{
    "Effect": "Allow",
    "Action": "lambda:InvokeFunction",
    "Resource": [
      "arn:aws:lambda:merchant-classification-pbc",
      "arn:aws:lambda:points-ledger-pbc"
    ]
  }]
}

This policy is attached to the basic card orchestrator’s execution role, allowing it to invoke only Merchant Classification and Points Ledger, not Earning Rate Engine or Promotional Multiplier. If the orchestrator is compromised, the attacker cannot access premium card capabilities.

Avoid the Trap: Three DDCA Anti-Patterns

Even with solid intentions, teams often stumble into patterns that undo the benefits of DDCA. These pitfalls recreate the very distributed monolith you are trying to escape.

  1. Shared database between PBCs: The most damaging anti-pattern. For example, if Merchant Classification and Earning Rate Engine both query the same rewards database table, you have tight coupling at the data layer. Each PBC must own its data completely.
  2. Orchestrator with business logic: The orchestrator should only coordinate. If the Rewards Orchestrator starts deciding which promotions apply or calculating bonus thresholds, business logic has leaked outside the PBC. That logic must stay inside Promotional Multiplier or Milestone Tracker PBCs.
  3. Over fragmentation: Splitting capabilities too finely increases network chatter and operational overhead without adding real business value. For example, creating separate PBCs for Calculate Points and Validate Points, even though they always run together and share the same business rules, introduces unnecessary calls and complexity. Both responsibilities should remain within a single Points Engine PBC.

Beyond Code: The Organizational and Business Impact

The Domain-Driven Design approach aligns technical architecture with business structure, creating a powerful organizational advantage.

  • Team structure: Teams align to business-bound contexts, such as the Rewards Processing Squad. This alignment creates autonomy, and by Conway’s Law, the resulting architecture naturally evolves into a decoupled, higher-quality system.
  • Product agility: Product Owners can compose new card products or reward flows directly from existing Packaged Business Capabilities, without waiting on multiple teams. This accelerates time to market for new offerings.
  • Policy and auditing: Business policy changes, such as updates to rewards eligibility or promotional rules, are isolated to the specific PBC affected. This reduces audit scope and deployment risk.

Strangler Fig Migration From Monolith to PBCs

Start with your highest value PBC. In rewards processing, Merchant Classification is a strong candidate because it changes frequently with MCC updates, has clear inputs and outputs, and delivers quick wins when deployed independently. Build this PBC alongside the monolith, shift a small percentage of traffic to it, and gradually ramp up over four to six weeks while monitoring accuracy. Retire the legacy code only after full confidence is established.

From there, the pace of extraction depends on the value and complexity of each capability. Take one PBC at a time, starting with the most impactful, and move at a pace that fits the system and team capacity. Each extraction becomes easier as teams gain domain knowledge and refine automation. Success can be measured through concrete signals such as faster deployment frequency, shorter regression cycles, lower change failure rates, and reduced lead time for new features. Tracking these signals makes it clear whether the architecture is gaining genuine composability or only shifting complexity to new boundaries.

Conclusion

Packaged Business Capabilities transform distributed monoliths into genuinely composable architectures. By aligning technical boundaries with business capabilities and mapping them to AWS services such as EventBridge, Step Functions, and DynamoDB Streams, teams can reduce coupling and accelerate delivery. The payoff is measurable as deployment cycles shorten from weeks to days, audit scope narrows to individual modules, and new products can be assembled by composing existing capabilities instead of rewriting code.

Composability is not about making services small; it is about making them interchangeable. With intentional boundaries and disciplined execution, organizations can move beyond accidental coupling and achieve lasting agility.

AWS Amazon DynamoDB Architecture

Opinions expressed by DZone contributors are their own.

Related

  • Cost Is a Distributed Systems Bug
  • Serverless at Scale
  • AWS Managed Database Observability: Monitoring DynamoDB, ElastiCache, and Redshift Beyond CloudWatch
  • AWS EventBridge as Your System's Nervous System: The Architecture Nobody Talks About

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook