{"id":16627116,"url":"https://github.com/ttulka/ddd-example-ecommerce","last_synced_at":"2025-04-06T04:09:44.390Z","repository":{"id":63572473,"uuid":"254814986","full_name":"ttulka/ddd-example-ecommerce","owner":"ttulka","description":"Domain-driven design example in Java with Spring framework","archived":false,"fork":false,"pushed_at":"2023-12-11T15:02:57.000Z","size":651,"stargazers_count":361,"open_issues_count":1,"forks_count":80,"subscribers_count":13,"default_branch":"main","last_synced_at":"2025-03-30T02:08:55.498Z","etag":null,"topics":["architecture","ddd","design","domain-driven-design","event-driven","example","hexagonal-architecture","high-cohesion","java","low-coupling","modular-monolith","ood","oop","rich-domain-model","screaming-architecture","service-oriented-architecture","services","soa","spring","spring-boot"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ttulka.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-11T07:23:36.000Z","updated_at":"2025-03-27T04:10:05.000Z","dependencies_parsed_at":"2024-10-26T20:36:07.485Z","dependency_job_id":"60ca6fd3-da61-4b60-b30e-933e5ac548b1","html_url":"https://github.com/ttulka/ddd-example-ecommerce","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ttulka%2Fddd-example-ecommerce","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ttulka%2Fddd-example-ecommerce/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ttulka%2Fddd-example-ecommerce/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ttulka%2Fddd-example-ecommerce/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ttulka","download_url":"https://codeload.github.com/ttulka/ddd-example-ecommerce/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247430869,"owners_count":20937874,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["architecture","ddd","design","domain-driven-design","event-driven","example","hexagonal-architecture","high-cohesion","java","low-coupling","modular-monolith","ood","oop","rich-domain-model","screaming-architecture","service-oriented-architecture","services","soa","spring","spring-boot"],"created_at":"2024-10-12T04:13:25.964Z","updated_at":"2025-04-06T04:09:44.373Z","avatar_url":"https://github.com/ttulka.png","language":"Java","readme":"# DDD Example Project in Java: eCommerce\n\nThe purpose of this project is to provide a sample implementation of an e-commerce product following **Domain-Driven Design (DDD)** and **Service-Oriented Architecture (SOA)** principles.\n\nProgramming language is Java with heavy use of Spring framework.\n\n```sh\n# build\n./mvnw clean install\n\n# run \n./mvnw spring-boot:run\n\n# open in browser http://localhost:8080\n```\n\n## Table of Contents\n\n- [Domains](#domains)\n  + [Core Domain](#core-domain)\n  + [Supporting Subdomains](#supporting-subdomains)\n  + [Event Workflow](#event-workflow)\n  + [Services Dependencies](#services-dependencies)\n- [Architectural Overview](#architectural-overview)\n  + [Screaming Architecture](#screaming-architecture)\n  + [Packaging](#packaging)\n  + [Assembling](#assembling)\n  + [Anatomy of a Service](#anatomy-of-a-service)\n- [Conclusion](#conclusion)\n  + [Where to Next](#where-to-next)\n\n## Domains\n\nSeveral [Business Capabilities][vcha] have been identified:\n\n[vcha]: http://bill-poole.blogspot.com/2008/07/value-chain-analysis.html\n\n### Core Domain\n\n- **Sales**\n  - put a product for sale\n  - categorize a product\n  - update a product\n  - change a product price\n  - validate an order\n  - place an order\n  \n### Supporting Subdomains\n  \n- **Warehouse**\n  - stack goods\n  - fetch goods for shipping\n  \n- **Billing**\n  - collect a payment\n\n- **Shipping**\n  - dispatch a delivery\n\nLater, we can think about more supporting domains (not implemented in this project):\n\n- **Marketing**\n  - discount a product\n  - promote a product\n  \n- **User Reviews**\n  - add a product review\n  \n- **Customer Care**\n  - resolve a complain\n  - answer a question\n  - provide help\n  - loyalty program\n  \nThe e-commerce system is a web application using a **Portal** component implementing the [Backends For Frontends (BFF)][bff] pattern.\n\nThe idea of [Microfrontends][microf] is implemented in an [alternative branch](https://github.com/ttulka/ddd-example-ecommerce/tree/microfrontend).\n\n[bff]: https://samnewman.io/patterns/architectural/bff/\n[microf]: https://martinfowler.com/articles/micro-frontends.html\n\n### Event Workflow\n\nThe communication among domains is implemented via events:\n\n![Event Workflow](doc/event-workflow.png)\n\nWhen the customer places an order the following process starts up (the happy path):\n\n1. Shipping prepares a new delivery.\n1. Sales creates a new order and publishes the `OrderPlaced` event.\n1. Shipping accepts the delivery.\n1. Billing collects payment for the order and publishes the `PaymentCollected` event.\n1. Warehouse fetches goods from the stock and publishes the `GoodsFetched` event.\n1. Shipping dispatches the delivery and publishes the `DeliveryDispatched` event.\n1. Warehouse updates the stock.\n\nThere is only the basic \"happy path\" workflow implemented with a big room for improvement, for example when Shipping doesn't get bot Events within a time period, the delivery process should be cancelled etc.. \n\n### Services Dependencies\n\nServices cooperate together to work out the Business Capabilities: sale and deliver goods.\n\nThe actual dependencies come only from Listeners which fulfill the role of the Anti-Corruption Layer and depend only on Domain Events.\n\n![Event and Listener](doc/event-listener.png)\n\nEvents contain no Domain Objects. \n\nFor communication across Services an Event Publisher abstraction is used, located in the package `..ecommerce.common.events`. The interface is an Output Port (in the Hexagonal Architecture) and as a cross-cutting concern is its implementation injected by the Application.  \n\n## Architectural Overview\n\nWhile no popular architecture ([Onion][onion], [Clean][clean], [Hexagonal][hexagonal], [Trinity][trinity]) was strictly implemented, the used architectural style follows principles and good practices found over all of them.\n- Low coupling, high cohesion\n- Implementation hiding\n- Rich domain model\n- Separation of concerns\n- The Dependency Rule\n\nThe below proposed architecture tries to solve one problem often common for these architectural styles: [exposing internals of objects](https://blog.ttulka.com/object-oriented-design-vs-persistence) and breaking their encapsulation. The proposed architecture employs full object encapsulation and rejects anti-patterns like Anemic Domain Model or JavaBean. An Object is a solid unit of behavior. A Service is an Object on higher level of architectural abstraction. \n\n[onion]: http://jeffreypalermo.com/blog/the-onion-architecture-part-1\n[clean]: https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html\n[hexagonal]: https://alistair.cockburn.us/hexagonal-architecture/\n[trinity]: https://github.com/oregor-projects/trinity-demo-java\n\n### Screaming Architecture\n\nThe architecture \"screams\" its intentions just by looking at the code structure:\n```\n..ecommerce\n    billing\n        payment\n    sales\n        category\n        order\n        product\n    shipping\n        delivery\n    warehouse\n```\n\nGoing deeper the technical concepts are visible too:\n```\n..ecommerce\n    billing\n        payment\n            jdbc\n        listeners\n        rest\n```\n\n### Packaging\n\nAs shown in the previous section, the code is structured by the domain together with packages for technical concerns (`jdbc`, `rest`, `web`, etc.).\n\nSuch a packaging style is the first step for a further modularization. \n\nThe semantic of a package is following: `company.product.domain.service.[entity|impl]`, where `entity` and `impl` are optional. Full example: `com.ttulka.ecommerce.billing.payment.jdbc`. \n\n### Assembling\n\nWhile a physically monolithic deployment is okay for most cases, a logically monolithic design, where everything is coupled with everything, is evil.\n\nTo show that the Monolith architectural pattern is not equal to the Big Ball Of Mud, a modular monolithic architecture was chosen as the start point.\n\nThe services can be further cut into separate modules (eg. Maven artifacts) by feature:\n```\ncom.ttulka.ecommerce:ecommerce-application\ncom.ttulka.ecommerce.sales:catalog-service\ncom.ttulka.ecommerce.sales:cart-service\ncom.ttulka.ecommerce.sales:order-service\ncom.ttulka.ecommerce.billing:payment-service\ncom.ttulka.ecommerce.shipping:delivery-service\ncom.ttulka.ecommerce.warehouse:warehouse-service\n```\n\nOr by [component](https://blog.ttulka.com/package-by-component-with-clean-modules-in-java):\n```\ncom.ttulka.ecommerce.billing:payment-domain\ncom.ttulka.ecommerce.billing:payment-jdbc\ncom.ttulka.ecommerce.billing:payment-rest\ncom.ttulka.ecommerce.billing:payment-events\ncom.ttulka.ecommerce.billing:payment-listeners\n```\n\nIn detail:\n```\ncom.ttulka.ecommerce.billing:payment-domain\n    ..billing\n        payment\n            Payment\n            PaymentId\n            CollectPayment\n            FindPayments\ncom.ttulka.ecommerce.billing:payment-jdbc\n    ..billing.payment.jdbc\n        PaymentJdbc\n        CollectPaymentJdbc   \n        FindPaymentsJdbc     \ncom.ttulka.ecommerce.billing:payment-rest\n    ..billing.payment.rest\n        PaymentController\ncom.ttulka.ecommerce.billing:payment-events\n    ..billing.payment\n        PaymentCollected\ncom.ttulka.ecommerce.billing:payment-listeners\n    ..billing.payment.listeners\n        OrderPlacedListener\n```\n\nWhich can be brought together with a Spring Boot Starter, containing only Configuration classes and dependencies on other modules:\n```\ncom.ttulka.ecommerce.billing:payment-spring-boot-starter\n    ..billing.payment\n        jdbc\n            PaymentJdbcConfig\n        listeners\n            PaymentListenersConfig\n    META-INF\n        spring.factories\n```\n\nNote: Events are actually part of the domain, that's why they are in the package `..ecommerce.billing.payment` and not in `..ecommerce.billing.payment.events`. They are in a separate module to break the build cyclic dependencies: a dependent module (Listener) needs to know only Events and not the entire Domain. \n\nSee this approach in an alternative branch: [modulith](https://github.com/ttulka/ddd-example-ecommerce/tree/modulith).\n\n### Anatomy of a Service \n\n**[Service](http://udidahan.com/2010/11/15/the-known-unknowns-of-soa/)** is the technical authority for a specific business capability.\n- There is a one-to-one mapping between a Bounded Context and a Subdomain (ideal case).\n- A Bounded Context defines the boundaries of the biggest services possible.\n- A Bounded Context can be decomposed into multiple service boundaries.\n    - For example, Sales domain contains Catalog, Cart and Order services.\n- A service boundaries are based on service responsibilities and behavior.\n- A service is defined by its logical boundaries, not a physical deployment unit.\n\n**Application** is a deployment unit. A monolithic Application can have more Services.\n- Bootstrap (application container etc.). \n- Cross-cutting concerns (security, transactions, messaging, logging, etc.).\n\n![Application and Services](doc/application-services.png)\n\n**Configuration** assemblies the Service as a single component.\n- Has dependencies to all inner layers.\n- Can be implemented by Spring's context `@Configuration` or simply by object composition and Dependency Injection.\n- Implements the Dependency Inversion Principle.  \n\n**Gateways** create the published API of the Service.\n - Driving Adapters in the Hexagonal Architecture.\n - REST, SOAP, or web Controllers,\n - Event Listeners,\n - CLI.\n \n**Use-Cases** are entry points to the service capabilities and together with **Entities** form the _Domain API_.\n- Ports in the Hexagonal Architecture.\n- No implementation details.\n- None or minimal dependencies.\n \n_Domain Implementation_ fulfills the Business Capabilities with particular technologies.\n- Driven Adapters in the Hexagonal Architecture.\n- Tools and libraries,\n- persistence,\n- external interfaces access.\n\nSource code dependencies point always inwards and, except Configuration, are strict: allows coupling only to the one layer below it (for example, Gateways mustn't call Entities directly, etc.).\n \n![Service Anatomy](doc/service-anatomy.png)\n\n#### Example of a Service Anatomy \n\nAs a concrete example consider the Business Capability to find payments in Billing service:\n\n- Application is implemented via Spring Boot Application.\n- `PaymentJdbcConfig` configures the JDBC implementations for the Domain. \n- Gateway is implemented as a REST Controller.\n- Use-Case interface  `FindPayments` is implemented with `PaymentsJdbc` in Use-Cases Implementation.  \n- Entity `Payment` is implemented with `PaymentJdbc` in Entities Implementation.\n\n![Service Anatomy](doc/service-anatomy-example.png)\n\nThere is no arrow from Configuration to Gateways because `PaymentController` is annotated with Spring's `@Component` which makes it available for component scanning the application is based on. This is only one possible approach. Another option would be to put the Controller as a Bean into the Configuration, etc..\n\n## Conclusion\n\nThe goal of this project is to demonstrate basic principles of Domain-Driven Design in a simple but non-trivial example.\n\nFor the sake of simplicity a very well-known domain (e-commerce) was chosen. As every domain differs in context of business, several assumption must have been made.\n\nAlthough all fundamental use-case were implemented, there is still a room for improvement. Cross-cutting concerns like authentication, authorization or monitoring are not implemented.\n\n### Where to Next\n\nCheck out the alternative branches and repos to see additional concepts and technologies in action:\n\n- [Modulith](https://github.com/ttulka/ddd-example-ecommerce/tree/modulith): A separate Maven module per service.\n- [Microfrontends](https://github.com/ttulka/ddd-example-ecommerce/tree/microfrontend): Service Web Components as part of the service codebase.\n- [Microservices](https://github.com/ttulka/ddd-example-ecommerce-microservices): Deployments with Docker and Kubernetes.\n- [Kotlin](https://github.com/ttulka/ddd-example-ecommerce-kotlin): The same project again, this time in Kotlin.\n\n","funding_links":[],"categories":["Java"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fttulka%2Fddd-example-ecommerce","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fttulka%2Fddd-example-ecommerce","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fttulka%2Fddd-example-ecommerce/lists"}