Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The return of the native principles

The return of the native principles

Bartłomiej Słota

April 08, 2019
Tweet

More Decks by Bartłomiej Słota

Other Decks in Programming

Transcript

  1. THE RETURN OF THE NATIVE PRINCIPLES Time Procedural Programming Framework

    Database ORM Junior Developer Regular Developer Object Oriented Programming Functional Programming TDD SOLID GRASP Patterns Architecture Microservices Distributed Systems DDD Event Driven Architecture ETAPY DOJRZAŁOŚCI
  2. THE RETURN OF THE NATIVE PRINCIPLES Time Procedural Programming Framework

    Database ORM Junior Developer Regular Developer Object Oriented Programming Functional Programming TDD SOLID GRASP Patterns Architecture Microservices Distributed Systems DDD Event Driven Architecture ETAPY DOJRZAŁOŚCI
  3. THE RETURN OF THE NATIVE PRINCIPLES Time Procedural Programming Framework

    Database ORM Junior Developer Regular Developer Object Oriented Programming Functional Programming TDD SOLID GRASP Patterns Architecture Microservices Distributed Systems DDD Event Driven Architecture ETAPY DOJRZAŁOŚCI
  4. THE RETURN OF THE NATIVE PRINCIPLES TEXT ZAŁOŻENIA PARADYGMATU OBIEKTOWEGO

    ▸ Abstrakcja ▸ Enkapsulacja ▸ Polimorfizm ▸ Dziedziczenie, kompozycja, delegacja
  5. THE RETURN OF THE NATIVE PRINCIPLES POZIOMY ABSTRAKCJI W KODZIE

    Bill customer Sum charging costs Calculate charging cost Poziom abstrakcji Read tariff from repository Read tariff document from MongoDB … 1 0 0 0 1 0 1 1 0 0 …. 1 1 0
  6. THE RETURN OF THE NATIVE PRINCIPLES HEXAGONAL ARCHITECTURE CORE DOMAIN

    CORE DOMAIN PORTY wysoki poziom abstrakcji ADAPTERY niski poziom abstrakcji
  7. THE RETURN OF THE NATIVE PRINCIPLES AGGREGATE, ENTITIES & VALUE

    OBJECTS public class Customer { private CustomerId id; private CustomerStatus status; ... public Customer activate() { if (canBeActivated()) { return new Customer(this.id, CustomerStatus.ACTIVE); } else { throw IllegalStateException("Customer cannot be activated"); } } ... }
  8. THE RETURN OF THE NATIVE PRINCIPLES SERWIS APLIKACYJNY public class

    CustomerActivation { ... @Transactional public Customer activate(CustomerActivationCommand command) { final Customer customer = customerRepository.findById(command.customerId()); final Customer activatedCustomer = customer.activate(); return customerRepository.save(activatedCustomer); } }
  9. THE RETURN OF THE NATIVE PRINCIPLES POLITYKA CZYLI “WHAT” VS

    “HOW” class LinearIncomeTaxCalculation implements IncomeTaxCalculationPolicy { private final BigDecimal RATE = BigDecimal.valueOf(0.19d); @Override public Tax calculate(YearlyIncome income) { return new Tax(income.getValue().multiply(RATE)); } } interface IncomeTaxCalculationPolicy { Tax calculate(YearlyIncome income); } Wysoki poziom abstrakcji Niski poziom abstrakcji
  10. THE RETURN OF THE NATIVE PRINCIPLES POLITYKA CZYLI “WHAT” VS

    “HOW” class LinearIncomeTaxCalculation implements IncomeTaxCalculationPolicy { private final BigDecimal RATE = BigDecimal.valueOf(0.19d); @Override public Tax calculate(YearlyIncome income) { return new Tax(income.getValue().multiply(RATE)); } } interface IncomeTaxCalculationPolicy { Tax calculate(YearlyIncome income); } Wysoki poziom abstrakcji class GeneralIncomeTaxCalculation implements IncomeTaxCalculationPolicy { private final BigDecimal FIRST_LEVEL_RATE = BigDecimal.valueOf(0.19d); private final BigDecimal SECOND_LEVEL_RATE = BigDecimal.valueOf(0.32d); private final BigDecimal FIRST_LEVEL_LIMIT = BigDecimal.valueOf(85000); @Override public Tax calculate(YearlyIncome income) { BigDecimal firstLevelValue = income.getValueBelowOrEqual(FIRST_LEVEL_LIMIT); BigDecimal secondLevelValue = income.getValueAbove(FIRST_LEVEL_LIMIT); return new Tax(firstLevelValue.multiply(FIRST_LEVEL_RATE) + secondLevelValue.multiply(SECOND_LEVEL_RATE)); } } Niski poziom abstrakcji
  11. THE RETURN OF THE NATIVE PRINCIPLES WYCIEK ABSTRAKCJI - INFRASTRUKTURA

    Wysoki poziom abstrakcji Niski poziom abstrakcji import javax.sql.rowset.CachedRowSet; interface CustomerRepository { CachedRowSet findAll(); } import javax.sql.rowset.CachedRowSet; class SqlCustomerRepository implements CustomerRepository { @Override public CachedRowSet findAll() { // sql specific implementation } }
  12. THE RETURN OF THE NATIVE PRINCIPLES WYCIEK ABSTRAKCJI - INFRASTRUKTURA

    MICROSERVICE ENTITY MICROSERVICE MICROSERVICE ENTITY ENTITY ENTITY
  13. THE RETURN OF THE NATIVE PRINCIPLES DLACZEGO CHCECIE NAPISAĆ TEN

    SYSTEM OD NOWA? “To stoi na jakimś archaicznym Glassfish’u, cały soap, logowanie, deployment wszystko zrobione na natywnych rozwiązaniach Glassfish. Dostęp do bazy nawet nie jest przez Hibernate tylko jest jakiś kastomizowany Hades." “Ta logika biznesowa jest już nie na czasie. Obecnie biznes rządzi się już innymi prawami.” vs.
  14. THE RETURN OF THE NATIVE PRINCIPLES WYCIEK ABSTRAKCJI - DOMENA

    class LinearIncomeTaxCalculation implements IncomeTaxCalculationPolicy { private final BigDecimal RATE = BigDecimal.valueOf(0.19d); @Override public Tax calculate(YearlyIncome income) { return new Tax(income.getValue().multiply(RATE)); } } Wysoki poziom abstrakcji Niski poziom abstrakcji interface IncomeTaxCalculationPolicy { Tax calculate(YearlyIncome income); }
  15. THE RETURN OF THE NATIVE PRINCIPLES WYCIEK ABSTRAKCJI - DOMENA

    class LinearIncomeTaxCalculation implements IncomeTaxCalculationPolicy { private final BigDecimal RATE = BigDecimal.valueOf(0.19d); @Override public Tax calculate(YearlyIncome income) { return new Tax(income.getValue().multiply(RATE)); } } Wysoki poziom abstrakcji Niski poziom abstrakcji class AnnualSettlementUseCase { void account(CustomerId customerId) { Customer customer = customerRepository.findOne(customerId); IncomeTaxCalculationPolicy incomeTaxPolicy = //choose correct policy Tax tax = incomeTaxPolicy.calculate(customer.getYearlyIncome()); // do sth with calculated tax } } interface IncomeTaxCalculationPolicy { Tax calculate(YearlyIncome income); }
  16. THE RETURN OF THE NATIVE PRINCIPLES WYCIEK ABSTRAKCJI - DOMENA

    class LinearIncomeTaxCalculation implements IncomeTaxCalculationPolicy { private final BigDecimal RATE = BigDecimal.valueOf(0.19d); @Override public Tax calculate(YearlyIncome income) { return new Tax(income.getValue().multiply(RATE)); } } Wysoki poziom abstrakcji Niski poziom abstrakcji class AnnualSettlementUseCase { void account(CustomerId customerId) { Customer customer = customerRepository.findOne(customerId); IncomeTaxCalculationPolicy incomeTaxPolicy = //choose correct policy if (incomeTaxPolicy instanceof LinearIncomeTaxCalculation) { //do something only for this special case } } } interface IncomeTaxCalculationPolicy { Tax calculate(YearlyIncome income); }
  17. THE RETURN OF THE NATIVE PRINCIPLES SINGLE RESPONSIBILITY ▸ Powinien

    istnieć jeden powód do zmiany w klasie, na przykład: ▸ Zmienia się flow obsługi przypadku użycia ▸ Zmienia się sposób obliczenia opłaty za nocne ładowanie ▸ Zmieniają się wymaganie dotyczące wydajności bazy danych
  18. THE RETURN OF THE NATIVE PRINCIPLES SINGLE RESPONSIBILITY ▸ Żadna

    klasa która miesza kod domenowy z technologią nie jest zgodna z SRP 1. Zmienia się domena 2. Zmienia się technologia CLASS /REST/full
  19. THE RETURN OF THE NATIVE PRINCIPLES SINGLE RESPONSIBILITY ▸ Hexagonal

    architecture ‣ Port - zmienia się domena ‣ Adapter - zmieniają się technikalia CORE DOMAIN
  20. THE RETURN OF THE NATIVE PRINCIPLES TEXT OPEN CLOSED PRINCIPLE

    ▸ Tworzymy klasy / komponenty które są zamknięte na modyfikacje… ale są otwarte na rozszerzenia ▸ Otwartość na rozszerzenia - możliwość dodawania nowej funkcjonalności bez zmian w klasach / komponentach zamkniętych na modyfikacje
  21. THE RETURN OF THE NATIVE PRINCIPLES OCP - POLITYKA /

    STRATEGIA POLICY SOME CONCRETE POLICY FANCY POLICY BUSINESS LOGIC Wysoki poziom abstrakcji Niski poziom abstrakcji
  22. THE RETURN OF THE NATIVE PRINCIPLES OCP - POLITYKA /

    STRATEGIA POLICY SOME CONCRETE POLICY FANCY POLICY ANOTHER POLICY BUSINESS LOGIC Wysoki poziom abstrakcji Niski poziom abstrakcji
  23. THE RETURN OF THE NATIVE PRINCIPLES OCP - POLITYKA /

    STRATEGIA POLICY SOME CONCRETE POLICY FANCY POLICY ANOTHER POLICY BUSINESS LOGIC YET ANOTHER POLICY Wysoki poziom abstrakcji Niski poziom abstrakcji
  24. THE RETURN OF THE NATIVE PRINCIPLES LISKOV SUBSTITUTION PRINCIPLE ▸

    Przez dziedziczenie lub implementację interfejsu tworzymy specyficzne obiekty które spełniają bazowy kontrakt
  25. THE RETURN OF THE NATIVE PRINCIPLES LISKOV SUBSTITUTION PRINCIPLE class

    Employee { void takeSalary() { //do sth } } @Test public void shouldTakeSalary() { //given Employee employee = someEmplyee(); //when employee.takeSalary(); //then salaryTaken(employee); }
  26. THE RETURN OF THE NATIVE PRINCIPLES LISKOV SUBSTITUTION PRINCIPLE class

    Employee { void takeSalary() { //do sth } } @Test public void shouldTakeSalary() { //given Employee employee = someEmplyee(); //when employee.takeSalary(); //then salaryTaken(employee); } class Volunteer extends Employee { @Override void takeSalary() { throw new UnsupportedOperationException(); } }
  27. THE RETURN OF THE NATIVE PRINCIPLES LISKOV SUBSTITUTION PRINCIPLE class

    Employee { void takeSalary() { //do sth } } @Test public void shouldTakeSalary() { //given Employee employee = new Volunteer(); //when employee.takeSalary(); //then salaryTaken(employee); } class Volunteer extends Employee { @Override void takeSalary() { throw new UnsupportedOperationException(); } }
  28. THE RETURN OF THE NATIVE PRINCIPLES INTERFACE SEGREGATION PRINCIPLE class

    Service { void methodA() { } void methodB() { } void methodC() { } } class ClientA { @Autowired Service service; void doSth() { service.methodA(); } } class ClientB { @Autowired Service service; void doSth() { service.methodB(); } }
  29. THE RETURN OF THE NATIVE PRINCIPLES DEPENDENCY INVERSION PRINCIPLE ▸

    Moduły wysokiego poziomu nie powinny zależeć od modułów niskiego poziomu ▸ Abstrakcje nie powinny zależeć od detali - to detale powinny zależeć od abstrakcji
  30. THE RETURN OF THE NATIVE PRINCIPLES DEPENDENCY INVERSION PRINCIPLE class

    InMemoryCustomerRepository implements CustomerRepository { private final Map<CustomerId, Customer> customers = new HashMap<>(); @Override public Customer findBy(CustomerId customerId) { return customers.get(customerId); } } Wysoki poziom abstrakcji Niski poziom abstrakcji public class CustomerActivation { private final CustomerRepository customerRepository; public CustomerActivation(CustomerRepository customerRepository) { this.customerRepository = customerRepository; } public Customer activateBy(CustomerId customerId) { Customer customer = customerRepository .findBy(customerId); return customer.activate(); } } public interface CustomerRepository { Customer findBy(CustomerId customerId); Customer save(Customer customer); }
  31. THE RETURN OF THE NATIVE PRINCIPLES TEXT DEPENDENCY INVERSION PRINCIPLE

    Wysoki poziom abstrakcji Niski poziom abstrakcji public class CustomerActivation { private final CustomerRepository customerRepository; public CustomerActivation(CustomerRepository customerRepository) { this.customerRepository = customerRepository; } public Customer activateBy(CustomerId customerId) { Customer customer = customerRepository.findBy(customerId); return customer.activate(); } } @RestController public class CustomerController { private final CustomerActivation activation; public CustomerController(CustomerActivation activation) { this.activation = activation; } @PutMapping(“/customers/{id}") Customer activate(@PathVariable("id") String id) { return activation.activateBy(CustomerId.from(id)); } }