Professional Documents
Culture Documents
Evolving
A Clean, Pragmatic Architecture
A Craftsman's Guide
The Art of Clean Code
= The Next Chapter =
victor.rentea@gmail.com ♦ ♦ @victorrentea ♦ VictorRentea.ro
When something is painful
but you can't avoid doing it…
postpone it
When something is painful
but you can't avoid doing it…
delegate it
When something is painful
but you can't avoid doing it…
Do It More Often!
"Bring The Pain Forward!"
Continuous Integration
Pair Programming
Continuous Refactoring
Test-First
e Xtreme
"Bring The Pain Forward!"
Are you Agile ?
Software Craftsmanship
Technical Practices Professionalism
Lead Architect
Internal Coach
14 VictorRentea.ro
Single Responsibility Principle
EmployeeManager
-read/persist
-compute pay-roll vs
-generate PDF report
-manage projects
15 VictorRentea.ro
Coupling
vs
16 VictorRentea.ro
Don’t Repeat Yourself
17 VictorRentea.ro
Keep It Short & Simple
Premature encapsulation is the root of all evil
Overengineering
– Adam Bien
Simpler code Developer Happiness
18 VictorRentea.ro
Protect the Developers
Developer
Invisible Magic to reduce effort and risk Comfort
...
Developer
Fear Kills Creativity Simplify Unit Testing
Safety
- Strong regression defense
21 VictorRentea.ro
Building Software
28 VictorRentea.ro
This talk is about…
A Simple Architecture
that Evolves
to Match
the Growing Complexity
30 VictorRentea.ro
Agenda
Core Principles
Modeling Data
Organizing Logic
Tests. Fear.
31 VictorRentea.ro
VictorRentea.ro
Entities = your persistent data
You control them!
Entity
BlOAt dAnGeR
}
“canBeDeleted”: true
37 VictorRentea.ro
Agenda
Core Principles
Modeling Data
Organizing Logic
Tests. Fear.
38 VictorRentea.ro
39 VictorRentea.ro
"canBeDeleted":true
DTO ~ JSON
Controller
Validation Mapping
Transactions
Facade
≈ Application Service [DDD]
calls
Service Entity
Repository Infrastructure
? DTO
VictorRentea.ro
41 VictorRentea.ro
Data Conversion
Complex? ➔ Extract Mappers
API Domain
Mapper
DTO
id
Entity VO
➔ DTO constructors
Logic CustomerDto();
CustomerDto dto = new CustomerDto(customer);
dto.fullName = customer.getFullName();
dto.birthDate = customer.getBirthDate();
dto.phoneNumber = customer.getPhoneNumber();
42 VictorRentea.ro
Validation
43 VictorRentea.ro
Validation
44 VictorRentea.ro
Validation
only fields always true
Facade
HOW?
Logic
OOP
Service
VO
Entities
https://www.amazon.com/Domain-Driven-Design-
Tackling-Complexity-Software/dp/0321125215
VictorRentea.ro
Evolutionary Start writing all domain logic in a
Approach: Facade
Then extract logic into
Mapper id
Entity VO
Domain Services
57 Read more about this approach in Java EE Patterns - Rethinking Best Practices, by Adam Bien VictorRentea.ro
Domain Services
speak your Domain Model
parameters and return types
id
Mapper Entity VO
DTOs are fragile
under enemy control
* I like them dumb (no logic) Facade Domain
DTO Service
58 VictorRentea.ro
Aspects
- Transactions
Convert Data Facade Roles
- Logging Mapper
- Exception Handling*
- Access Control*
id
Entity VO
Controller Façade
DTO Domain
Service
Fç
Validator
Validate Data Implement Logic
VictorRentea.ro
What’s that? How? Huh!? Then I extract? Piece a cake!
That’s it?
He-he!☺
When a class “There are only two things
grows too big Look for a good class
hard in programming:
(>~200 lines?) name that summarizes
Yup! Cache Invalidation and
➔ break it some of its methods
Naming Things”
VictorRentea.ro
SRP
applied to reduce complexity
CustomerOpsFacade
CustomerFacade CustomerPreferencesFacade
saveCustomer() saveCustomerPreferences()
getCustomer() getCustomerPreferences()
searchCustomer() validateAddress()
resetPassword()
saveCustomerPreferences() checkPassworStrength()
getCustomerPreferences()
validateAddress()
resetPassword()
checkPassworStrength() at the same level of abstraction
> 300 lines
VictorRentea.ro
Extract when it Grows
Vertical Extraction
OrderService DeliveryService
Pair Programming
VictorRentea.ro
VictorRentea.ro
69
http://wiki.c2.com/?PairProgramming
Developer Comfort
is essential for
Emerging Architectures
VictorRentea.ro
n
Jr. Architect
(prev: Jr JS Developer)
Modeling Data
Organizing Logic
Tests. Fear.
72 VictorRentea.ro
VictorRentea.ro
The code you want to protect
Domain Objects
id
Entity VO
Domain
Service
DTO id
Entity VO
application
Domain
Façade
Service
Validator domain
depends on domain
74 VictorRentea.ro
domain
Domain External
Service Service
DTO
75 VictorRentea.ro
domain <dependency> infrastructure
Domain External
Adapter
Service Service
DTO
VictorRentea.ro
<dependency>
domain infrastructure
When you need express your need in and implement it in a so nothing foreign
to call outside… a domain interface… lower-level module… enters your domain.
Domain External
IAdapter Adapter
Service implements Service
DTO
<dependency>
higher-level lower-level
module calls module
"Best of OOP"
- Uncle Bob
78 VictorRentea.ro
lower-level
module
<dependency>
higher-level JMS
module calls
FTP
DB
80 VictorRentea.ro
An agnostic Domain
lets you focus on
YOUR logic
VictorRentea.ro
What code would you protect?
Domain Objects
Interfaces for
id
Entity VO External Services
IExtSrv you consume
Domain Adapter
Service
Priceless Domain Logic IRepo
Interfaces for
Repositories
DTO id
Entity VO
IExtSrv
application
infra
Domain Adapter ExtSrv
Façade Adapter
Service
IRepo
F
Repo
Validator implem
85 VictorRentea.ro
Mapper
WS DTO
DTO id
Entity VO Interface
IExtSrv
application
infra
Domain Adapter
Façade Adapter
Service
IRepo
F
Repo
Validator implem
96 VictorRentea.ro
Pragmatic
for decent apps, 2 modules are enough
Mapper
WS DTO
DTO id
Entity VO Interface
IExtSrv
Domain Adapter
Façade Adapter
Service
IRepo
F
domain
Repo
Validator implem
97 application VictorRentea.ro
Naming …
98 VictorRentea.ro
Package Names
com.myorg.myapp .facade
.order. …
.service .product. …
.order. …
They grew too big! .entity .product. …
.infra
Let’s restructure it.
Clean Architecture
99
.repo that speaks in domain words
- Uncle Bob
VictorRentea.ro
com.myorg.myapp. Modularizing the Monolith
.order. … Majestic Monolith*
MICRO…
Facade
SELECT
DEPENDS
FK?
EVENT
CALLS
TX Replication
DTO
Infra
ArchRule rule =
classes().that().resideInAPackage("..service..")
.should().onlyBeAccessed()
.byAnyPackage("..controller..", "..service..");
102 VictorRentea.ro
104 VictorRentea.ro
tardigrade
105 VictorRentea.ro
Evolution
Only Happens
Under Constraints
fitness function
106 VictorRentea.ro
fitness function
source file size
coupling
performance
scalability
security
107 VictorRentea.ro
Further Reading
122 VictorRentea.ro
Agenda
Core Principles
Modeling Data
Organizing Logic
The Onion Architecture
Tests. Fear.
123 VictorRentea.ro
VictorRentea.ro
Takeaways
Agenda
Core Principles
Modeling Data
Organizing Logic
The Onion Architecture
Tests. Fear.
124 VictorRentea.ro
VictorRentea.ro
Takeaways
KISS : Avoid overengineering
Magic to protect your Developers
Modeling Data
Organizing Logic
The Onion Architecture
Tests. Fear.
125 VictorRentea.ro
VictorRentea.ro
Takeaways
KISS : Avoid overengineering
Magic to protect your Developers
Enemy data in your DTOs: keep them out
Organizing Logic
The Onion Architecture
Tests. Fear.
126 VictorRentea.ro
VictorRentea.ro
Takeaways
KISS : Avoid overengineering
Magic to protect your Developers
Enemy data in your DTOs: keep them out
Extract when it Grows : for SRP or DRY
131 VictorRentea.ro
What's next for you?
VictorRentea.ro
Put Passion In
All That You Do!!
137 VictorRentea.ro
¡¡ PLEASE !!
Hunt me down for questions!
138 VictorRentea.ro
A SCALABILITY PROBLEM:
OUT OF STICKERS
¡¡ PLEASE !! AND KEY CHEAT-SHEETS
Speaking Romanian? join me Trainings, talks, goodies Follow me for quality posts:
victorrentea.ro/community VictorRentea.ro @VictorRentea