aaaaThis presentation focuses on two of the most advanced design tools in your toolbox, whatever the language or framework you might be using. After understanding the basics, we'll see how these concepts can be used in real-world scenarios to simplify those several most complex use-cases in your application. At the end of a mix of slides and live-coding, you'll finally understand the power of these ideas and become prepared to apply them in your day-to-day work.
Along the way, we'll introduce concepts like Side Effects, Idempotency, Referential Transparency, Pure Functions and Deep/Shallow Immutability. Also, we'll talk about the powerful Functional Code / Imperative Shell architecture that you can use for your complex workflows.
Prepare for an entertaining, highly interactive session that will answer all your questions.
Written in Java and spoken in English.
2. Victor Rentea
Best Talks, Goodies, Blog:
VictorRentea.ro
Independent Trainer & Consultant
Founder of
Bucharest Software Craftsmanship Community
Java Champion
โค๏ธ Simple Design, Refactoring, Unit Testing โค๏ธ
3. Technical Training
Hibernate
Spring Func Prog in Java
300+ days
2000 devs
8 years
Training for you or your company: VictorRentea.ro
40 companies
Follow me:
35K 4K 3K
Java Performance
Reactive-X
Design Patterns
Clean Code
Refactoring
Unit Testing
TDD
any
lang
5. 175 ยฉ VictorRentea.ro
a training by
checkCustomer(customer);
checkOrder(customer, order);
Mock-full tests
Race Bugs
A method changes a parameter: Surprise!
Unexpected Different Results for Same Inputs
customer.setActive(true);
Temporal Coupling
6. 176 ยฉ VictorRentea.ro
a training by
do side-effects
return void sendEmail(Email):void
Command-Query Separation
setActive(true):void
return results
search(criteria):List
computePrice(flight):int
in 1994, by Bertrand Meyer
Pure Functions
7. 177 ยฉ VictorRentea.ro
a training by
No side effects
No INSERTs, POSTs, queues, files, fields,โฆ
= ๐๐๐กโ๐๐๐๐ก๐๐๐๐ ๐น๐ข๐๐๐ก๐๐๐๐ : ๐ ๐ฅ, ๐ฆ = ๐ฅ2
+ ๐ฆ
(logging doesn't count)
Referential Transparent
Same Inputs โ Same Output
No current time, random, GET, SELECTโฆ
โ Idempotent
Pure Functions
8. 178 ยฉ VictorRentea.ro
a training by
Referential Transparent Idempotent
โ
f(1,2) = 3
f(1,2) can be replaced with 3 everywhere
After calling f once
Calling it again n times
will not produce any extra changes
Can Have Side Effects
eg: DELETE FROM X WHERE ID =
f(1,2)
f(1,2)
f(1,2)
9. 179 ยฉ VictorRentea.ro
a training by
Pure Functions : Quiz
f1(int x) {return x + 1;}
f2(Data d) {return ++d.x;}
f3() {d.incrementX(); return d.x;}
f4() {return querySQL(...);}
f5(int y) { return this.x + y; }
f6(Data d, int y) { return d.getX() + y; }
f7(int i) { if (i<0) throw new WrongInputException(); }
is this immutable?
Probable side effects
Expected to be pure
10. 180 ยฉ VictorRentea.ro
a training by
throw new E(); is pure
f(x) {
try {
//
}
}
catch (E) is pure?
if it always throws for the same inputs
it depends ...
* Some slightly disagree
on E
NO, if E can happen randomly
eg. IOException, OutOfMemory
YES, if E is thrown deterministically*
โ Catch unexpected exceptions
in the outskirts of your code
11. 181 ยฉ VictorRentea.ro
a training by
Why we Love Pure Functions
โขNo hidden inputs, only plain-sight return values and parameters
โขEasier to understand
โขNo temporal coupling
โขTestable with less setup
โขFast & Composable: free to call them n times โ
โขParallelizable
(careful with instance functions on mutable objects)
r=f();
a=g(r);
12. 182 ยฉ VictorRentea.ro
a training by
Replace Temp Variable with Query
If a function is pure + fast, it's safe to call it multiple times:
Replace Parameter with Query
var data = f(a,b);
data
data
f(a,b)
f(a,b)
big(..., f(a,b));
param
param
void big(..., param) {
f(a,b)
f(a,b)
they typically are
13. 183 ยฉ VictorRentea.ro
a training by
you don't care how many times
(and if) you call a pure function
15. 185 ยฉ VictorRentea.ro
a training by
That's it!
I'll make all my functions pure
that's usually impossible
What kind of app doesn't change anything?
16. 186 ยฉ VictorRentea.ro
a training by
In Java there's no way to strictly enforce purity
โ We have to live with both pure and impure functions
How do we distinguish them?
17. 187 ยฉ VictorRentea.ro
a training by
do side-effects
return void sendEmail(Email):void
Command-Query Separation
setActive(true):void
return results
pure functions
search():List
computePrice(movie):int
Highlight Side Effects
computePriceAndAdjustMetrics(movie):int
20. 190 ยฉ VictorRentea.ro
a training by
functional core
Side-effects (Writes) +
Non-deterministic Reads
Expose them
Purify the most complex parts of your logic!
22. 193 ยฉ VictorRentea.ro
a training by
Purifying Logic
Time and Random
Amount of time-dependent logic:
โขNone (e.setCreationDate(now());) โ tolerate
โขVery little โ Inject a Clock / TimeProvider
โขHeavy (x-rare) โ expose a ..., time); parameter
29. 201 ยฉ VictorRentea.ro
a training by
void f(Data data) {
...
if (data.getX() == 1) {
// will this run ?
}
}
void h() {
Data data = new Data(1);
obj.setData(data);
g(data);
}
obj
void g(Data data) {
data.setX(2);
mutateParam(data);
obj.mutateField();
f(data);
}
void setData(Data data) {
this.data = data;
}
void mutateField() {
this.data.setX(2);
}
same obj
in h() and g()
void mutateParam(Data data) {
data.setX(1);
}
x=
Long-lived mutable data
A Code Inspection Session
What code ran before,
having a reference
to my data instance?!
Mutable Data
...
...
30. 202 ยฉ VictorRentea.ro
a training by
void f(Data data) {
...
if (data.getX() == 1) {
// will this run ?
}
}
void h() {
Data data = new Data(1);
obj.setData(data);
g(data);
}
obj
void g(Data data) {
data.setX(2);
mutateParam(data);
obj.mutateField();
f(data);
}
void setData(Data data) {
this.data = data;
}
void mutateField() {
this.data.setX(2);
}
same obj
in h() and g()
void mutateParam(Data data) {
data.setX(1);
}
x=
Long-lived mutable data
A Code Inspection Session
What code ran before,
having a reference
to my data instance?!
Mutable Data
Immutable Data
...
...
31. 203 ยฉ VictorRentea.ro
a training by
void f(Data data) {
...
if (data.getX() == 1) {
// will this run ?
}
}
void g(Data data) {
f(data);
}
void h() {
Data data = new Data(1);
g(data);
}
A Code Inspection Session
Immutable Data
Who created
the instance?!
Easier to trace
data changes
x=
32. 204 ยฉ VictorRentea.ro
a training by
Designing Immutable Classes
public class A {
private final String s;
private final B b;
private final List<String> list;
public A(String s, B b, List<String> list) {
this.s = s;
this.b = b;
this.list = new ArrayList<>(list);
// validation ...
}
public List<String> getList() {
return unmodifiableList(list);
}
// getters
// hashCode, equals on all fields = Value Object
// bits of LOGIC ๐ช
public A withS(String newS) {
return new A(newS, b, list);
}
}
Mutates by creating a new instance
Stops creator keeping a reference
Overkill, as problem is not the creator but the "man-in-the-middle"
Oh, so
we CAN mutate them!
@lombok.With
Iterable<String> getList() {
List<? extends String> getList() {
or
final fields,
but not strictly required
record
(java 15)
Java collections are mutable๐
final
Afraid of hackers? ๐จ
@lombok.Value
or, until then...
34. 206 ยฉ VictorRentea.ro
a training by
A function changing an immutable object has to return it:
data = updx(data);
Imagine data
has 20 fields
... every time
data = updy(data);
data = updz(data);
The mess is still here!
๐ต Who changed the field X?
How to fix?
35. 207 ยฉ VictorRentea.ro
a training by
data = updx(data);
data = updy(data);
data = updz(data);
final variables won't allow this
IntelliJ underlines
reassigned variables โค๏ธ
By the way, there are ways to add final automatically at code cleanup
Real Problem
Too Large Immutable Objects
data.xyz = createXYZ(...);
โ break them
If they change together,
they stick together
= clutter; Extreme:
Mark only the non-final with @Var
(errorprone Java compiler from Google)
39. 211 ยฉ VictorRentea.ro
a training by
Why we Immutable objects
Easier to trace data changes
Can enforce validation in constructor
Safe to put in Set or Map(as keys)
Thread-safe โ no race bugs, since they can't be changed
โ their hashCode
doesn't change
40. 212 ยฉ VictorRentea.ro
a training by
All right cowboy!
Only immutable objects from now on!
usually that's too much!
41. 214 ยฉ VictorRentea.ro
a training by
instead,
Extract immutable Value Objects from their fields
Leaving the root Entity mutable
NO*
*there are few cases when it pays to, but those apps typically don't persist their data
Should Entities be immutable?
42. 215 ยฉ VictorRentea.ro
a training by
@Entity
(mutable)
Persistent
Immutable Leaf
eg. FullName
Immutable Objects in Real Life
Non-Persistent
Runtime Objects
that you write heavy logic with
continuously break
Large Entities
@Embeddable
43. 216 ยฉ VictorRentea.ro
a training by
Non-Persistent
Runtime Objects
that you write heavy logic with
Always Immutable
45. 219 ยฉ VictorRentea.ro
a training by
The Big Deal
Don't mutate objects on long workflows!
a(e) b(x) c(x) d(x) e(x) f(x) g(e) {
e.setField(...);
}
a(e) {
String s = b(vo);
e.setField(s);
}
b(โฆ) c(โฆ) d(โฆ) e(โฆ) f(โฆ) g(โฆ) {return ...;}
1) vavr.Tuple3<String,String,Integer>
2) NewConceptVO #kudos if you can find a good name!
can be pure functions
Immutable Arguments
Return the change to the surface, and apply it there
Return multiple changes:
48. 222 ยฉ VictorRentea.ro
a training by
Concerned of Performance?
Measure it !
(and you might have a surprise)
49. 224 ยฉ VictorRentea.ro
a training by
Avoid Immutable Objects If
- Trashing millions of instances/second
- Cloning Lost of Collections
- Trivial logic (overkill)
- Persistent Entities or DTOs
50. 225 ยฉ VictorRentea.ro
a training by
Take-Aways
โข Complex logic โ pure functions using immutable objects
โข Functional Core / Imperative Shell
โข Pull impure remote/DB calls in the shell
โข We'll change it in there โ compute and return
โข Without proper mindset, immutability can hurt
โข Don't mutate: argument state, variables or collections
โข Immutable: runtime data or persistent leaves
โข We'll change it in there โ compute and return
And no, I'm against OOP; but not in huge logic code โ
51. 226 ยฉ VictorRentea.ro
a training by
victorrentea@gmail.com โฆ โฆ Training: VictorRentea.ro
โขWe'll change it in there โ compute and return