add static builder
This commit is contained in:
290
content/talks/orleans-tech-event-sourcing/index.html
Normal file
290
content/talks/orleans-tech-event-sourcing/index.html
Normal file
@@ -0,0 +1,290 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
|
||||
<title>L'Event Sourcing en pratique, ça donne quoi ?</title>
|
||||
|
||||
<link rel="stylesheet" href="css/reveal.css">
|
||||
<link rel="stylesheet" href="css/theme/solarized.css">
|
||||
<link rel="stylesheet" href="css/font-awesome/css/font-awesome.min.css">
|
||||
|
||||
<!-- Theme used for syntax highlighting of code -->
|
||||
<link rel="stylesheet" href="lib/css/zenburn.css">
|
||||
|
||||
<!-- Printing and PDF exports -->
|
||||
<script>
|
||||
var link = document.createElement( 'link' );
|
||||
link.rel = 'stylesheet';
|
||||
link.type = 'text/css';
|
||||
link.href = window.location.search.match( /print-pdf/gi ) ? 'css/print/pdf.css' : 'css/print/paper.css';
|
||||
document.getElementsByTagName( 'head' )[0].appendChild( link );
|
||||
</script>
|
||||
|
||||
<style media="screen">
|
||||
div.flex-icons {
|
||||
width: 60%;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.flex-icons .fa {
|
||||
font-size: 80px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="reveal">
|
||||
<div class="slides">
|
||||
<section>
|
||||
<h3>L'Event Sourcing en pratique, ça donne quoi ?</h3>
|
||||
<h4>Thibaud Dauce</h4>
|
||||
<small><a href="https://twitter.com/ThibaudDauce">@ThibaudDauce</a> | <a href="https://thibaud.dauce.fr">https://thibaud.dauce.fr</a></small>
|
||||
</section>
|
||||
<section>
|
||||
<img src="images/quantic-telecom.png" alt="Quantic Telecom" />
|
||||
<h4>Co-fondateur de Quantic Telecom</h4>
|
||||
<small><a href="https://www.quantic-telecom.net">https://www.quantic-telecom.net</a></small>
|
||||
<hr>
|
||||
<img src="images/laravel.png" alt="Formations Laravel" />
|
||||
<h4>Formations Laravel</h4>
|
||||
<small><a href="https://www.formations-laravel.fr">https://www.formations-laravel.fr</a></small>
|
||||
</section>
|
||||
<section>
|
||||
<h3>Qu'est-ce que l'Event Sourcing ?</h3>
|
||||
<h4 class="fragment">Stocker l'état de l'application comme une succession d'évènements</h4>
|
||||
</section>
|
||||
<section>
|
||||
<h3>3 concepts importants sur les évènements</h3>
|
||||
|
||||
<div class="flex-icons">
|
||||
<i class="fa fa-database fragment" aria-hidden="true"></i>
|
||||
<i class="fa fa-clock-o fragment" aria-hidden="true"></i>
|
||||
<i class="fa fa-lock fragment" aria-hidden="true"></i>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<h3>Portefeuille en ligne</h3>
|
||||
<h4 class="fragment" data-fragment-index="2">Que se passe-t-il si je ne suis pas d'accord ?</h4>
|
||||
|
||||
<div class="fragment" data-fragment-index="1">
|
||||
<table style="font-size: 35px">
|
||||
<tr><th>Compte</th><th>Montant</th></tr>
|
||||
<tr><td>Thibaud</td><td style="text-align: right">42,00€</td></tr>
|
||||
<tr><td>Jane</td><td style="text-align: right">1337,00€</td></tr>
|
||||
<tr><td>John</td><td style="text-align: right">-123,00€</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<h3>Event Sourcing à la rescousse</h3>
|
||||
|
||||
<table>
|
||||
<tr><th>Date</th><th>Compte</th><th>Libellé</th><th>Changement</th></tr>
|
||||
<tr><td>20/01/2017</td><td>Thibaud</td><td>Remboursement</td><td style="text-align: right"><strong>+</strong>20,00€</td></tr>
|
||||
<tr><td>12/01/2017</td><td>Thibaud</td><td>Facture</td><td style="text-align: right"><strong>-</strong>20,00€</td></tr>
|
||||
<tr><td>08/01/2017</td><td>Thibaud</td><td>Courses</td><td style="text-align: right"><strong>-</strong>58,00€</td></tr>
|
||||
<tr><td>06/01/2017</td><td>Thibaud</td><td>Virement initial</td><td style="text-align: right"><strong>+</strong>100,00€</td></tr>
|
||||
</table>
|
||||
</section>
|
||||
<section>
|
||||
<h3>Avantages</h3>
|
||||
<h4>Un audit complet des évènements de notre application</h4>
|
||||
<h4>Les nouvelles fonctionnalités profitent des informations passées</h4>
|
||||
</section>
|
||||
<section>
|
||||
<h3>Inconvénients</h3>
|
||||
<h4>Impossible d'effectuer des requêtes simplement</h4>
|
||||
<h4>Plus long et compliqué à mettre en place</h4>
|
||||
</section>
|
||||
<section>
|
||||
<h3>En pratique</h3>
|
||||
</section>
|
||||
<section>
|
||||
<h3>Les évènements</h3>
|
||||
<pre class="fragment"><code data-trim data-noescape>
|
||||
<?php
|
||||
|
||||
class TransactionMade extends Event
|
||||
{
|
||||
private $account;
|
||||
private $label;
|
||||
private $amount;
|
||||
|
||||
public function __construct($account, $label, $amount)
|
||||
{
|
||||
$this->account = $account;
|
||||
$this->label = $label;
|
||||
$this->amount = $amount;
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<h3>Stockage des évènements</h3>
|
||||
<ul>
|
||||
<li>NoSQL avec <a href="https://geteventstore.com/">EventStore</a></li>
|
||||
<li>SQL avec une table par évènement</li>
|
||||
<li>SQL ou NoSQL (type MongoDB) avec une table unique avec un champ JSON libre pour les données additionnelles</li>
|
||||
<li>Sérialisés dans un fichier</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section>
|
||||
<h3>Aggregates</h3>
|
||||
<pre class="fragment"><code data-trim data-noescape>
|
||||
<?php
|
||||
|
||||
class Account extends Aggregate
|
||||
{
|
||||
public static function new($name, $amount)
|
||||
{
|
||||
if ($amount < 0) {
|
||||
throw new InitialAccountTransactionMustBePositive;
|
||||
}
|
||||
|
||||
$account = new self;
|
||||
$account->raise(
|
||||
new TransactionMade($name, 'Virement initial', $amount)
|
||||
);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<h3>Aggregates</h3>
|
||||
<pre><code data-trim data-noescape>
|
||||
<?php
|
||||
|
||||
abstract class Aggregate
|
||||
{
|
||||
public function raise(Event $event)
|
||||
{
|
||||
$event->save();
|
||||
$this->apply($event);
|
||||
dispatch($event);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<h3>Aggregates</h3>
|
||||
<pre><code data-trim data-noescape>
|
||||
<?php
|
||||
|
||||
class Account extends Aggregate
|
||||
{
|
||||
public function apply(Event $event)
|
||||
{
|
||||
if ($event instanceof TransactionMade) {
|
||||
if (! isset($this->name)) {
|
||||
$this->name = $event->getAccount();
|
||||
}
|
||||
$this->amount += $event->getAmount();
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<h3>Aggregates</h3>
|
||||
<pre><code data-trim data-noescape>
|
||||
<?php
|
||||
|
||||
class Account extends Aggregate
|
||||
{
|
||||
public function pay($label, $amount)
|
||||
{
|
||||
if ($amount > $this->amount) {
|
||||
throw new NotEnoughMoney;
|
||||
}
|
||||
|
||||
$this->raise(
|
||||
new TransactionMade($this->name, $label, -1 * $amount)
|
||||
);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<h3>Aggregates</h3>
|
||||
<pre><code data-trim data-noescape>
|
||||
<?php
|
||||
|
||||
abstract class Aggregate
|
||||
{
|
||||
public static function fromEvents($events)
|
||||
{
|
||||
$aggregate = new static;
|
||||
foreach($events as $event) {
|
||||
$aggregate->apply($event);
|
||||
}
|
||||
|
||||
return $aggregate;
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<h3>Read models</h3>
|
||||
|
||||
<pre class="fragment"><code data-trim data-noescape>
|
||||
// Save current amount in SQL database
|
||||
public function onTransactionMade($event)
|
||||
{
|
||||
$account = $this->getAccountByName($event->getAccount());
|
||||
$account->update([
|
||||
'amount' => $account->getAmount() + $event->getAmount(),
|
||||
]);
|
||||
}
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<h3>Read models</h3>
|
||||
|
||||
<pre><code data-trim data-noescape>
|
||||
// Save suspicious accounts in Redis
|
||||
public function onTransactionMade($event)
|
||||
{
|
||||
if ($event->getAmount() > 1000) {
|
||||
Redis::set('suspicious.' . $event->getAccount(), true);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<h3>Et en vraie pratique</h3>
|
||||
</section>
|
||||
<section>
|
||||
<h3>En conclusion</h3>
|
||||
<div class="fragment">
|
||||
<h3 class="flex-icons">
|
||||
<i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
|
||||
</h3>
|
||||
<h3>Ne faites pas d'Event Sourcing…</h3>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<h3>… mais pensez y</h3>
|
||||
<small><a href="https://twitter.com/ThibaudDauce">@ThibaudDauce</a> | <a href="https://thibaud.dauce.fr">https://thibaud.dauce.fr</a></small>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="lib/js/head.min.js"></script>
|
||||
<script src="js/reveal.js"></script>
|
||||
|
||||
<script>
|
||||
// More info https://github.com/hakimel/reveal.js#configuration
|
||||
Reveal.initialize({
|
||||
history: true,
|
||||
|
||||
// More info https://github.com/hakimel/reveal.js#dependencies
|
||||
dependencies: [
|
||||
{ src: 'plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } }
|
||||
]
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user