Take control of your SAP testing with UiPath Test Suite
Ddd cqrs - Forat Latif
1. ROME 11-12 april 2014ROME 11-12 april 2014
Moving Away From CRUD: Domain Driven Design (DDD) and
Command Query Responsibility Segregation (CQRS)
Email: forat.latif@gmail.com
Twitter: @foratlatif
Forat Latif
2. ROME 11-12 april 2014 - Speaker’s name
Time to start a greenfield project
3. ROME 11-12 april 2014 - Speaker’s name
Process
1) Gather Requirements
2) Model our “Entities”
3) Scaffold our projects and our database based on those entities
4. ROME 11-12 april 2014 - Speaker’s name
What the Architecture looks like?
5. ROME 11-12 april 2014 - Speaker’s name
Our Domain
class Product {
String name;
String
description;
Integer price;
Integer discount;
String category;
}
class Customer {
Address address;
String name;
}
class Order {
String
description;
Customer
customer;
List<LineItems>
lineItems;
}
class LineItem {
Product product;
}
6. ROME 11-12 april 2014 - Speaker’s name
Just what do we mean by Entity?
class Product {
String name;
String description;
Integer price;
Integer discount;
String category;
String getDescription() {
return this.description;
}
void setDescription(String aDescription) {
this.description = aDescription;
}
String getName() {
…….
……
}
7. ROME 11-12 april 2014 - Speaker’s name
So … Where is the business logic?
class ProductService {
public void discountProduct(String productId, Integer discount) {
Product product = productRepository.find(productId);
product.setDiscount(discount);
if (discount > 30) {
product.setStatus(“Super Discount”);
}
productRepository.save(aProduct);
}
}
8. ROME 11-12 april 2014 - Speaker’s name
So … Where is the business logic?
class ProductController {
public void updateProduct(Product product) {
productRepository.save(product);
}
}
9. ROME 11-12 april 2014 - Speaker’s name
Are we really doing OOP?
Objects are supposed to have a
state and behavior that modifies
that state
State shouldn’t be exposed (getters
and setters are not encapsulation)
Objects should be loosely coupled
Business rules should be placed in
one place
class Product {
String name;
String description;
String category;
String getName() {
return this.description;
}
void setName(String name) {
this.name= name;
}
String getPrice() {
…….
……
}
10. ROME 11-12 april 2014 - Speaker’s name
Implicit Business Rules
class PromoService {
void discountProduct (String productId, Integer discount) {
Product product = productRepository.find(productId);
product.setDiscount(discount);
if (discount > 30) {
product.setStatus(“Super Discount”);
}
}
}
class AnotherService {
void discountSomethinElse (String productId) {
Product product = productRepository.find(productId);
someValue = calculateValue();
product.setDiscount(someValue);
}
}
11. ROME 11-12 april 2014 - Speaker’s name
Objects should expose BEHAVIOR
class Product {
String name;
String status;
Integer price;
Integer discount;
String category;
void discount(Integer discount) {
this.discount = discount;
if (discount > 30) {
this.status = “Super Discount”;
}
}
}
12. ROME 11-12 april 2014 - Speaker’s name
Back to our “Entities”
class Customer {
String name;
Address address;
}
class Address {
String street;
Integer streetNumber;
}
13. ROME 11-12 april 2014 - Speaker’s name
Entities and Value Objects
Entities in DDD are not defined by their attributes, they are defined
by a conceptual identity and we care about its changes
Value Objects represent a description of something at a certain
point in time. Thats why they are immutable and we care only
about its attributes
14. ROME 11-12 april 2014 - Speaker’s name
What a purchase looks like
class OrderService {
@Transactional
public void purchaseOrder(String orderId) {
Order order = orderRepository .find(orderId);
order.purchase();
productService.removeFromInventory(order.products());
emailService.sendConfirmationEmail(order);
}
}
15. ROME 11-12 april 2014 - Speaker’s name
Suddenly our mail server goes
down …
16. ROME 11-12 april 2014 - Forat Latif
Domain Events
A Domain Event, represents something that already
happened, that is relevant to the business
17. ROME 11-12 april 2014 - Forat Latif
Domain Events
class Service {
void handle(SomeEvent event) {
doSomething();
}
}
18. ROME 11-12 april 2014 - Forat Latif
Domain Events
class OrderService {
@Transactional
public void purchaseOrder(String orderId) {
Order order = orderRepository .find(orderId);
order.purchase();
productService.removeFromInventory(order.products());
eventBus.push(new OrderPurchased(order.orderId());
}
}
class EmailSender {
public void handle(OrderPurchased orderPurchased) {
Order order = orderRepository.find(orderPurchased.orderId);
emailService.sendConfirmationEmail(order);
}
}
19. ROME 11-12 april 2014 - Forat Latif
Sales of a Product skyrocket ….
20. ROME 11-12 april 2014 - Forat Latif
Eventual Consistency
class OrderService {
@Transactional
public void purchaseOrder(String orderId) {
Order order = orderRepository .find(orderId);
order.purchase();
eventBus.push(new OrderPurchased(order.orderId());
}
}
class OrderProcessManager {
public void handle(OrderPurchased orderPurchased) {
Order order = orderRepository.find(orderPurchased.orderId);
productService.removeFromInventory(order.products());
}
}
21. ROME 11-12 april 2014 - Forat Latif
Aggregate Roots
Aggregate is a pattern in Domain-Driven Design. A DDD
aggregate is a cluster of domain objects that can be treated as a
single unit.
An aggregate has a root that acts as an outside interface and
keeps all invariants inside the aggregate.
Each request should strive to load one aggregate and execute a
single operation on it.
Hence, Aggregates guarantee transactional consistency inside its
boundaries
22. ROME 11-12 april 2014 - Forat Latif
What our new Architecture looks
like
23. ROME 11-12 april 2014 - Forat Latif
Product Inventory and Catalog
class Product {
String name;
Integer price;
Integer priceFromSupplier;
String supplier;
String shippingStatus;
String shippingMethod;
}
24. ROME 11-12 april 2014 - Forat Latif
Bounded Contexts
Explicitly define the context within which a model applies. Explicitly
set boundaries in terms of team organization, usage within specific
parts of the application, and physical manifestations such as code
bases and database schemas. Keep the model strictly consistent
within these bounds, but don’t be distracted or confused by issues
outside.
Inventory
E-commerce
Shipping
25. ROME 11-12 april 2014 - Forat Latif
Bounded Contexts
class Product {
String name;
Integer price;
} class Item {
String shippingStatus;
String shippingMethod;
}
class Product {
Integer priceFromSupplier;
String supplier;
}
E-Commerce Context
Inventory Context
Shipping Context
26. ROME 11-12 april 2014 - Forat Latif
Communication between BCs
Inventory
E-commerce
Shipping
27. ROME 11-12 april 2014 - Forat Latif
How to identify BCs
Ubiquitous Language
Goals and Concerns
Teams
Organizational Structure
28. ROME 11-12 april 2014 - Forat Latif
So .. just what is DDD?
Domain Driven Design is an approach to software development in
which the Domain is the center of attention.
- Strategic Design
- Tactical Design
We should focus on what matters, and thats adding value to our
business through software, the software itself is just a byproduct of
our strategy
29. ROME 11-12 april 2014 - Forat Latif
What about User Interfaces?
class ProductController {
Product viewProduct (String productId) {
Product product = productRepository.find(productId);
return product;
}
}
31. ROME 11-12 april 2014 - Forat Latif
User Dashboard
class ProductController {
ProductDTO viewProduct (String productId) {
//Solution 1: Do a manual query and map it to the DTO
//Solution 2: Use your ORM to get all the objects you need
// and map them to the DTO
return productDTO;
}
}
32. ROME 11-12 april 2014 - Forat Latif
List the products of a category
36. ROME 11-12 april 2014 - Forat Latif
Possible Solutions
Nested Query:
with CTQ as (
select * from Categories c where c.parentId = 1
union all
select * from CTQ p, Categories c where c.parentId =
p.categoryId
)
select * from CTQ
37. ROME 11-12 april 2014 - Forat Latif
Possible Solutions
Modify The domain:
//Impedance Mismatch Pain
class Category {
List<Product> products;
List<Category> children;
}
class Product {
Category category;
}
38. ROME 11-12 april 2014 - Forat Latif
Possible Solutions
Another possibility:
class Category {
String parent1Id;
String parent2Id;
String parent3Id;
….
String categoryId;
String name;
}
39. ROME 11-12 april 2014 - Forat Latif
Command Query Separation (CQS)
Principle
Command–query separation (CQS) is a principle that states that
every method should either be a command that performs an
action, or a query that returns data to the caller, but not both. In
other words, asking a question should not change the answer
Commands and Queries have different concerns
40. ROME 11-12 april 2014 - Forat Latif
Command Query Responsibility
Segregation (CQRS)
We can do CQS at the architectural level too .....
class CategoryReadService{
List<Categories> getChildrenCategories(String categoriId);
}
class CategoryWriteService{
void addCategory (String parendId, String name);
}
41. ROME 11-12 april 2014 - Forat Latif
Command Query Responsibility
Segregation (CQRS)
where are do we need to do queries? when returning a DTO, not
when performing a write operation
when it comes to queries just query the database, why load a
behavioral object to show data on a screen?
You should modify your domain objects only when you need that
change for write operations.
If queries become too complex thats another sign that they are two
different concerns
43. ROME 11-12 april 2014 - Forat Latif
User Dashboard with CQRS
class UserDashboardProjector {
handle(ProductAdded productAdded) {
//insert into “user dashboard entry” with the data in the event
}
handle(ProductShipped productShipped) {
//update “user dashboard entry” with the data in the event
}
}
class ProductQueryProcessor {
List<UserDashboardEntryDTO> getProducts(String userId) {
//Select from “user dashboard entry” where userId =
userId
}
}
45. ROME 11-12 april 2014 - Forat Latif
Category Tree with CQRS
Books
Technical
Accademi
c
DDD Blue
Book
Some
Weird
Book
Category
Book Book
Category
46. ROME 11-12 april 2014 - Forat Latif
Category Tree with CQRS
class CategoryProjector {
handle(CategoryAdded categoryAdded) {
Vertex child = createVertex();
child.setProperty(“name”, categoryAdded.name());
Vertex parent = getVertex(categoryAdded.parentId());
parent.addEdge(child);
}
}
class ProductQueryProcessor {
List<ProductDTO> getProducts(String categoryId) {
// graph query to get all children of type x;
}
}
48. ROME 11-12 april 2014 - Forat Latif
Multiple categories
Without CQRS:
Nested Query : ….
Modify the domain (even more Impedance mismatch pain)
Mixed: (join table unavoidable)
49. ROME 11-12 april 2014 - Forat Latif
Multiple categories
With CQRS:
class Product {
List<Categories> categories;
}
and … thats it! The read model doesnt need to be modified
50. ROME 11-12 april 2014 - Forat Latif
Notice a pattern?
Read model is data driven
Write model is Domain Driven (database not important)
To design your write model you can imagine that you dont need a
database (you have infinite persisant RAM)
51. ROME 11-12 april 2014 - Forat Latif
Aggregates as Documents
- consistency easier to maintain,
- performance
- scalability
- technical simplicity (no lazy load config nor impedence
mismatch)
class Product {
String productId;
@EmbedSomehow // hopefully with a doc database
List<String> categoryIds;
}
52. ROME 11-12 april 2014 - Forat Latif
Commands
class OrderService {
@Transactional
public void purchaseOrder(String orderId) {
……
}
}
class PurchaseOrderCommandHandler {
@Transactional
public void handle(PurchaseOrderCommand command) {
……
}
}
53. ROME 11-12 april 2014 - Forat Latif
Advantages of Commands
Command log (not your regular log)
Clear user intention
Improved Testability
Integration
Get rid of AOP
Command Sourcing
54. ROME 11-12 april 2014 - Forat Latif
Advantages of Commands
Represent an intention, which usually maps to a command method
in your aggregate, which causes one or many events to be
pushed.
class ChangeCustomerTelephoneCommandHandler {
@Transactional
public void handle(ChangeCustomerTelephoneCommand command) {
……
}
}
56. ROME 11-12 april 2014 - Forat Latif
Recap of CQRS
CQS is a principle that can be applied at the architecturale level.
Read and Write are two separate concerns
You cannot solve all problems with the same model, especially if
the problem domains have different points of view
57. ROME 11-12 april 2014ROME 11-12 april 2014
Moving Away From CRUD: Domain Driven Design (DDD) and
Command Query Responsibility Segregation (CQRS)
Forat Latif
Email: forat.latif@gmail.com
Twitter: @foratlatif
Questions?