Domain Driven Design etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Domain Driven Design etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

6 Ekim 2021 Çarşamba

Domain Driven Design (DDD) Specification

Giriş
Kuralları daha kolay kodlamayı sağlayan predicate gibi düşünülebilir.

Örnek
Şöyle yaparız.
public interface Specification<T> {
  boolean isSatisfiedBy(T t);
}
public class IsUnderageSpecification extends CompositeSpecification<Discount> {
  ...
}
public class IsSeniorSpecification extends CompositeSpecification<Discount> {
  ...
}
public class IsWeekendSpecification extends CompositeSpecification<Discount> {
   ...
}
Bu predicate'leri and ve or yapma imkanı da var. Şöyle yaparız.
public abstract class CompositeSpecification<T> implements Specification<T> {
  public CompositeSpecification<T> or(Specification<T> specification) {
    return new OrSpecification<>(this, specification);
  }

  public CompositeSpecification<T> and(Specification<T> specification) {
    return new AndSpecification<>(this, specification);
  }

  public CompositeSpecification<T> not() {
    return new NotSpecification<T>(this);
} }
Kuralımızı yazmak için şöyle yaparız.
public class DiscountSpecification extends CompositeSpecification<Person> {

  CompositeSpecification<Person> isUnderage = ...;
  CompositeSpecification<Person> isSenior = ...;
CompositeSpecification<Person> isWeekend = ...;
@Override public boolean isSatisfiedBy(Person person) {
return isUnderage .and(isWeekend) .or(isSenior) .isSatisfiedBy(); } }

27 Mayıs 2021 Perşembe

Domain Driven Design - Application Services

Giriş
Domain Driven Design servisleri iki çeşit olarak sınıflandırıyor

1. Application Services

Application Services - Dış Dünyaya Sunulan Servisler
Açıklaması şöyle.
Application Services are the services used by the outside world which may have representations of data. A example of an application service is a database CRUD operation.
Örnek
Application services olarak Real-time stock control alanından şunlar verilebilir
payments microservices
ensure specific focus on consistent integration with the retail organizations preferred payment infrastructure

promotions microservices
allow the retail organization to provide consistent integration with price and supplier fluctuations in stock they are maintaining.

available to sell microservices
providing retail locations and suppliers with consistent integration to stock information, such as depleted stock items, updating stock items, and more

retail processes 
where long running processes can be captured, implemented, and leverage tasks for retail associates at the store level integration microservices and integration data microservices

4 Aralık 2020 Cuma

Domain Driven Design - Domain Services

Giriş
Açıklaması şöyle.
Domain Services contain operations, actions, or business process and provide the functionality that the domain needs. It deals with all the domain-related manipulation.
Bir başka açıklama şöyle. Örneğin Shipper şeklinde bir  servis olabilir.
Sometimes it is not just a thing or a noun. You can model verbs or business processes as Domain Service, too.

ProductPricer, which uses different pricing algorithms by taking other inputs in e-commerce, can be modeled as Domain Service.
Domain Services Artık Micro Services İle de Kullanılıyor
Açıklaması şöyle
What is a Domain Service or Domain API?
A domain service builds on the basic definition of a microservice: it’s a loosely-coupled, independently deployable element of software architecture which is owned by a single team.

Domain Driven Design - Aggregates - Oluşum

Neden Gereki
Amaç big ball of mud olarak tabir edilen devasa bir sınıf ilişki ve hiyerarşisinden kaçınmak.

Giriş
Oluşum (Aggregate veya Root Aggregate)  bir Bounded Context içinde bulunur. Birbirleri ile ilintili nesnelerin bir araya gelerek oluşturdukları anlamlı daha büyük parçadır.  Şeklen şöyle. Burada 4 farklı bounded context içindeki oluşum hiyerarşisi görülebilir.


Aggregate mantıksal bir yapıdır, fiziksel bir karşılığı olmak zorunda değildir. Açıklaması şöyle
Aggregate is a logical concept. At the root of aggregate, there is an Entity!
Açıklaması şöyle.
Aggregates are a collection of objects to calm the complexity by reducing the connected objects into a single unit that are bound together by a root entity. It's a cluster of associated objects that we treat as a single unit.
Eric Evans'ın kitabından alıntı
An AGGREGATE is a cluster of associated objects that we treat as a unit for the purpose of data changes. Each AGGREGATE has a root and a boundary. The boundary defines what is inside the AGGREGATE. The root is a single, specific ENTITY contained in the AGGREGATE.
Diğer Oluşuma Erişim
Bir oluşum diğer oluşuma pointer tutamaz. Bunu yaparsak Object Graph tekrar yumak gibi olur. Onun yerine RefId ya da bir çeşit anahtar değer tutar. Şeklen şöyle


Invariants - İş Kuralları
Açıklaması şöyle. Yani invariant her zaman tutarlı ve geçerli olan değiştirilemez kural demek
Invariants/consistency rules/business rules applied within an Aggregate will be enforced with each transaction's completion, like adding product to the cart, removing the product from the cart, etc. Example — Cart total price should match the sum of all the product prices in the cart.
Açıklaması şöyle
Now, is time to explain one of the most DDD important concepts when it comes to aggregate design, the invariants ( also known as business invariants or true invariants ):

> An invariant is a business rule that must always be consistent.
> Vaughn Vernon, Implementing Domain Driven Design, p.355

This simple definition give us a strong statement, no matter what happens in our system, an invariant is a business rule that will always hold, it can not be broken, therefore:

- Models can not be created if invariants are not ensured
- Models can not be changed if any invariant is broken
- Consistency must be preserved in a concurrent environment
Oluşum Örnekleri
Bazı örnekler aşağıda

Örnek - Sinema
Şeklen şöyle


Örnek - Customer
Elimizde şu nesneler olsun
Customer
Customer Home Address
Order
Order Line: where it has count of each product
Shipping Address
Product
Product Category
Product
Açıklaması şöyle
Given the requirements above, we group the entities with Customer, Order, Product as the Aggregate Roots. This also means that all database queries should only query against these aggregate root entities. e.g) You shouldn't create a SQL query selecting on Address table; Address should only be accessed by traversing through Customer or Order entity.
Açıklaması şöyle
In other words, we should only have CustomerRepositoryOrderRepository, ProductRepository (Do not cheat by defining custom queries inside the repositories "select"ing on a different entity than the aggregate root entity the repository was meant for.)
Örnek - Cart Aggregate
Açıklaması şöyle
In the Shopping cart bounded context, Cart is Aggregate, and at the root of it, there is the Cart Entity.

Aggregate is a cluster of associated objects that we treat as a unit for data changes. The aggregate root is at the top and is the only entity through which Aggregate can be accessed and has the global identifier.

Other Objects inside aggregate can have local identifiers and are NOT accessible outside aggregate directly. Aggregate root controls access to them from the outside world.
Örnek - User Aggregate
Şöyle yaparız. Burada aggregate aslında çok iş yapmıyor, sadece User nesnesini doldurup kaydediyor.
public class UserAggregate {
  private UserWriteRepository writeRepository = ...;

public User handleCreateUserCommand(CreateUserCommand command) {
  User user = new User(command.getUserId(),command.getFirstName(),command.getLastName());
    writeRepository.addUser(user.getUserid(), user);
    return user;
  }

  public User handleUpdateUserCommand(UpdateUserCommand command) {
    User user = writeRepository.getUser(command.getUserId());
    user.setAddresses(command.getAddresses());
    user.setContacts(command.getContacts());
    writeRepository.addUser(user.getUserid(), user);
    return user;
  }
}
Aggregate Yaratmak
Aggregate zengin bir nesne olduğu için yaratması da çok kolay olmayabilir. Bunun için Builder örüntüsüne başvurulabilir.

Spring Repository 
Açıklaması şöyle
Spring Repository should only be defined for Aggregate Root Entities




12 Kasım 2020 Perşembe

Domain Driven Design - Domain Events - Bounded Context İçinde Yaratılır

Kitabın İlk Baskısında Bu Kavram Yoktu
Açıklaması şöyle
The concept of Domain Events was however not included in Eric Evans' great book about Domain-Driven Design when it was first written but added as an appendix later,...
Domain Events Nedir?
Açıklaması şöyle. Bounded Context içindeki model'e ait Aggregate tarafından yaratılan olay nesnesidir.
In Domain-Driven Design we create a model that is valid within a Bounded Context. The context is our solution to a particular problem that we are addressing, so it can be a subsystem or a Microservice, or a monolithic application. The core principle of the Domain Model is the same - it is only valid within this context.
...
A Domain Event is an event that is spawned from this model that is a result of a decision within the domain. Within the model, our Aggregates have the role of maintaining business rules and this is where we implement decision points in our model, so the Aggregates are also responsible for creating the Domain Events.
Domain Event vs Integration Event
Açıklaması şöyle. Domain Event aynı domain içindeki diğer servislere de gönderilir. Böylece onlar da bir haberdar olup bir iş yaparlar.
Domain events indicate something important that has happened in the system from the perspective of the Business Team. Let’s take the example of Cart Entity in the Shopping cart bounded context. Events like ProductAddedToCart, ProductRemovedFromCart, CartCheckedOut are important to business teams.

Domain Events can not be updated or deleted once they happen. They can be used as a communication mechanism between different bounded contexts. So CartCheckoutEvent, when generated by Cart, can be used by Payment bounded context in e-commerce to initiate a payment from User.

Domain Event helps with building loosely coupled, scalable systems.

They are also the basis for designing Event Sourced systems.
Ancak Integration Event farklı domain'lere gönderilir. Açıklaması şöyle
... it’s important to distinguish between domain events and integration events. A domain event is something that happened in the domain that is relevant to other microservices within the same bounded context. Domain events can be part of the execution of a single business transaction. An integration event is something that happened which is (also) relevant to other bounded contexts in the system, often when the business transaction is completed successfully.

This distinction is important because events continuously adapt to new requirements as the system evolves and integration events tend to be more challenging to adapt as they form a cross-bounded context contact. Different bounded contexts are often implemented and maintained by different teams. Changes across teams require more planning and alignment since teams tend to have their own goals, priorities, and roadmap.
Domain Event İsimlendirmesi
Açıklaması şöyle
Each event is expressed in a past term verb,
 - RentExpired
 - RenctCancelled
 - RentRejected

Domain Event Hangi Bilgiyi Taşır?
Bounded Context içindeki Aggregate'ler yaratır. İçinde şu bilgiler olabilir
It is useful to include the originating aggregateId, from where the event was spawned and include the aggregateType and eventType to help consumers of the event to interpret it. They should be serializable just like any other type of event, and you should not include deep references to objects in the code representation of your Domain Events.
Örnek
Elimizde şöyle bir kod olsun
/**
 * The actual transportation of the cargo, as opposed to
 * the customer requirement (RouteSpecification) and the plan (Itinerary). 
 *
 */
@Embeddable
public class Delivery implements ValueObject<Delivery> {
  // code omitted
}
Açıklaması şöyle. Burada Event Storming kullanılmadan da Domain Event nesnesi/kod yaratılabileceği anlatılıyor
Delivery is a very intricate object which ties together a number of other key abstractions from the Cargo domain. It’s a result of a deep modeling insight which allows for a correct correlation between “actual transportation” (a series of actually occurred movements of a cargo through geographically determined Leg s) and the “route specification” and “itinerary” as has been specified by “customer requirement”. Almost all invariants in Cargo aggregate will involve some logic implemented in Delivery and most of the business functionality for the cargo tracking bounded context will depend on it.

Coming up with Delivery value object, especially the way it encapsulates other value objects and embodies the relationship between Cargo , Voyage, Location , and HandlingEvent aggregates — is an example of an “ah-ha moment”, an breakthrough insight which unlocks an elegant solution for the Cargo tracking problem.

The point is: the solution revolving around Delivery value object in Cargo tracking problem space was introduced without the use of Event Storming. It most certainly did result from many discussions with domain experts where specific business concepts and relations were tackled using precise Ubiquitous Language. But “distillation” of the deep model (to use Evans’ own terminology) certainly came from a developer trying out different competing models. We can imagine solutions like no Delivery value object (all logic in Cargo aggregate), Delivery as an aggregate in itself, etc.
Domain Event Ne Değildir?
- Kendi Bounded Context'imiz içinde olsa bile önem taşımayan bazı olaylar Domain Event değildir. 
- Bizim Bounded Context'imize dışarıdan gelen komutlar Domain Event değildir. 
Açıklaması şöyle
Examples of things that happen that might not be suitable to model as Domain Events:

- Something technical (a ButtonClicked, ExceptionThrown, etc) happened that we want to record or handle, but it is not described in the ubiquitous language of our domain.

- Something that happened outside of our bounded context. This could a Domain Event in another system or a different bounded context.

- Requests to your system. These we define as Commands rather than events since they can be rejected by our system.
Domain Events ve Event Sourcing
Bu iki kavram yakında ilgili. Event Sourcing yazısına bakabilirsiniz.

Domain Events ve CRUD
Açıklaması şöyle
One of the most common mistakes when starting with Domain Events and with DDD, in general, is to not go the whole way and figure out what is actually going on in the domain. It is easy to fall into the trap of naming all events SomethingCreated, SomethingUpdated and SomethingDeleted. While not a problem in itself it does not make use of the powerful thing we get by adding the context and meaning to the actual change that the Domain Event represent. You lose the intent of the event and reading the event log later will not provide that much value.
Domain Events Kullanarak Bounded Contest Arasında İletişim?
Bu mümkün. Açıklaması şöyle
Domain Events enable communication between bounded contexts by avoiding direct calls. So a bounded context, B1, raises an event and one or more bounded contexts, B2...Bn subscribers to this event, should handle the event to consume it.

5 Ekim 2020 Pazartesi

Domain Driven Design - Anemic Domain Model

Giriş
Bu konuyu ilk olarak burada gördüm. Bu konuda vurgulanan şey Bounded Context içindeki modelin hiç bir logic içermemesi. Normalde beklenen şey şöyle.
The Domain Model should be useful for the problem we're trying to solve. The model is there to enforce the business rules that we have ...
Örnek
Elimizde şöyle bir Spring servisi olsun.
@Service
public class ExpenseService {
  private ExpenseRepo expenseRepo;
  private AuthenticationBO authenticationBO;
  ...
  // other injected classes

  @Override
  @Transactional
  public void createExpense(ExpenseDTO expenseDTO) throws ValidationException {
    validateExpense(expenseDTO);
    ExpenseEntity expenseEntity = new ExpenseEntity();
    initExpenseEntity(expenseEntity, expenseDTO);
    expenseRepo.save(expenseEntity);
  }

  ...
  // other methods
  private void initExpenseEntity(ExpenseEntity expenseEntity, ExpenseDTO expenseDTO) {
    UserEntity userEntity = authenticationBO.getLoggedUser();
    expenseEntity.setUser(userEntity);
    expenseEntity.setPrice(expenseDTO.getPrice());
    expenseEntity.setComment(expenseDTO.getComment());
    expenseEntity.setDate(LocalDateTime.now());
    initExpenseTypes(expenseEntity, expenseDTO.getTypes());
  }
  ...
  // other methods
}
Bu kodda domain nesnesi sadece getter/setter'lardan oluştuğu için anemic kabul ediliyor. Zararı şöyle
Official Spring tutorials teach us that domain objects shouldn’t have any methods except getters and setters and they should be POJOs. Many authors (like Martin Fowler) consider it an antipattern and call it the Anemic Domain Model.

With Anemic Domain Design, all a program’s logic is kept in the business logic layer (classes with Service or BO suffixes). Then domain objects don’t have methods that operate with class fields, hence the object doesn’t have behavior. That breaks OOP principles, GRASP patterns, and prevent us from implementing design patterns.
Bu kodu zengin alan modeli (rich domain model) kapsamında şu hale getirebiliriz. Bu sefer de @Entity nesnesi içine Repository eklemek zorunda kaldık. Bence bu da iyi değil
@Entity
public class ExpenseEntity {
  ...
  @Autowired // model has dependency from other layers and from infrastructure
  private ExpenseRepo expenseRepo;
  @Autowired
  private AuthenticationBO authenticationBO;
  @Autowired
  private UserRepo userRepo;
  ...
  @Transactional
  public void createExpense(ExpenseDTO expenseDTO) {
    // model does too much!
    validateExpense(expenseDTO);
    ExpenseEntity expenseEntity = new ExpenseEntity();
    initExpenseEntity(expenseEntity, expenseDTO);
    expenseRepo.save(expenseEntity);
  }
  private void initExpenseEntity(ExpenseEntity expenseEntity, ExpenseDTO expenseDTO) {
    UserEntity userEntity = authenticationBO.getLoggedUser();
    expenseEntity.setUser(userEntity);
    ...
    initExpenseTypes(expenseEntity, expenseDTO.getTypes());
  }
  private void initExpenseTypes(ExpenseEntity expenseEntity, List<String> types) {
    // model persists to a DB other objects!
    List<ExpenseTypeDictEntity> expenseTypes = new ArrayList<>();
    types.forEach(x -> {
      ExpenseTypeDictEntity typeDict = expenseTypeDictRepo
        .findByNameIgnoreCase(x.trim())
        .orElseGet(() -> createExpenseTypeDict(x));
       ...
    });
    expenseEntity.setExpenseTypeDict(expenseTypes);
  }
  private ExpenseTypeDictEntity createExpenseTypeDict(String name) {...}
}
Bu kodun şu akışa uygun hale gelmesi gerekir.
Böylece alan nesneleri ile JPA teknolojisi birbirinden ayrılabilir. Yani basit bir kural olarak alan modeli teknolojiden bağımsız olmalıdır. Açıklaması şöyle.
The business logic pertaining to the Product class can exist within the class itself and the business logic for the domain can be tested in isolation. The Product class contains data fields and these can be persisted to a database. As part of that process the data fields are first wrapped in another class, and then transformed into a JPA entity before being persisted. 
Örnek
Yine sadece Spring servisleri kullanan bir başka örnek şöyle
@Transactional
public void clearBills(Long customerId) {
  // Get bills needed for clearing
  ClearContext context = getClearContext(customerId);
  // Verify that the amount is legal
  checkAmount(context);
  // Determine whether coupons are available and return the deductible amount
  CouponDeductibleResponse deductibleResponse = couponDeducted(context);
  // clear all bills
  DepositClearResponse response = clearBills(context);
  // Send repayment reconciliation message
  repaymentService.sendVerifyBillMessage(customerId, context.getDeposit());
  // Update account balance
  accountService.clear(context, response);
  // Dealing with cleared coupons, used up or unbound
  couponService.clear(deductibleResponse);
  // Save coupon deduction records
  clearCouponDeductService.add(context, deductibleResponse);
}
Örnek - Anemic Mesajlaşma Sistemi
Bir mesajlaşma yazılımını güncellerken şöyle bir durumla karşılaştım. Güncellediğimiz yazılım, mesajlar arasında graph tarzı ilişkiler tutuyordu. Mesajlar ara katman yazılımından gelen ve behaviour içermeyen, sadece veri içeren nesnelerdi.

Mesajları çeşitli durumlara göre sıralayan (örneğin öncelik) bir servis katmanı da yoktu.

Dolayısıyla domain sadece getter/setter'lardan oluşan data nesnelerinin graph'ından ibaretti.

Örnek - Anemic İstek (Request) Sistemi
Bir  yazılım, çeşitli istekler gönderiyordu. Bu istekler bir ICD mesajında tanımlıydı. Ancak istekleri sarmalayan bir domain nesnesi yoktu. Gönderilen istekler farklı listelerde saklanıyordu. Mesela sentList, acceptedList, deniedList gibi. Gelen cevaba göre istek farklı listeye taşınıyordu. Bir zaman sonra farklı bir liste daha eklenmesi gerekti. Bu liste notHitList yani işlenen ancak istenilen sonucun alınamadığı bir listeydi. Kod çorbaya döndü.

Domain anemic olmasaydı, Request nesnesi diye bir şey olurdu. Bu nesnenin status diye bir alanı olurdu. Bu alan tüm listelerin bir enum'u şeklinde olurdu. Yeni liste eklemek yerine yeni enum eklenir ve elimizde tek bir liste olurdu

Aslında her gönderilen istek bir Request içinde saklansa 

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

9 Nisan 2019 Salı

Domain Driven Design

Giriş
Domain Driven Design (DDD) yazılım ile sürekli evrilen alan bilgisini (domain) birbirine bağlamak için kullanılır. Burada özellikle model yerine domain kelimesini kullanılıyor. Çünkü modelde statik veri daha ön plana çıkıyor hissi var.

DDD Eric Evans'ın 2003 yılında yayınlanan "Domain-Driven Design: Tackling Complexity in the Heart of Software" adlı kitabından doğmuştur

Model Driven Architecture vs Domain Driven Design
Model Driven Architecture ile Domain Driven Design arasındaki fark şudur:
In MDA, we start with database table diagrams or ERDs, and build objects to match.  In DDD, we start with interactions and behaviors, and build models to match.
DDD ve Nesneye Yönelik Tasarım el ele birbirlerine destek olan kavramlardır.

Clean Domain Driven Design
DDD'yi olgunluk modellerine göre sınıflandırır

Level 0: S.O.L.I.D code
Level 1: Hexagonal Architecture
Level 2: Clean Architecture
Açıklaması şöyle
Oftentimes used interchangeably with Hexagonal Architecture, Clean Architecture, nevertheless, presents a distinct, again — qualitative — break away from the former layer. If one have to resume in one concept the most important architectural innovation which application design exhibits on Level 2, it is this — Use Case.
Level 3: Domain-Driven Design
Son aşamada da Use Case kullanan DDD'ye erişiyoruz

Temel Kavramlar
DDD kodun belli şekilde düzenlenmesini bekler. Açıklaması şöyle.
One of the ways DDD helps teams of developers is by suggesting a specific (yet still subjective) way of organising your code concepts and behaviours. This convention makes it easier to discover things, and therefore easier to maintain the application.

-Domain concepts are encoded as Entities and Aggregates
-Domain behaviour resides in Entities or Domain Services
-Consistency is ensured by the Aggregate Roots
-Persistence concerns are handled by Repositories

This arrangement is not objectively easier to maintain. It is, however, measurably easier to maintain when everyone understands they're operating in a DDD context.
Şeklen şöyle


1. Ubiquitous Language
Müşteri ile konuşulan ortak dil. Açıklaması şöyle.
Ubiquitous Language is the practice for building up a communication language between developers and users. It helps developers and the business share a common language platform that both parties understand to mean the same things. Ubiquitous Language should evolve as the team's understanding of the domain grows.
2 Bounded Context
Bounded Context yazısına taşıdım.

3. Entity
Kendine ait bir kimliği olan nesne. Açıklaması şöyle.
An Entity is an object that can be identified uniquely or by its identifier. An Entity can be identified either by its IDs or a combination of some attributes. An entity is an identity.
4. Value Object
Kendine ait bir kimliği olmayan nesne. Açıklaması şöyle.
A Value Object is an object that contains attributes but has no conceptual identity. It is a descriptor or property which is important in the domain you are modeling.
5. Repository
Nesnelerin saklandığı alan. Açıklaması şöyle.
A Repository mediates between the domain and data mapping using a collection-like interface for accessing domain objects. It is more like a façade to your data store that pretends to be a collection of your domain. A Repository provides a centralized façade, storing data in a database, XML, SOAP, REST, and so on.
Repository sorgu inşa eder. Repository örüntüsüne alternatif olarak direkt Query Object kullanımı (yani sorgunun kendisi) sunuluyor.

Klasik bir Repository nesnesine şuna benzer metodlar bulubur
getById(), deleteById(), getAll(), save(), update(). Repository altta "Entity Framework" veya "JPA" gibi bir ORM kullanabilir.

Nesne çekmek için örnek
CSAgent agent= (CSAgent) EmployeeRepository.getById(agentId);
Order order= OrderRepository.getById(orderId);
6. Aggregate Root veya Aggregates
Aggregates yazısına taşıdım.

Altyapı
Açıklaması şöyle.
...main point is to split the Domain Logic (Business Logic) from the Infrastructure (DB, File System, etc.).
Veri tabanı
Açıklaması şöyle.
These days, you are likely to see reads (queries) handled differently than writes (commands). In a system with a complicated query, the query itself is unlikely to pass through the domain model (which is primarily responsible for maintaining the consistency of writes).
Servisler
Yukarıdaki kavramların bazılarının servis olarak ta anlatıldığı görülebilir.
- Application services.
- Domain services.
- Infrastructure services.
- Factories, Repositories, Specifications
Application Services - Dış Dünyaya Sunulan Servisler
Application Services yazısına taşıdım.

Specifications - İş kuralları
Specifications yazısına taşıdım

Domain Services
Domain Services yazısına taşıdım.

Infrastructure Services - Kendi Kaynaklarımıza Erişmek İçin Servisler
Açıklaması şöyle.
An Infrastructure Service is a service that communicates directly with external resource. For example, accessing file system, registry, SMTP, database, and so forth in the application.
Anti Corruption Layer
Anti Corruption Layer yazısına taşıdım.

Anemic Design Model
Anemic Design Model yazısına taşıdım..