SlideShare a Scribd company logo
REFACTORING CODE
DOMAIN DRIVEN DESIGN WAY
Supported By:
Supported By:
I’M ANDI PANGERAN
@andi_pangeran
cybercoding.wordpress.com
Supported By:
AGENDA
 PRACTICE HOW TO REFACTORING CODE BASED ON DOMAIN
DRIVEN DESIGN MINDSET
 PRACTICE HOW TO WRITE UNIT TESTING
Supported By:
JOKO
Individual who has significant expertise in the
domain of the system being developed.
DOMAIN EXPERT
MEET OUR ACTOR
Supported By:
BENTO
Individual who has spend all of his life for coding.
PROGRAMMER
MEET OUR ACTOR
Supported By:
PRACTICE
Supported By:
Protect your invariants
REFACTORING
Supported By:
JOKO
PRACTICE
“A customer must
always have an
email address.”
Supported By:
PRACTICE
BENTO
public class Customer {
private String email;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Supported By:
PRACTICE
BENTO
public class CostumerTest {
@Test
public void should_always_have_an_email() {
Customer customer = new Customer();
assertEquals(customer.getEmail(), "andi.pangeran@jtravl.com");
}
}
TEST FAIL
Supported By:
PRACTICE
BENTO
public class CostumerTest {
@Test
public void should_always_have_an_email() {
Customer customer = new Customer();
customer.setEmail("andi.pangeran@jtravl.com");
assertEquals(customer.getEmail(), "andi.pangeran@jtravl.com");
}
}
TEST PASSED
Supported By:
PRACTICE
BENTO
public class Customer {
private String email;
public Customer(String email) {
this.email = email;
}
}
Supported By:
PRACTICE
BENTO
public class CostumerTest {
@Test
public void should_always_have_an_email() {
Customer customer = new Customer("andi.pangeran@jtravl.com");
assertEquals(customer.getEmail(), "andi.pangeran@jtravl.com");
}
}
TEST PASSED
Supported By:
Use object as concistency boundaries
REFACTORING
Supported By:
JOKO
PRACTICE
“later prospective customer can be
upgraded to paying customer“
“Paying customer must have phone
number”
“we have two type of customer,
prospective and paying customer.”
Supported By:
PRACTICE
BENTO
public class ProspectiveCustomer extends Customer {
/* other attribute */
}
public class PayingCustomer extends Customer {
/* other attribute */
private String phone;
public PayingCustomer(String email, String phone) {
super(email);
this.phone = phone;
}
}
Supported By:
PRACTICE
BENTO
@Test
public void upgraded_prospective_paying() {
ProspectiveCustomer pcustomer = new
ProspectiveCustomer("andi.pangeran@jtravl.com");
assertEquals(pcustomer.getEmail(), "andi.pangeran@jtravl.com");
PayingCustomer payCustomer =
new PayingCustomer(pcustomer.getName(), “0852xxx”);
assertEquals(payCustomer.getEmail(), "andi.pangeran@jtravl.com");
assertEquals(payCustomer.getPhone(), " 0852xxx");
}
TEST FAIL
Supported By:
PRACTICE
BENTO
@Test
public void upgraded_prospective_paying() {
ProspectiveCustomer pcustomer = new
ProspectiveCustomer("andi.pangeran@jtravl.com");
assertEquals(pcustomer.getEmail(), "andi.pangeran@jtravl.com");
PayingCustomer payCustomer =
new PayingCustomer(pcustomer.getEmail(), “0852xxx”);
assertEquals(payCustomer.getEmail(), "andi.pangeran@jtravl.com");
assertEquals(payCustomer.getPhone(), " 0852xxx");
}
TEST PASSED
Supported By:
PRACTICE
BENTO
public class ProspectiveCustomer extends Customer {
/* other attribute */
public PayingCustomer upgradeToPayingCustomer(String phone) {
return new PayingCustomer(this.email, phone);
}
}
public class PayingCustomer extends Customer {
/* other attribute */
private String phone;
public PayingCustomer(String email, String phone) {
super(email);
this.phone = phone;
}
}
Supported By:
PRACTICE
BENTO
@Test
public void upgraded_prospective_paying() {
ProspectiveCustomer pcustomer = new
ProspectiveCustomer("andi.pangeran@jtravl.com");
assertEquals(pcustomer.getEmail(), "andi.pangeran@jtravl.com");
PayingCustomer payCustomer = pcostumer.upgradeToPaying(“0852xxx”);
assertEquals(payCustomer.getEmail(), "andi.pangeran@jtravl.com");
assertEquals(payCustomer.getPhone(), " 0852xxx");
}
TEST PASSED
Supported By:
JOKO
PRACTICE
“Paying customer must always have a
valid phone number”
Supported By:
PRACTICE
BENTO
@Test
public void upgraded_prospective_paying() {
PayingCustomer payCustomer =
new PayingCustomer(“test@mail.com", “badphonenumber”);
exception.expect(IllegalArgumentException.class);
}
TEST FAIL
Supported By:
PRACTICE
BENTO
public class PayingCustomer extends Customer {
/* other attribute */
private String phone;
public PayingCustomer(String email, String phone) {
super(email);
if (/* validation stuff of phone*/ ) {
throw new IllegalArgumentException();
}
this.phone = phone;
}
}
TEST PASSED
Supported By:
PRACTICE
BENTO
public class PayingCustomer extends Customer {
/* other attribute */
private String phone;
public PayingCustomer(String email, String phone) {
super(email);
if (/* validation stuff of phone*/ ) {
throw new IllegalArgumentException();
}
this.phone = phone;
}
}
TEST PASSED
Supported By:
Encapulate state and behavior with
value object
REFACTORING
Supported By:
PRACTICE
 Intro to value object
 Intro to immutable object
Supported By:
PRACTICE
BENTO
public class PhoneNumber {
private final String phone;
public PhoneNumber(String phone) {
if (/* validation stuff of phone*/ ) {
throw new IllegalArgumentException();
}
this.phone = phone;
}
public String getPhone() {
{
return this.phone;
}
}
Supported By:
PRACTICE
BENTO
public class PayingCustomer extends Customer {
/* other attribute */
private PhoneNumber phone;
public PayingCustomer(String email, PhoneNumber phone) {
super(email);
this.phone = phone;
}
}
TEST PASSED
Supported By:
PRACTICE
BENTO
@Test
public void upgraded_prospective_paying() {
PayingCustomer payCustomer =
new PayingCustomer(“test@mail.com", new
PhoneNumber(“badphonenumber”));
exception.expect(IllegalArgumentException.class);
}
TEST PASSED
Supported By:
Encapulate Operations
REFACTORING
Supported By:
JOKO
PRACTICE
“a Customer orders product and pays for
them”
Supported By:
Service.create
BENTO
Order order = new Order();
order.setCustomer(customer);
order.setProducts(products);
order.setStatus(PAYMENTSTATUS.UNPAID);
order.setPaidAmount(500);
order.setPaidCurrency(CURRENCY.IDR);
order.setStatus(PAYMENTSTATUS.PAID);
PRACTICE
Service.pay
Supported By:
Service.create
BENTO
Order order = new Order();
order.setCustomer(customer);
order.setProducts(products);
order.setStatus(new PaymentStatus(PAYMENTSTATUS.UNPAID));
order.setPaidAmount(500);
order.setPaidCurrency(CURRENCY.IDR);
order.setStatus(new PaymentStatus(PAYMENTSTATUS.PAID));
PRACTICE
Service.pay
Supported By:
Service.create
BENTO
Order order = new Order();
order.setCustomer(customer);
order.setProducts(products);
order.setStatus(new PaymentStatus(PAYMENTSTATUS.UNPAID));
order.setPaidMonetary(new Money(500, CURRENCY.IDR));
order.setStatus(new PaymentStatus(PAYMENTSTATUS.PAID));
PRACTICE
Service.pay
Supported By:
Service.create
BENTO
Order order = new Order(customer, products);
//set payment status in order constructor
order.setPaidMonetary(new Money(500, CURRENCY.IDR));
order.setStatus(new PaymentStatus(PAYMENTSTATUS.PAID));
PRACTICE
Service.pay
Supported By:
Service.create
BENTO
Order order = new Order(customer, products);
//set payment status in order constructor
order.pay (new Money(500, CURRENCY.IDR));
//set payment status in pay procedure
PRACTICE
Service.pay
Supported By:
Use Spefication
REFACTORING
Supported By:
JOKO
PRACTICE
“premium customers get special offers”
Supported By:
Service.premium
BENTO
If (customer.isPremium()) {
//send offer
}
PRACTICE
Supported By:
JOKO
PRACTICE
“order 3 times to become premium
customer”
Supported By:
Specification Interface
BENTO
public interface Specification<T> {
boolean isSatisfiedBy(T t);
Class<T> getType();
}
PRACTICE
Specification Abstract
abstract public class AbstractSpecification<T> implements
Specification<T> {
@Override
public boolean isSatisfiedBy(T t) {
throw new NotImplementedException();
}
/othercode
}
Supported By:
BENTO
public class CustomerIsPremium extends
AbstractSpecification<Customer> {
private OrderRepository orderRepository
public CustomerIsPremium(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
@Override
public boolean isSatisfiedBy(Customer customer) {
int count =
this.orderRepository.countByCustomer(customer.getId);
return (count > 3);
}
}
PRACTICE
Supported By:
PRACTICE
BENTO
@Test
public void specification_customer_premium() {
CustomerIsPremium<Customer> spec= new CustomerIsPremium();
customer2order = …
customer3order = …
assertFalse(spec.isSatisfiedBy(customer2order));
assertTrue(spec.isSatisfiedBy(customer3order));
}
TEST PASSED
Supported By:
JOKO
PRACTICE
“different rules apply for different
tenants.”
Supported By:
BENTO
public class CustomerWith3OrdersIsPremium implement
CustomerIsPremium {}
public class CustomerWith500kPremium implement
CustomerIsPremium {}
public class CustomerWithSpecialRequiredmentPremium
implement CustomerIsPremium {}
PRACTICE
Specification Interface
public interface CustomerIsPremium extends
Specification<Customer> {
boolean isSatisfiedBy(Customer cust);
}
Supported By:
BENTO
PRACTICE
public class SpecialOfferSender {
private CustomerIsPremium premiumSpec
public SpecialOfferSende(CustomerIsPremium premiumSpec) {
this.orderRepository = orderRepository;
}
public void sendOffersTo(Customer customer) {
if (this.premiumSpec.isSatisfiedBy(customer)) {
//send offers
}
}
}
Supported By:
Use Spefication for Object Selection
REFACTORING
Supported By:
JOKO
PRACTICE
“get a list of all premium customers”
Supported By:
PRACTICE
 Intro to predicate pattern
 Collection predicate
 JPA predicate
Supported By:
BENTO
PRACTICE
Specification Interface
public interface Specification<T> {
boolean isSatisfiedBy(T t);
Predicate toCollectionPredicate();
}
@Override
public Predicate toCollectionPredicate(Customer customer) {
Predicate<Customer> predicate =
new predicate<Customer>() {
@Override
public boolean apply(Customer input) {
return this.isSatisfiedBy(input);
}
};
return predicate;
}
Supported By:
BENTO
PRACTICE
CustomerIsPremium<Customer> spec= new CustomerIsPremium();
List<Customer> allCustomer = …
Collection<Customer> result =
Collections2.filter(
allCustomer,
spec.toCollectionPredicate()
);
assertArrayEquals(result, … testarray);
TEST PASSED
Supported By:
BENTO
PRACTICE
Specification Interface
public interface Specification<T> {
boolean isSatisfiedBy(T t);
Predicate toCollectionPredicate();
Predicate toPredicate(Root<T> root, CriteriaBuilder cb);
}
@Override
public Predicate toPredicate
(Root<Customer> root, CriteriaBuilder cb) {
return
cb.and (cb.greaterThan(root.get(Customer_.order),3)
);
}
Supported By:
BENTO
PRACTICE
public class DBRepository {
private EntityManager entityManager = ...
public <T> List<T> findAllBySpecification(Specification<T> specification) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
// use specification.getType() to create a Root<T> instance
CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(specification.getType());
Root<T> root = criteriaQuery.from(specification.getType());
// get predicate from specification
Predicate predicate = specification.toPredicate(root, criteriaBuilder);
// set predicate and execute query
criteriaQuery.where(predicate);
return entityManager.createQuery(criteriaQuery).getResultList();
}
}
Supported By:
BENTO
PRACTICE
CustomerIsPremium<Customer> spec= new CustomerIsPremium();
List<Customer> Customer = DBRepository.
findAllBySpecification(spec);
assertArrayEquals(result, … testarray);
TEST PASSED
Supported By:
SUMMARY
 Protect your invariants
 Use object as consistency boundaries
 Encapulate state and behavior with value object
 Encapulate Operations
 Use specification pattern
 Use predicate pattern
Supported By:
Questions ?
Supported By:
Identity CTM for Refactoring,
each monday
REFACTORING
Supported By:
Thanks

More Related Content

PPTX
Code contract
PDF
Two Trains and Other Refactoring Analogies
PPTX
Understanding Async/Await in Javascript
PDF
Evolving The Java Language
KEY
Unit testing zend framework apps
PDF
Refactoring
PDF
Advanced Developer Testing
PDF
Dutch php a short tale about state machine
Code contract
Two Trains and Other Refactoring Analogies
Understanding Async/Await in Javascript
Evolving The Java Language
Unit testing zend framework apps
Refactoring
Advanced Developer Testing
Dutch php a short tale about state machine

Viewers also liked (18)

PPTX
Our way to microservices
PPTX
Liquidating database frustrations with liquibase
PDF
Unbreakable Domain Models - DPC13
PDF
Modularity and Domain Driven Design; a killer combination?
PDF
DDD Basics - Context mapping
PDF
Towards Modelling Processes
PDF
Domain Driven Design
PPT
Liquibase – a time machine for your data
PPTX
Liquibase migration for data bases
PDF
How Symfony Changed My Life
PDF
Integrating Bounded Contexts - Mini-workshop
KEY
Context Mapping In Action
PPTX
Liquibase
PDF
Programming with Cmdr. Chris Hadfield
PDF
Tactical DDD (just better OOP?) - PHPBenelux 2017
PPT
LiquiBase
PDF
reveal.js 3.0.0
PDF
Build Features, Not Apps
Our way to microservices
Liquidating database frustrations with liquibase
Unbreakable Domain Models - DPC13
Modularity and Domain Driven Design; a killer combination?
DDD Basics - Context mapping
Towards Modelling Processes
Domain Driven Design
Liquibase – a time machine for your data
Liquibase migration for data bases
How Symfony Changed My Life
Integrating Bounded Contexts - Mini-workshop
Context Mapping In Action
Liquibase
Programming with Cmdr. Chris Hadfield
Tactical DDD (just better OOP?) - PHPBenelux 2017
LiquiBase
reveal.js 3.0.0
Build Features, Not Apps
Ad

Similar to Refactoring domain driven design way (20)

PDF
Unbreakable Domain Models PHPUK 2014 London
PPTX
Maintaining Your Code Clint Eastwood Style
KEY
Learning from GOOS - work in progress
PDF
Legacy Code and Refactoring Workshop - Session 1 - October 2019
PDF
Pragmatic Functional Refactoring with Java 8
PDF
Google guava
ODP
Simple design/programming nuggets
PDF
Domain Driven Design
PDF
Fake It Outside-In TDD
PDF
Greach 2018 - I've seen Grails code you wouldn't believe...
PDF
Refactoring Example
PDF
TDD Trade-Offs @Softwerkskammer Karlsruhe
PDF
OverviewWe will be adding some validation to our Contact classes t.pdf
PDF
黑豹 ch4 ddd pattern pracrice
PDF
TDD for the Newb Who Wants to Become an Apprentice
PPT
Spring data
PDF
What NOT to test in your project
PDF
Marvel of Annotation Preprocessing in Java by Alexey Buzdin
PDF
Testing survival Guide
Unbreakable Domain Models PHPUK 2014 London
Maintaining Your Code Clint Eastwood Style
Learning from GOOS - work in progress
Legacy Code and Refactoring Workshop - Session 1 - October 2019
Pragmatic Functional Refactoring with Java 8
Google guava
Simple design/programming nuggets
Domain Driven Design
Fake It Outside-In TDD
Greach 2018 - I've seen Grails code you wouldn't believe...
Refactoring Example
TDD Trade-Offs @Softwerkskammer Karlsruhe
OverviewWe will be adding some validation to our Contact classes t.pdf
黑豹 ch4 ddd pattern pracrice
TDD for the Newb Who Wants to Become an Apprentice
Spring data
What NOT to test in your project
Marvel of Annotation Preprocessing in Java by Alexey Buzdin
Testing survival Guide
Ad

Recently uploaded (20)

PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PPTX
CHAPTER 2 - PM Management and IT Context
PDF
System and Network Administraation Chapter 3
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PDF
medical staffing services at VALiNTRY
PPTX
Operating system designcfffgfgggggggvggggggggg
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PPTX
L1 - Introduction to python Backend.pptx
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
PDF
PTS Company Brochure 2025 (1).pdf.......
PDF
Nekopoi APK 2025 free lastest update
PDF
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
PDF
System and Network Administration Chapter 2
PDF
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
PDF
How Creative Agencies Leverage Project Management Software.pdf
PDF
Adobe Illustrator 28.6 Crack My Vision of Vector Design
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PDF
Understanding Forklifts - TECH EHS Solution
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
Upgrade and Innovation Strategies for SAP ERP Customers
Which alternative to Crystal Reports is best for small or large businesses.pdf
CHAPTER 2 - PM Management and IT Context
System and Network Administraation Chapter 3
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
medical staffing services at VALiNTRY
Operating system designcfffgfgggggggvggggggggg
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
L1 - Introduction to python Backend.pptx
How to Choose the Right IT Partner for Your Business in Malaysia
PTS Company Brochure 2025 (1).pdf.......
Nekopoi APK 2025 free lastest update
Audit Checklist Design Aligning with ISO, IATF, and Industry Standards — Omne...
System and Network Administration Chapter 2
T3DD25 TYPO3 Content Blocks - Deep Dive by André Kraus
How Creative Agencies Leverage Project Management Software.pdf
Adobe Illustrator 28.6 Crack My Vision of Vector Design
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
Understanding Forklifts - TECH EHS Solution

Refactoring domain driven design way

  • 1. REFACTORING CODE DOMAIN DRIVEN DESIGN WAY Supported By:
  • 2. Supported By: I’M ANDI PANGERAN @andi_pangeran cybercoding.wordpress.com
  • 3. Supported By: AGENDA  PRACTICE HOW TO REFACTORING CODE BASED ON DOMAIN DRIVEN DESIGN MINDSET  PRACTICE HOW TO WRITE UNIT TESTING
  • 4. Supported By: JOKO Individual who has significant expertise in the domain of the system being developed. DOMAIN EXPERT MEET OUR ACTOR
  • 5. Supported By: BENTO Individual who has spend all of his life for coding. PROGRAMMER MEET OUR ACTOR
  • 7. Supported By: Protect your invariants REFACTORING
  • 8. Supported By: JOKO PRACTICE “A customer must always have an email address.”
  • 9. Supported By: PRACTICE BENTO public class Customer { private String email; public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
  • 10. Supported By: PRACTICE BENTO public class CostumerTest { @Test public void should_always_have_an_email() { Customer customer = new Customer(); assertEquals(customer.getEmail(), "andi.pangeran@jtravl.com"); } } TEST FAIL
  • 11. Supported By: PRACTICE BENTO public class CostumerTest { @Test public void should_always_have_an_email() { Customer customer = new Customer(); customer.setEmail("andi.pangeran@jtravl.com"); assertEquals(customer.getEmail(), "andi.pangeran@jtravl.com"); } } TEST PASSED
  • 12. Supported By: PRACTICE BENTO public class Customer { private String email; public Customer(String email) { this.email = email; } }
  • 13. Supported By: PRACTICE BENTO public class CostumerTest { @Test public void should_always_have_an_email() { Customer customer = new Customer("andi.pangeran@jtravl.com"); assertEquals(customer.getEmail(), "andi.pangeran@jtravl.com"); } } TEST PASSED
  • 14. Supported By: Use object as concistency boundaries REFACTORING
  • 15. Supported By: JOKO PRACTICE “later prospective customer can be upgraded to paying customer“ “Paying customer must have phone number” “we have two type of customer, prospective and paying customer.”
  • 16. Supported By: PRACTICE BENTO public class ProspectiveCustomer extends Customer { /* other attribute */ } public class PayingCustomer extends Customer { /* other attribute */ private String phone; public PayingCustomer(String email, String phone) { super(email); this.phone = phone; } }
  • 17. Supported By: PRACTICE BENTO @Test public void upgraded_prospective_paying() { ProspectiveCustomer pcustomer = new ProspectiveCustomer("andi.pangeran@jtravl.com"); assertEquals(pcustomer.getEmail(), "andi.pangeran@jtravl.com"); PayingCustomer payCustomer = new PayingCustomer(pcustomer.getName(), “0852xxx”); assertEquals(payCustomer.getEmail(), "andi.pangeran@jtravl.com"); assertEquals(payCustomer.getPhone(), " 0852xxx"); } TEST FAIL
  • 18. Supported By: PRACTICE BENTO @Test public void upgraded_prospective_paying() { ProspectiveCustomer pcustomer = new ProspectiveCustomer("andi.pangeran@jtravl.com"); assertEquals(pcustomer.getEmail(), "andi.pangeran@jtravl.com"); PayingCustomer payCustomer = new PayingCustomer(pcustomer.getEmail(), “0852xxx”); assertEquals(payCustomer.getEmail(), "andi.pangeran@jtravl.com"); assertEquals(payCustomer.getPhone(), " 0852xxx"); } TEST PASSED
  • 19. Supported By: PRACTICE BENTO public class ProspectiveCustomer extends Customer { /* other attribute */ public PayingCustomer upgradeToPayingCustomer(String phone) { return new PayingCustomer(this.email, phone); } } public class PayingCustomer extends Customer { /* other attribute */ private String phone; public PayingCustomer(String email, String phone) { super(email); this.phone = phone; } }
  • 20. Supported By: PRACTICE BENTO @Test public void upgraded_prospective_paying() { ProspectiveCustomer pcustomer = new ProspectiveCustomer("andi.pangeran@jtravl.com"); assertEquals(pcustomer.getEmail(), "andi.pangeran@jtravl.com"); PayingCustomer payCustomer = pcostumer.upgradeToPaying(“0852xxx”); assertEquals(payCustomer.getEmail(), "andi.pangeran@jtravl.com"); assertEquals(payCustomer.getPhone(), " 0852xxx"); } TEST PASSED
  • 21. Supported By: JOKO PRACTICE “Paying customer must always have a valid phone number”
  • 22. Supported By: PRACTICE BENTO @Test public void upgraded_prospective_paying() { PayingCustomer payCustomer = new PayingCustomer(“test@mail.com", “badphonenumber”); exception.expect(IllegalArgumentException.class); } TEST FAIL
  • 23. Supported By: PRACTICE BENTO public class PayingCustomer extends Customer { /* other attribute */ private String phone; public PayingCustomer(String email, String phone) { super(email); if (/* validation stuff of phone*/ ) { throw new IllegalArgumentException(); } this.phone = phone; } } TEST PASSED
  • 24. Supported By: PRACTICE BENTO public class PayingCustomer extends Customer { /* other attribute */ private String phone; public PayingCustomer(String email, String phone) { super(email); if (/* validation stuff of phone*/ ) { throw new IllegalArgumentException(); } this.phone = phone; } } TEST PASSED
  • 25. Supported By: Encapulate state and behavior with value object REFACTORING
  • 26. Supported By: PRACTICE  Intro to value object  Intro to immutable object
  • 27. Supported By: PRACTICE BENTO public class PhoneNumber { private final String phone; public PhoneNumber(String phone) { if (/* validation stuff of phone*/ ) { throw new IllegalArgumentException(); } this.phone = phone; } public String getPhone() { { return this.phone; } }
  • 28. Supported By: PRACTICE BENTO public class PayingCustomer extends Customer { /* other attribute */ private PhoneNumber phone; public PayingCustomer(String email, PhoneNumber phone) { super(email); this.phone = phone; } } TEST PASSED
  • 29. Supported By: PRACTICE BENTO @Test public void upgraded_prospective_paying() { PayingCustomer payCustomer = new PayingCustomer(“test@mail.com", new PhoneNumber(“badphonenumber”)); exception.expect(IllegalArgumentException.class); } TEST PASSED
  • 31. Supported By: JOKO PRACTICE “a Customer orders product and pays for them”
  • 32. Supported By: Service.create BENTO Order order = new Order(); order.setCustomer(customer); order.setProducts(products); order.setStatus(PAYMENTSTATUS.UNPAID); order.setPaidAmount(500); order.setPaidCurrency(CURRENCY.IDR); order.setStatus(PAYMENTSTATUS.PAID); PRACTICE Service.pay
  • 33. Supported By: Service.create BENTO Order order = new Order(); order.setCustomer(customer); order.setProducts(products); order.setStatus(new PaymentStatus(PAYMENTSTATUS.UNPAID)); order.setPaidAmount(500); order.setPaidCurrency(CURRENCY.IDR); order.setStatus(new PaymentStatus(PAYMENTSTATUS.PAID)); PRACTICE Service.pay
  • 34. Supported By: Service.create BENTO Order order = new Order(); order.setCustomer(customer); order.setProducts(products); order.setStatus(new PaymentStatus(PAYMENTSTATUS.UNPAID)); order.setPaidMonetary(new Money(500, CURRENCY.IDR)); order.setStatus(new PaymentStatus(PAYMENTSTATUS.PAID)); PRACTICE Service.pay
  • 35. Supported By: Service.create BENTO Order order = new Order(customer, products); //set payment status in order constructor order.setPaidMonetary(new Money(500, CURRENCY.IDR)); order.setStatus(new PaymentStatus(PAYMENTSTATUS.PAID)); PRACTICE Service.pay
  • 36. Supported By: Service.create BENTO Order order = new Order(customer, products); //set payment status in order constructor order.pay (new Money(500, CURRENCY.IDR)); //set payment status in pay procedure PRACTICE Service.pay
  • 40. Supported By: JOKO PRACTICE “order 3 times to become premium customer”
  • 41. Supported By: Specification Interface BENTO public interface Specification<T> { boolean isSatisfiedBy(T t); Class<T> getType(); } PRACTICE Specification Abstract abstract public class AbstractSpecification<T> implements Specification<T> { @Override public boolean isSatisfiedBy(T t) { throw new NotImplementedException(); } /othercode }
  • 42. Supported By: BENTO public class CustomerIsPremium extends AbstractSpecification<Customer> { private OrderRepository orderRepository public CustomerIsPremium(OrderRepository orderRepository) { this.orderRepository = orderRepository; } @Override public boolean isSatisfiedBy(Customer customer) { int count = this.orderRepository.countByCustomer(customer.getId); return (count > 3); } } PRACTICE
  • 43. Supported By: PRACTICE BENTO @Test public void specification_customer_premium() { CustomerIsPremium<Customer> spec= new CustomerIsPremium(); customer2order = … customer3order = … assertFalse(spec.isSatisfiedBy(customer2order)); assertTrue(spec.isSatisfiedBy(customer3order)); } TEST PASSED
  • 44. Supported By: JOKO PRACTICE “different rules apply for different tenants.”
  • 45. Supported By: BENTO public class CustomerWith3OrdersIsPremium implement CustomerIsPremium {} public class CustomerWith500kPremium implement CustomerIsPremium {} public class CustomerWithSpecialRequiredmentPremium implement CustomerIsPremium {} PRACTICE Specification Interface public interface CustomerIsPremium extends Specification<Customer> { boolean isSatisfiedBy(Customer cust); }
  • 46. Supported By: BENTO PRACTICE public class SpecialOfferSender { private CustomerIsPremium premiumSpec public SpecialOfferSende(CustomerIsPremium premiumSpec) { this.orderRepository = orderRepository; } public void sendOffersTo(Customer customer) { if (this.premiumSpec.isSatisfiedBy(customer)) { //send offers } } }
  • 47. Supported By: Use Spefication for Object Selection REFACTORING
  • 48. Supported By: JOKO PRACTICE “get a list of all premium customers”
  • 49. Supported By: PRACTICE  Intro to predicate pattern  Collection predicate  JPA predicate
  • 50. Supported By: BENTO PRACTICE Specification Interface public interface Specification<T> { boolean isSatisfiedBy(T t); Predicate toCollectionPredicate(); } @Override public Predicate toCollectionPredicate(Customer customer) { Predicate<Customer> predicate = new predicate<Customer>() { @Override public boolean apply(Customer input) { return this.isSatisfiedBy(input); } }; return predicate; }
  • 51. Supported By: BENTO PRACTICE CustomerIsPremium<Customer> spec= new CustomerIsPremium(); List<Customer> allCustomer = … Collection<Customer> result = Collections2.filter( allCustomer, spec.toCollectionPredicate() ); assertArrayEquals(result, … testarray); TEST PASSED
  • 52. Supported By: BENTO PRACTICE Specification Interface public interface Specification<T> { boolean isSatisfiedBy(T t); Predicate toCollectionPredicate(); Predicate toPredicate(Root<T> root, CriteriaBuilder cb); } @Override public Predicate toPredicate (Root<Customer> root, CriteriaBuilder cb) { return cb.and (cb.greaterThan(root.get(Customer_.order),3) ); }
  • 53. Supported By: BENTO PRACTICE public class DBRepository { private EntityManager entityManager = ... public <T> List<T> findAllBySpecification(Specification<T> specification) { CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); // use specification.getType() to create a Root<T> instance CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(specification.getType()); Root<T> root = criteriaQuery.from(specification.getType()); // get predicate from specification Predicate predicate = specification.toPredicate(root, criteriaBuilder); // set predicate and execute query criteriaQuery.where(predicate); return entityManager.createQuery(criteriaQuery).getResultList(); } }
  • 54. Supported By: BENTO PRACTICE CustomerIsPremium<Customer> spec= new CustomerIsPremium(); List<Customer> Customer = DBRepository. findAllBySpecification(spec); assertArrayEquals(result, … testarray); TEST PASSED
  • 55. Supported By: SUMMARY  Protect your invariants  Use object as consistency boundaries  Encapulate state and behavior with value object  Encapulate Operations  Use specification pattern  Use predicate pattern
  • 57. Supported By: Identity CTM for Refactoring, each monday REFACTORING