Are you in a mood for a brainstorm? Join this critical review of the major decisions taken in a typical enterprise application architecture and learn to balance pragmatism with your design goals. Find out how to do just-in-time design to keep as much use-cases as simple as possible. The core purpose of this presentation is to learn to strike a **balance between pragmatism and maintainability** in your design. Without continuous refactoring, a simple design will inevitably degenerate into a Big Ball of Mud, under the assault of the new features and bugfixes. On the other hand, very highly-factored code can burden the take-off of the development and end up freezing the mindset in some rigid 'a-priori' design. The end goal of this talk is to challenge you to rethink critically the architecture of your own systems, and seek ways to simplify it to match your actual needs, with a pragmatic mindset. "Architecture is the art of postponing decisions", said Uncle Bob. This talk takes this idea further and explains an optimal mindset about designing enterprise applications: Evolving (Continuously Refactoring) a Pragmatic (Simple), Clean (aka Onion) Architecture, aiming to provide Developer Safety™️ and Comfort™️. It’s the philosophy that Victor distilled over the past 5 years, designing and implementing 9 applications as IBM Lead Architect, and delivering trainings and advises to many other companies. You’ll learn how to break data into pieces (Fit Entities, Value Objects, Data Transfer Objects), how to keep the logic simple (Facades, Domain Services, logic extraction patterns, Mappers, AOP), layering to enforce boundaries (keeping DTOs out of your logic, Dependency Inversion Principle), and many more, all in a dynamic, interactive and extremely entertaining session.
17. 32
Keep It Short & Simple
Premature encapsulation is the root of all evilOverengineering
– Adam Bien
18. 33
Keep It Short & Simple
Premature encapsulation is the root of all evilOverengineering
Simpler code Developer Happiness
19. 34
Invisible Magic to reduce effort and risk
Protect the Developers
...
Avoid building an intrusive
Custom Framework
(bugs to learn)
Developer
Comfort
29. 46
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
}
30. 47
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<Address> 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
31. Entityid
48
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();
32. 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
49
isDeletable: true
(to show the Delete button)
33. I like dumb DTOs
(you'll see soon why)
public fields ?! ! !..
VOEntityid
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;
}
}
50
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();
36. 63
Start implementing all domain logic in a
Facade
Mapper VOEntityid
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]
37. 65
Keep DTOs out!
(parameters and return types)
Mapper VOEntityid
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)
38. Fç
Validate Data
Façade
Convert Data
Implement Logic
Aspects
- Transactions
- Logging
- Exception Handling*
- Access Control*
66
Facade Roles
DTO
Validator
Mapper
Domain
Service
VOEntityid
39. 67
What do you mean ?
When a class
gets too big
(>~200 lines?)
➔ break it
Extract when it Grows
How?
Find a good class name
to summarize some of
its methods
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”
43. 72
Duplication
Pair Programming
Imposed
validate in JS/TS and in Java
Rush/Lazy
Inadvertent
you forget and implement it again
Inter-developer
you didn't knew that was already implemented (Δt=5-10s)
bus factor =2
53. 83
External
Service
DTO
IAdapter Adapterimplements
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
<dependency>
domain infrastructure
72. Maintainable Tests
Pure Functions
No side effects. No dependencies.
Mock-based
In-memory Emulation
or JPQL tests on H2/* db
Fragile data fixtures
On Real Systems
Eg: Connecting to a real DB
119
𝑓 𝑥, 𝑦 = 𝑥2 + 𝑦2
74. ▪ 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
127
78. 131 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
79. 132 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
80. 133 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)
81. 134 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)