Cheddar is a Java framework for enterprise applications on Amazon Web Services (AWS) using domain-driven design (DDD). Bounded contexts are implemented as microservices, which are integrated using an event-driven architecture and expose a REST API. Cheddar has full AWS integration using native services such as SQS, SNS, DynamoDB and CloudSearch.
It's worth subscribing to our blog for handy tips on how to get the best out of Cheddar, and for all the latest news.
Domain-Driven Design (DDD) is an approach for developing software that closely aligns the implementation to evolving business concepts.
DDD promotes focus on the subjects most important to the business problem at hand, identifying these as core domains. Complex systems are decomposed to several orthogonal domains using strategic modelling, avoiding cross-contamination and enabling modelling of relationships between domains.
To talk about the domain, a domain model and supporting ubiquitous language is used. Domain experts use the ubiquitous language every day when talking about the domain. The ubiquitous language and domain model form the basis for a solution that addresses the domain, known as a bounded context. A rich domain model encapsulates all its domain (business) logic.
Domain models publish domain events when something of potential interest occurs in the model. Domain events may be consumed by the local or (after mapping by an anti-corruption layer) foreign bounded contexts. This application of the observer pattern promotes decoupling of the domains.
Practical concerns irrelevant to the domain but vital for a working implementation are kept out of the domain, such as persistence, security and transactions.
By modelling the business in software, DDD enables building of flexible, scalable solutions tightly aligned with business goals.
- Wikipedia article on Domain-Driven Design
- Vaughn Vernon's blog
- Martin Fowler's blog articles on Domain-Driven Design
- DDD Community
- Short intro to DDD
- Domain-Driven Design presentation
- An Introduction To Domain-Driven Design
- Vaughn Vernon - Implementing Domain-Driven Design
- Eric Evans - Domain-driven Design: Tackling Complexity in the Heart of Software
- InfoQ free book - Domain Driven Design Quickly
Cheddar provides a well-defined Java project structure for implementing each bounded context as a REST HTTP application hosted on AWS.
Cheddar uses a hexagonal architecture to house each bounded context, meaning an application layer and an adapter layer surround the domain model.
Central to the implementation is the domain model, containing rich domain objects, repositories and supporting domain services. All domain logic belongs in the domain model.
The application layer is responsible for co-ordination of operations performed on the domain model, application of security and transaction boundaries. The public interfaces for the application layer form the API for the bounded context. This API satisfies the use cases for the bounded context. No domain logic resides in the application layer.
The adapter layer adapts all communication for the bounded context, both inbound and outbound. It abstracts technical detail for various communication forms:
- Messaging using SQS
- Persistence using DynamoDB
- Multiple data versions and formats
- RESTful web services
The adapter layer is also responsible for mapping between foreign concepts outside the bounded context and the native ubiquitous language inside.
The adapter layer maps between data types present in the APIs and a canonical data model (CDM). The CDM is shared by all bounded contexts and is authored using XML Schema. The REST resource representations are defined using types defined in the CDM.
The bounded contexts are integrated using a loosely coupled event-driven architecture. The adapter layer supports this integration by implementing event messaging via SQS and SNS.
Each bounded context is packaged as a standalone Java application. It can be deployed on any number of AWS EC2 instances according to scaling needs. Grizzly and Jersey are used as the basis for the REST HTTP server application. Any client capable of consuming REST services can easily work with Cheddar applications.
The Test Pyramid shows categories of automated tests for a system. As we move up the pyramid, the tests increase in scope but decrease in number as each test has a higher maintenance cost. Typically Junit or TestNG is used for unit testing of individual or small groups of classes. For service and end-to-end (e2e) tests, acceptance test tools such as JBehave or Concordion would be used. Service tests focus on a single bounded context, whereas e2e tests are executed against the system as a whole.
Cheddar has explicit support for in-process service testing. All services external to the service under test are replaced by test doubles which serve to isolate the service under test. Cheddar includes test doubles of common AWS services; DynamoDB, SQS, SNS, S3 and CloudSearch. These are simple in-process implementations which act as substitutes for the real external services. Tests have in-process access to the state of the test doubles for easy state set-up and test verification. Service tests are executed against the application directly, which is configured using Spring Test in a Jersey Test container.