- Basics: BEAM Ecosystem and Erlang Programming Language
- Functional Programming: How Make your code Beautiful
- Concurrency: You need to be concurrent to survive in the parallel world
- Fault Tolerance: Keep calm and let it crash
- Soft Real-time: Accept the reality, be real, be yourself
- Software Architecture: How to look nice in a bigger picture
3. Basics -> BEAM Ecosystem
BEAM
BEAM is the virtual machine at the core of
the Erlang Open Telecom Platform (OTP). It
compiles Erlang source code into bytecode,
which is then executed on the BEAM.
OTP
OTP is a collection of useful middleware,
libraries, and tools written in the Erlang
programming language. It is an integral part
of the open-source distribution of Erlang.
5. Basics -> Syntax
partition([], _, [], []).
partition([X|Xs], Pivot, Smalls, Bigs) :-
( X @< Pivot ->
Smalls = [X|Rest],
partition(Xs, Pivot, Rest, Bigs)
; Bigs = [X|Rest],
partition(Xs, Pivot, Smalls, Rest)
).
quicksort([]) --> [].
quicksort([X|Xs]) -->
{ partition(Xs, X, Smaller, Bigger) },
quicksort(Smaller), [X], quicksort(Bigger).
partition(_, [], {L, E, G}) ->
{L, E, G};
partition(Pivot, [H|List], {L, E, G}) when Pivot > H ->
partition(Pivot, List, {[H|L], E, G});
partition(Pivot, [H|List], {L, E, G}) when Pivot < H ->
partition(Pivot, List, {L, E, [H|G]});
partition(Pivot, [H|List], {L, E, G}) when Pivot == H ->
partition(Pivot, List, {L, [H|E], G}).
quicksort([]) -> [];
quicksort([H|_] = List) ->
{L, E, G} = partition(H, List, {[], [], []}),
quicksort(L) ++ E ++ quicksort(G).
function() -> expression, expression; expression, expression, etc.
-> , ; , , .
?
?
6. Basics -> Syntax
partition([], _, [], []).
partition([X|Xs], Pivot, Smalls, Bigs) :-
( X @< Pivot ->
Smalls = [X|Rest],
partition(Xs, Pivot, Rest, Bigs)
; Bigs = [X|Rest],
partition(Xs, Pivot, Smalls, Rest)
).
quicksort([]) --> [].
quicksort([X|Xs]) -->
{ partition(Xs, X, Smaller, Bigger) },
quicksort(Smaller), [X], quicksort(Bigger).
partition(_, [], {L, E, G}) ->
{L, E, G};
partition(Pivot, [H|List], {L, E, G}) when Pivot > H ->
partition(Pivot, List, {[H|L], E, G});
partition(Pivot, [H|List], {L, E, G}) when Pivot < H ->
partition(Pivot, List, {L, E, [H|G]});
partition(Pivot, [H|List], {L, E, G}) when Pivot == H ->
partition(Pivot, List, {L, [H|E], G}).
quicksort([]) -> [];
quicksort([H|_] = List) ->
{L, E, G} = partition(H, List, {[], [], []}),
quicksort(L) ++ E ++ quicksort(G).
function() -> expression, expression; expression, expression, etc.
-> , ; , , .
7. Basics -> Shell
In Erlang, you can test most of your stuff in an emulator; it will run your scripts when
compiled and deployed, but it will also let you edit stuff live.
$ erl
Erlang/OTP 25 [erts-13.2] [source] [64-bit] [smp:8:8] [ds:8:8:10]
[async-threads:1] [jit] [dtrace]
Eshell V13.2 (abort with ^G)
1>
User switch command
--> h
c [nn] - connect to job
i [nn] - interrupt job
k [nn] - kill job
j - list all jobs
s [shell] - start local shell
r [node [shell]] - start remote shell
q - quit erlang
-->
8. Basics -> Shell Commands
> help().
** shell internal commands **
b() -- display all variable bindings
f() -- forget all variable bindings
h() -- history
history(N) -- set how many previous commands to keep
v(N) -- use the value of query <N>
c(Mod) -- compile and load module or file <Mod>
cd(Dir) -- change working directory
flush() -- flush any messages sent to the shell
h(M,F,A) -- module function arity documentation
ls() -- list files in the current directory
pwd() -- print working directory
q() -- quit - shorthand for init:stop()
...
9. Basics -> Numbers
1> 2 + 15.
17
2> 49 * 100.
4900
3> 1892 - 1472.
420
4> 5 / 2.
2.5
5> 5 div 2.
2
6> 5 rem 2.
1
Integers and floating values are
pretty much the only types of data
Erlang's mathematical operators
will handle transparently for you.
10. Basics -> Invariable Variables
1> One.
* 1: variable 'One' is unbound
2> One = 1.
1
3> Un = Uno = One = 1.
1
4> Two = One + One.
2
5> Two = 2.
2
6> Two = Two + 1.
** exception error: no match of right hand side value 3
7> two = 2.
** exception error: no match of right hand side value 2
There are no variables
in Erlang.
There are Dummy
Variables which can
take matching values in
functions. Once
matched, their values
do not change.
Variables in Erlang
must start with a
Capital letter.
11. Basics -> Atoms
Atoms are literals, constants with their own name for
value.
What you see is what you get and don't expect more.
The atom cat means "cat" and that's it. You can't
play with it, you can't change it, you can't smash it
to pieces;
it's cat. Deal with it.
1> atom.
atom
2> atoms_rule.
atoms_rule
3> atoms_rule@erlang.
atoms_rule@erlang
4> 'Atoms can be cheated!'.
'Atoms can be cheated!'
5> atom = 'atom'.
atom
12. Basics -> Boolean
Boolean algebra
is
dead simple
like itâs creator
1> true and false.
false
2> false or true.
true
3> true xor false.
true
4> not false.
true
5> not (true and true).
false
6> 5 =:= 5.
true
7> 1 =:= 0.
false
8> 1 =/= 0.
true
9> 5 =:= 5.0.
false
10> 5 == 5.0.
true
11> 5 /= 5.0.
false
13. Basics -> Tuples
A tuple is a way to organize data. It's a way to
group together many terms when you know how many
there are.
1> X = 10, Y = 4.
4
2> Point = {X,Y}.
{10,4}
3> Point = {4,5}.
{4,5}
4> Coordinates = {3,4,1}.
{3,4,1}
14. Basics -> Lists
Lists are the bread and butter of many
functional languages.
They're used to solve all kinds of problems and
are undoubtedly the most used data structure in
Erlang.
Lists can contain anything!
String is a list of character numbers.
1> [1, 2, {numbers,[3,4]}, 6.7].
[1,2,{numbers,[3,4]},6.7]
2> [97, 98, 99].
"abc"
3> [97,98,99,4,5,6].
[97,98,99,4,5,6]
4> [233].
"ĂŠ"
5> "diginext".
"diginext"
15. Basics -> Listâs head and tail
The first element of a list is named the Head,
and the rest of the list is named the Tail.
We will use hd/1 and tl/1 built-in functions
to get them.
Accessing or adding the head is fast and
efficient.
There is a nicer way to separate the head from
the tail of a list with the help of pattern
matching: [Head|Tail].
1> hd([1,2,3,4]).
1
2> tl([1,2,3,4]).
[2,3,4]
3> [Head|Tail] = [1,2,3,4].
[1,2,3,4]
4> {Head, Tail}.
{1, [2,3,4]}
16. Basics -> Pattern Matching
Every assignment is just a pattern-matching!
With pattern-matching, Erlang saves you a whole lot of boilerplate code.
The anonymous variable is denoted by underscore (_) and can be used when a
variable is required but its value can be ignored.
1> User = {"Hamidreza", male, 36}.
{"Hamidreza", male, 36}
2> {_, Gender, Age} = User.
{"Hamidreza", male, 36}
3> Age.
36
4> Gender.
male
17. Basics -> Functions
A function declaration is a sequence of function clauses separated by semicolons,
and terminated by period.
It consists of a clause head and a clause body, separated by ->.
function greet(Gender, Name) {
if (Gender == male) {
print("Hello, Mr. %s!", Name)
} else if (Gender == female) {
print("Hello, Mrs. %s!", Name)
} else {
print("Hello, %s!", Name)
}
}
greet(male, Name) ->
io:format("Hello, Mr. ~s!", [Name]);
greet(female, Name) ->
io:format("Hello, Mrs. ~s!", [Name]);
greet(_, Name) ->
io:format("Hello, ~s!", [Name]).
18. Basics -> Modules
Working with the interactive shell is often considered a vital part of using
dynamic programming languages. But code needs to be saved somewhere to be used!
This is what modules are for. Modules are a bunch of functions regrouped in a
single file, under a single name.
-module(useless).
-export([add/2, hello/0, greet_and_add_two/1]).
add(A, B) -> A + B.
%% This is comment
hello() -> io:format("Hello, world!~n").
greet_and_add_two(X) ->
hello(),
add(X, 2).
21. Functional Programming -> Paradigms
As the name suggests is a type of programming paradigm that describes how
the program executes. Developers are more concerned with how to get an
answer step by step. It comprises the sequence of command imperatives.
Itâs sub-paradigms are:
- Procedural Programming (e.g., Fortran, COBOL, Pascal, C)
- Object-oriented programming (C++, Java, Python, Ruby)
Imperative Programming
Imperative Programming is like saying What To Do!
22. Functional Programming -> Paradigms
As the name suggests is a type of programming paradigm that describes what
programs to be executed. Developers are more concerned with the final
answer that is received. It declares what kind of results we want and
leave programming language aside focusing on simply figuring out how to
produce them. In simple words, it mainly focuses on end result.
Itâs sub-paradigms are:
- Logic Programming (e.g., Prolog, Oz, Datalog)
- Functional programming (e.g., Erlang, Haskell, Lisp, Clojure)
- Query Languages (e.g., SQL, GraphQL, CQL)
Declarative Programming
Declarative Programming is like saying What You Want!
23. Functional Programming -> Paradigms
using std::vector;
vector< int > numbers;
for ( int i = -10; i <= 10; ++i ) {
numbers.push_back( i );
}
vector< int > positive_numbers;
for ( vector< int >::const_iterator it = numbers.begin(),
end = numbers.end();
it != end; ++it
) {
if ( number > 0 ) {
positive_numbers.push_back( *it );
}
}
SELECT *
INTO positive_numbers
FROM numbers
WHERE num > 0
24. Functional Programming -> Paradigms
public static <E extends Comparable<? super E>> List<E> quickSort(List<E>
arr) {
if (arr.isEmpty())
return arr;
else {
E pivot = arr.get(0);
List<E> less = new LinkedList<E>();
List<E> pivotList = new LinkedList<E>();
List<E> more = new LinkedList<E>();
// Partition
for (E i: arr) {
if (i.compareTo(pivot) < 0)
less.add(i);
else if (i.compareTo(pivot) > 0)
more.add(i);
else
pivotList.add(i);
}
// Recursively sort sublists
less = quickSort(less);
more = quickSort(more);
// Concatenate results
less.addAll(pivotList);
less.addAll(more);
return less;
}
}
quicksort([]) -> [];
quicksort([X|Xs]) ->
quicksort([ Y || Y <- Xs, Y < X])
++ [X] ++
quicksort([ Y || Y <- Xs, Y >= X]).
26. Functional Programming -> Immutability
The literal meaning of Immutability is unable to change.
Pros:
- Avoiding data races
- Reducing synchronization overhead
- Enabling parallelism
Cons:
- Increasing memory usage (which can be solved)
- Optimizing memory allocation
- Choosing the right data structure
27. Functional Programming -> Immutability
def factorial(n: Int): Int = {
var i = n
var f = 1
while (i > 0) {
f = f * i
i = i - 1
}
return f
}
def factorial(n: Int): Int = {
if (n <= 0)
return 1
else
return n * factorial(n - 1)
}
How can we program without a variable?
Mutable Immutable
28. Functional Programming -> Immutability
Sir Charles Antony Richard Hoare is a
British computer scientist who has made
foundational contributions to programming
languages, algorithms, operating systems,
formal verification, and concurrent
computing.
29. Functional Programming -> Immutability
Sir Charles Antony Richard Hoare is a
British computer scientist who has made
foundational contributions to programming
languages, algorithms, operating systems,
formal verification, and concurrent
computing.
But,
he is also the inventor of null.
30. Functional Programming -> Immutability
Speaking at a software conference in 2009, Tony Hoare apologized for
inventing the null reference:
âI call it my billion-dollar mistake. It
was the invention of the null reference in
1965. My goal was to ensure that all use
of references should be absolutely safe,
with checking performed automatically by
the compiler. But I couldn't resist the
temptation to put in a null reference,
simply because it was so easy to
implement. This has led to innumerable
errors, vulnerabilities, and system
crashes, which have probably caused a
billion dollars of pain and damage in the
last forty years.â
Tony Hoare (right) as an exchange student at Moscow
State University, 1960
31. Functional Programming -> Immutability
In the Functional Programming world, we create values when initializing.
So, there is no null value
Which makes the code
- Safer
- Easier to read
- Easier to debug
- And more beautiful!
33. Functional P. -> Referential Transparency
In computer science, a called referentially transparent expression must be
the same for the same inputs and its evaluation must have no side effects.
34. Functional P. -> Referential Transparency
What is side-effect in your code?
35. Functional P. -> Referential Transparency
How side-effect looks in your code?
36. Functional P. -> Referential Transparency
What is side-effect in your application?
37. Functional P. -> Referential Transparency
In contrast, object oriented programs create a huge dependency as a result
of adding abstraction on top of abstraction to modularize complex systems.
When the submodules try to access the global state simultaneously,
complexity arises.
38. Functional P. -> Referential Transparency
With side effects:
â Side effects are natural for code that interacts with outside.
â They make many algorithms simple to implement.
Without side effects:
â It is easy to parallelize.
â It is easy to read.
â It is easy to mock and test.
â It is easy to prove correct.
39. Functional P. -> Referential Transparency
To avoid using side effects, you need to implement
loops by recursion, thus your programming language
implementation needs tail call optimization.
42. Functional P. -> Programming Languages
Why Erlang for this workshop?
- It is a programming language invented by industry
(Ericsson AB).
- Erlang's motivation is seen as purely practical.
- Erlang is purpose-built for writing distributed
services, and it has a lot of great engineering behind
it.
44. Concurrency -> Story
Back in the day at Ericsson in 1980s, Erlang's development as a
language was extremely quick with frequent feedback from
engineers working on telephone switches in Erlang itself.
These interactions proved processes-based concurrency and
asynchronous message passing to be a good way to model the
problems they faced.
This was latter figured to be the Actor Model concurrency.
Moreover, the telephony world already had a certain culture going
towards concurrency before Erlang came to be. This was inherited
from PLEX, a language created earlier at Ericsson, and AXE, a
switch developed with it.
Erlang followed this tendency and attempted to improve on
previous tools available.
45. Concurrency -> Story
Letâs watch
âErlang the Movieâ
to get some of the
history behind!
00:00 - 05:30
of Youtube Link
46. Concurrency -> Actors
This story would not be complete if it wouldn't show the
three primitives required for concurrency in Erlang:
1) Spawning new processes
2) Sending messages
3) Receiving messages
47. Concurrency -> Spawning actors
Actor == Process
1> ProcessFun = fun() -> 2 + 2 end.
#Fun<erl_eval.20.67289768>
2> ProcessPid = spawn(ProcessFun).
<0.44.0>
3> spawn(fun() -> io:format("~p~n", [2 + 2]) end).
4
<0.46.0>
4> spawn(fun() -> timer:sleep(10000), io:format("~p~n", [2 + 2]) end).
<0.48.0>
... after 10 seconds ...
4
Erlang is designed for massive concurrency, so its processes are lightweight
with small memory footprint, fast to create and terminate, and the
scheduling overhead is low.
48. Concurrency -> Sending messages
6> self().
<0.41.0>
7> exit(self()).
** exception exit: <0.41.0>
8> self().
<0.285.0>
9> self() ! hello.
hello
11> flush().
Shell got hello
Shell got double
ok
The next primitive required to do message passing is the operator â!â, also
known as the bang symbol.
49. Concurrency -> Receiving messages
-module(dolphins).
-export([dolphin/0]).
dolphin() ->
receive
do_a_flip ->
io:format("How about no?~n");
fish ->
io:format("So long and thanks for the fish!~n");
_ ->
io:format("Heh, we're smarter than you humans.~n")
end.
Sending messages that nobody will read is super sad! This is why we need the
receive statement.
51. Fault Tolerance -> Story
Letâs get back to
the movie when
Mike canât call
Joe.
05:30 - 10:30
of Youtube Link
52. Fault Tolerance -> Background
Some facts:
1) Hardware can be damaged
2) Network can be unreliable
3) The software can have bugs
4) Last but not least, programmers make mistakes!
So, instead of denying the reality, we should acknowledge
it and try to find a way out to have reliable systems.
53. Fault Tolerance -> Philosophy
This is also a coding philosophy for Erlang Language.
The view is that you don't need to program defensively. If
there are any errors, the process is automatically
terminated, and this is reported to any processes that were
monitoring the crashed process.
It is possible because the processes are lightweight.
It is called corrective programming, where you donât waste
resources to catch the exceptions and resolve it.
55. Fault Tolerance -> Supervisors
Supervisors are also actors. They can
supervise other actors (workers) and other
supervisors. They know if their workers are
working correctly, otherwise acts based on
their strategy.
57. Fault Tolerance -> Principles
- Code for the happy path
Focus on what your code should do in the successful case. Code that first and only
if necessary deal with some of the unhappy paths.
- Donât catch exceptions you canât handle properly
Never catch exceptions when you donât know how to remedy them in the current
context. Trying to work around something you canât remedy can often lead to other
problems and make things worse at inopportune times.
- Software should fail loudly
The worst thing software can do when encountering a fault is to continue silently.
Unexpected faults should result in verbose exceptions that get logged and reported
to an error tracking system.
58. Fault Tolerance -> Benefits
- Less code
Less code means less work and fewer places for bugs to hide. Error handling code is
seldom used and often contains bugs of its own due to being poorly tested.
- Less work
Faster development in the short term. More predictable program behavior in the long
term. Programs that simply crash when a fault is encountered are predictable.
- Reduced coupling
Catching a specific exceptions is connascence of name. When you have a lot of
exceptions that you are catching by name, your exception handling code is coupled to
the code that raises the exceptions. If the code raising the exceptions changes you
may have to change your exception handling code as well.
- Clarity
Smaller programs are easier to understand, and the code more clearly indicate the
programmer intent - unexpected faults are not handled by the code.
- Better performance
An uncaught exception is going to terminate the program or process almost
immediately. Custom exception handling logic will use additional CPU cycles.
60. Time indicates that the correctness of the system
depends not only on the logical result of the
computation but also on the time at which the results
are produced.
Real indicates that the reaction of the systems to
external events must occur during their evolution.
62. Hard Real-time
Missing a deadline is a
total system failure.
The world's ďŹrst wearable,
battery-powered, transistorized cardiac
pacemaker which was made in late 1957
at the University of Minnesota.
63. Soft Real-time
Missing a deadline is
NOT a system failure,
but degrades the total
quality of service.
Zidaneâs penalty in ďŹnal
match of World Cup 2006.
64. âWeb usersâ tolerable waiting time is
approximately 2 seconds.â
- Behavior and Information Technology (2004) Journal
65. âIn order to meet response times, it is
necessary for a system to be
predictableâ
- Real-time System and Programming Languages, 3rd Edition
66. âThe main difference between a real-time
and a non-real-time task is that a
real-time task is characterized by a
deadlineâ
- Hard Real-time Computing Systems, 1st Edition, Giorgio C. Buttazzo
67. select
accept awake_driver do
keep_running
end;
or
delay 3000.0
stop_the_train;
end select
driver ! awake,
receive
accepted ->
keep_running()
after 3000 ->
stop_the_train;
end
Ada Tasks run
concurrently and use
rendezvous for
communication.
Erlang Processes run
concurrently and use
message passing for
communication.
Deadline as a Primitive in Real-time Languages
68. The Memory Layout, Garbage Collection, and
Scheduling of BEAM make it responsive and
predictable, even under peak time.
70. - Data in private heap are divided into young and old
- Young generation are newly generated data
- Old generation are the ones who survived a GC cycle
- Generational GC (Minor) collects young generation
- Full Sweep GC (Major) collects old generation
- GC occurs when the heap grows more than min_heap_size
- GC is per process and independent
- It does not stop the world!
Private Heap GC
71. - Reference Counting Collection
- Collects Refc when the counter reaches zero
- Cheap, so causes short pauses
- It reduces IO of passing large messages
- Its speed comes at cost and challenge
Shared Heap GC
72. - Maximizes throughput and fairness
- Minimizes response time and latency
Real-time Scheduling
73. Preemptive scheduler does context
switching among running tasks.
It preempts and resumes tasks
without their cooperation.
Cooperative scheduler needs tasksâ
cooperation for context switching.
It lets them voluntarily release the
control back.
Process 1 Process 2
run
run
run
run
run
switch
switch
switch
switch
preempt
preempt
preempt
Process 1 Process 2
run
run
run
switch
switch
release
release
74. Cooperative Scheduling system cannot satisfy a real-time system
because a running task in such system might never return control back or
returns late after a deadline. So real-time systems commonly use
Preemptive Scheduling.
- Erlang Scheduler is Preemptive like Linux
- It is responsible for Code Execution
- Also, Garbage Collection and Memory Management
75. Priority is the main factor of
selecting a process for execution.
Reduction is the main factor of
preempting a process execution.
The reduction is a counter per process that is normally incremented by one for each function call. It is used
for preempting processes and context switching them when the counter of a process reaches the maximum
number of reductions. For example in Erlang/OTP R12B this maximum number was 2000 reductions.
1> process_info(PID, priority).
{priority, process_priority()}
2> process_flag(priority, process_priority()).
low | normal | high | max
3> process_info(PID, reductions).
{reductions, integer()}
76. Scheduling Before R11B
One Scheduler, One Run Queue
No SMP
Scheduling In R11B and R12B
Many Schedulers, One Run Queue
SMP Support
77. Run Queues hold the processesâ tasks which
are ready for execution before picking them by
schedulers.
1> statistics(run_queue).
integer()
2> statistics(schedulers_online).
integer().
78. Scheduling After R13B
Many Schedulers, Many Run Queue
SMP Support
Migration Logic tries to control and
balance run queues based on the
statistics that collects from the system.
However we should not depend on the
scheduling to remain exactly as it is today,
because it is likely to be changed in future
releases in order to get better.
79. How scheduler works under peak
%% Everything is clean and ready
1> statistics(online_schedulers). %% => 4
2> statistics(run_queue). %% => 0
%% Spawn 10 heavy number crunching processes concurrently
3> [spawn(fun() -> calc:prime_numbers(10000000) end) || _ <- lists:seq(1, 10)].
%% Run queues have remaining tasks to do
4> statistics(run_queue). %% => 8
%% Itis still responsive, great!
5> calc:prime_numbers(10). %% => [2, 3, 5, 7]
%% Wait a moment
6> statistics(run_queue). %% => 4
%% Wait a moment
6> statistics(run_queue). %% => 0
Scheduler doesnât let those heavy
processes chew all the runtime out
without letting other light but likely
important processes to execute.
81. S. Architecture -> What is it?
Software Architecture is an ambiguous term
which not only relates to the discipline of
software architecture itself, but also
structure and connections between
components.
82. S. Architecture -> What is it?
"We are still far from having a
well-accepted taxonomy of such architectural
paradigms, let alone a fully-developed
theory of software architecture. But we can
now clearly identify a number of
architectural patterns, or styles, that
currently form the basics of a software
architect."
â David Garlan in An introduction to software architecture book
83. S. Architecture -> Architectural Patterns
â Monolithic
â Multitier
â Micro-services
â Event-driven
â Domain-driven design
â Representational state transfer
â Component-based
â Asynchronous messaging
â Microkernel
â Database-centric
â Modelâviewâcontroller
â Publish-subscribe
â Client-server
â Peer-to-peer
etc.
84. S. Architecture -> Monolith
Monolithic applications are analogous to monoliths such
as Uluru, Australia: a large single (mono) rock (lith)
It is a single, unified,
self-contained and independent
architectural pattern, but
typically lacks flexibility.
Alternatives:
- Multi-tier
- Microservices
- Event-driven
85. S. Architecture -> Multi-tier
Overview of a three-tier application
It is a clientâserver
architecture which separates
everything into layers.
The most widespread use of it
is the 3-tier which includes
presentation, logic and data.
The Three-tier architecture is
not inherently flawed; it is
just out of date. Its drawbacks
derive from the fact that the
application is written as
single, unified code base.
86. S. Architecture -> Microservices (SOA)
It is a variant of the service-oriented architecture (SOA)
that arranges an application as a collection of
loosely-coupled, fine-grained services, communicating
through lightweight protocols.
A microservice is not a layer within a monolithic
application, rather it is a self-contained piece of
business functionality with clear interfaces, and may,
through its own internal components, implement a layered
architecture.
87. S. Architecture -> Microservice
It should does one thing and does it well
â Lucas Krause. Microservices: Patterns and Applications.
88. S. Architecture -> Microliths
Make sure we donât end up with Microliths!
89. S. Architecture -> Event-driven
âWhen you start modeling
events, it forces you to
think about the behaviour
of the system. As opposed
to thinking about the
structure of the system.â
â Greg Young, A Decade of DDD, CQRS, Event Sourcing
90. S. Architecture -> Event-driven
â´ Donât focus on the things
The Nouns
The Domain Objects
â´ Focus on what happens
The Verbs
The Events
91. S. Architecture -> Take a step back!
What do we really need?
- Highly available
- Tolerant of failure
- Amenable to change
- Loosely-coupled
- Scalable
- Flexible
- Easy to develop
92. S. Architecture -> Letâs talk about needs!
What do we really need?
- Highly available
- Tolerant of failure
- Amenable to change
- Loosely-coupled
- Scalable
- Flexible
- Easy to develop
- Responsive
- Resilient
- Elastic
- Message Driven
93. S. Architecture -> Reactive Manifesto
- Responsive: The system responds in a timely manner if at all
possible.
- Resilient: The system stays responsive in the face of
failure.
- Elastic: The system stays responsive under varying workload.
- Message Driven: The system relies on asynchronous
message-passing to establish a boundary between components
that ensures loose coupling, isolation and location
transparency.
94. S. Architecture -> Reactive
âReactive,
what an
overloaded
word!â
- Reactive Programming (declarative with data streams and the propagation of change)
- React Framework (Web Framework)
- ReactiveX (API for asynchronous programming with observable streams, e.g., RxJava)
- Reactive Manifesto (Architectural Pattern)
95. S. Architecture -> Story time!
The Reactive Manifesto was created in 2013
by a group of developers led by Jonas
Boner. The primary motivation for this
manifesto was to come up with a name for a
new type of architectural style for
applications and to define a common
vocabulary for describing them. The
manifesto aimed to address new
requirements in application development
and provide a common vocabulary to discuss
complex concepts. It is signed by many
senior software engineers and architect
around the world.
Jonas Boner at Devoxx conference,
Antwerp, Belgium
96. S. Architecture -> Back to events
The nature of events:
â´ Events represent Facts of information
â´ Facts are immutable
â´ Facts accumulate - Knowledge can only grow
â´ Events and Facts can be disregarded or ignored
â´ Events and Facts can not be deleted (once accepted)
â´ Events and Facts (new) can invalidate existing Facts
97. S. Architecture -> Immutability
Facts == Immutable Events
Events are immutable. So, no null or
destructive update on events are allowed
which saves that billion-dollar damage
to the industry.
98. S. Architecture -> Immutability
âUpdate-in-place strikes systems
designers as a cardinal sin: it violates
traditional accounting practices that have
been observed for hundreds of years.â
â Transaction Concept, Jim Gray
99. S. Architecture -> Immutability
âThe truth is the log.
The database is a cache
of a subset of the log.â
â Immutability Changes Everything,
Pat Helland (2015)
100. S. Architecture -> Event Sourcing
Event Sourcing,
A Cure For the Cardinal Sin
101. S. Architecture -> Event-Sourcing
One single Source of Truth
with All history
Allows for Memory Image
(Durable In-Memory State)
Avoids the
Object-relational mismatch
Allows others to Subscribe
to state changes
102. S. Architecture -> Event-Driven Services
Receive & react (or
not) to facts that
are coming its way
Publish new facts
asynchronously to the
rest of the world
Invert the control
flow to minimize
coupling and increase
autonomy
103. S. Architecture -> CQRS
On an event-driven
architecture, you can
untangle Your
Read and Write Models
With CQRS
- Independent scaling
- Fewer lock contentions
- Optimized data schemas
- Security
- Separation of concerns
- Simpler queries
- etc.