SlideShare a Scribd company logo
Java, with a
Clojure mindset
@DanLebrero
www.akvo.org
Java with a Clojure mindset
Java with a Clojure mindset
Java with a Clojure mindset
Java with a Clojure mindset
Java with a Clojure mindset
Java with a Clojure mindset
Java with a Clojure mindset
((((((
((((((()))))))
))))))
Clojure
•Functional
•Hosted
•Dynamic
•Strongly typed
•Lisp
Java with a Clojure mindset
Java with a Clojure mindset
Give 10$ free cash
if client makes 1000 bets
in less than 1 week
Functional (vs OO)
Pure Functions
Java with a Clojure mindset
“Programmers are constantly in maintenance mode.”
― The Pragmatic Programmer
Side Effects
Java with a Clojure mindset
Side effects are the
enemy
Side Effects
State IO
EffectsCo-effects
State
ClientBonus12
23
54
…
Client
Bonus
DepositList
Deposit
Deposit
BetList Bet
Bet
Atom
=~ j.u.c.a.AtomicReference
Atom
Thread-1
Thread-2 fn2( ) =
fn1( ) =
====fn2( ) =
==?
==? ==?
Atom
Thread-1
Thread-2 X
Atom
Thread-1
Thread-2
Thread-3
12
23
54
…
ClientBonusClientBonus
BetList
Bet
12
23
54
…
Client
Bonus
DepositList
Deposit
Deposit
BetList Bet
Bet
“Is this thread safe?”
― Every Java developer, every day.
1. State is consistent
2. Function must be pure
3. Only safe within the pure function
public class ClientBonus {
private final Client client;
private final Bonus bonus;
private final DepositList deposits;
…
ClientBonus12
23
54
…
Client
Bonus
DepositList
Deposit
Deposit
BetList Bet
Bet
public interface ConcurrentMap<…> extends Map<…> {
V compute(K key, BiFunction<…> remappingFunction)
V computeIfAbsent(K key, Function<…> mappingFunction)
V computeIfPresent(K key, BiFunction<…> remappingFunction)
…
}
public class TheStateHolder {
private final Map<Long, ClientBonus> state = new ConcurrentHashMap<>();
public ClientBonus nextState(Long client, Bet bet) {
return state.computeIfPresent(
client,
(k, currentState) -> currentState.nextState(bet));
}
public class ClientBonus {
private final Client client;
private final Bonus bonus;
private final DepositList deposits;
public ClientBonus nextState(Bet bet) {
...
}
…
Effects
xxxxService
INotificationSender
NotificationSenderImpl
TheStateHolder
public class ClientBonus {
private final Client client;
private final Bonus bonus;
private final DepositList deposits;
public ClientBonus nextState(Bet bet) {
...
}
…
public class ClientBonus {
private final Client client;
private final Bonus bonus;
private final DepositList deposits;
public Pair<ClientBonus,Effects> next(Bet bet) {
...
}
…
NotifyClientEffect
IgnoreError
NotifyClientEffect
IgnoreError
NotifyClientEffect
StopTheJVM
NotifyClientEffect
Effect1 Effect2 Effect3SequentialEffects
Effect1
Effect2
Effect3
IndependentEffects
StopTracking Pay NotifyClient
public interface Effect {
void run(AllDependencies dependencies);
}
Pair<ClientBonus, Effects> pair = theStateHolder.nextState(bet);
pair.effects.run(dependencies);
Pair<ClientBonus, Effects> pair = theStateHolder.nextState(bet);
pair.effects.run(dependencies);
“Is this thread safe?”
Thread-1
Thread-2
Pair<> pair = theStateHolder.nextState(bet);
Pair<> pair = theStateHolder.nextState(bet);
pair.effects.run(dependencies);
pair.effects.run(dependencies);
Pair<> pair = theStateHolder.nextState(bet);
Pair<> pair = theStateHolder.nextState(bet);
pair.effects.run(dependencies);
pair.effects.run(dependencies);
Thread-1
Thread-1
Thread-2
Thread-2
Agents (=~~~ Actors)
Java with a Clojure mindset
Can I pay?Can I pay?
ACID
Can I pay?
NoYes No
AtMostOnce
StopTracking Pay NotifyClient
Co-Effects
Java with a Clojure mindset
Event Sourcing
Functional Programming
Event Sourcing
Functional Programming
public class KafkaConsumer {
private AllDependencies allDependencies;
private TheStateHolder theStateHolder;
public void run() {
while (!stop) {
Bet bet = readNext();
Effects effects = theStateHolder.event(bet);
effects.run(allDependencies);
}
}
…
}
public class KafkaConsumer {
private AllDependencies allDependencies;
private TheStateHolder theStateHolder;
public void run() {
while (!stop) {
Bet bet = readNext();
Effects effects = theStateHolder.event(bet);
effects.run(allDependencies);
}
}
…
}
public class KafkaConsumer {
private AllDependencies allDependencies;
private TheStateHolder theStateHolder;
public void run() {
while (!stop) {
Bet bet = readNext();
Effects effects = theStateHolder.event(bet);
effects.run(allDependencies);
}
}
…
}
public class KafkaConsumer {
private AllDependencies allDependencies;
private TheStateHolder theStateHolder;
public void run() {
while (!stop) {
Bet bet = readNext();
Effects effects = theStateHolder.event(bet);
effects.run(allDependencies);
}
}
…
}
public class KafkaConsumer {
private AllDependencies allDependencies;
private TheStateHolder theStateHolder;
public void run() {
while (!stop) {
Bet bet = readNext();
Effects effects = theStateHolder.event(bet);
effects.run(allDependencies);
}
}
…
}
•No getters
•No locks or synch blocks
•No try/catch
•No logging
•No mocks
•No useless interfaces
Imperative
Shell
https://www.destroyallsoftware.com/screencasts/catalog/functional-core-imperative-shell
Function
al Core
INotificationSender
NotificationSenderImpl
ClientBonus
Dynamic (vs Static) typing
clientBonus = Map.of(
"client", Map.of("id", "123233"),
"deposits",
List.of(
Map.of("amount", 3,
"type", "CASH"),
Map.of("amount", 234,
"type", "CARD")));
((List) clientBonus.get("deposits"))
.stream()
.collect(
Collectors.summarizingInt(
m -> (int) ((Map) m).get("amount")));
Java with a Clojure mindset
public class Bet {
private String id;
private int amount;
private long timestamp;
}
“It is better to have 100 functions operate
on one data structure than 10 functions on
10 data structures.”
― Alan Perlis
{:type :bet
:id "client1"
:amount 23
:timestamp 123312321323}
apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave
interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all
partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take-
nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge
merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index
{:type :bet
:id "client1"
:amount 23
:timestamp 123312321323}
{:request-method :get
:uri “/foobaz"
:query-params {"somekey" “somevalue"}
:headers {"accept-encoding" "gzip, deflate"
"connection" "close"}
:body nil
:scheme :http
:content-length 0
:server-port 8080
:server-name “localhost"}
apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave
interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all
partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take-
nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge
merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index
{:status 200
:headers {"Content-Type" "text/html"}
:body "Hello World"}}
apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave
interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all
partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take-
nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge
merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index
{:select [:id :client :amount]
:from [:transactions]
:where [:= :client "a"]}
apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave
interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all
partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take-
nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge
merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index
[{:id 1 :client 32 :amount 3}
{:id 2 :client 87 :amount 7}
{:id 3 :client 32 :amount 4}
{:id 4 :client 40 :amount 6}]
apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave
interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all
partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take-
nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge
merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index
[:html
[:body
[:p "Count: 4"]
[:p "Total: 20"]]]
apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave
interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all
partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take-
nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge
merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index
{:web-server {:listen 8080}
:db-config {:host "xxxx"
:user "xxxx"
:password "xxxx"}
:http-defaults {:connection-timeout 10000
:request-timeout 10000
:max-connections 2000}
:user-service {:url “http://user-service”
:connection-timeout 1000}}
apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave
interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all
partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take-
nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge
merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index
{:id :string
:name :string
:deposits [{:id :string
:amount :int
:timestamp :long}]}
apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave
interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all
partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take-
nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge
merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index
•Business logic
•Infrastructure code
•Configuration
•Reflection/Metadata
apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave
interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all
partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take-
nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge
merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index
Dynamic (vs Static)
development
REPL
https://danlebrero.com/repl
Lisp (vs Fortan)
Java with a Clojure mindset
Java with a Clojure mindset
Java with a Clojure mindset
Java with a Clojure mindset
.filter(removeCsvHeaders(firstHeader))
.map(splitCsvString())
.map(convertCsvToMap(csvHeaders))
.map(convertToJson(eventCreator))
(filter not-header?)
(map parse-csv-line)
(map (partial zipmap headers))
(map ->event)
1
2 3 4
5 6
7
8
9 10
11
12
13 14 15 16
1 2
3 4
87
65
9 10
-
40%!!
Java with a Clojure mindset
List.of(
new Symbol("defn"),
new Symbol("plus-one"),
List.of(
new Symbol("a"),
new Symbol("b")),
Map.of(
new Keyword("time"), List.of(new Symbol("System/currentTimeMillis")),
new Keyword("result"), List.of(
new Symbol("+"),
new Symbol("a"),
new Symbol("b"),
new Long(1))));
List.of(
new Symbol("defn"),
new Symbol("plus-one"),
List.of(
new Symbol("a"),
new Symbol("b")),
Map.of(
new Keyword("time"), List.of(new Symbol("System/currentTimeMillis")),
new Keyword("result"), List.of(
new Symbol("+"),
new Symbol("a"),
new Symbol("b"),
new Long(1))));
apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave
interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all
partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take-
nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge
merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index
Summary
Imperative
Shell
Function
al Core
DYNAMIC STATIC
TYPES
DYNAMIC
STATIC
DEVELOPMENT
Java with a Clojure mindset
“A language that doesn’t affect the way you
think about programming, is not worth knowing.”
― Alan Perlis
Java with a Clojure mindset
Java with a Clojure mindset
Java with a Clojure mindset
@DanLebrero
dlebrero@gmail.com
danlebrero.com
@Akvo
https://akvo.org/
Java with a Clojure mindset
Come to ClojureCooomeeeee…Clojure is your friendClojure is happinessClojure is beauty

More Related Content

PDF
Clojure ♥ cassandra
PDF
Java Concurrency Idioms
PDF
durability, durability, durability
PDF
Coroutines in Kotlin. UA Mobile 2017.
PDF
Actor Concurrency
PDF
Coroutines in Kotlin
PDF
03 - Qt UI Development
PPTX
Grand Central Dispatch in Objective-C
Clojure ♥ cassandra
Java Concurrency Idioms
durability, durability, durability
Coroutines in Kotlin. UA Mobile 2017.
Actor Concurrency
Coroutines in Kotlin
03 - Qt UI Development
Grand Central Dispatch in Objective-C

What's hot (20)

PDF
02 - Basics of Qt
PDF
Counter Wars (JEEConf 2016)
PDF
Java Concurrency Gotchas
PDF
Dynamo: Not Just For Datastores
PDF
От Java Threads к лямбдам, Андрей Родионов
PDF
Python Asíncrono - Async Python
PDF
Cascadia.js: Don't Cross the Streams
PDF
Circuit breaker
PDF
Compose Async with RxJS
PDF
Csw2016 gong pwn_a_nexus_device_with_a_single_vulnerability
PDF
Think Async: Asynchronous Patterns in NodeJS
PDF
Новый InterSystems: open-source, митапы, хакатоны
PDF
Multithreading done right
PDF
Guaranteeing Memory Safety in Rust
PDF
Qt Network Explained (Portuguese)
PPTX
System Calls
PDF
Java Concurrency Gotchas
PDF
Rust tutorial from Boston Meetup 2015-07-22
PDF
Csw2016 gawlik bypassing_differentdefenseschemes
02 - Basics of Qt
Counter Wars (JEEConf 2016)
Java Concurrency Gotchas
Dynamo: Not Just For Datastores
От Java Threads к лямбдам, Андрей Родионов
Python Asíncrono - Async Python
Cascadia.js: Don't Cross the Streams
Circuit breaker
Compose Async with RxJS
Csw2016 gong pwn_a_nexus_device_with_a_single_vulnerability
Think Async: Asynchronous Patterns in NodeJS
Новый InterSystems: open-source, митапы, хакатоны
Multithreading done right
Guaranteeing Memory Safety in Rust
Qt Network Explained (Portuguese)
System Calls
Java Concurrency Gotchas
Rust tutorial from Boston Meetup 2015-07-22
Csw2016 gawlik bypassing_differentdefenseschemes
Ad

Similar to Java with a Clojure mindset (20)

PDF
Project "Babelfish" - A data warehouse to attack complexity
ODP
Intravert Server side processing for Cassandra
ODP
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"
ODP
Clojure: Practical functional approach on JVM
PDF
Pune Clojure Course Outline
PDF
Solid And Sustainable Development in Scala
PDF
Naked Performance With Clojure
PDF
Groovy On Trading Desk (2010)
PDF
Solid and Sustainable Development in Scala
PDF
Kafka Summit SF 2017 - Building Stateful Financial Applications with Kafka St...
PDF
NoSQL overview #phptostart turin 11.07.2011
PDF
Overview of Grails Object Relational Mapping (GORM)
ODP
Buenos Aires Drools Expert Presentation
KEY
Active Record Query Interface (1), Season 2
PPT
NOSQL and Cassandra
PPTX
MongoDB Use Cases: Healthcare, CMS, Analytics
PPT
Architecture | Busy Java Developers Guide to NoSQL | Ted Neward
PDF
Java 8 - functional features
PDF
NYC Cassandra Day - Java Intro
PDF
Clojure: Functional Concurrency for the JVM (presented at OSCON)
Project "Babelfish" - A data warehouse to attack complexity
Intravert Server side processing for Cassandra
NYC* 2013 - "Advanced Data Processing: Beyond Queries and Slices"
Clojure: Practical functional approach on JVM
Pune Clojure Course Outline
Solid And Sustainable Development in Scala
Naked Performance With Clojure
Groovy On Trading Desk (2010)
Solid and Sustainable Development in Scala
Kafka Summit SF 2017 - Building Stateful Financial Applications with Kafka St...
NoSQL overview #phptostart turin 11.07.2011
Overview of Grails Object Relational Mapping (GORM)
Buenos Aires Drools Expert Presentation
Active Record Query Interface (1), Season 2
NOSQL and Cassandra
MongoDB Use Cases: Healthcare, CMS, Analytics
Architecture | Busy Java Developers Guide to NoSQL | Ted Neward
Java 8 - functional features
NYC Cassandra Day - Java Intro
Clojure: Functional Concurrency for the JVM (presented at OSCON)
Ad

Recently uploaded (20)

PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Encapsulation theory and applications.pdf
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
cuic standard and advanced reporting.pdf
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
20250228 LYD VKU AI Blended-Learning.pptx
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
Dropbox Q2 2025 Financial Results & Investor Presentation
Building Integrated photovoltaic BIPV_UPV.pdf
Encapsulation theory and applications.pdf
Network Security Unit 5.pdf for BCA BBA.
Reach Out and Touch Someone: Haptics and Empathic Computing
Spectral efficient network and resource selection model in 5G networks
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
cuic standard and advanced reporting.pdf
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
NewMind AI Weekly Chronicles - August'25 Week I
Chapter 3 Spatial Domain Image Processing.pdf
Per capita expenditure prediction using model stacking based on satellite ima...
Programs and apps: productivity, graphics, security and other tools
MIND Revenue Release Quarter 2 2025 Press Release
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf

Java with a Clojure mindset

  • 1. Java, with a Clojure mindset @DanLebrero www.akvo.org
  • 13. Give 10$ free cash if client makes 1000 bets in less than 1 week
  • 17. “Programmers are constantly in maintenance mode.” ― The Pragmatic Programmer
  • 20. Side effects are the enemy
  • 22. State
  • 25. Atom Thread-1 Thread-2 fn2( ) = fn1( ) = ====fn2( ) = ==? ==? ==?
  • 29. “Is this thread safe?” ― Every Java developer, every day.
  • 30. 1. State is consistent 2. Function must be pure 3. Only safe within the pure function
  • 31. public class ClientBonus { private final Client client; private final Bonus bonus; private final DepositList deposits; …
  • 33. public interface ConcurrentMap<…> extends Map<…> { V compute(K key, BiFunction<…> remappingFunction) V computeIfAbsent(K key, Function<…> mappingFunction) V computeIfPresent(K key, BiFunction<…> remappingFunction) … }
  • 34. public class TheStateHolder { private final Map<Long, ClientBonus> state = new ConcurrentHashMap<>(); public ClientBonus nextState(Long client, Bet bet) { return state.computeIfPresent( client, (k, currentState) -> currentState.nextState(bet)); }
  • 35. public class ClientBonus { private final Client client; private final Bonus bonus; private final DepositList deposits; public ClientBonus nextState(Bet bet) { ... } …
  • 38. public class ClientBonus { private final Client client; private final Bonus bonus; private final DepositList deposits; public ClientBonus nextState(Bet bet) { ... } …
  • 39. public class ClientBonus { private final Client client; private final Bonus bonus; private final DepositList deposits; public Pair<ClientBonus,Effects> next(Bet bet) { ... } …
  • 46. public interface Effect { void run(AllDependencies dependencies); }
  • 47. Pair<ClientBonus, Effects> pair = theStateHolder.nextState(bet); pair.effects.run(dependencies);
  • 48. Pair<ClientBonus, Effects> pair = theStateHolder.nextState(bet); pair.effects.run(dependencies); “Is this thread safe?”
  • 49. Thread-1 Thread-2 Pair<> pair = theStateHolder.nextState(bet); Pair<> pair = theStateHolder.nextState(bet); pair.effects.run(dependencies); pair.effects.run(dependencies);
  • 50. Pair<> pair = theStateHolder.nextState(bet); Pair<> pair = theStateHolder.nextState(bet); pair.effects.run(dependencies); pair.effects.run(dependencies); Thread-1 Thread-1 Thread-2 Thread-2
  • 53. Can I pay?Can I pay? ACID Can I pay?
  • 60. public class KafkaConsumer { private AllDependencies allDependencies; private TheStateHolder theStateHolder; public void run() { while (!stop) { Bet bet = readNext(); Effects effects = theStateHolder.event(bet); effects.run(allDependencies); } } … }
  • 61. public class KafkaConsumer { private AllDependencies allDependencies; private TheStateHolder theStateHolder; public void run() { while (!stop) { Bet bet = readNext(); Effects effects = theStateHolder.event(bet); effects.run(allDependencies); } } … }
  • 62. public class KafkaConsumer { private AllDependencies allDependencies; private TheStateHolder theStateHolder; public void run() { while (!stop) { Bet bet = readNext(); Effects effects = theStateHolder.event(bet); effects.run(allDependencies); } } … }
  • 63. public class KafkaConsumer { private AllDependencies allDependencies; private TheStateHolder theStateHolder; public void run() { while (!stop) { Bet bet = readNext(); Effects effects = theStateHolder.event(bet); effects.run(allDependencies); } } … }
  • 64. public class KafkaConsumer { private AllDependencies allDependencies; private TheStateHolder theStateHolder; public void run() { while (!stop) { Bet bet = readNext(); Effects effects = theStateHolder.event(bet); effects.run(allDependencies); } } … }
  • 65. •No getters •No locks or synch blocks •No try/catch •No logging •No mocks •No useless interfaces
  • 69. clientBonus = Map.of( "client", Map.of("id", "123233"), "deposits", List.of( Map.of("amount", 3, "type", "CASH"), Map.of("amount", 234, "type", "CARD"))); ((List) clientBonus.get("deposits")) .stream() .collect( Collectors.summarizingInt( m -> (int) ((Map) m).get("amount")));
  • 71. public class Bet { private String id; private int amount; private long timestamp; }
  • 72. “It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures.” ― Alan Perlis
  • 73. {:type :bet :id "client1" :amount 23 :timestamp 123312321323}
  • 74. apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take- nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index {:type :bet :id "client1" :amount 23 :timestamp 123312321323}
  • 75. {:request-method :get :uri “/foobaz" :query-params {"somekey" “somevalue"} :headers {"accept-encoding" "gzip, deflate" "connection" "close"} :body nil :scheme :http :content-length 0 :server-port 8080 :server-name “localhost"} apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take- nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index
  • 76. {:status 200 :headers {"Content-Type" "text/html"} :body "Hello World"}} apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take- nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index
  • 77. {:select [:id :client :amount] :from [:transactions] :where [:= :client "a"]} apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take- nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index
  • 78. [{:id 1 :client 32 :amount 3} {:id 2 :client 87 :amount 7} {:id 3 :client 32 :amount 4} {:id 4 :client 40 :amount 6}] apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take- nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index
  • 79. [:html [:body [:p "Count: 4"] [:p "Total: 20"]]] apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take- nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index
  • 80. {:web-server {:listen 8080} :db-config {:host "xxxx" :user "xxxx" :password "xxxx"} :http-defaults {:connection-timeout 10000 :request-timeout 10000 :max-connections 2000} :user-service {:url “http://user-service” :connection-timeout 1000}} apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take- nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index
  • 81. {:id :string :name :string :deposits [{:id :string :amount :int :timestamp :long}]} apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take- nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index
  • 82. •Business logic •Infrastructure code •Configuration •Reflection/Metadata apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take- nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index
  • 84. REPL
  • 93. List.of( new Symbol("defn"), new Symbol("plus-one"), List.of( new Symbol("a"), new Symbol("b")), Map.of( new Keyword("time"), List.of(new Symbol("System/currentTimeMillis")), new Keyword("result"), List.of( new Symbol("+"), new Symbol("a"), new Symbol("b"), new Long(1))));
  • 94. List.of( new Symbol("defn"), new Symbol("plus-one"), List.of( new Symbol("a"), new Symbol("b")), Map.of( new Keyword("time"), List.of(new Symbol("System/currentTimeMillis")), new Keyword("result"), List.of( new Symbol("+"), new Symbol("a"), new Symbol("b"), new Long(1)))); apply butlast concat cons count cycle diff distinct distinct? drop drop-last drop-while empty empty? every? ffirst filter first flatten fnext for frequencies group-by interleave interpose into into-array keep keep-indexed last lazy-cat map map-indexed mapcat next nfirst nnext not-any? not-empty not-every? nth nthnext partition partition-all partition-by pmap postwalk prewalk rand-nth reduce reductions remove replace rest reverse second seq? seque set shuffle some sort sort-by split-at split-with take take- nth take-while to-array-2d vec walk when-first assoc pop subvec replace conj rseq update-in update get get-in contains? find keys vals assoc assoc-in dissoc merge merge-with select-keys update-in update rename-keys map-invert reduce-kv dissoc-in disj join select project union difference intersection index
  • 100. “A language that doesn’t affect the way you think about programming, is not worth knowing.” ― Alan Perlis
  • 106. Come to ClojureCooomeeeee…Clojure is your friendClojure is happinessClojure is beauty