All Projects → josecelano → Ddd Laravel Sample

josecelano / Ddd Laravel Sample

A Laravel DDD sample application using CQRS and persisting entities serialized without ORM

Projects that are alternatives of or similar to Ddd Laravel Sample

Php Ddd Example
🐘🎯 Hexagonal Architecture + DDD + CQRS in PHP using Symfony 5
Stars: ✭ 1,960 (+1039.53%)
Mutual labels:  laravel, ddd, cqrs
Interviews
A list of fancy questions I've been asked during the interviews I had. Some of them I ask when interviewing people.
Stars: ✭ 140 (-18.6%)
Mutual labels:  ddd, cqrs
Java Ddd Skeleton
♨️ DDD in Java skeleton & examples. Course:
Stars: ✭ 140 (-18.6%)
Mutual labels:  ddd, cqrs
Eventflow
Async/await first CQRS+ES and DDD framework for .NET
Stars: ✭ 1,932 (+1023.26%)
Mutual labels:  ddd, cqrs
Eventflow.example
DDD+CQRS+Event-sourcing examples using EventFlow following CQRS-ES architecture. It is configured with RabbitMQ, MongoDB(Snapshot store), PostgreSQL(Read store), EventStore(GES). It's targeted to .Net Core 2.2 and include docker compose file.
Stars: ✭ 131 (-23.84%)
Mutual labels:  ddd, cqrs
Todomvc Ddd Cqrs Eventsourcing
Implementation of basic Todo app via tastejs/todomvc in C#/Typescript with eventsourcing, cqrs, and domain driven design
Stars: ✭ 134 (-22.09%)
Mutual labels:  ddd, cqrs
Kotlin Ddd Sample
A sample DDD/CQRS project using KOTLIN 🍺
Stars: ✭ 145 (-15.7%)
Mutual labels:  ddd, cqrs
Java Ddd Example
☕🎯 Hexagonal Architecture + DDD + CQRS in a Java project using SpringBoot
Stars: ✭ 119 (-30.81%)
Mutual labels:  ddd, cqrs
Bicing Api
Get statistics and locations of bicycle stations through REST API
Stars: ✭ 149 (-13.37%)
Mutual labels:  ddd, cqrs
Php Ddd Skeleton
🐘🚀 PHP DDD Skeleton: Bootstrap your new projects or be inspired by this example project
Stars: ✭ 152 (-11.63%)
Mutual labels:  ddd, cqrs
Event Sourcing Jambo
An Hexagonal Architecture with DDD + Aggregates + Event Sourcing using .NET Core, Kafka e MongoDB (Blog Engine)
Stars: ✭ 159 (-7.56%)
Mutual labels:  ddd, cqrs
Spring Boot Axon Sample
Sample application using Spring Boot, Axon, AngularJS and Websockets
Stars: ✭ 169 (-1.74%)
Mutual labels:  ddd, cqrs
Eshoponcontainersddd
Fork of dotnet-architecture/eShopOnContainers in full DDD/CQRS design using my own patterns
Stars: ✭ 126 (-26.74%)
Mutual labels:  ddd, cqrs
Cronus
Cronus is a lightweight framework for building event driven systems with DDD/CQRS in mind
Stars: ✭ 139 (-19.19%)
Mutual labels:  ddd, cqrs
Qframework
Unity3D System Design Architecture
Stars: ✭ 2,326 (+1252.33%)
Mutual labels:  cqrs, ddd
Goes
Go Event Sourcing made easy
Stars: ✭ 144 (-16.28%)
Mutual labels:  ddd, cqrs
Dev Stuff
😎 Programming stuff for everyone. Collection of articles, videos about architecture, Domain Driven Design, microservices, testing etc.
Stars: ✭ 105 (-38.95%)
Mutual labels:  ddd, cqrs
Bifrost
This is the stable release of Dolittle till its out of alpha->beta stages
Stars: ✭ 111 (-35.47%)
Mutual labels:  ddd, cqrs
Laravel Api Templates
Laravel API starter kit collection using different structures.
Stars: ✭ 149 (-13.37%)
Mutual labels:  laravel, ddd
Stove
Domain Driven Design oriented application framework, meets CRUD needs
Stars: ✭ 160 (-6.98%)
Mutual labels:  ddd, cqrs

Laravel DDD sample application

By Jose Celano

A Laravel DDD sample application.

The purpose: build a simple DDD Laravel application to be compared with the CRUD approach.

You can find the CRUD approach here: https://github.com/josecelano/my-favourite-appliances.

I have read a lot of posts saying that DDD is ony valid for complex domains. But sometimes I also have read some of them saying DDD can also be applied for simple problems. I think I would use a CRUD approach for prototypes and refactor later to DDD as soon as the project becomes a long term project. But on the other hand I do not think that the DDD approach can be much more expensive than the CRUD one. With this sample I want to test both solutions for the same simple problem, in order to compare them.

In this example I have used CQRS. Domain entities are stored in a serialized object in the database. The idea was to do something as what Vaughn Vernon describes here:

The Ideal Domain-Driven Design Aggregate Store? https://vaughnvernon.co/?p=942

On the other hand Read Models are created using Eloquent models.

  • Write model -> Table with to columns: id, data (serialized object)
  • Read model -> Eloquent models

Please, see "Problems" section if you want to know what kind of drawbacks I had for this architecture.

Specifications

Create a website where users will be able to see a variety of home appliances, creating a wishlist of their favourite ones which can be shared with friends.

The application will use another site as a primary data source: https://www.appliancesdelivered.ie . The new site should contain products from both the small appliances and dishwashers categories:

Users will be able to see the data for these products presented in a clean and attractive format, regardless of the device they're using to view the site.

  • Users can order the data by title or price.
  • When on the site, a user can create an account to save their favourite appliances to their wishlist.
  • Their wishlist can then be shared with other friends.
  • Their friends may not like the appliances the user has selected, so the user may also need to quickly remove items from their wishlist!

We'll want our new site to have good data, so need the ability to regularly sync new data from AppliancesDelivered.ie to our great new site. But keep in mind that if our new site gets very popular, we don't want to kill the source site with increased requests and server load, so we need to think carefully about how we handle this syncing process (how often it's run, when it's triggered, what we do with the resulting data etc).

We also need to allow for the case that AppliancesDelivered.ie may be down for maintenance, but we want our site to stay alive, so keep that in mind also when thinking about your approach here. The more confidence we can have in the continued operation of the site, the better! At some point in the future, if this site is successful the data source may be migrated from this crawler approach to a more formal API-based approach, so keep that path in mind when structuring your code.

The above are the main points of the application, but if you feel the application can be improved or any interesting other features implemented, then feel free to go wild!

Installation

mysqladmin -u homestead -psecret create dddlaravelsample
git clone [email protected]:josecelano/ddd-laravel-sample.git
cd dddlaravelsample
php -r "file_exists('.env') || copy('.env.example', '.env');"
composer install
php artisan storage:link
php artisan migrate
php artisan db:seed
php artisan serve

Run crawler

php artisan import:dishwashers
php artisan import:small-appliances

Scheduler is set to execute import hourly:

php artisan schedule:run

Reset all application data

php artisan migrate:refresh --seed
php artisan import:dishwashers
php artisan import:small-appliances

Live demo

Open localhost:8000 in the browser.

TODO

  • Dispatch events with static service when they are produced instead of storing them in the entity and distpactching them in the command handler.
  • Use JSON instead of serialized object in database.
  • Remove appliances not updated in the last 24 hours.
  • Enable more social authentication providers.
  • Order list by title and price.
  • Dislike button on each wishlist item (ReactJS component). Show different icon if user has already clicked.
  • Dislikes counter (ReactJS component).
  • Add username to user profile and change permalink for users' wishlist (http://localhost:8000/1/wishlist to http://localhost:8000/username/wishlist)
  • Store events.
  • REST API for events.
  • Add tests.

Problems

  • Since we only query from read model tables, even when we want to get a domain entity we could not find domain entities even if they exist, if the read model does not exist. For example: if there is an error after creating a domain entity, and the app can not create the read model, then the entity can not be found. The only way to fix this problem is using a database which supports queries using filtering by JSON attributes in JSON column types.

  • Since we store entities serialized with all attributes instead of JSON format, we also store events if we do not release the events before persisting the entity, in other words we have to call save method always after releasing events:

$this->emitter->emitGeneratedEvents($appliance);
$this->applianceRepository->save($appliance);

If we do not do that events will be trigger again every time we load the entity from database. This could be solve by storing entities in JSON without the events. We could also dispatch events before saving in the repository, or finally we could use a static method to dispatch events where there are produced without storing them in the entity.

More info about different approaches here: https://youtu.be/dXcHRcvgcUc?list=PLfgj7DYkKH3Cd8bdu5SIHGYXh_bPV2idP&t=338 (Spanish)

Acknowledgment

I have used this boilerplate: https://github.com/rappasoft/laravel-5-boilerplate

Links

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].