22 Temmuz 2019 Pazartesi

Domain Driven Design - Bounded Context

Giriş
Domain Driven Design'ın en önemli kavramlarından birisi olan Bounded Context ile ilgili notlarım

Bounded Context Nedir?
Bounded Context bir yazılımı daha küçük alt bileşenlere bölmek içindir. MIL-STD- 498 terminolojisi ile konuşursak CSCI (Computer Software Configuration Item) yazılım ise CSC (Computer Software Component) gibi düşünülebilir. Bir bakıma tabii ki :) Açıklaması şöyle.  
Building just one domain model for entire e-commerce will be tough to comprehend and implement in the code. Bounded context helps split the e-commerce domain into smaller subdomains: E.g. Inventory, Shopping Cart, Product Catalog, Fulfilment & Shipment, and Payment. We can use technics like event-storming to identify such subdomains and bounded contexts. So we now have Inventory bounded context, Product Catalog bounded Context, and so on…
Bounded Context ve Ubiquitous Language İlişkisi Nedir?
Konuşulan ortak dildeki (Ubiquitous Language) bazı kavramlar bağlama göre farklı anlamlara gelebilir. Bounded Context kavramın hangi bağlamda kullanıldığını belirtir. Örneğin Product sınıfı context'e göre farklı bir şeyi temsil edebilir. Açıklaması şöyle
It is important to note that the Product in each bounded context has very different behavior. In Inventory, Context Product is concerned about weight, expiry date, and supplier, whereas in Shopping Cart bounded context, the expiry, the Supplier of the Product, is not in the picture. So it is better to model different Product classes in each bounded context instead of having a common Product class across the bounded context.
Bir örnek şöyle
Let us consider an enterprise application in the telecom domain. There will be more than 70 applications in the system. Imagine 70 applications that have to integrate successfully to run the business. It starts with a person approaching the service provider like Airtel, Jio, etc., for a new connection. The moment he approaches the service provider, he will be considered as a Lead. He is not the customer yet. If he shows interest in any plan, he will be considered as an opportunity. His details will go to application verification systems.

If everything is fine, the helpline guy or the sales guy will call and confirm his plan. Once he confirms a plan, he will be provisioned into the system. Then he becomes a customer. His account will be created in a profile application. Note that the same person is identified as lead, opportunity, and customer in different applications.

His details are captured in CRM — customer relationship management system, billing system, sales and marketing system, package management system, fraud management system, inventory systems, analytics tools, dealer management systems, secondary sales systems, revenue leakage tools, debt management systems, etc.

Now imagine if you want a single model — customer in this enterprise application. The leads and opportunities system will be interested in details like what is his existing service provider, through which channel did he get to know about us, etc. Profiling and the account creation systems will be interested in other details like name, address, age, profession, etc. The CRM system might be interested if there are any previous service tickets raised by the person. The sales and marketing team will be interested in his profile and usage details to get an idea of what packages could be recommended to him down the line. The billing system will be focused on the billing address and payment mode, etc. Similarly, the fraud management system, inventory systems, analytics tools, etc., will be interested in other details.

Imagine how confusing your model will be if it includes all these details. The address required for the billing application is the billing address. For the profiling system or CRM application, it will be the current address and permanent address. If the same model is used across the system, at some point in time, the billing team could feel that naming the address field as billing address is more appropriate than the current address and rename the current address field to the billing address. The model integrity is compromised which in turn breaks the system.

So, when the billing team says address, it might be billing address and when the CRM team says address it might be mailing address. The CRM team is not aware of the billing address and the billing team might not be aware of the other addresses. If these two teams discuss with each other the model you could guess the confusion it creates because of the conceptual differences.

Even if both the addresses are saved as different attributes, the billing address will be redundant and irrelevant to profiling and other applications.

The same person is a Lead in leads application and opportunity in the opportunities application. He is a customer in the provisions and accounting systems. In case he did not pay the bills, he will be a defaulter in another system. If you observe, the details of the same person are interpreted differently in different applications based on the context. This is where the bounded contexts come into the picture.

The sales team cannot go to the leads/opportunities team and ask for the customer details because their model is not supposed to have customers but instead have leads /opportunities. They will understand only if you ask for the leads or opportunities details.

To get rid of these, you need to define the boundaries of your model and confine it to a context. Otherwise, there will be a lot of confusion and chaos that creeps into your system and makes the model unmanageable and impure.
Bounded Context ve Noun Based Models
Açıklaması şöyle
Noun based domain models have the downside of introducing high functional coupling in a system.

Which is contrary to the recommendation to keep coupling low and cohesion high.

When data is grouped in noun based models, subsequent steps in a business workflow need access to show, or amend, some of the data embedded in that model.

This couples each subsequent step to that functional model.

As more nouns are introduced to the model, the functional coupling tends to increase.

A better way to divide your domain model is by business capability.

Only store the data required by the respective capability in a local model. Individual capabilities usually only care about a subset of the data.

As the workflow progresses, pass data from one capability to the next.

This can be done either via the frontend, or via event publishing in the backend (depends on how much time there is between the steps).
Şeklen şöyle


Bounded Context'in Varlığını Nasıl Anlarız?
 Açıklaması şöyle. Her ortak dildeki bir kavramın farklılaştığını görüyorsak, orada bir Bounded Context olabilir.
So bounded context is a linguistic boundary! Any time you see that the Product is acting differently, it is a clue that there are different bounded contexts in the play.

One bounded context typically has few (or one) micro-services
Şeklen şöyle. Burada iki tane bounded context var. Her ikisinde de Customer ve Product kavramları var ancak kendi bağlamlarında farklıklar gösteriyorlar. Aslında bu şekli yukarıdaki Noun Based Model'e uymuyor.


Ayrıca Bounded Context'in Kendi Domain Modeli ve Kendi Ubiquitous Language'i Vardır
Bounded Context kendi başına bir birim olduğu için kendine mahsus bir domain modele ve dile sahiptir. Açıklaması şöyle
The ubiquitous language applies within a bounded context. Each bounded context has its own ubiquitous language. It is a language that is spoken both by the Business Teams and the Development teams. It helps them to communicate better.

If your Business team is talking in terms of Database tables, then as the Development Team, you have influenced them incorrectly.
Context Map Nedir?
Açıklaması şöyle
Context Map defines the relationship between different bounded contexts.

How different bounded contexts communicate with each other and how they influence each other.
Bounded Context ve Yeniden Kullanılabilirlik
Açıklaması şöyle. Amaç yeniden kullanılabilir bir yapı ortaya çıkartmak değil. Amaç mantıksal olarak bölünmüş ve yalıtılmış yapılar yaratmak
The promise of reusable components, just as the idea of reusable business logic across applications didn't turn out to be practical. Modern trends reflect this insight well. The microservices approach suggests that instead of reusing code, we should separate things and make them easily replaceable. Domain-Driven Design's Bounded Context concept says the same: that there should be clearly separated contexts that create semantic boundaries, which, in turn, make sharing "business code" among contexts unnecessary and unwelcome by definition.
Dikey bölümleme için açıklama şöyle.
New trends like Domain-Driven Design and microservices advocate splitting applications vertically instead of horizontally. And, new types of development processes and organization, like cross-functional and DevOps teams, support this vertical slicing and scaling much more efficiently.
Isolation Layer
Açıklaması şöyle.
Code reuse between Bounded Contexts  should be avoided. The integration of functionality and data must go through a translation. The translation logic provided by the Isolation Layer.
Isolation Layer için 3 temel yöntem var. Bunlar şöyle.
Customer/Supplier
Conformist
Anticorruption Layer (ACL)
Anticorruption Layer (ACL) Nedir
Aslında ismi Translation Layer'da olabilirdi. Anti Corruption Layer yazısına taşıdım

Bounded Context ve İşbirliği
Benim için ufuk açıcı yazı şu. Her bounded context diğeri ile olan ilişkisini "Foreign Key" benzeri yapılar ile yürütüyor. Aslında bu kullanım bounded context'in daha büyük bir aggregate'in parçası olduğunu gösteriyor. Bu büyük aggregate daha küçük ve yönetilebilir hale getirilmiş.

Örnek
Elimizde şöyle bir mesaj olsun. Foreign key'leri göndererek mesajı işleyen diğer kod parçalarına da bilgiye erişme imkanı tanırız.
{
  "Status": "Closed",
  "RentalAgreementID": 1234,
  "CustomerID": 8965,
  "VehicleID": 98263,
  "RentalAgent": 24352,
  "Broker": 6723
}
Bounded Context'ler Arası İletişim - Domain Events
Domain Events yazısına taşıdım.

Plugin Yapısı ve Bounded Context
Şöyle bir yapı ile karşılaştım. Her plugin için bir bounded context yapılmıştı. Plugin kendi bilgilerini burada saklıyordu.
AbstractBoundexContext <-(extends)-AppBoundexContext
                ^-(extends)--PluginABoundedContex,PluginBBoundedContex
Ana uygulama AppBoundedContext'i kullanıyordu. Her plugin ise sadece kendi bounded context'ini biliyordu.

Ana uygulama çalışırken plugin içindeki bazı bilgiler var ise farklı davranıyordu. Dolayısıyla iki tane bounded context arasında işbirliği (collaboration) gerekiyordu.

Bu durumda kurtulmak için geliştirenler PluginABoundedContex içindeki bilgileri AppBoundexContext'e geçmişlerdi.
PluginABoundedContex --(calls)--> AppBoundexContext
Ana uygulamada oluşan olayları plugine bildirmek için de listener yapısı vardı.
AppBoundexContext -- (notifies)-->PluginABoundedContex

Hiç yorum yok:

Yorum Gönder