SlideShare a Scribd company logo
1 of 39
Knots – the Lazy Data Transfer
Objects for Dealing with the
Microservices Craze
[ashopov@ashmac ~]$ whoami
By day: Software Engineer at Uber
By night: OSS contributor
Coordinator of Bulgarian Gnome TP
Git, bash, Sentry, Jenkins speak Bulgarian
Contacts:
E-mail: ash@kambanaria.org
LinkedIn: http://www.linkedin.com/in/alshopov
SlideShare: http://www.slideshare.net/al_shopov
GitHub: https://github.com/alshopov
Web: Just search “al_shopov”
Please Learn and Share
License: Creative Commons
Attribution 4.0 International
(CC-BY v4.0)
The Whole Lecture in One Slide
// KNOT
public class UserKnot {
private final int userId;
private User user;
public UserKnot(int userId) {
this.userId = userId;
}
public int getUserId() {
return userId;
}
public User getUser() {
if (user == null) {
user = USER_SERVICE.
getUserById(userId);
}
return user;
}
}
// BEAN-ish, no no-args constr.
public class UserBean {
private int userId;
private User user;
public UserBean(int userId,
User user) {
this.userId = userId;
this.user = user;
}
public int getUserId() {
return userId;
}
public User getUser() {
return user;
}
}
|
|
What Did Microservices Give Us?
● Many services:
– Bigger than micro (geodes)
– Lesser than micro (nanoservices)
● Every solution is another micro service:
– Did we have a problem?
– Was it the right problem?
Fundamental Theorem of Software
Engineering
All problems in computer
science can be solved by
another level of indirection,
except of course for the
problem of too many
indirections
Fundamental Theorem of Software
Practice
All problems in a
microservices architecture
can be solved by other
microsrvices, except of
course for the problem of too
many microservices.
What Did Microservices Take Away
From Us?
?
Dude, Where Are My JOINs?
● Data relates to other data.
● You may denormalize but you cannot have all
microservices have all the data
● Data is isolated in domains, different microservices
serve it and you have to re-join it
● Single source of truth? What do you mean by truth?
● A whole workflow is like a quest – Raiders of the Lost
Join – you go to different services, ask questions and
get answers
– What order?
– How many times?
micro SERVICES
● No matter how big they are, they are services
● They are at least a network call away
● Money cannot buy time!
● Money can buy memory, servers, disks, more
bandwidth, engineers
● 299 792 458 m / s – it is the law. Even in
Pernik!
DRY, KISS, YAGNI for Microservices
● Do not repeat your queries for the same data if
you can avoid it
– Once you get the data – keep it
● Keep this avoiding simple
– There are many services, you cannot pass
the data of all of them as arguments in all
combinations
● If you do not need some data – you ain’t gonna
need it
– Load as lazily as you can
Keep on Adding, Pass it All Around
● Through layers ● Through modules
This Is the Essence of Tying a Knot
// KNOT
public class UserKnot {
private final int userId;
private User user;
public UserKnot(int userId) {
this.userId = userId;
}
public int getUserId() {
return userId;
}
public User getUser() {
if (user == null) {
user = Registry.
getInstance().
getUserService().
getUserById(userId);
}
return user;
}
}
DRY – the second call to getUser
does not repeat the request
KISS – getUser hides specifics
service are behind a getter
YAGNI – if you never call getUser –
you will not incur a network call
This Is the Essence of Tying a Knot
// KNOT
public class UserKnot {
private final int userId;
private User user;
public UserKnot(int userId) {
this.userId = userId;
}
public int getUserId() {
return userId;
}
public User getUser() {
if (user == null) {
user = Registry.
getInstance().
getUserService().
getUserById(userId);
}
return user;
}
}
DRY – the second call to getUser
does not repeat the request
KISS – getUser hides specifics
service are behind a getter
YAGNI – if you never call getUser –
you will not incur a network call
SELECT *
FROM users AS u
WHERE u.id=42;
Extendable – Direct Joins
public class ExtendedUserKnot {
private final int userId;
private User user;
private List<Account> accounts;
public ExtendedUserKnot(int userId) {
this.userId = userId;
}
public int getUserId() {
return userId;
}
public User getUser() {
if (user == null) {
user = USER_SERVICE.getUserById(userId);
}
return user;
}
public List<Account> getAccounts() {
if (accounts == null) {
accounts = ACCOUNT_SERVICE.getAccountByUserId(userId);
}
return accounts;
}
}
Join another service
Extendable – Direct Joins
public class ExtendedUserKnot {
private final int userId;
private User user;
private List<Account> accounts;
public ExtendedUserKnot(int userId) {
this.userId = userId;
}
public int getUserId() {
return userId;
}
public User getUser() {
if (user == null) {
user = USER_SERVICE.getUserById(userId);
}
return user;
}
public List<Account> getAccounts() {
if (accounts == null) {
accounts = ACCOUNT_SERVICE.getAccountByUserId(userId);
}
return accounts;
}
}
Join another service
SELECT *
FROM users AS u
JOIN accounts AS a
ON u.id=a.user_id
WHERE u.id=42;
Extendable – Multiple Joins
public class DoubleUserKnot {
private final int userId;userId;
private final int bankId;
private User user;
private Bank bank;
private accounts;
public DoubleUserKnot(int userId, int bankId) {
this.userId = userId;
this.bankId = bankId;
}
public int getUserId() {
return userId;
}
public User getUser() {
if (user == null) {
user = USER_SERVICE.getUserById(userId);
}
return user;
}
public List<Account> getAccounts() {
if (accounts == null) {
accounts = ACCOUNT_SERVICE.
getAccountByUserIdBankId(userId, bankId);
}
return accounts;
}
public Bank getBank() {
if (bank == null) {
bank = BANK_SERVICE.getBankById(bankId);
}
return bank;
}
}
Capture several attributes
Join many services
Service depends on several attributes
Extendable – Multiple Joins
public class DoubleUserKnot {
private final int userId;userId;
private final int bankId;
private User user;
private Bank bank;
private accounts;
public DoubleUserKnot(int userId, int bankId) {
this.userId = userId;
this.bankId = bankId;
}
public int getUserId() {
return userId;
}
public User getUser() {
if (user == null) {
user = USER_SERVICE.getUserById(userId);
}
return user;
}
public List<Account> getAccounts() {
if (accounts == null) {
accounts = ACCOUNT_SERVICE.
getAccountByUserIdBankId(userId, bankId);
}
return accounts;
}
public Bank getBank() {
if (bank == null) {
bank = BANK_SERVICE.getBankById(bankId);
}
return bank;
}
}
Capture several attributes
Join many services
Service depends on several attributes
SELECT *
FROM users AS u
JOIN accounts AS a
ON u.id=a.user_id
JOIN banks AS b
ON u.id=a.bank_id
WHERE u.id=42
AND b.id=666;
Composable – Knot Within a Knot
public class CountryKnot {
private final int id;
private Country country;
private Currency currency;
public CountryKnot(int id) {
this.id = id;
}
public int getId() {
return id;
}
public Country getCountry() {
if (country == null) {
country = COUNTRY_SERVICE.
getCountryById(id);
}
return country;
}
public Currency getCurrency() {
if (currency == null) {
currency = CURRENCY_SERVICE.
GetCurrencyById(
getCountry().
getCurrencyId());
}
return currency;
}
}
public class ComposedUserKnot {
private final int userId;
private User user;
private CountryKnot countryKnot;
public ComposedUserKnot(int userId) {
this.userId = userId;
}
public User getUser(){
if (user == null){
user = USER_SERVICE.
getUserById(userId);
}
return user;
}
public Country getCountry(){
if (countryKnot == null){
countryKnot = new CountryKnot(
getUser().
getCountryId());
}
return countryKnot.getCountry();
}
public Currency getCurrency() {
return countryKnot.getCurrency();
}
}
Composable – Knot Within a Knot
public class CountryKnot {
private final int id;
private Country country;
private Currency currency;
public CountryKnot(int id) {
this.id = id;
}
public int getId() {
return id;
}
public Country getCountry() {
if (country == null) {
country = COUNTRY_SERVICE.
getCountryById(id);
}
return country;
}
public Currency getCurrency() {
if (currency == null) {
currency = CURRENCY_SERVICE.
GetCurrencyById(
getCountry().
getCurrencyId());
}
return currency;
}
}
public class ComposedUserKnot {
private final int userId;
private User user;
private CountryKnot countryKnot;
public ComposedUserKnot(int userId) {
this.userId = userId;
}
public User getUser(){
if (user == null){
user = USER_SERVICE.
getUserById(userId);
}
return user;
}
public Country getCountry(){
if (countryKnot == null){
countryKnot = new CountryKnot(
getUser().
getCountryId());
}
return countryKnot.getCountry();
}
public Currency getCurrency() {
return countryKnot.getCurrency();
}
}
SELECT *
FROM users AS u
JOIN countries AS c
ON u.country_id=c.id
JOIN currency AS cu
ON c.currency_id=cu.id
WHERE u.id=42;
Threads, Anybody?
● A lot of frameworks get a request–response cycle
in a single thread, all the layers are in the thread
that got the initial data, so no synchronization is
needed
● If your knots will be touched by many threads –
you need some synchronization.
● First to request – will block until knot is tied.
● The rest of requesters – will also have to wait.
– It is rare that you need to issue the same
request several times – unreliable network,
changing routing, etc.
Thread safety
Double checked
locking
public class ThreadSafeUserKnot {
// User MUST be immutable, reference MUST be volatile
// userId MUST be final
// Every service MUST have own lock
private final int userId;
private volatile User user;
private final Object userLock = new Object();
public ThreadSafeUserKnot(int userId) {
this.userId = userId;
}
public int getUserId() {
return userId;
}
public User getUser() {
if (user == null) {
synchronized (userLock) {
if (user == null) {
user = USER_SERVICE.getUserById(userId);
}}}
return user;
}
}
Lazily Instantiated
● The magic behind knots is that we query external
services lazily – not earlier than needed.
● We do not incur network latency if we do not need
the network call.
● While the full workflow may need many calls,
parts may take decision based on partial
information – quick bailout.
● It is easier going from lazy to eager fetches – but
more about this when we talk about observables.
Facade
● The knots serve as a facade to external
services
● You capture request info in constructor
● All peculiarities of the different network services
are hidden behind a simple getter.
● Easier to use, easier to read
Proxy
● Network calls are expensive, so we proxy
● Proxying and forwarding allows us to cache the
result per request
● Proxying works because we mainly read, thus
we do not need full functioning objects that we
can modify
Data Transfer Object
● It holds all data
● But no need for serialization – a knot is always
local. Crossing microservices frequently means
crossing language and framework barriers.
● Similarly – no business logic, but consistency
checking and validation are important since
data is shared across many services. There is
duplication and a knot may check consistency
of data.
Compared to ORM Entities
● Knot is readonly
● Synchronizes once per request
● Explicitly shows slow calls
● Always starts lazy and predominantly stays so
● When knots stop being so lazy they become
parallel
● SELECT n+1 – for entities bad performance, for
knots – impossible performance
– Entities – joins or lazy
– Knots – already lazy, no joins – bulk APIs
What About Testing?
● Testing is very easy if you have mocked the
services. Knots basically aggregate the objects
returned by the mocks
● No business logic – nothing to test
● Verification of data from different services
– Very important
– Couples with observability
Refactoring
● If you have too many services calls per request –
make whoever calls you provide you with some of
the information you need, you push more in the
constructor, you have shorter chain of knots
● If you cannot trust the input and need to get it on
your own – you go the other direction
● Knots make both possible and compatible
● The rest of refactoring is your microservice. Knots
separate you from changes in other
microservices.
Observable
● Most often you log network calls and then
reconstruct calls, usually you have a request
identifier
● Knots allow you to reverse and/or augment this
logging
● Do you always call service B after calling
service A?
– Issue both calls together
● If you call service T to get some data but it is
also available elsewhere – stop calling T.
Knots’ Single Responsibility
● On the one hand they break it because they
knot together many services
● On the other – their primary purpose is to
minimize network calls
● Make using microservices easier
● Transparent yet not abstract
Open/Closed
● Knots are closed for modification and not
extendable
● You can implement an open basic class and do
tricks with generics, however this implies very
similar microservices which is not true in
practice
● There is only so much you can get from
extension, sorry
● Knots should be easy to understand and trace,
do not be overly creative with them
Law of Demeter
● Talk to immediate friends, not strangers
● Method A.a() calls method B.b() and not
B.c.d.f()
● Tell, don’t ask
● Break it regarding to knots, you may reach
inside them – they can be arbitrarily nested
even though microservices have flatter
structure at least initially
● This allows to organize the rest of the codebase
to upkeep the law
Compare Similar Solutions
● Spring’s Request Scoped Beans
– Only Java
– Only Spring
– Web container targeted
● VMWare’s Xenon
– Again Java only
– Much larger scope – whole framework
– Much tighter integration, your code functions
inside it
That’s All, Folks
● Questions?
● Anything to declare?
● Microservices? To Knot or Not?
● Images: Wikimedia Commons

More Related Content

Similar to Knots - the Lazy Data Transfer Objects for Dealing with the Microservices Craze

Creating an Uber Clone - Part XIII - Transcript.pdf
Creating an Uber Clone - Part XIII - Transcript.pdfCreating an Uber Clone - Part XIII - Transcript.pdf
Creating an Uber Clone - Part XIII - Transcript.pdfShaiAlmog1
 
Server Side Swift with Swag
Server Side Swift with SwagServer Side Swift with Swag
Server Side Swift with SwagJens Ravens
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
Creating a Facebook Clone - Part XX - Transcript.pdf
Creating a Facebook Clone - Part XX - Transcript.pdfCreating a Facebook Clone - Part XX - Transcript.pdf
Creating a Facebook Clone - Part XX - Transcript.pdfShaiAlmog1
 
Building Java and Android apps on the blockchain
Building Java and Android apps on the blockchain Building Java and Android apps on the blockchain
Building Java and Android apps on the blockchain Conor Svensson
 
The JSON Architecture - BucharestJS / July
The JSON Architecture - BucharestJS / JulyThe JSON Architecture - BucharestJS / July
The JSON Architecture - BucharestJS / JulyConstantin Dumitrescu
 
Java Svet - Communication Between Android App Components
Java Svet - Communication Between Android App ComponentsJava Svet - Communication Between Android App Components
Java Svet - Communication Between Android App ComponentsAleksandar Ilić
 
Java Svet - Communication Between Android App Components
Java Svet - Communication Between Android App ComponentsJava Svet - Communication Between Android App Components
Java Svet - Communication Between Android App ComponentsPSTechSerbia
 
Writing SOLID C++ [gbgcpp meetup @ Zenseact]
Writing SOLID C++ [gbgcpp meetup @ Zenseact]Writing SOLID C++ [gbgcpp meetup @ Zenseact]
Writing SOLID C++ [gbgcpp meetup @ Zenseact]Dimitrios Platis
 
Learned lessons in a real world project by Luis Rovirosa at PHPMad
Learned lessons in a real world project by Luis Rovirosa at PHPMadLearned lessons in a real world project by Luis Rovirosa at PHPMad
Learned lessons in a real world project by Luis Rovirosa at PHPMadCodium
 
Consume Spring Data Rest with Angularjs
Consume Spring Data Rest with AngularjsConsume Spring Data Rest with Angularjs
Consume Spring Data Rest with AngularjsCorneil du Plessis
 
Addressing Scenario
Addressing ScenarioAddressing Scenario
Addressing ScenarioTara Hardin
 
Java beginners meetup: Introduction to class and application design
Java beginners meetup: Introduction to class and application designJava beginners meetup: Introduction to class and application design
Java beginners meetup: Introduction to class and application designPatrick Kostjens
 
Cloudbase.io MoSync Reload Course
Cloudbase.io MoSync Reload CourseCloudbase.io MoSync Reload Course
Cloudbase.io MoSync Reload Coursecloudbase.io
 
Hooks and Events in Drupal 8
Hooks and Events in Drupal 8Hooks and Events in Drupal 8
Hooks and Events in Drupal 8Nida Ismail Shah
 
Architecture your android_application
Architecture your android_applicationArchitecture your android_application
Architecture your android_applicationMark Brady
 
Nko workshop - node js crud & deploy
Nko workshop - node js crud & deployNko workshop - node js crud & deploy
Nko workshop - node js crud & deploySimon Su
 
GraphQL Bangkok Meetup 2.0
GraphQL Bangkok Meetup 2.0GraphQL Bangkok Meetup 2.0
GraphQL Bangkok Meetup 2.0Tobias Meixner
 

Similar to Knots - the Lazy Data Transfer Objects for Dealing with the Microservices Craze (20)

Creating an Uber Clone - Part XIII - Transcript.pdf
Creating an Uber Clone - Part XIII - Transcript.pdfCreating an Uber Clone - Part XIII - Transcript.pdf
Creating an Uber Clone - Part XIII - Transcript.pdf
 
Server Side Swift with Swag
Server Side Swift with SwagServer Side Swift with Swag
Server Side Swift with Swag
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
Creating a Facebook Clone - Part XX - Transcript.pdf
Creating a Facebook Clone - Part XX - Transcript.pdfCreating a Facebook Clone - Part XX - Transcript.pdf
Creating a Facebook Clone - Part XX - Transcript.pdf
 
Codemotion appengine
Codemotion appengineCodemotion appengine
Codemotion appengine
 
Hexagonal architecture
Hexagonal architectureHexagonal architecture
Hexagonal architecture
 
Building Java and Android apps on the blockchain
Building Java and Android apps on the blockchain Building Java and Android apps on the blockchain
Building Java and Android apps on the blockchain
 
The JSON Architecture - BucharestJS / July
The JSON Architecture - BucharestJS / JulyThe JSON Architecture - BucharestJS / July
The JSON Architecture - BucharestJS / July
 
Java Svet - Communication Between Android App Components
Java Svet - Communication Between Android App ComponentsJava Svet - Communication Between Android App Components
Java Svet - Communication Between Android App Components
 
Java Svet - Communication Between Android App Components
Java Svet - Communication Between Android App ComponentsJava Svet - Communication Between Android App Components
Java Svet - Communication Between Android App Components
 
Writing SOLID C++ [gbgcpp meetup @ Zenseact]
Writing SOLID C++ [gbgcpp meetup @ Zenseact]Writing SOLID C++ [gbgcpp meetup @ Zenseact]
Writing SOLID C++ [gbgcpp meetup @ Zenseact]
 
Learned lessons in a real world project by Luis Rovirosa at PHPMad
Learned lessons in a real world project by Luis Rovirosa at PHPMadLearned lessons in a real world project by Luis Rovirosa at PHPMad
Learned lessons in a real world project by Luis Rovirosa at PHPMad
 
Consume Spring Data Rest with Angularjs
Consume Spring Data Rest with AngularjsConsume Spring Data Rest with Angularjs
Consume Spring Data Rest with Angularjs
 
Addressing Scenario
Addressing ScenarioAddressing Scenario
Addressing Scenario
 
Java beginners meetup: Introduction to class and application design
Java beginners meetup: Introduction to class and application designJava beginners meetup: Introduction to class and application design
Java beginners meetup: Introduction to class and application design
 
Cloudbase.io MoSync Reload Course
Cloudbase.io MoSync Reload CourseCloudbase.io MoSync Reload Course
Cloudbase.io MoSync Reload Course
 
Hooks and Events in Drupal 8
Hooks and Events in Drupal 8Hooks and Events in Drupal 8
Hooks and Events in Drupal 8
 
Architecture your android_application
Architecture your android_applicationArchitecture your android_application
Architecture your android_application
 
Nko workshop - node js crud & deploy
Nko workshop - node js crud & deployNko workshop - node js crud & deploy
Nko workshop - node js crud & deploy
 
GraphQL Bangkok Meetup 2.0
GraphQL Bangkok Meetup 2.0GraphQL Bangkok Meetup 2.0
GraphQL Bangkok Meetup 2.0
 

More from Alexander Shopov

Нови приключения на преводачите
Нови приключения на преводачитеНови приключения на преводачите
Нови приключения на преводачитеAlexander Shopov
 
Bundling Packages and Deploying Applications with RPM
Bundling Packages and Deploying Applications with RPMBundling Packages and Deploying Applications with RPM
Bundling Packages and Deploying Applications with RPMAlexander Shopov
 
Beyond the Final Frontier of jQuery Selectors
Beyond the Final Frontier of jQuery SelectorsBeyond the Final Frontier of jQuery Selectors
Beyond the Final Frontier of jQuery SelectorsAlexander Shopov
 
I Know Kung Fu - Juggling Java Bytecode
I Know Kung Fu - Juggling Java BytecodeI Know Kung Fu - Juggling Java Bytecode
I Know Kung Fu - Juggling Java BytecodeAlexander Shopov
 
Lifting The Veil - Reading Java Bytecode During Lunchtime
Lifting The Veil - Reading Java Bytecode During LunchtimeLifting The Veil - Reading Java Bytecode During Lunchtime
Lifting The Veil - Reading Java Bytecode During LunchtimeAlexander Shopov
 
Lifting The Veil - Reading Java Bytecode
Lifting The Veil - Reading Java BytecodeLifting The Veil - Reading Java Bytecode
Lifting The Veil - Reading Java BytecodeAlexander Shopov
 

More from Alexander Shopov (10)

700 Tons of Code Later
700 Tons of Code Later700 Tons of Code Later
700 Tons of Code Later
 
Нови приключения на преводачите
Нови приключения на преводачитеНови приключения на преводачите
Нови приключения на преводачите
 
In Vogue Dynamic
In Vogue DynamicIn Vogue Dynamic
In Vogue Dynamic
 
Bundling Packages and Deploying Applications with RPM
Bundling Packages and Deploying Applications with RPMBundling Packages and Deploying Applications with RPM
Bundling Packages and Deploying Applications with RPM
 
Beyond the Final Frontier of jQuery Selectors
Beyond the Final Frontier of jQuery SelectorsBeyond the Final Frontier of jQuery Selectors
Beyond the Final Frontier of jQuery Selectors
 
Oracle's Take On NoSQL
Oracle's Take On NoSQLOracle's Take On NoSQL
Oracle's Take On NoSQL
 
I Know Kung Fu - Juggling Java Bytecode
I Know Kung Fu - Juggling Java BytecodeI Know Kung Fu - Juggling Java Bytecode
I Know Kung Fu - Juggling Java Bytecode
 
Lifting The Veil - Reading Java Bytecode During Lunchtime
Lifting The Veil - Reading Java Bytecode During LunchtimeLifting The Veil - Reading Java Bytecode During Lunchtime
Lifting The Veil - Reading Java Bytecode During Lunchtime
 
Caching in HTTP
Caching in HTTPCaching in HTTP
Caching in HTTP
 
Lifting The Veil - Reading Java Bytecode
Lifting The Veil - Reading Java BytecodeLifting The Veil - Reading Java Bytecode
Lifting The Veil - Reading Java Bytecode
 

Recently uploaded

Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfhans926745
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdflior mazor
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesBoston Institute of Analytics
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 

Recently uploaded (20)

Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 

Knots - the Lazy Data Transfer Objects for Dealing with the Microservices Craze

  • 1. Knots – the Lazy Data Transfer Objects for Dealing with the Microservices Craze
  • 2. [ashopov@ashmac ~]$ whoami By day: Software Engineer at Uber By night: OSS contributor Coordinator of Bulgarian Gnome TP Git, bash, Sentry, Jenkins speak Bulgarian Contacts: E-mail: ash@kambanaria.org LinkedIn: http://www.linkedin.com/in/alshopov SlideShare: http://www.slideshare.net/al_shopov GitHub: https://github.com/alshopov Web: Just search “al_shopov”
  • 3. Please Learn and Share License: Creative Commons Attribution 4.0 International (CC-BY v4.0)
  • 4. The Whole Lecture in One Slide // KNOT public class UserKnot { private final int userId; private User user; public UserKnot(int userId) { this.userId = userId; } public int getUserId() { return userId; } public User getUser() { if (user == null) { user = USER_SERVICE. getUserById(userId); } return user; } } // BEAN-ish, no no-args constr. public class UserBean { private int userId; private User user; public UserBean(int userId, User user) { this.userId = userId; this.user = user; } public int getUserId() { return userId; } public User getUser() { return user; } } | |
  • 5. What Did Microservices Give Us? ● Many services: – Bigger than micro (geodes) – Lesser than micro (nanoservices) ● Every solution is another micro service: – Did we have a problem? – Was it the right problem?
  • 6. Fundamental Theorem of Software Engineering All problems in computer science can be solved by another level of indirection, except of course for the problem of too many indirections
  • 7. Fundamental Theorem of Software Practice All problems in a microservices architecture can be solved by other microsrvices, except of course for the problem of too many microservices.
  • 8. What Did Microservices Take Away From Us? ?
  • 9. Dude, Where Are My JOINs? ● Data relates to other data. ● You may denormalize but you cannot have all microservices have all the data ● Data is isolated in domains, different microservices serve it and you have to re-join it ● Single source of truth? What do you mean by truth? ● A whole workflow is like a quest – Raiders of the Lost Join – you go to different services, ask questions and get answers – What order? – How many times?
  • 10. micro SERVICES ● No matter how big they are, they are services ● They are at least a network call away ● Money cannot buy time! ● Money can buy memory, servers, disks, more bandwidth, engineers ● 299 792 458 m / s – it is the law. Even in Pernik!
  • 11. DRY, KISS, YAGNI for Microservices ● Do not repeat your queries for the same data if you can avoid it – Once you get the data – keep it ● Keep this avoiding simple – There are many services, you cannot pass the data of all of them as arguments in all combinations ● If you do not need some data – you ain’t gonna need it – Load as lazily as you can
  • 12. Keep on Adding, Pass it All Around ● Through layers ● Through modules
  • 13. This Is the Essence of Tying a Knot // KNOT public class UserKnot { private final int userId; private User user; public UserKnot(int userId) { this.userId = userId; } public int getUserId() { return userId; } public User getUser() { if (user == null) { user = Registry. getInstance(). getUserService(). getUserById(userId); } return user; } } DRY – the second call to getUser does not repeat the request KISS – getUser hides specifics service are behind a getter YAGNI – if you never call getUser – you will not incur a network call
  • 14. This Is the Essence of Tying a Knot // KNOT public class UserKnot { private final int userId; private User user; public UserKnot(int userId) { this.userId = userId; } public int getUserId() { return userId; } public User getUser() { if (user == null) { user = Registry. getInstance(). getUserService(). getUserById(userId); } return user; } } DRY – the second call to getUser does not repeat the request KISS – getUser hides specifics service are behind a getter YAGNI – if you never call getUser – you will not incur a network call SELECT * FROM users AS u WHERE u.id=42;
  • 15. Extendable – Direct Joins public class ExtendedUserKnot { private final int userId; private User user; private List<Account> accounts; public ExtendedUserKnot(int userId) { this.userId = userId; } public int getUserId() { return userId; } public User getUser() { if (user == null) { user = USER_SERVICE.getUserById(userId); } return user; } public List<Account> getAccounts() { if (accounts == null) { accounts = ACCOUNT_SERVICE.getAccountByUserId(userId); } return accounts; } } Join another service
  • 16. Extendable – Direct Joins public class ExtendedUserKnot { private final int userId; private User user; private List<Account> accounts; public ExtendedUserKnot(int userId) { this.userId = userId; } public int getUserId() { return userId; } public User getUser() { if (user == null) { user = USER_SERVICE.getUserById(userId); } return user; } public List<Account> getAccounts() { if (accounts == null) { accounts = ACCOUNT_SERVICE.getAccountByUserId(userId); } return accounts; } } Join another service SELECT * FROM users AS u JOIN accounts AS a ON u.id=a.user_id WHERE u.id=42;
  • 17. Extendable – Multiple Joins public class DoubleUserKnot { private final int userId;userId; private final int bankId; private User user; private Bank bank; private accounts; public DoubleUserKnot(int userId, int bankId) { this.userId = userId; this.bankId = bankId; } public int getUserId() { return userId; } public User getUser() { if (user == null) { user = USER_SERVICE.getUserById(userId); } return user; } public List<Account> getAccounts() { if (accounts == null) { accounts = ACCOUNT_SERVICE. getAccountByUserIdBankId(userId, bankId); } return accounts; } public Bank getBank() { if (bank == null) { bank = BANK_SERVICE.getBankById(bankId); } return bank; } } Capture several attributes Join many services Service depends on several attributes
  • 18. Extendable – Multiple Joins public class DoubleUserKnot { private final int userId;userId; private final int bankId; private User user; private Bank bank; private accounts; public DoubleUserKnot(int userId, int bankId) { this.userId = userId; this.bankId = bankId; } public int getUserId() { return userId; } public User getUser() { if (user == null) { user = USER_SERVICE.getUserById(userId); } return user; } public List<Account> getAccounts() { if (accounts == null) { accounts = ACCOUNT_SERVICE. getAccountByUserIdBankId(userId, bankId); } return accounts; } public Bank getBank() { if (bank == null) { bank = BANK_SERVICE.getBankById(bankId); } return bank; } } Capture several attributes Join many services Service depends on several attributes SELECT * FROM users AS u JOIN accounts AS a ON u.id=a.user_id JOIN banks AS b ON u.id=a.bank_id WHERE u.id=42 AND b.id=666;
  • 19. Composable – Knot Within a Knot public class CountryKnot { private final int id; private Country country; private Currency currency; public CountryKnot(int id) { this.id = id; } public int getId() { return id; } public Country getCountry() { if (country == null) { country = COUNTRY_SERVICE. getCountryById(id); } return country; } public Currency getCurrency() { if (currency == null) { currency = CURRENCY_SERVICE. GetCurrencyById( getCountry(). getCurrencyId()); } return currency; } } public class ComposedUserKnot { private final int userId; private User user; private CountryKnot countryKnot; public ComposedUserKnot(int userId) { this.userId = userId; } public User getUser(){ if (user == null){ user = USER_SERVICE. getUserById(userId); } return user; } public Country getCountry(){ if (countryKnot == null){ countryKnot = new CountryKnot( getUser(). getCountryId()); } return countryKnot.getCountry(); } public Currency getCurrency() { return countryKnot.getCurrency(); } }
  • 20. Composable – Knot Within a Knot public class CountryKnot { private final int id; private Country country; private Currency currency; public CountryKnot(int id) { this.id = id; } public int getId() { return id; } public Country getCountry() { if (country == null) { country = COUNTRY_SERVICE. getCountryById(id); } return country; } public Currency getCurrency() { if (currency == null) { currency = CURRENCY_SERVICE. GetCurrencyById( getCountry(). getCurrencyId()); } return currency; } } public class ComposedUserKnot { private final int userId; private User user; private CountryKnot countryKnot; public ComposedUserKnot(int userId) { this.userId = userId; } public User getUser(){ if (user == null){ user = USER_SERVICE. getUserById(userId); } return user; } public Country getCountry(){ if (countryKnot == null){ countryKnot = new CountryKnot( getUser(). getCountryId()); } return countryKnot.getCountry(); } public Currency getCurrency() { return countryKnot.getCurrency(); } } SELECT * FROM users AS u JOIN countries AS c ON u.country_id=c.id JOIN currency AS cu ON c.currency_id=cu.id WHERE u.id=42;
  • 21. Threads, Anybody? ● A lot of frameworks get a request–response cycle in a single thread, all the layers are in the thread that got the initial data, so no synchronization is needed ● If your knots will be touched by many threads – you need some synchronization. ● First to request – will block until knot is tied. ● The rest of requesters – will also have to wait. – It is rare that you need to issue the same request several times – unreliable network, changing routing, etc.
  • 22. Thread safety Double checked locking public class ThreadSafeUserKnot { // User MUST be immutable, reference MUST be volatile // userId MUST be final // Every service MUST have own lock private final int userId; private volatile User user; private final Object userLock = new Object(); public ThreadSafeUserKnot(int userId) { this.userId = userId; } public int getUserId() { return userId; } public User getUser() { if (user == null) { synchronized (userLock) { if (user == null) { user = USER_SERVICE.getUserById(userId); }}} return user; } }
  • 23. Lazily Instantiated ● The magic behind knots is that we query external services lazily – not earlier than needed. ● We do not incur network latency if we do not need the network call. ● While the full workflow may need many calls, parts may take decision based on partial information – quick bailout. ● It is easier going from lazy to eager fetches – but more about this when we talk about observables.
  • 24. Facade ● The knots serve as a facade to external services ● You capture request info in constructor ● All peculiarities of the different network services are hidden behind a simple getter. ● Easier to use, easier to read
  • 25. Proxy ● Network calls are expensive, so we proxy ● Proxying and forwarding allows us to cache the result per request ● Proxying works because we mainly read, thus we do not need full functioning objects that we can modify
  • 26. Data Transfer Object ● It holds all data ● But no need for serialization – a knot is always local. Crossing microservices frequently means crossing language and framework barriers. ● Similarly – no business logic, but consistency checking and validation are important since data is shared across many services. There is duplication and a knot may check consistency of data.
  • 27. Compared to ORM Entities ● Knot is readonly ● Synchronizes once per request ● Explicitly shows slow calls ● Always starts lazy and predominantly stays so ● When knots stop being so lazy they become parallel ● SELECT n+1 – for entities bad performance, for knots – impossible performance – Entities – joins or lazy – Knots – already lazy, no joins – bulk APIs
  • 28. What About Testing? ● Testing is very easy if you have mocked the services. Knots basically aggregate the objects returned by the mocks ● No business logic – nothing to test ● Verification of data from different services – Very important – Couples with observability
  • 29. Refactoring ● If you have too many services calls per request – make whoever calls you provide you with some of the information you need, you push more in the constructor, you have shorter chain of knots ● If you cannot trust the input and need to get it on your own – you go the other direction ● Knots make both possible and compatible ● The rest of refactoring is your microservice. Knots separate you from changes in other microservices.
  • 30. Observable ● Most often you log network calls and then reconstruct calls, usually you have a request identifier ● Knots allow you to reverse and/or augment this logging ● Do you always call service B after calling service A? – Issue both calls together ● If you call service T to get some data but it is also available elsewhere – stop calling T.
  • 31.
  • 32. Knots’ Single Responsibility ● On the one hand they break it because they knot together many services ● On the other – their primary purpose is to minimize network calls ● Make using microservices easier ● Transparent yet not abstract
  • 33.
  • 34. Open/Closed ● Knots are closed for modification and not extendable ● You can implement an open basic class and do tricks with generics, however this implies very similar microservices which is not true in practice ● There is only so much you can get from extension, sorry ● Knots should be easy to understand and trace, do not be overly creative with them
  • 35.
  • 36. Law of Demeter ● Talk to immediate friends, not strangers ● Method A.a() calls method B.b() and not B.c.d.f() ● Tell, don’t ask ● Break it regarding to knots, you may reach inside them – they can be arbitrarily nested even though microservices have flatter structure at least initially ● This allows to organize the rest of the codebase to upkeep the law
  • 37. Compare Similar Solutions ● Spring’s Request Scoped Beans – Only Java – Only Spring – Web container targeted ● VMWare’s Xenon – Again Java only – Much larger scope – whole framework – Much tighter integration, your code functions inside it
  • 38. That’s All, Folks ● Questions? ● Anything to declare? ● Microservices? To Knot or Not?