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

Clean, Pragmatic Architecture at Virtual JUG

Clean, Pragmatic Architecture at Virtual JUG

In a mood for a closing brainstorm? Let’s have a critical review of the major decisions taken in a typical enterprise application architecture and learn to balance pragmatism with design goals. Find out how to do just-in-time design to keep as many use-cases as simple as possible (KISS).

We’ve all seen that without continuous refactoring simplistic design eventually degenerates into a Big Ball of Mud, under the assault of new features and bugfixes. At the other end, over-engineered code can burden the start-up of the development and then end up freezing the code in some rigid ‘a-priori’ design. It’s up to us to strike a balance that will preserve Developer Happiness™. To do that, we should regularly challenge the architecture of our system and seek ways to simplify it to fit our present needs, with a pragmatic mindset.

“Architecture is the art of postponing decisions”, said Uncle Bob. This session takes this idea further and explains how to Evolve a Pragmatic, Clean Architecture (aka Onion), guiding the design by what Genetic Programming would call a fitness function. It’s the philosophy Victor applied to design and develop 9 applications for IBM, and a key topic of the trainings he delivered at dozens of companies.

Along the way, you’ll also get a nice review of the fundamental data structure types, how to keep the logic simple by two types of extractions, enforcing boundaries using dependency directions, and crafting a testable design, all in a fun, dynamic and interactive session.

Victor Rentea

March 28, 2019
Tweet

More Decks by Victor Rentea

Other Decks in Programming

Transcript

  1. When something is painful
    but you can't avoid doing it…
    postpone it

    View full-size slide

  2. When something is painful
    but you can't avoid doing it…
    delegate it

    View full-size slide

  3. When something is painful
    but you can't avoid doing it…
    Do It More Often!
    "Bring The Pain Forward!"

    View full-size slide

  4. Continuous Integration
    Pair Programming
    Continuous Refactoring
    TDD
    XP
    "Bring The Pain Forward!"

    View full-size slide

  5. Victor Rentea
    14 years of Java
    Clean Code Evangelist
    VictorRentea.ro
    30+ talks, 12 meetups
    .NET
    Lead Architect
    Tech Team Lead and Consultant
    Software Craftsman
    XP: Pair Programming, Refactoring, TDD

    View full-size slide

  6. VictorRentea.ro @victorrentea [email protected]
    Independent
    Technical Trainer & Coach
    Hibernate
    Spring Java 8
    Architecture, DDD
    Design Patterns
    Clean Code Unit Testing, TDD
    Java Performance and much more…
    Scala
    180+ days
    1300 devs
    6 years
    VictorRentea.ro
    [email protected]
    30 companies
    Posting daily on

    View full-size slide

  7. 26
    The most important principle
    in programming?

    View full-size slide

  8. 27
    Single Responsibility Principle
    EmployeeManager
    -read/persist
    -compute pay-roll
    -generate PDF report
    -manage projects
    vs

    View full-size slide

  9. 28
    Coupling
    vs

    View full-size slide

  10. 29
    Don’t Repeat Yourself

    View full-size slide

  11. 30
    Keep It Short & Simple
    Premature encapsulation is the root of all evil
    Overengineering
    – Adam Bien

    View full-size slide

  12. 31
    Keep It Short & Simple
    Premature encapsulation is the root of all evil
    Overengineering
    Simpler code Developer Happiness

    View full-size slide

  13. 32
    Invisible Magic to reduce effort and risk
    Protect the Developers
    ...
    Avoid building an intrusive
    Custom Framework
    (bugs to learn)
    Developer
    Comfort

    View full-size slide

  14. 33
    Request/Thread Scope
    @Autowired
    private MyRequestContext requestContext;
    ... {
    entity.setModifiedBy(requestContext.getCurrentUser());
    }
    @Component
    @Scope(value = "request", proxyMode = TARGET_CLASS)
    class MyRequestContext { ... }
    Request
    Metadata

    View full-size slide

  15. Fear Kills Creativity Simplify Unit Testing
    - Strong regression defense
    Protect the Developers
    34
    Developer
    Safety

    View full-size slide

  16. Always Think
    Regular Brainstorming
    35
    Continuous Refactoring
    There are NO boring tasks
    automate them

    View full-size slide

  17. 39
    Keep Struggling for a
    Can you predict the future ?
    What features will grow
    super-complex in time?
    Simple Design
    At all times!

    View full-size slide

  18. 40
    - Kent Beck
    https://martinfowler.com/bliki/BeckDesignRules.html
    2. Reveals Intention
    3. No Duplication
    4. Fewest Elements
    1. Passes the Tests
    Rules of Simple Design

    View full-size slide

  19. 41
    A Simple Architecture
    that Evolves
    to Match
    the Growing Complexity
    This talk is about…

    View full-size slide

  20. 42
    Core Principles
    Modeling Data
    Organizing Logic
    The Onion Architecture
    Tests. Fear.
    Agenda
    VictorRentea.ro

    View full-size slide

  21. You control them!
    Entities = your persistent data
    43
    Entity
    They simplify your logic

    View full-size slide

  22. 44
    Put small bits of
    highly reusable
    domain logic in your
    Domain Entities
    public class Customer {
    [...]
    public String getFullName() {
    return firstName + " " + lastName;
    }
    public void activate(User user) {
    if (status != Status.DRAFT) {
    throw new IllegalStateException();
    }
    status = Status.ACTIVE;
    activatedBy = user;
    activatedDate = new Date();
    }
    public boolean isActive() {
    return status == Status.ACTIVE;
    }
    public boolean canPlaceOrders() {
    return status == Status.ACTIVE && !isBann
    }

    View full-size slide

  23. 45
    activatedBy = user;
    activatedDate = new Date();
    }
    public boolean isActive() {
    return status == Status.ACTIVE;
    }
    public boolean canPlaceOrders() {
    return status == Status.ACTIVE && !isBann
    }
    public void addAddress(Address address) {
    address.setCustomer(this);
    addresses.add(address);
    }
    public List getAddresses() {
    return Collections.unmodifiableList(
    addresses);
    }
    }
    public String toExportString() {
    return String.format("%s;%s;%d",
    firstName, lastName, isActive()?1:0);
    }
    BlOAt dAnGeR
    Fit
    Put small bits of
    highly reusable
    domain logic in your
    Domain Entities

    View full-size slide

  24. Entity
    id
    46
    Small
    Immutable
    Lombok?
    No persistent ID
    unlike an Entity
    Equal by value
    of all fields
    Embeddable
    In larger entities
    Value Object: a grouping of domain data
    VO
    public class Money {
    private final Currency currency;
    private final BigDecimal amount;
    public Money(Currency currency,
    BigDecimal amount) {
    this.currency = currency;
    this.amount = amount;
    }
    public Currency getCurrency() {
    return currency;
    }
    public BigDecimal getAmount() {
    return amount;
    }
    public boolean equals(Object other)
    { ... }
    }
    validate();

    View full-size slide

  25. Then, you start exposing data to UI
    (SPA, WS, JSF, desktop)
    UI has different goals
    They want data structures to match their screens.
    Never expose your Entities in your API
    47
    isDeletable: true
    (to show/hide the Delete button)

    View full-size slide

  26. I like dumb DTOs
    (you'll see soon why)
    public fields ?! ! !..
    VO
    Entity
    id
    Logic
    public class CustomerDto {
    private String fullName;
    private String phoneNumber;
    private Date birthDate;
    public final String getFullName
    return fullName;
    }
    public final void setFullName(S
    this.fullName = fullName;
    }
    public final String getPhoneNum
    return phoneNumber;
    }
    public final void setPhoneNumbe
    this.phoneNumber = phoneNumbe
    }
    public final Date getBirthDate(
    return birthDate;
    }
    public final void setBirthDate(
    this.birthDate = birthDate;
    }
    }
    48
    Form/Request
    View/Response
    DTO
    SearchCriteria/SearchResult
    Data Transfer Objects
    DTO
    Instead, expose in your API
    public class CustomerDto {
    public String fullName;
    public String phoneNumber;
    public Date birthDate;
    }
    dto.fullName = customer.getFullName();

    View full-size slide

  27. 49
    Core Principles
    Modeling Data
    Organizing Logic
    The Onion Architecture
    Tests. Fear.
    Agenda

    View full-size slide

  28. 50
    Complex Conversion?
    Extract Mappers
    VO
    Entity
    id
    DTO
    Mapper
    Logic
    API Domain
    CustomerDto dto = new CustomerDto();
    dto.fullName = customer.getFullName();
    dto.birthDate = customer.getBirthDate();
    dto.phoneNumber = customer.getPhoneNumber();
    CustomerDto dto = new CustomerDto(customer);

    View full-size slide

  29. 61
    Start implementing all domain logic in a
    Facade
    Mapper VO
    Entity
    id
    DTO
    Facade
    Facade Domain
    Service
    Domain
    Service
    Domain Services
    This approach is detailed in Java EE Patterns - Rethinking Best Practices, by Adam Bien
    Then extract logic into
    -To hide complexity: SRP
    -For Reuse: DRY
    ▪ (across Facades or Services)
    ≈ Application Service
    [DDD]

    View full-size slide

  30. 63
    Keep DTOs out!
    (parameters and return types)
    Mapper VO
    Entity
    id
    DTO
    Facade
    Facade Domain
    Service
    Domain
    Service
    Domain Services
    speak your Domain Model
    Convert them to your Domain Objects ASAP
    DTOs are fragile
    (under enemy control)
    * I like them dumb (no methods)

    View full-size slide


  31. Validate Data
    Façade
    Convert Data
    Implement Logic
    Aspects
    - Transactions
    - Logging
    - Exception Handling*
    - Access Control*
    64
    Facade Roles
    DTO
    Validator
    Mapper
    Domain
    Service
    VO
    Entity
    id

    View full-size slide

  32. 65
    What do you mean ?
    When a class
    grows too big
    (>~200 lines?)
    ➔ break it
    Extract when it Grows
    How?
    Look for a good class
    name to summarize
    some of its methods
    Huh? If I find a good name,
    I extract? That’s it?
    Exactly!
    Piece a cake!
    A Good
    Name
    He-he!☺
    “There are only two things
    hard in programming:
    Cache Invalidation and
    Naming Things”

    View full-size slide

  33. 66
    CustomerFacade
    saveCustomer()
    getCustomer()
    searchCustomer()
    saveCustomerPreferences()
    getCustomerPreferences()
    validateAddress()
    resetPassword()
    checkPassworStrength()
    CustomerPreferecesFacade
    saveCustomerPreferences()
    getCustomerPreferences()
    validateAddress()
    resetPassword()
    checkPassworStrength()
    CustomerFacade
    saveCustomer()
    getCustomer()
    searchCustomer()
    Extract when it Grows
    at the same level of abstraction
    Horizontal Splitting
    > 300 lines

    View full-size slide

  34. AlertService
    CompositeOrder
    Service
    67
    Separation by Layers of Abstraction
    OrderService DeliveryService
    Extract when it Grows
    Vertical Extraction
    more abstract,
    more higher-level

    View full-size slide

  35. 69
    Duplication
    Pair Programming
    Imposed
    repeat in .js the validations from .java
    Rush/Lazy
    Inadvertent
    you forget and implement it again
    Inter-developer
    you didn't knew that was already implemented
    bus factor =2

    View full-size slide

  36. Practice
    Pair Programming

    View full-size slide

  37. Developer Comfort
    is essential for
    Emerging Architectures

    View full-size slide

  38. 75
    Core Principles
    Modeling Data
    Organizing Logic
    The Onion Architecture
    Tests. Fear.
    Agenda
    VictorRentea.ro

    View full-size slide

  39. 76
    VO
    Entity
    id
    Domain
    Service
    Domain
    Service
    What code would you protect?
    Put it in the domain module
    Priceless
    Domain Logic
    Domain Objects
    domain

    View full-size slide

  40. Façade
    DTO
    Validator
    Mapper
    F
    application
    77
    domain
    depends on domain
    VO
    Entity
    id
    Domain
    Service
    Domain
    Service

    View full-size slide

  41. 78
    External
    Service
    DTO
    Domain
    Service
    Domain
    Service
    domain

    View full-size slide

  42. 79
    External
    Service
    DTO
    Adapter
    Domain
    Service
    Domain
    Service

    domain infrastructure
    A huge Adapter® Pattern
    - Hide their ugly API
    - Handle their Exceptions
    - Decouple their DTOs  your Entities
    - Validate their evil data

    View full-size slide

  43. 80
    External
    Service
    DTO
    IAdapter Adapter
    implements
    class OrderRepository
    implements IOrderRepo {
    public Order getById(id){
    ...
    }
    }
    interface IOrderRepo {
    Order getById(id);
    }
    class OrderService {
    @Autowired
    IOrderRepository repo;
    ... {
    repo.getById(id);
    }
    }
    express your need in
    a domain interface…
    and implement it in a
    lower-level module…
    When you need
    to call outside…
    so nothing foreign
    enters your domain.
    Domain
    Service
    Domain
    Service

    domain infrastructure

    View full-size slide

  44. 81
    calls
    Dependency Inversion Principle

    higher-level
    module
    lower-level
    module
    "Best of OOP"
    - Uncle Bob
    Abstractions should not depend on details
    Low level classes
    are not visible

    View full-size slide

  45. infra
    Adapter
    83
    External
    Service
    XML, JSON
    IAdapter

    implements
    HTTP, RMI, …
    FTP
    JMS
    domain
    DB
    DTO

    View full-size slide

  46. 86
    VO
    Entity
    id
    Domain
    Service
    Domain
    Service
    IExtSrv
    Adapter
    IRepo
    What code would you protect?
    Put it in the domain module
    Interfaces for
    External Services
    you consume
    Interfaces for
    Repositories
    Priceless Domain Logic
    Domain Objects

    View full-size slide

  47. infra
    ExtSrv
    Adapter
    Repo
    implem
    87
    Façade
    DTO
    Validator
    Mapper
    VO
    Entity
    id
    Domain
    Service
    Domain
    Service
    IExtSrv
    Adapter
    IRepo
    F
    application
    The Onion Architecture
    Behold,
    a.k.a. Clean, Hexagonal, Ports-and-Adapters

    View full-size slide

  48. 98
    Façade
    DTO
    Validator
    Mapper
    VO
    Entity
    id
    Domain
    Service
    Domain
    Service
    IRepo
    Repo
    implem
    F
    application
    infra
    IExtSrv
    Adapter
    Adapter
    WS
    Interface
    DTO

    View full-size slide

  49. 99
    Façade
    DTO
    Validator
    Mapper
    VO
    Entity
    id
    Domain
    Service
    Domain
    Service
    IRepo
    Repo
    implem
    F
    application
    IExtSrv
    Adapter
    Adapter
    WS
    Interface
    DTO
    domain
    Pragmatic
    for decent apps, 2 modules are enough

    View full-size slide

  50. Use-case
    Optimal
    Query
    100
    CALLS
    DEPENDS
    Breaking into Bounded Contexts
    DTO
    Facade
    Infra
    Tip: Measure boundary violations
    com.myapp.order. …
    com.myapp.product. …
    EVENT
    TX FK?
    SELECT
    MICRO…
    "Light CQRS"
    consistency

    View full-size slide

  51. 103
    tardigrade

    View full-size slide

  52. 104
    fitness function

    View full-size slide

  53. 105
    coupling
    performance
    scalability
    fitness function
    security
    source code size

    View full-size slide

  54. 108
    Core Principles
    Modeling Data
    Organizing Logic
    The Onion Architecture
    Tests. Fear.
    Agenda
    VictorRentea.ro

    View full-size slide

  55. 109
    Lots of Unit Tests are Good !
    A sense of confidence
    Developer Courage
    Continuous Refactoring
    (It’s still a single )

    View full-size slide

  56. 110
    As you fight to write Unit Tests,
    the Production code gets simpler

    View full-size slide

  57. 112
    First couple of unit tests : The most valuable
    Test no.
    difficulty

    View full-size slide

  58. Maintainable Tests
    Pure Functions
    No side effects. No dependencies.
    Mock-based
    Less readable
    In-memory Emulation
    or JPQL tests on H2/* db
    Fragile data fixtures
    On Real Systems
    Eg: Connecting to a real DB
    113
    , = 2 + 2

    View full-size slide

  59. infrastructure
    domain
    side effects
    116
    pure logic

    View full-size slide

  60. ▪ 7 Virtutes of a Good Object
    ▪ NULL – the worst mistake in IT
    - https://dzone.com/articles/the-worst-mistake-of-computer-science-1
    ▪ The Clean Architecture:
    - http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html
    ▪ Some ☺ Programming Jargon
    - http://blog.codinghorror.com/new-programming-jargon/
    ▪ Code quality: WTFs/minute
    - http://commadot.com/wtf-per-minute/
    ▪ SOLID is WRONG
    - https://speakerdeck.com/tastapod/why-every-element-of-solid-is-wrong
    ▪ Good software is written 3 times
    - http://www.javaworld.com/article/2072651/becoming-a-great-programmer--
    use-your-trash-can.html
    ▪ Prezi-like effect in PowerPoint 2016: “Morph”
    ▪ Value Objects vs Entity
    - http://enterprisecraftsmanship.com/2016/01/11/entity-vs-value-object-the-
    ultimate-list-of-differences/
    ▪ Extends is bad
    - http://www.yegor256.com/2016/09/13/inheritance-is-procedural.html
    ▪ “Measure Don’t Ask” is TM of Kirk Pepperdine
    Further Reading
    121

    View full-size slide

  61. 122
    Agenda
    VictorRentea.ro
    Core Principles
    Modeling Data
    Organizing Logic
    The Onion Architecture
    Tests. Fear.

    View full-size slide

  62. 123
    Core Principles
    VictorRentea.ro
    Modeling Data
    Organizing Logic
    The Onion Architecture
    Tests. Fear.
    Agenda
    Takeaways

    View full-size slide

  63. 124 VictorRentea.ro
    Tests. Fear.
    Organizing Logic
    The Onion Architecture
    Modeling Data
    KISS: Avoid overengineering
    Magic to protect your Developers
    Takeaways

    View full-size slide

  64. 125 VictorRentea.ro
    Tests. Fear.
    Organizing Logic
    The Onion Architecture
    Enemy data
    KISS: Avoid overengineering
    Magic to protect your Developers
    in your DTOs: keep them out
    Takeaways

    View full-size slide

  65. 126 VictorRentea.ro
    Tests. Fear.
    Extract when it Grows
    The Onion Architecture
    KISS: Avoid overengineering
    Magic to protect your Developers
    : for SRP or DRY
    Enemy data in your DTOs: keep them out
    Takeaways

    View full-size slide

  66. 127 VictorRentea.ro
    Extract when it Grows
    The Onion
    KISS: Avoid overengineering
    Magic to protect your Developers
    : for SRP or DRY
    Enemy data in your DTOs: keep them out
    , DIP: domain agnostic to externals
    Tests. Fear.
    Takeaways
    (Adapt® them)

    View full-size slide

  67. 128 VictorRentea.ro
    Extract when it Grows
    The Onion
    KISS: Avoid overengineering
    Magic to protect your Developers
    : for SRP or DRY
    Enemy data in your DTOs: keep them out
    , DIP: domain agnostic to externals
    Tests: let them smash your design
    Takeaways
    (Adapt® them)

    View full-size slide

  68. 130
    Keep It simple

    View full-size slide

  69. 136
    Put Passion In
    All That You Do!!

    View full-size slide