Reduce system complexity in Java
with
Data-Oriented programming
Taming objects
April 2021
Yehonathan Sharvit viebel
Reduce system complexity in Java
with
Data-Oriented programming
Taming objects
April 2021
Yehonathan Sharvit viebel
๐ป Developer since 2001 (C++, Java, JavaScript, Ruby, Clojure)
๐ Author of Data-Oriented programming
๐ Blogger at blog.klipse.tech
Set of best practices that reduce complexity of information systems by treating data as a first-class citizen
โ๏ธComputational complexity
The amount of machine resources (e.g. CPU, memory) required to run a program.
๐ฐ System Complexity
The amount of brain resources required to understand a system.
Systems that manipulate information in various ways.
Examples of information systems:
Web services that fetch data from the database and serves it as JSON
Web workers that listen to events and enrich event data from multiple data sources
Front end applications that store application state
๐ธ๏ธSources of complexity
Nodes with many edges
Many kind of arrows
Association
Composition
Inheritance
Usage
โWhat makes this system less complex?
Separation of concerns
Code diagram constraints
Stateless (static)
Only usage relation
Data diagram constraints
Only association and composition
class AuthorData {
private String firstName;
private String lastName;
// setters
// getters
}
class AuthorCode {
static String fullName(AuthorData author) {
return author.firstName() +
" " + author.lastName();
}
}
var asimov = new AuthorData("Isaac", "Asimov");
AuthorCode.fullName(asimov); // "Isaac Asimov"
By reference or by value?
In Java, object references are passed by value
var asimov = new AuthorData("Isaac", "Asimov");
var asimov2 = AuthorCode.toUpperLastName(asimov);
asimov2.lastName() // "ASIMOV"
asimov.lastName() // ??
โ ๏ธWe could trust the implementation
๐ We protect ourselves by copying the object
๐ฑ It makes the code hard to understand
Thread-safety
class MemberData {
private boolean blocked;
private String firstName;
private String lastName;
// getters and setters
}
class MemberCode {
static borrow(MemberData member, String bookId) {
if(!member.isBlocked()) {
System.out.println("The book is yours!");
}
}
}
โ ๏ธThis code is not thread safe!
๐ We add lock mechanisms.
๐ฑ It makes the code hard to understand.
Treat data as a value. Values never change.
Main benefits of immutable data
Inherently Thread-safe
No side-effects
We can solve any problem in Java with Java annotations (anonymous)
@value
annotation by Project Lombok
@value class AuthorData {
String firstName;
String lastName;
}
Auto generation of:
constructor, immutable private fields
getters, setters
toString()
, hashCode()
, equals()
Java records (Only since Java 14!)
public record AuthorData (String firstName,
String lastName) {}
Native implementation of:
constructor, immutable private fields
getters, setters
toString()
, hashCode()
, equals()
var asimov = new AuthorData("Isaac", "Asimov");
var asimov2 = AuthorCode.toUpperLastName(asimov);
asimov.lastName() // "asimov"
No mutations!
No unpleasant surprises
No need to do a defensive copy!
class MemberCode {
static borrow(MemberData member, String bookId) {
if(!member.isBlocked()) {
System.out.println("The book is yours!");
}
}
}
Thread-safe!
No race conditions!
No need to protect with a lock!
Efficient immutable collections
Represent record with immutable maps
Polymorphism without inheritance
Manage the application state
Highly-scalable concurrent systems
Flexible access to the database