API/
Hi, I'm Victor Rentea
Java Champion – drinking since 2006
Trainer – 3000+ devs / 80+ companies, since 2013
Speaker – Conferences & Meetups
Hibernate
Spring Java8/FP
Java Performance Secure Coding
Reactive
Architecture Clean Code Unit Testing
$
Hibernate
Spring Java8/FP
Architecture Clean Code Unit Testing
Masterclass
Company
Training
Video
Courses
YouTube
Channel
💗 Join My
Community
Blog
@victorrentea
VictorRentea.ro
victorrentea@gmail.com
Java Performance Secure Coding
Reactive
172 VictorRentea.ro
a training by
Chapter 1. Data Structures
173 VictorRentea.ro
a training by
Can I have a chicken?
The data structure they send you
The data structure you want to use in your core logic
DTO
domain
Object
175 VictorRentea.ro
a training by
DTOs*
are Evil
*Data Transfer Objects – data structures that move across APIs
176 VictorRentea.ro
a training by
☢ Beware of Foreign Data Structures ☢
➢ Bloated (more fields than you need)
➢ Flat
➢ Different perspective 🐔 (bounded context)
➢ Fixed design (often generated or in client-lib)
➢ Mutable (pain from frameworks otherwise)
➢ No constraints (nulls, validation, invariants)
➢ Diverging in time (v2)
We 💗 small, cohesive data structures
We 💗 Logic next to data (OOP)
We 💗 Immutable objects
We 💗 Deep, Rich Domain Model
We 💗 Models to guard their invariants
We want control over our structures
Because DTOs are: In our core logic:
We 💗 Structures tailored to our problem
177 © VictorRentea.ro
a training by
Don't implement complex logic
on foreign data structures
Elders Wisdom
What's complex?
What's foreign?
178 VictorRentea.ro
a training by
Bounded Context A
(TeamA)
The Curious Case of Nanoservices
DTOs can be shared
within the same Bounded Context (team)
=tiny microservice
eg. 5 devs maintaining
20 microservices
1
2
3
Bounded Context B
(TeamB)
X
But not with others
What's foreign?
179 VictorRentea.ro
a training by
⚠ Returning entities as JSON ⚠
➢ Couples your clients to your internal entity structure
➢ Is risky to marshal
and of course...
180 VictorRentea.ro
a training by
Decouple
DTO
Domain
Model
< >
Price: more classes + more mapping
Exception:
Boundary Systems
= Huge Adapters without own Domain
Software Ecosystem
A
- Manually Crafted DTO
- Generated DTOs:
XML: .xsd/.wsdl ➔ xjc
JSON: .yaml ➔ swagger-gen
Auto-Generated
Mappers
181 VictorRentea.ro
a training by
Auto-Generated Mappers
Converting Entity  DTO with
as long as the field names match,
mapping happens automatically
eg MapStruct
Temptation to keep the models in sync
Entities and DTOs must be allowed to diverge
Customer.firstName  CustomerDto.firstName
War Stories: When mapping gets complex, deep knowledge of MapStruct is required
➔ Consider switching to manual mapping (simpler) ?
182 © VictorRentea.ro
a training by
Don't implement complex logic
on foreign data structures
Elders Wisdom
183 VictorRentea.ro
a training by
Chapter 2. Logic
184 VictorRentea.ro
a training by
you
185 VictorRentea.ro
a training by
The Code - anonymous developer
186 VictorRentea.ro
a training by
Layers
SUB-DOMAINS
Controller
Service
Repository
APIs
order Product user
customer
API
infrastructure
too complex ➔
187 VictorRentea.ro
a training by
Layers
Controller
Repository
APIs
Facade / Application Service
Layered Architecture
DOMAIN Service
188 VictorRentea.ro
a training by
Controller
Repository
call
direction
pull orchestration up,
let Repos trivial
Relaxed Layered Architecture
allows skipping layers
Layered Architecture
DOMAIN Service
Facade / Application Service
190 VictorRentea.ro
a training by
by pushing details in lower-level classes
Muscle
Fascicle
Fiber
Myofibril
Myofilaments
Goal = Simplify the top-level view of your flow
Facade = Separation by Layers of Abstraction
191
Code is NOT a Construction
VictorRentea.ro
192
193 VictorRentea.ro
a training by
requirements
Logic
Service
Facade
HOW?
Entities
OOP
1) One class/use-case
GetOrderByIdService - ⚠ tiny class
PlaceOrderService - ⚠ god class
-or-
2) N use-cases in a class
class OrderFacade { ⚠ god class
placeOrder()
getOrderById()
}
5-10%..more?💪
Continuously Extract
ApplicationService DomainService
simplify the most complex flows
194 VictorRentea.ro
a training by
Mapper
DTO
Facade
Facade Domain
Service
Domain
Service Domain Services
Ideas inspired by the book Java EE Patterns - Rethinking Best Practices, by Adam Bien
Push Domain Logic into
Start implementing every use-case in a
Facade
For trivial User Cases
a method is enough
eg. getOrderById
When logic gets complex,
or has to be reused
(evolutionary architecture)
195 VictorRentea.ro
a training by
Mapper
DTO
Facade Domain
Service
Domain
Service
take and return only
Domain Objects or primitives
Don't Depend on DTOs
Domain Boundary
DTOs are Evil
VO
Entity
id
Convert them to your Domain Objects ASAP
Domain Services
196 VictorRentea.ro
a training by
Cohesive Domain Services
OrderService
PlaceOrderService
⚠Bloat Risk, if Order is a large Entity
@VictorRentea
197
Facade Roles - Summary
• Converts DTOs  Entities
• inline, via [Auto-]Mappers, or Dto constructors/methods.
• Validates inputs
• @javax.validation.NotNull, if ...
• Transaction / use-case
• Except in high-TPS systems
• Orchestrates the workflow of a 🧠 use-case
• By delegating to lower-level components
@VictorRentea
198
Dependency Inversion
199 VictorRentea.ro
a training by
Domain
Service
Domain
Service
External
Service
domain
DTO
call
may get in
200 VictorRentea.ro
a training by
External
Service
DTO
Adapter
Domain
Service
Domain
Service
domain
201 VictorRentea.ro
a training by
External
Service
DTO
Adapter
Domain
Service
Domain
Service
<dependency>
domain infrastructure
VictorRentea.ro
202
External
Service
DTO
IAdapter Adapter
implements
class UserApiClient
implements IUserAdapter {
public User getById(id){
<external call>
}
}
interface IUserAdapter {
User getById(id);
}
class OrderService {
@Autowired
IUserAdapter adapter;
...
adapter.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
<dependency>
domain infrastructure
203 VictorRentea.ro
a training by
calls
Dependency Inversion Principle
<dependency>
higher-level
module
lower-level
module
"Best of OOP"
- Uncle Bob
Abstractions should not depend on details
Low level classes
are not visible
(SOLID Principles)
Dependency Inversion
204 VictorRentea.ro
a training by
calls
<dependency>
higher-level
module
lower-level
module RMI,
HTTP
gRPC..
FTP
Queue
DB
DTO
Dependency Inversion
206 VictorRentea.ro
a training by
Stop Code Dependencies
from complex logic ➔ externals
Dependency Inversion
Package Dependency Checks - via static code analysis
- by compiler
@Test
public void dependencyInversionTest() {
ArchRuleDefinition
.noClasses().that().resideInAPackage("..domain")
.should().dependOnClassesThat().resideInAPackage("..infra")
.check(new ClassFileImporter().importPackages("my.corp.app"));
}
testImplementation com.tngtech.archunit:archunit-junit4:0.15.0 or NDepend (C#)
https://nx.dev/latest/angular/structure/monorepo-tags
https://github.com/MaibornWolff/ts-arch
207 VictorRentea.ro
a training by
An Agnostic Domain
lets you focus on
YOUR problem
Agnostic Domain
209 VictorRentea.ro
a training by
infrastructure
EXTERNAL
API
Value Object
Entity
id
Domain
Service
IAdapter
Onion Architecture
Behold, the famous
Database
domain
Repo
Dep Inv
Dep Inv
DTO
Agnostic Domain
application
DTO
Your
Client
Validation
Separate
Persistence
Model
if DB == enemy
Façade
Mapper
Controller
Msg Handler
Adapter
Spring Data
IRepo
210 VictorRentea.ro
a training by
DTO
Value Object
Entity
id
Domain
Service
application Database
domain
DTO
Onion Architecture
Pragmatic
Agnostic Domain
EXTERNAL
API
Your
Client
Façade
Mapper
Controller
Adapter
IAdapter
IRepo
Dep Inv
"Light-CQRS"
Selecting DTOs directly from queries
211 VictorRentea.ro
a training by
Independent of Intrusive Frameworks
Testable Standalone
without a DB, UI, Web Server, etc...
https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
Independent of UI
mobile, web, or desktop
Independent of DB
avoid PL/SQL, no vendor lock-in
Independent of External APIs
= external Bounded Contexts
Is an ORM intrusive?
Keep core logic ...
Agnostic Domain
aka Hexagonal
aka Ports-and-Adapters
aka Clean Architecture
Onion Architecture
Learn Hibernate: https://www.youtube.com/watch?v=iw0tOx7Zbjc
Façade
DTO
Mapper
Value Object
Entity
id
Domain
Service
Domain
Service
IRepo
application
IAdapter
Adapter
External
API
DTO
domain
Controller
DIP
DIP
UI
3rd party
213 VictorRentea.ro
a training by
Anemic Domain Model
("classic" approach)
Rich Domain Model
(Domain-Driven Design)
vs
Getters & Setters for all fields
All logic written in Services
Getters but less setters
Logic using fields of class X stays in X
Self-validating model
eg. Address constructor validates its consistency
Aggregates as consistency boundaries
Invariants enforced by Services
eg. Shipment requires a postal code, unless city=Bucharest
214 VictorRentea.ro
a training by
Chapter 3. Value Objects
215 VictorRentea.ro
a training by
How many fields it has?
Can you make it immutable?
Tell me about that big entity ...
How do you feel about moving logic inside?
216 VictorRentea.ro
a training by
How many fields it has?
Can you make it immutable?
How do you feel about moving logic inside?
Yes!
(use @Embeddable for JPA)
But, How to identify Value Objects?
Extract Value Objects from Entities:
217 VictorRentea.ro
a training by
Conceptual Whole
Money {amount, currency}
FullName {first, last}
Changes Together
LastModified-Time/-ByUser
How to identify Value Objects?
Screens
InvoicingDetails
Moves Together
PriceComputationInput
218 VictorRentea.ro
a training by
Key Points
DTOs are evil
Build a Deep, Rich Domain Model
Protect your Domain with DIP or ArchUnit
Don't let persistence concerns influence your Model design
Continuously Refactor to keep code suple
The entire team should understand the Design Goals
Be Pragmatic. Think Critically! dogmas
@victorrentea
VictorRentea.ro
victorrentea@gmail.com
== What I teach ==
Thank You !

Clean pragmatic architecture @ devflix

  • 1.
  • 2.
    Hi, I'm VictorRentea Java Champion – drinking since 2006 Trainer – 3000+ devs / 80+ companies, since 2013 Speaker – Conferences & Meetups Hibernate Spring Java8/FP Java Performance Secure Coding Reactive Architecture Clean Code Unit Testing
  • 3.
    $ Hibernate Spring Java8/FP Architecture CleanCode Unit Testing Masterclass Company Training Video Courses YouTube Channel 💗 Join My Community Blog @victorrentea VictorRentea.ro victorrentea@gmail.com Java Performance Secure Coding Reactive
  • 4.
    172 VictorRentea.ro a trainingby Chapter 1. Data Structures
  • 5.
    173 VictorRentea.ro a trainingby Can I have a chicken?
  • 6.
    The data structurethey send you The data structure you want to use in your core logic DTO domain Object
  • 7.
    175 VictorRentea.ro a trainingby DTOs* are Evil *Data Transfer Objects – data structures that move across APIs
  • 8.
    176 VictorRentea.ro a trainingby ☢ Beware of Foreign Data Structures ☢ ➢ Bloated (more fields than you need) ➢ Flat ➢ Different perspective 🐔 (bounded context) ➢ Fixed design (often generated or in client-lib) ➢ Mutable (pain from frameworks otherwise) ➢ No constraints (nulls, validation, invariants) ➢ Diverging in time (v2) We 💗 small, cohesive data structures We 💗 Logic next to data (OOP) We 💗 Immutable objects We 💗 Deep, Rich Domain Model We 💗 Models to guard their invariants We want control over our structures Because DTOs are: In our core logic: We 💗 Structures tailored to our problem
  • 9.
    177 © VictorRentea.ro atraining by Don't implement complex logic on foreign data structures Elders Wisdom What's complex? What's foreign?
  • 10.
    178 VictorRentea.ro a trainingby Bounded Context A (TeamA) The Curious Case of Nanoservices DTOs can be shared within the same Bounded Context (team) =tiny microservice eg. 5 devs maintaining 20 microservices 1 2 3 Bounded Context B (TeamB) X But not with others What's foreign?
  • 11.
    179 VictorRentea.ro a trainingby ⚠ Returning entities as JSON ⚠ ➢ Couples your clients to your internal entity structure ➢ Is risky to marshal and of course...
  • 12.
    180 VictorRentea.ro a trainingby Decouple DTO Domain Model < > Price: more classes + more mapping Exception: Boundary Systems = Huge Adapters without own Domain Software Ecosystem A - Manually Crafted DTO - Generated DTOs: XML: .xsd/.wsdl ➔ xjc JSON: .yaml ➔ swagger-gen Auto-Generated Mappers
  • 13.
    181 VictorRentea.ro a trainingby Auto-Generated Mappers Converting Entity  DTO with as long as the field names match, mapping happens automatically eg MapStruct Temptation to keep the models in sync Entities and DTOs must be allowed to diverge Customer.firstName  CustomerDto.firstName War Stories: When mapping gets complex, deep knowledge of MapStruct is required ➔ Consider switching to manual mapping (simpler) ?
  • 14.
    182 © VictorRentea.ro atraining by Don't implement complex logic on foreign data structures Elders Wisdom
  • 15.
    183 VictorRentea.ro a trainingby Chapter 2. Logic
  • 16.
  • 17.
    185 VictorRentea.ro a trainingby The Code - anonymous developer
  • 18.
    186 VictorRentea.ro a trainingby Layers SUB-DOMAINS Controller Service Repository APIs order Product user customer API infrastructure too complex ➔
  • 19.
    187 VictorRentea.ro a trainingby Layers Controller Repository APIs Facade / Application Service Layered Architecture DOMAIN Service
  • 20.
    188 VictorRentea.ro a trainingby Controller Repository call direction pull orchestration up, let Repos trivial Relaxed Layered Architecture allows skipping layers Layered Architecture DOMAIN Service Facade / Application Service
  • 21.
    190 VictorRentea.ro a trainingby by pushing details in lower-level classes Muscle Fascicle Fiber Myofibril Myofilaments Goal = Simplify the top-level view of your flow Facade = Separation by Layers of Abstraction
  • 22.
    191 Code is NOTa Construction
  • 23.
  • 24.
    193 VictorRentea.ro a trainingby requirements Logic Service Facade HOW? Entities OOP 1) One class/use-case GetOrderByIdService - ⚠ tiny class PlaceOrderService - ⚠ god class -or- 2) N use-cases in a class class OrderFacade { ⚠ god class placeOrder() getOrderById() } 5-10%..more?💪 Continuously Extract ApplicationService DomainService simplify the most complex flows
  • 25.
    194 VictorRentea.ro a trainingby Mapper DTO Facade Facade Domain Service Domain Service Domain Services Ideas inspired by the book Java EE Patterns - Rethinking Best Practices, by Adam Bien Push Domain Logic into Start implementing every use-case in a Facade For trivial User Cases a method is enough eg. getOrderById When logic gets complex, or has to be reused (evolutionary architecture)
  • 26.
    195 VictorRentea.ro a trainingby Mapper DTO Facade Domain Service Domain Service take and return only Domain Objects or primitives Don't Depend on DTOs Domain Boundary DTOs are Evil VO Entity id Convert them to your Domain Objects ASAP Domain Services
  • 27.
    196 VictorRentea.ro a trainingby Cohesive Domain Services OrderService PlaceOrderService ⚠Bloat Risk, if Order is a large Entity
  • 28.
    @VictorRentea 197 Facade Roles -Summary • Converts DTOs  Entities • inline, via [Auto-]Mappers, or Dto constructors/methods. • Validates inputs • @javax.validation.NotNull, if ... • Transaction / use-case • Except in high-TPS systems • Orchestrates the workflow of a 🧠 use-case • By delegating to lower-level components
  • 29.
  • 30.
    199 VictorRentea.ro a trainingby Domain Service Domain Service External Service domain DTO call may get in
  • 31.
    200 VictorRentea.ro a trainingby External Service DTO Adapter Domain Service Domain Service domain
  • 32.
    201 VictorRentea.ro a trainingby External Service DTO Adapter Domain Service Domain Service <dependency> domain infrastructure
  • 33.
    VictorRentea.ro 202 External Service DTO IAdapter Adapter implements class UserApiClient implementsIUserAdapter { public User getById(id){ <external call> } } interface IUserAdapter { User getById(id); } class OrderService { @Autowired IUserAdapter adapter; ... adapter.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 <dependency> domain infrastructure
  • 34.
    203 VictorRentea.ro a trainingby calls Dependency Inversion Principle <dependency> higher-level module lower-level module "Best of OOP" - Uncle Bob Abstractions should not depend on details Low level classes are not visible (SOLID Principles) Dependency Inversion
  • 35.
    204 VictorRentea.ro a trainingby calls <dependency> higher-level module lower-level module RMI, HTTP gRPC.. FTP Queue DB DTO Dependency Inversion
  • 36.
    206 VictorRentea.ro a trainingby Stop Code Dependencies from complex logic ➔ externals Dependency Inversion Package Dependency Checks - via static code analysis - by compiler @Test public void dependencyInversionTest() { ArchRuleDefinition .noClasses().that().resideInAPackage("..domain") .should().dependOnClassesThat().resideInAPackage("..infra") .check(new ClassFileImporter().importPackages("my.corp.app")); } testImplementation com.tngtech.archunit:archunit-junit4:0.15.0 or NDepend (C#) https://nx.dev/latest/angular/structure/monorepo-tags https://github.com/MaibornWolff/ts-arch
  • 37.
    207 VictorRentea.ro a trainingby An Agnostic Domain lets you focus on YOUR problem Agnostic Domain
  • 38.
    209 VictorRentea.ro a trainingby infrastructure EXTERNAL API Value Object Entity id Domain Service IAdapter Onion Architecture Behold, the famous Database domain Repo Dep Inv Dep Inv DTO Agnostic Domain application DTO Your Client Validation Separate Persistence Model if DB == enemy Façade Mapper Controller Msg Handler Adapter Spring Data IRepo
  • 39.
    210 VictorRentea.ro a trainingby DTO Value Object Entity id Domain Service application Database domain DTO Onion Architecture Pragmatic Agnostic Domain EXTERNAL API Your Client Façade Mapper Controller Adapter IAdapter IRepo Dep Inv "Light-CQRS" Selecting DTOs directly from queries
  • 40.
    211 VictorRentea.ro a trainingby Independent of Intrusive Frameworks Testable Standalone without a DB, UI, Web Server, etc... https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html Independent of UI mobile, web, or desktop Independent of DB avoid PL/SQL, no vendor lock-in Independent of External APIs = external Bounded Contexts Is an ORM intrusive? Keep core logic ... Agnostic Domain aka Hexagonal aka Ports-and-Adapters aka Clean Architecture Onion Architecture Learn Hibernate: https://www.youtube.com/watch?v=iw0tOx7Zbjc
  • 41.
  • 42.
    213 VictorRentea.ro a trainingby Anemic Domain Model ("classic" approach) Rich Domain Model (Domain-Driven Design) vs Getters & Setters for all fields All logic written in Services Getters but less setters Logic using fields of class X stays in X Self-validating model eg. Address constructor validates its consistency Aggregates as consistency boundaries Invariants enforced by Services eg. Shipment requires a postal code, unless city=Bucharest
  • 43.
    214 VictorRentea.ro a trainingby Chapter 3. Value Objects
  • 44.
    215 VictorRentea.ro a trainingby How many fields it has? Can you make it immutable? Tell me about that big entity ... How do you feel about moving logic inside?
  • 45.
    216 VictorRentea.ro a trainingby How many fields it has? Can you make it immutable? How do you feel about moving logic inside? Yes! (use @Embeddable for JPA) But, How to identify Value Objects? Extract Value Objects from Entities:
  • 46.
    217 VictorRentea.ro a trainingby Conceptual Whole Money {amount, currency} FullName {first, last} Changes Together LastModified-Time/-ByUser How to identify Value Objects? Screens InvoicingDetails Moves Together PriceComputationInput
  • 47.
    218 VictorRentea.ro a trainingby Key Points DTOs are evil Build a Deep, Rich Domain Model Protect your Domain with DIP or ArchUnit Don't let persistence concerns influence your Model design Continuously Refactor to keep code suple The entire team should understand the Design Goals Be Pragmatic. Think Critically! dogmas
  • 48.