Merhaba Sevgili Okurlar,
Bu yazımda sizlere bir arhitectural pattern olan Domain Driven Design(DDD)'den bahsedeceğim. DDD aslında çok daha geniş bir konu fakat kısa ve öz bir biçimde bu yazımda bahsetmeye çalışacağım.
DDD karmaşık sorunları modellemeyi sağlayan bir mimari yaklaşımdır. Karmaşıklığı modellemek için domain'i merkezine alır. Domain'in nasıl kullanılacağı üzerine eğilir. Bir bakışta domain uzmanlarının domain'i anlaması için bir mimari modelleme yapar. Geliştiricileri ve domain uzmanlarını ortak bir noktaya getirmeyi hedefler.
DDD'ya ait aşağıdaki kavramlardan bahsedelim:
- The Ubiquitous Language
- Bounded Contexts
- Entities
- Value Objects
- Aggregates
- Domain Events
The Ubiquitous Language
Az öncede dediğimiz gibi DDD domain experts ve developer'leri aynı paydada buluşturmayı hedefler. Bu sebeple domain experts ve developers domain hakkında konuşurken ve birlikte çalışırken kullandıkları ortak dile the ubiquitous language denir. OnOrderCreatedDomainEvent gibi event'ler ortak dile güzel bir örnek. Sipariş oluştuğunda ne yapmanız gerektiğini domain uzmanı ile konuşarak gerekli aksiyonları bu event'de alabilirsiniz. Domain gerekliliğine göre yeni eventler oluşturabilirsiniz. OrderCanceledDomainEvent gibi.
Bounded Contexts
Bounded context karmaşık domain içinde anlamlı, kendi içinde tutarlı, birbirinden bağımsız ya da az bağımlı domain parçacıklarıdır. Her biri domain'in bir problemini çözmek için modellenir.
Bizim örneğimiz bir e-ticaret domaini olarak düşünürsek bu büyük ve complex problemi modellemek için customer, order, product olmak üzere üç bounded context'lerine ayrıdık. Sizin domaninize ve ihtiyacınıza göre logical boundy-domain context değişecektir. Bounded context hakkında detaylı bilgi için bu yazıyı ziyaret edebilirsiniz.
Biz ilk olarak müşteri oluşturuyoruz ve daha sonra ürünler, son olarak da müşteri ve ürünleri eşleştirerek sipariş oluşturuyoruz. Bu üç mantıksal sınır bizim domanimizi çözümlüyor. Biz bu projemizde single repo kullandığımız için ve tek bir API içinde bounded context'leri enpoint olarak ayırdığımız için aşağıdaki şeklide. Siz ihtiyacınıza göre her bir bounded-contexti ayrı bir API yapabilirsiniz. Ayrı repolarda tutabilirsiniz.
Entities
Entity'ler domain içindeki bir nesneyi temsil ederler ve id'leri ile birbirlerinden ayrışırlar.
Örneğin customer domain içindeki müşteriyi temsil eden bir objedir.
DDD yaklaşımında entity'ler domain logic barındırır. Dilerseniz domain logic'i Domain Service adında ayrı bir katman yazıp bu layer'da da tutabilirsiniz. Aşağıda customer Entity'sinde validateEmail , validatePassword gibi bazı basit domain logic'ler oluşturdum. Daha karmaşık olanları ise customerService'de tutmak istedim.
Value Objects
Value Object'ler domainde oluşturulduktan sonra değişmeyen (immutable), encapsule edilmek istenen bir objeyi temsil eder. Identity'leri yoktur. Eşit olup olmadıklarını ayırt etmek için bütün property'leri kıyaslanır eğer aynı ise bu iki value object aynıdır denir. Aşağıda customer Entity'sin bir parçası olan address Value Object'i görüyorsunuz.
Bu encapsule edilmiş objeyi bir event'de başka bir servise de iletebiliriz.
Aggregates
Aggregate'ler basit anlamda birkaç nesneden oluşurlar. Aşağıda sipariş ve sipariş detaydan oluşan bir Aggreate'i inceleyelim. Görüldüğü gibi hem Order hem de OrderDetail tek bir Entitiy içinde tutulmak istenmediği için birleşik bir yapı oluşturuduk. Veri tabanında OrderDetail nesnelerini ayrı bir tabloda tuttuğumuz için böyle bir Aggregate kullandık.
Domain Events
Domain Event'ler DDD'nin bize kattığı en büyük faydalardan biridir. Komplex problemin çözümünü, okunabilirliğini artıran bir yapıdır. Domain içinde oluşan bir aksiyon sonrası başka bir aksiyon almamızı sağlar.
Aşağıda müşteri oluştuktan sonra müşteriye email attığımız örnek bir senaryoyu görüyoruz.
OrderCreatedDomainHandler'da bulunan orderReadytoShipping event'inde ise farklı bir durum söz konusu askenkron olarak Shpping API'ına bir mesaj bıraktığımızı düşünelim. Shipping API de bu mesajı alıp okuyup siparişi kargolamaya hazır hale getirdiğini düşünelim . İşte buradaki gibi eğer bir event bir domain'den diğerine sıçrıyor ise buna Integration Event diyoruz. Domain içinde kalıyorsa Domain Event diyoruz.
DDD Katmanlarını anlamak için önceki yazımı buradan okuyabilirsiniz. Aşağıda görüldüğü gibi temel olarak Infrastructure, Domain ve Application katmanlarından oluşuyor.
Konu ile ilgili GitHub reposunu burada bulabilirsiniz, okuduğunuz için teşekkürler,
Sağlıkla kalın.
Bu yazıyı oluştururken okuduğum faydalı kaynaklar:
https://learn.microsoft.com/en-us/azure/architecture/microservices/model/domain-analysis
https://ec2-3-68-183-64.eu-central-1.compute.amazonaws.com/blog/entities-and-value-objects-diving-deep-into-domain-driven-design/
https://github.com/dotnet-architecture/eShopOnContainers/blob/dev/src/Services/Ordering/Ordering.Domain/SeedWork/ValueObject.cs
https://www.spiceworks.com/tech/devops/articles/what-is-domain-driven-design/
https://redis.com/glossary/domain-driven-design-ddd/
http://mustafabas.me/en/what-is-domain-driven-design-ddd--b-1011
https://khalilstemmler.com/articles/typescript-domain-driven-design/entities/
https://github.com/yerinadler/typescript-ddd-demo-app/blob/master/src/core/Entity.ts ***
https://github.com/stemmlerjs/white-label/blob/master/src/infra/sequelize/index.ts
https://github.com/luizcalaca/ddd-typescript-sequelize-node-api/blob/main/src/infrastructure/database/sequelize.ts
https://smit90.medium.com/sequelize-vs-typeorm-choosing-the-right-orm-for-your-node-js-project-a6f8a0cd2b8c
https://github.com/yerinadler/typescript-ddd-demo-app/blob/master/src/domain/property/Property.ts
https://medium.com/@elijahbanjo/implementing-event-driven-architecture-in-typescript-with-node-js-and-express-eefecadaf95f
Hiç yorum yok:
Yorum Gönder