Files
olla/content/talks/orleans-tech-event-sourcing/index.html
2026-02-18 17:23:24 +01:00

291 lines
12 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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>
&#x3C;?php
class TransactionMade extends Event
{
private $account;
private $label;
private $amount;
public function __construct($account, $label, $amount)
{
$this-&#x3E;account = $account;
$this-&#x3E;label = $label;
$this-&#x3E;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>
&#x3C;?php
class Account extends Aggregate
{
public static function new($name, $amount)
{
if ($amount < 0) {
throw new InitialAccountTransactionMustBePositive;
}
$account = new self;
$account-&#x3E;raise(
new TransactionMade($name, 'Virement initial', $amount)
);
}
}
</code></pre>
</section>
<section>
<h3>Aggregates</h3>
<pre><code data-trim data-noescape>
&#x3C;?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>
&#x3C;?php
class Account extends Aggregate
{
public function apply(Event $event)
{
if ($event instanceof TransactionMade) {
if (! isset($this-&#x3E;name)) {
$this-&#x3E;name = $event-&#x3E;getAccount();
}
$this-&#x3E;amount += $event-&#x3E;getAmount();
}
}
}
</code></pre>
</section>
<section>
<h3>Aggregates</h3>
<pre><code data-trim data-noescape>
&#x3C;?php
class Account extends Aggregate
{
public function pay($label, $amount)
{
if ($amount > $this-&#x3E;amount) {
throw new NotEnoughMoney;
}
$this-&#x3E;raise(
new TransactionMade($this-&#x3E;name, $label, -1 * $amount)
);
}
}
</code></pre>
</section>
<section>
<h3>Aggregates</h3>
<pre><code data-trim data-noescape>
&#x3C;?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>