<html>
<head>
<link rel="stylesheet" href="css/reveal.css">
<link rel="stylesheet" href="css/theme/white.css" id="theme">
<link rel="stylesheet" href="css2/github-gist.css">
<style type="text/css">
.reveal kbd {
font-size: 0.8em;
padding: 0.1em;
border: outset 0.2em #888;
background-color: #AAA;
color: #EEE;
}
</style>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Sietima — a minimalist MLM</title>
</head>
<body>
<div class="reveal">
<div class="slides">
<section>
<h1>Sietima — a minimalist MLM</h1>
<p>Author: dakkar <<a href="mailto:dakkar@thenautilus.net">dakkar@thenautilus.net</a>></p>
<p>Date: 2016-08-08</p>
</section>
<section>
<h2>A bit of history</h2>
<section>
<h3>Siesta</h3>
<aside class="notes">
<p>Yes, I ran Siesta. It works!</p>
<p>I ran 3 lists, with 10-30 people on each</p>
</aside>
</section>
<section>
<p>written in 2003</p>
</section>
<section>
<p>14 years ago</p>
</section>
<section>
<p><code>Class::DBI</code></p>
<p class="fragment">no <code>Moo(?:se)?</code></p>
<p class="fragment">Perl 5.8</p>
<aside class="notes">
<p>Surely things have got better!</p>
<p>Can I rewrite it better?</p>
</aside>
</section>
</section>
<section>
<h2>Plugin style</h2>
<section>
<p>simple base class</p>
<pre><code class="perl">sub handle_mail($self,$incoming_mail) {
my (@outgoing_messages) = $self->munge_mail($incoming_mail);
for my $outgoing_message (@outgoing_messages) {
$self->send_message($outgoing_message);
}
return;
}</code></pre>
</section>
<section>
<p>provide all the needed extensions points</p>
<pre><code class="perl">sub munge_mail($self,$incoming_mail) {
return Sietima::Message->new({
mail => $incoming_mail,
from => $self->return_path,
to => $self->subscribers_to_send_to($incoming_mail),
});
}</code></pre>
</section>
<section>
<p>but no more than that</p>
</section>
<section>
<p>traits / roles</p>
<ul class="fragment">
<li><code>AvoidDups</code></li>
<li><code>Debounce</code></li>
<li><code>Headers</code></li>
<li><code>ManualSubscription</code></li>
<li><code>NoMail</code></li>
<li><code>ReplyTo</code></li>
<li><code>SubjectTag</code></li>
<li><code>SubscriberOnly::Drop</code></li>
<li><code>SubscriberOnly::Moderate</code></li>
</ul>
</section>
<section>
<p>try to avoid cross-trait dependencies</p>
<p class="fragment">«<code>ReplyTo</code>
needs <code>WithPostAddress</code>» is fine</p>
<p class="fragment">but
«<code>SubscriberOnly::Moderate</code> should be added
after <code>Debounce</code>» is not</p>
<p class="fragment">sadly I couldn't avoid it, suggestions
welcome</p>
<aside class="notes">
<p>Debounce adds a X-Been-Here header; if that happens
before the message is put into moderation, when the
message comes out it will be dropped because it was
already seen!</p>
<p>Adding the header after the moderation happens is
fine</p>
</aside>
</section>
</section>
<section>
<h2>Driver</h2>
<section>
<p><code>App::Spec</code></p>
</section>
<section>
<p>minimal spec in base class</p>
<pre><code class="perl">sub command_line_spec($self) {
return {
name => 'sietima',
title => 'a simple mailing list manager',
subcommands => {
send => {
op => 'handle_mail_from_stdin',
summary => 'send email from STDIN',
},
},
};
}</code></pre>
</section>
<section>
<p>enriched by plugins</p>
<pre><code class="perl">around command_line_spec => sub ($orig,$self) {
my $spec = $self->$orig();
$spec->{subcommands}{'show-held'} = {
op => 'show_mail_from_moderation_queue',
parameters => [ {
name => 'mail-id', required => 1,
completion => { op => sub ($self,$runner,$args) {
$self->mail_store->retrieve_ids_by_tags('moderation');
} },
} ],
};
# etc etc
return $spec;
};</code></pre>
</section>
<section>
<pre>$ sietima-test <kbd>TAB</kbd>
drop-held -- drop the given mail, currently held for moderation
help -- Show command help
list-held -- list all mails currently held for moderation
resume-held -- resume the given mail, currently held for moderation
send -- send email from STDIN
show-held -- show the given mail, currently held for moderation</pre>
</section>
<section>
<pre>$ sietima-test show-held <kbd>TAB</kbd>
0f0571203ef5ee2f786b7f7f2832093ed4c34fe8
4d43ee7a2a17457606c07475b14054839fad9b7e</pre>
</section>
</section>
<section>
<h2>Production ready!</h2>
<section>
<p>all my lists now run with Sietima</p>
</section>
<section>
<p>on CPAN now</p>
</section>
</section>
<section>
<h2>CPAN is awesome</h2>
<section>
<p><code>Email::*</code>, RJBS</p>
</section>
<section>
<p><code>Moo</code>, MST + HAARG</p>
<p><code>Type::Tiny</code>, TOBYINK</p>
</section>
<section>
<p><code>App::Spec</code>, TINITA</p>
</section>
<section>
<p><code>Test2</code>, EXODIST</p>
</section>
</section>
<section>
<h2>Thank you</h2>
</section>
</div>
</div>
<script src="lib/js/head.min.js"></script>
<script src="js/reveal.js"></script>
<script>
Reveal.initialize({
dependencies: [
{ src: 'plugin/highlight/highlight.js',
async: true,
callback: function() { hljs.initHighlightingOnLoad(); }
},
{ src: 'plugin/notes/notes.js', async: true }
],
});
</script>
</body>
</html>