<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.2">Jekyll</generator><link href="https://www.bertrand-bougon.fr/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.bertrand-bougon.fr/" rel="alternate" type="text/html" /><updated>2023-05-30T12:08:22+00:00</updated><id>https://www.bertrand-bougon.fr/feed.xml</id><title type="html">Bertrand Bougon</title><subtitle>Development, eXtreme Programming, Agile</subtitle><entry><title type="html">NewCrafts 2023</title><link href="https://www.bertrand-bougon.fr/conferences/software-development/testing/2023/05/27/ncrafts-2023.html" rel="alternate" type="text/html" title="NewCrafts 2023" /><published>2023-05-27T00:00:00+00:00</published><updated>2023-05-27T00:00:00+00:00</updated><id>https://www.bertrand-bougon.fr/conferences/software-development/testing/2023/05/27/ncrafts-2023</id><content type="html" xml:base="https://www.bertrand-bougon.fr/conferences/software-development/testing/2023/05/27/ncrafts-2023.html">&lt;p&gt;I have assisted to NewCrafts conference 2023, and I wanted to share the notes I have taken during this 2 amazing days.&lt;/p&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#newcrafts-2023&quot; id=&quot;markdown-toc-newcrafts-2023&quot;&gt;NewCrafts 2023&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#emily-bache---hands-on-techniques-for-getting-legacy-code-under-control&quot; id=&quot;markdown-toc-emily-bache---hands-on-techniques-for-getting-legacy-code-under-control&quot;&gt;Emily Bache - Hands-on techniques for getting legacy code under control&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#sophie-kuster---the-impostors-guide-to-tooting-you-own-horn&quot; id=&quot;markdown-toc-sophie-kuster---the-impostors-guide-to-tooting-you-own-horn&quot;&gt;Sophie Kuster - The impostor’s guide to tooting You Own Horn&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#adam-tornhill---code-red-the-business-impact-of-code-quality&quot; id=&quot;markdown-toc-adam-tornhill---code-red-the-business-impact-of-code-quality&quot;&gt;Adam Tornhill - Code red: The business impact of code quality&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#laurent-bossavit---dear-feedback-youre-loopy&quot; id=&quot;markdown-toc-laurent-bossavit---dear-feedback-youre-loopy&quot;&gt;Laurent Bossavit - Dear Feedback, you’re Loopy!&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#clare-sudbery---compassionate-refactoring&quot; id=&quot;markdown-toc-clare-sudbery---compassionate-refactoring&quot;&gt;Clare Sudbery - Compassionate Refactoring&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#maaret-pyhäjärvi---lets-do-a-thing-and-call-it-foo&quot; id=&quot;markdown-toc-maaret-pyhäjärvi---lets-do-a-thing-and-call-it-foo&quot;&gt;Maaret Pyhäjärvi - Let’s Do a Thing and Call It Foo&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#seb-rose---improving-software-quality-with-contract-testing-and-pact&quot; id=&quot;markdown-toc-seb-rose---improving-software-quality-with-contract-testing-and-pact&quot;&gt;Seb Rose - Improving Software Quality with Contract Testing and Pact&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#andrea-magnorsky---knowledge-sharing-is-systems-building&quot; id=&quot;markdown-toc-andrea-magnorsky---knowledge-sharing-is-systems-building&quot;&gt;Andrea Magnorsky - Knowledge sharing is Systems building&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#jessica-kerr---going-deep-on-gamification&quot; id=&quot;markdown-toc-jessica-kerr---going-deep-on-gamification&quot;&gt;Jessica Kerr - Going Deep on Gamification&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#cyrille-martraire---beyond-craft---revisiting-our-relationship-with-software-craft&quot; id=&quot;markdown-toc-cyrille-martraire---beyond-craft---revisiting-our-relationship-with-software-craft&quot;&gt;Cyrille Martraire - Beyond Craft - Revisiting Our Relationship with Software Craft&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;newcrafts-2023&quot;&gt;NewCrafts 2023&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://ncrafts.io/agenda&quot;&gt;Agenda&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;emily-bache---hands-on-techniques-for-getting-legacy-code-under-control&quot;&gt;&lt;a href=&quot;https://ncrafts.io/speaker/emilybache&quot;&gt;Emily Bache&lt;/a&gt; - Hands-on techniques for getting legacy code under control&lt;/h2&gt;

&lt;p&gt;Working on legacy, bad / poor testing code, technical debt is part of our work.&lt;/p&gt;

&lt;p&gt;To make the sufficient changes effective in order to make this code maintainable and testable, &lt;strong&gt;peel and slice strategy&lt;/strong&gt; is a useful technique.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quote from Emily:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Technical debt is deficiencies in internal qualities that make it harder than it would ideally be to modify and extend.&lt;/li&gt;
  &lt;li&gt;Everyone has an interest at reducing the technical debt.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Peel and Slice strategy:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://sammancoaching.org/learning_hours/testable_design/peel.html&quot;&gt;Peel strategy&lt;/a&gt;:
take away the untestable code. “Peel” technique is useful when the logic to be tested is in the between hard-to-test code (i.e. code with side effects). It consists of extracting the logic into a separate function, and then test that function instead of the initial one&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://sammancoaching.org/learning_hours/testable_design/slice.html&quot;&gt;Slice strategy&lt;/a&gt;:
replace the hard to test code with a stub or a fake&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advantages/disadvantages:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Advantages:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Don’t break the signature of the called method&lt;/li&gt;
  &lt;li&gt;Extract a testable code&lt;/li&gt;
  &lt;li&gt;Make untestable code testable&lt;/li&gt;
  &lt;li&gt;Identifying side effects (and push them on the boundaries)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disadvantages:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Event if we used refactoring tools, we didn’t have tests covering steps&lt;/li&gt;
  &lt;li&gt;Expose a method with a package visibility for testing purpose&lt;/li&gt;
  &lt;li&gt;Can introduce bugs during the slice and peel because the code is not covered in tests&lt;/li&gt;
  &lt;li&gt;The number of parameters can increase drastically and the combinatory of the test can explode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tips and tools:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use the tools you have in hands instead of redoing things. Use the refactoring tools from your IDE, look for tools that exists and that are adapted in your context (in such exercice, use approval testing)&lt;/p&gt;

&lt;p&gt;Some tools for approval testing:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/approvals&quot;&gt;Approvals&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;sophie-kuster---the-impostors-guide-to-tooting-you-own-horn&quot;&gt;&lt;a href=&quot;https://ncrafts.io/speaker/sophiekuster&quot;&gt;Sophie Kuster&lt;/a&gt; - The impostor’s guide to tooting You Own Horn&lt;/h2&gt;

&lt;p&gt;Impostor syndrome, also known as impostor phenomenon or impostorism, is a psychological occurrence in which people doubt their skills, talents, or accomplishments and have a persistent internalized fear of being exposed as frauds(&lt;a href=&quot;https://en.wikipedia.org/wiki/Impostor_syndrome&quot;&gt;Wikipedia&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;I feel like an impostor about having impostor syndrome.&lt;/p&gt;

&lt;p&gt;The following tips are Band-Aids, quick tips to help yourself about your feelings and start the process of acceptance:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Fake it till you make it, after all, we all pretend. Faking it is a start for self-confidence.&lt;/li&gt;
  &lt;li&gt;Make self advocacy a team sport&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the end, you need to face the monster whispering in your mind. You have to know this enemy and externalize impostor thoughts.&lt;/p&gt;

&lt;p&gt;But you Live with the monster, and he will always be there. The monster speaking into your head keeps you away from being humiliated.
You can make friend with the monster, or at least peace. Harness the power of good enough, internalize accomplishments 
(list all the achievements you’ve done, in your professional life or personal life), embrace failure&lt;/p&gt;

&lt;p&gt;Impostor Syndrome is a fear response!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Books:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.com/Secret-Thoughts-Successful-Women-Impostor/dp/0307452719&quot;&gt;The secret thoughts of successful women(Valerie Young)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.amazon.fr/Imposter-Cure-Escape-Mind-Trap-Syndrome/dp/B07P6DL185/ref=sr_1_1?adgrpid=78543238022&amp;amp;hvadid=392889237584&amp;amp;hvdev=c&amp;amp;hvlocphy=9056139&amp;amp;hvnetw=g&amp;amp;hvqmt=e&amp;amp;hvrand=8989166867632260901&amp;amp;hvtargid=kwd-745855150536&amp;amp;hydadcr=27712_1756335&amp;amp;keywords=the+imposter+cure&amp;amp;qid=1685084188&amp;amp;sr=8-1&quot;&gt;The imposter cure (Jessamy Hibberd)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;adam-tornhill---code-red-the-business-impact-of-code-quality&quot;&gt;&lt;a href=&quot;https://ncrafts.io/speaker/adamtornhill&quot;&gt;Adam Tornhill&lt;/a&gt; - Code red: The business impact of code quality&lt;/h2&gt;

&lt;p&gt;What is a technical debt?&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;code that is more expensive to maintain than to create it&lt;/li&gt;
  &lt;li&gt;23 to 42% of developer time is spent on dealing with technical debt&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It goes way beyond financial waste, unseen vulnerabilities have a disaster effect on finance at some point.&lt;/p&gt;

&lt;p&gt;The laws of software evolution:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;continuing change (a system must be continually adapted, or it becomes progressively less satisfactory) =&amp;gt; quick reward&lt;/li&gt;
  &lt;li&gt;Increasing complexity (as a system evolves, its complexity increases unless work is done to maintain or reduce it) =&amp;gt; slow feedback&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Technical debt is a shortcut to slow death.&lt;/p&gt;

&lt;p&gt;Why short-term gains win over long-term maintainability: Hyperbolic discounting (we might make choice today that in the future we may regret).&lt;/p&gt;

&lt;p&gt;Fighting hyperbolic discounting: visualize technical debt and code complexity (&lt;a href=&quot;https://codescene.com/code-health-factor&quot;&gt;code health&lt;/a&gt;) 
makes it obvious that you deal with a codebase that will be unmaintainable if you don’t accept to do the necessary 
effort to keep every change simple.&lt;/p&gt;

&lt;p&gt;The result of the study, &lt;a href=&quot;https://arxiv.org/pdf/2203.04374.pdf&quot;&gt;Research to quantify the impact of code quality&lt;/a&gt; spotted that:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;implementing a feature is twice as fast on a healthy code quality than on a low code quality&lt;/li&gt;
  &lt;li&gt;A feature can take up to 9 times longer&lt;/li&gt;
  &lt;li&gt;contains 15 times more defect than healthy code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://www.amazon.fr/Rethinking-Productivity-Software-Engineering-Sadowski/dp/1484242203&quot;&gt;Rethinking Productivity in Software Engineering&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The most frequent causes of unhappiness:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;stuck in problem-solving&lt;/li&gt;
  &lt;li&gt;time pressure&lt;/li&gt;
  &lt;li&gt;work with bad code&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Code quality constraints a business:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Share the same awareness to all stakeholders (devs, product, management)&lt;/p&gt;

    &lt;p&gt;Fight hyperbolic discounting&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Discussing future risks primes you for starting to address them&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Build a business case of improvements&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Refactoring and larger improvements can come with a business expectation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Commit frequency can help to prioritize what part of the code needs to be refactored.&lt;/p&gt;

&lt;p&gt;All tech debt does not need to be fixed!&lt;/p&gt;

&lt;h2 id=&quot;laurent-bossavit---dear-feedback-youre-loopy&quot;&gt;&lt;a href=&quot;https://ncrafts.io/speaker/laurentbossavit&quot;&gt;Laurent Bossavit&lt;/a&gt; - Dear Feedback, you’re Loopy!&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Fear:&lt;/strong&gt; my job is to perfect you! (Fantasy experienced as reality).
It can interfere with many things in life, feedback is one of them.&lt;/p&gt;

&lt;p&gt;Feedback is more difficult when power is involved.&lt;/p&gt;

&lt;p&gt;It needs safety and consent.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;When somebody delivers some feedback to you (it gives information from the person giving feedback to you). 
If it comes from a third person, you cannot have clarification.&lt;/li&gt;
  &lt;li&gt;manipulation &amp;lt;&amp;gt; reject &amp;lt;&amp;gt; feedback&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Agile has been turned as a tool for pressure rather than a tool to socialize organisation.&lt;/p&gt;

&lt;p&gt;Feedback can change the relationship, hopefully in a good way but sometime in a bad way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;System thinking:&lt;/strong&gt; what matters are not the things but the relationship between things.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://miro.com/app/board/uXjVMEi3UjI=/&quot;&gt;miro&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Prefer feedback loop over feedback. A feedback is not a one way discussion, it is the opportunity to open a discussion.&lt;/li&gt;
  &lt;li&gt;take care of your relationship&lt;/li&gt;
  &lt;li&gt;system thinking is a great tool to work on relationship&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Books&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/2912931-what-did-you-say&quot;&gt;What did you say?: The Art of Giving and Receiving Feedback&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/393898.The_Logic_of_Failure&quot;&gt;the logic of failure&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;clare-sudbery---compassionate-refactoring&quot;&gt;Clare Sudbery - Compassionate Refactoring&lt;/h2&gt;
&lt;p&gt;when refactoring, you have to be compassionate with yourself and with other people.&lt;/p&gt;

&lt;h2 id=&quot;maaret-pyhäjärvi---lets-do-a-thing-and-call-it-foo&quot;&gt;&lt;a href=&quot;https://ncrafts.io/speaker/maaretpyhajarvi&quot;&gt;Maaret Pyhäjärvi&lt;/a&gt; - Let’s Do a Thing and Call It Foo&lt;/h2&gt;

&lt;p&gt;Maaret is a tester but what does it mean to be a tester?&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Manual testing? No, she never did a manual test in her entire career&lt;/li&gt;
  &lt;li&gt;Automated tester? No, writing some automated test from acceptance criteria or whatever is not her job&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s say my work is foo, because if you don’t know a thing that you want to create, call it foo. I hate the word foo, but I used it many times. 
The key is we don’t really understand what we are doing, we should name the thing after we understood what they are doing.&lt;/p&gt;

&lt;p&gt;Testing is about breaking illusions, my job is to find something others may have missed. In my area of work, 
manual testing should not exist. The joy rely on the feedback given by the team when they fix what you’ve found.&lt;/p&gt;

&lt;p&gt;We are accountable for:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Intent / Implementation&lt;/li&gt;
  &lt;li&gt;Domain for the Layman&lt;/li&gt;
  &lt;li&gt;Domain for the expert&lt;/li&gt;
  &lt;li&gt;Reference implementation&lt;/li&gt;
  &lt;li&gt;People filtering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s try this with &lt;a href=&quot;https://en.wikipedia.org/wiki/Roman_numerals&quot;&gt;roman numbers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Intent / Implementation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Developer intent. It might not do what you want to.&lt;/p&gt;

&lt;p&gt;IV and IIII are both acceptable roman numbers, their intent are different, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IIII&lt;/code&gt; is used in domain for luxury clocks and clock towers.&lt;/p&gt;

&lt;p&gt;Same for V, IIIII is used in tomb marking&lt;/p&gt;

&lt;p&gt;These are matters of business decisions.
Ask the PO, why are we doing this? What is the domain? Can you show examples?&lt;/p&gt;

&lt;p&gt;A simple Kata like roman number needs an intent and domain knowledge / decision. Decision matters!&lt;/p&gt;

&lt;p&gt;I care for the perfect information (not the perfect implementation).&lt;/p&gt;

&lt;p&gt;Business rules. You think you know them but you don’t.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Domain&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Be the resident expert. Ask around&lt;/li&gt;
  &lt;li&gt;Rules, more rules&lt;/li&gt;
  &lt;li&gt;find better experts&lt;/li&gt;
  &lt;li&gt;disagreeing with boundaries&lt;/li&gt;
  &lt;li&gt;oracles&lt;/li&gt;
  &lt;li&gt;find better oracles&lt;/li&gt;
  &lt;li&gt;no user would do what users would do&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Environment&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Dependencies&lt;/li&gt;
  &lt;li&gt;Interruptions. Both…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;People are not pure functions; they have all sorts of interesting side effects (&lt;a href=&quot;https://www.engmanagement.dev/&quot;&gt;Engineering Management for the rest of us, Sarah Granser&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Finally, we can call foo &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Contemporary Exploratory Testing&lt;/code&gt;, because that’s what my job does.&lt;/p&gt;

&lt;p&gt;A majority of bugs of the production failures (77%) can be reproduced by a unit test.&lt;/p&gt;

&lt;p&gt;The team needs information. Testers have to focus on that.&lt;/p&gt;

&lt;h2 id=&quot;seb-rose---improving-software-quality-with-contract-testing-and-pact&quot;&gt;&lt;a href=&quot;https://ncrafts.io/speaker/sebrose&quot;&gt;Seb Rose&lt;/a&gt; - Improving Software Quality with Contract Testing and Pact&lt;/h2&gt;

&lt;p&gt;Consumer challenges:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;component not ready&lt;/li&gt;
  &lt;li&gt;lack of documentation&lt;/li&gt;
  &lt;li&gt;new version available&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Provider challenges:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;don’t know the audience&lt;/li&gt;
  &lt;li&gt;don’t want to manage multiple test instances&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you cannot deploy a component independently, this is not a component (it is a componented monolith).&lt;/p&gt;

&lt;p&gt;Clients use a provider solution with the existing defects. If you update your service as a provider, fixing a bug, 
maybe you broke a client use case.&lt;/p&gt;

&lt;p&gt;Contract testing is about sharing the use cases of our clients in order to run them on our service to be sure, as a provider, 
we didn’t break their usage. &lt;a href=&quot;https://pact.io/&quot;&gt;Pact&lt;/a&gt; is a tool where clients share the expected outcome from the provider solution, 
the provider may use these expected outcome with pact and have a direct feedback of any breaking change with their new deployment.&lt;/p&gt;

&lt;h2 id=&quot;andrea-magnorsky---knowledge-sharing-is-systems-building&quot;&gt;&lt;a href=&quot;https://ncrafts.io/speaker/andreamagnorsky&quot;&gt;Andrea Magnorsky&lt;/a&gt; - Knowledge sharing is Systems building&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://bytesizearchitecturesessions.com/&quot;&gt;Workshop&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is it hard to share knowledge&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;You ship what is in your programmers brains&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At beginning, it is easy as it is tiny, but it will grow (more code, more complexity).
We focus on how do we solve this problem, we love those problem.
When it comes to people, it turns to ghost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Added difficulty:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Changing teams (new comers =&amp;gt; new ideas, leavers =&amp;gt; loose knowledge)&lt;/li&gt;
  &lt;li&gt;Coordination between teams (&amp;lt;&amp;gt; goal alignment, long asynchronous talk / feedback)&lt;/li&gt;
  &lt;li&gt;Conflicting long term plans (negotiation on conflicting things)&lt;/li&gt;
  &lt;li&gt;Role depends on information variance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A way to share knowledge: Bytesize Architecture Session&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bytesize Architecture Sessions[T] is a workshop format&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;simple&lt;/li&gt;
  &lt;li&gt;45 minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can’t reach the consensus, you only can approach a consensus.&lt;/p&gt;

&lt;p&gt;[Architecture Modernization]https://www.manning.com/books/architecture-modernization&lt;/p&gt;

&lt;p&gt;Teams need to understand the system they are working in.&lt;/p&gt;

&lt;h2 id=&quot;jessica-kerr---going-deep-on-gamification&quot;&gt;&lt;a href=&quot;https://ncrafts.io/speaker/jessicakerr&quot;&gt;Jessica Kerr&lt;/a&gt; - Going Deep on Gamification&lt;/h2&gt;

&lt;p&gt;Sorry, no notes as I gave my laptop to Jessica who faced technical issues.&lt;/p&gt;

&lt;h2 id=&quot;cyrille-martraire---beyond-craft---revisiting-our-relationship-with-software-craft&quot;&gt;&lt;a href=&quot;https://ncrafts.io/speaker/cyrillemartraire&quot;&gt;Cyrille Martraire&lt;/a&gt; - Beyond Craft - Revisiting Our Relationship with Software Craft&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/awslabs/deequ&quot;&gt;Deequ&lt;/a&gt;
&lt;a href=&quot;https://greatexpectations.io/&quot;&gt;Great expectations&lt;/a&gt;&lt;/p&gt;</content><author><name>Bertrand Bougon</name></author><category term="conferences" /><category term="software-development" /><category term="testing" /><summary type="html">I have assisted to NewCrafts conference 2023, and I wanted to share the notes I have taken during this 2 amazing days.</summary></entry><entry><title type="html">How to be proud of an experimentation</title><link href="https://www.bertrand-bougon.fr/experimentation/xp/2022/09/29/how-to-be-proud-of-an-experimentation.html" rel="alternate" type="text/html" title="How to be proud of an experimentation" /><published>2022-09-29T19:36:56+00:00</published><updated>2022-09-29T19:36:56+00:00</updated><id>https://www.bertrand-bougon.fr/experimentation/xp/2022/09/29/how-to-be-proud-of-an-experimentation</id><content type="html" xml:base="https://www.bertrand-bougon.fr/experimentation/xp/2022/09/29/how-to-be-proud-of-an-experimentation.html">&lt;p&gt;Sometime, even if it’s not that easy, trying hard to resolve something you are not sure about, at the end you can be 
proud about what you’ve done and God it’s good to feel proud about something you achieved.&lt;/p&gt;

&lt;ul id=&quot;markdown-toc&quot;&gt;
  &lt;li&gt;&lt;a href=&quot;#the-context&quot; id=&quot;markdown-toc-the-context&quot;&gt;The context&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#entering-the-solution-space&quot; id=&quot;markdown-toc-entering-the-solution-space&quot;&gt;Entering the solution space&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#how-to-reduce-feedback-loop&quot; id=&quot;markdown-toc-how-to-reduce-feedback-loop&quot;&gt;How to reduce feedback loop?&lt;/a&gt;        &lt;ul&gt;
          &lt;li&gt;&lt;a href=&quot;#identify-a-local-strategy-test&quot; id=&quot;markdown-toc-identify-a-local-strategy-test&quot;&gt;Identify a local strategy test&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#implement-sqlite-repository&quot; id=&quot;markdown-toc-implement-sqlite-repository&quot;&gt;Implement sqlite repository&lt;/a&gt;&lt;/li&gt;
          &lt;li&gt;&lt;a href=&quot;#configure-docker&quot; id=&quot;markdown-toc-configure-docker&quot;&gt;Configure docker&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#local-testing&quot; id=&quot;markdown-toc-local-testing&quot;&gt;Local testing&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#conclusion&quot; id=&quot;markdown-toc-conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#thanks&quot; id=&quot;markdown-toc-thanks&quot;&gt;Thanks&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#the-code&quot; id=&quot;markdown-toc-the-code&quot;&gt;The code&lt;/a&gt;    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#the-agent&quot; id=&quot;markdown-toc-the-agent&quot;&gt;The agent&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#the-process-class&quot; id=&quot;markdown-toc-the-process-class&quot;&gt;The Process class&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-context&quot;&gt;The context&lt;/h2&gt;
&lt;p&gt;With one of my colleague, we were working on a solution that would ensure a proper graceful shutdown for a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NodeJS&lt;/code&gt; application.&lt;/p&gt;

&lt;p&gt;Below is a minimized C4 model.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;plantuml&quot; src=&quot;http://www.plantuml.com/plantuml/svg/~h407374617274756d6c0a407374617274756d6c0a21646566696e652049434f4e55524c2068747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f747570616472332f706c616e74756d6c2d69636f6e2d666f6e742d737072697465732f76322e342e300a21696e636c7564652049434f4e55524c2f64657669636f6e732f72656163742e70756d6c0a21646566696e652049434f4e55524c2068747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f747570616472332f706c616e74756d6c2d69636f6e2d666f6e742d737072697465732f76322e342e300a21696e636c7564652049434f4e55524c2f64657669636f6e732f6e6f64656a732e70756d6c0a0a21696e636c7564652068747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f61647269616e766c7570752f43342d506c616e74554d4c2f6c61746573742f43345f436f6e7461696e65722e70756d6c0a0a736b696e706172616d206261636b67726f756e64436f6c6f7220234242420a4c41594f55545f574954485f4c4547454e4428290a0a506572736f6e28757365722c202255736572222c20224120706572736f6e207573696e67206f75722073797374656d20616e6420696e74657265737465642061626f75742072657472696576696e6720646174612066726f6d206f757220736572766963652e22290a0a53797374656d5f45787428657874736572762c202245787465726e616c2073657276696365222c2022416e2065787465726e616c20736572766963652070757368696e67206576656e7473206f6e206f75722052455354204150492e22290a53797374656d5f4578742872656469732c20225265646973222c20225468652072656469732073657276657220726573706f6e7369626c6520746f20717565756520746865206d65737361676573207265636569766564206f6e206576656e7473207265736f757263652e22290a53797374656d5f4578742864617461626173652c20224576656e7473206461746162617365222c2022546865206461746162617365207768657265206576656e7473206172652073746f7265642e22290a0a0a53797374656d5f426f756e646172792873797374656d2c20224f75722073797374656d2229207b0a20202020436f6e7461696e6572286167656e742c20224167656e74222c2022546865206167656e7420726573706f6e7369626c6520746f20636865636b2071756575657320616e6420696e7374616e746961746520717565756520636f6e73756d6572732e222c20247370726974653d226e6f64656a7322290a20202020436f6e7461696e65722872612c202252455354204170706c69636174696f6e222c202244656c69766572732052455354207265736f75726365732e222c20247370726974653d226e6f64656a7322290a0a2020202052656c28657874736572762c2072612c2022506f7374206576656e747322290a2020202052656c2872612c2072656469732c20225075626c697368206576656e7473206f6e206120717565756522290a0a7d0a0a52656c28757365722c2073797374656d2c20225573657320746865207365727669636522290a52656c286167656e742c2072656469732c2022436865636b2f726561642071756575657322290a52656c286167656e742c2064617461626173652c202250657273697374206576656e747322290a0a40656e64756d6c0a40656e64756d6c&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem :&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Asynchronous services to process thousands of data that gives business insight for our clients (message loss tolerance is 0)&lt;/li&gt;
  &lt;li&gt;A parent process forking a child process to instantiate a queue consumer&lt;/li&gt;
  &lt;li&gt;A queue consumer instance which is not available from the parent process&lt;/li&gt;
  &lt;li&gt;A &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SIGTERM&lt;/code&gt; sent on a node child process will instantly kill the child
    &lt;ul&gt;
      &lt;li&gt;Any consumer running at this time would be instantly killed resulting in:
        &lt;ul&gt;
          &lt;li&gt;queue consumed messages loss&lt;/li&gt;
          &lt;li&gt;missing to be processed data for our client&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;A local environment not ready to test this kind of scenario&lt;/li&gt;
  &lt;li&gt;The feedback loop was around 24 to 36 minutes (too long!) with at least all these steps:
    &lt;ul&gt;
      &lt;li&gt;commit / push&lt;/li&gt;
      &lt;li&gt;CI running:
        &lt;ul&gt;
          &lt;li&gt;execute test (5 minutes)&lt;/li&gt;
          &lt;li&gt;dockerize (5 minutes)&lt;/li&gt;
          &lt;li&gt;publish docker image (2 minutes)&lt;/li&gt;
          &lt;li&gt;deploy docker container (2 minutes)&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
      &lt;li&gt;create a new test instance (2 minutes)&lt;/li&gt;
      &lt;li&gt;clean data (2 minutes)&lt;/li&gt;
      &lt;li&gt;launch test (4-15 minutes)&lt;/li&gt;
      &lt;li&gt;observe result (2-3 minute)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Below is an example of our activity:
&lt;a href=&quot;/assets/images/2022-09-29_2.png&quot;&gt; &lt;img src=&quot;/assets/images/2022-09-29_2.png&quot; alt=&quot;&quot; /&gt; &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/images/2022-09-29_1.png&quot;&gt; &lt;img src=&quot;/assets/images/2022-09-29_1.png&quot; alt=&quot;&quot; /&gt; &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see there is a pattern with a long time interval between commit/push and test session (let’s say around 6 to 8 tests a day).&lt;/p&gt;

&lt;p&gt;BTW, thanks to &lt;a href=&quot;https://twitter.com/dr_c0d3&quot;&gt;@Arnaud Bailly&lt;/a&gt; and his wonderful &lt;a href=&quot;https://github.com/abailly/sensei&quot;&gt;sensei project&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;entering-the-solution-space&quot;&gt;Entering the solution space&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Our work in progress :&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Understand the current behaviour which can be resumed to:&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;mermaid&quot; src=&quot;https://mermaid.ink/svg/eyJjb2RlIjoiJSV7aW5pdDogeyd0aGVtZSc6ICdkYXJrJywgJ3RoZW1lVmFyaWFibGVzJzogeyAnZGFya01vZGUnOiAndHJ1ZScsICdwcmltYXJ5Q29sb3InOiAnI0NEQ0NGRid9fX0lJVxuc2VxdWVuY2VEaWFncmFtXG5QYXJlbnQgUHJvY2Vzcy0tPj5BZ2VudDogaW5zdGFudGlhdGUgYSBuZXcgYWdlbnRcbkFnZW50LT4-QWdlbnQ6IGNoZWNrIGF2YWlsYWJpbGl0eVxuQWdlbnQtLT4-Q2hpbGQgUHJvY2VzczogZm9yayBhIGNoaWxkXG5DaGlsZCBQcm9jZXNzLS0-PlF1ZXVlIENvbnN1bWVyOiBpbnN0YW50aWF0ZSBhIG5ldyBjb25zdW1lclxuQWdlbnQtLT4-UmVkaXMgcXVldWU6IHJlZ2lzdGVyIGxvY2tcblF1ZXVlIENvbnN1bWVyLT4-UXVldWUgQ29uc3VtZXI6IHBvbGxcblF1ZXVlIENvbnN1bWVyLS0-PlJlZGlzIHF1ZXVlOiBwb3AgbWVzc2FnZXMgaW4gcXVldWVcblF1ZXVlIENvbnN1bWVyLS0-PlJlZGlzIHF1ZXVlOiB1bnJlZ2lzdGVyIGxvY2tcbkFnZW50LT4-QWdlbnQ6IGNoZWNrIGF2YWlsYWJpbGl0eVxuQWdlbnQtLT4-Q2hpbGQgUHJvY2VzczogZm9yayBhIGNoaWxkXG5DaGlsZCBQcm9jZXNzLS0-PlF1ZXVlIENvbnN1bWVyOiBpbnN0YW50aWF0ZSBhIG5ldyBjb25zdW1lclxuUXVldWUgQ29uc3VtZXItLT4-UmVkaXMgcXVldWU6IHBvcCBtZXNzYWdlcyBpbiBxdWV1ZVxuUGFyZW50IFByb2Nlc3MtPj5BZ2VudDogc2VuZCBTSUdURVJNXG5BZ2VudC0tPj5QYXJlbnQgUHJvY2VzczogZXhpdCgwKSIsIm1lcm1haWQiOm51bGx9&quot; /&gt;&lt;/p&gt;

&lt;p&gt;What we intend to do, listen to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SIGTERM&lt;/code&gt; signal from the main node process, and properly shutdown the service by propagating the information
to the forked child. Which can be resumed to:&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;mermaid&quot; src=&quot;https://mermaid.ink/svg/eyJjb2RlIjoiJSV7aW5pdDogeyd0aGVtZSc6ICdkYXJrJywgJ3RoZW1lVmFyaWFibGVzJzogeyAnZGFya01vZGUnOiAndHJ1ZScsICdwcmltYXJ5Q29sb3InOiAnI0NEQ0NGRid9fX0lJVxuc2VxdWVuY2VEaWFncmFtXG5QYXJlbnQgUHJvY2Vzcy0tPj5BZ2VudDogaW5zdGFudGlhdGUgYSBuZXcgYWdlbnRcbkFnZW50LT4-QWdlbnQ6IGNoZWNrIGF2YWlsYWJpbGl0eVxuQWdlbnQtLT4-Q2hpbGQgUHJvY2VzczogZm9yayBhIGNoaWxkXG5DaGlsZCBQcm9jZXNzLS0-PlF1ZXVlIENvbnN1bWVyOiBpbnN0YW50aWF0ZSBhIG5ldyBjb25zdW1lclxuQWdlbnQtLT4-UmVkaXMgcXVldWU6IHJlZ2lzdGVyIGxvY2tcblF1ZXVlIENvbnN1bWVyLT4-UXVldWUgQ29uc3VtZXI6IHBvbGxcblF1ZXVlIENvbnN1bWVyLS0-PlJlZGlzIHF1ZXVlOiBwb3AgbWVzc2FnZXMgaW4gcXVldWVcblF1ZXVlIENvbnN1bWVyLS0-PlJlZGlzIHF1ZXVlOiB1bnJlZ2lzdGVyIGxvY2tcbkFnZW50LT4-QWdlbnQ6IGNoZWNrIGF2YWlsYWJpbGl0eVxuQWdlbnQtLT4-Q2hpbGQgUHJvY2VzczogZm9yayBhIGNoaWxkXG5DaGlsZCBQcm9jZXNzLS0-PlF1ZXVlIENvbnN1bWVyOiBpbnN0YW50aWF0ZSBhIG5ldyBjb25zdW1lclxuUXVldWUgQ29uc3VtZXItLT4-UmVkaXMgcXVldWU6IHBvcCBtZXNzYWdlcyBpbiBxdWV1ZVxuUGFyZW50IFByb2Nlc3MtPj5BZ2VudDogc2VuZCBTSUdURVJNXG5BZ2VudC0-PkFnZW50OiBzdG9wIGNoZWNraW5nIGF2YWlsYWJpbGl0eVxuQ2hpbGQgUHJvY2Vzcy0-PlF1ZXVlIENvbnN1bWVyOiBzdG9wIHBvbGxpbmdcblF1ZXVlIENvbnN1bWVyLS0-PlJlZGlzIHF1ZXVlOiB1bnJlZ2lzdGVyIGxvY2tcbkNoaWxkIFByb2Nlc3MtLT4-UGFyZW50IFByb2Nlc3M6IGV4aXQoMCkiLCJtZXJtYWlkIjpudWxsfQ&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Still, we are slowed down by the all process and feedback loop. Let’s take a step back for a moment and see if we don’t 
have a solution to reduce our feedback loop.&lt;/p&gt;

&lt;h3 id=&quot;how-to-reduce-feedback-loop&quot;&gt;How to reduce feedback loop?&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;By removing the actions that take time&lt;/li&gt;
  &lt;li&gt;By decreasing the number of actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our context it was obvious we should target our local development environment instead of going on a staging environment.&lt;/p&gt;

&lt;p&gt;… we don’t have a maintained local environment 😱, no problem, let’s experiment and identify what is needed to have a local environment.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;mermaid&quot; src=&quot;https://mermaid.ink/svg/eyJjb2RlIjoiJSV7aW5pdDogeyd0aGVtZSc6ICdkYXJrJywgICd0aGVtZVZhcmlhYmxlcyc6IHsgJ2RhcmtNb2RlJzogJ3RydWUnfSwgJ2dpdEdyYXBoJzogeydzaG93QnJhbmNoZXMnOiB0cnVlLCAnc2hvd0NvbW1pdExhYmVsJzp0cnVlLCdtYWluQnJhbmNoTmFtZSc6ICdsb2NhbC1lbnYnfX19JSVcbmdpdEdyYXBoXG5jb21taXQgaWQ6IFwicnVuIGRvY2tlclwiXG5jb21taXQgaWQ6IFwiZG9ja2VyLWNvbXBvc2UgY29uZmlndXJlIGVudiB2YXJpYWJsZVwiXG5jb21taXQgaWQ6IFwiZG9ja2VyLWNvbXBvc2UgY29uZmlndXJlIG1haW4gYXBwXCJcbmNvbW1pdCBpZDogXCJkb2NrZXItY29tcG9zZSBjb25maWd1cmUgcmVkaXNcIlxuY29tbWl0IGlkOiBcImRvY2tlci1jb21wb3NlIGV4cG9zZSBhZ2VudCBuZXR3b3JrXCJcbmNvbW1pdCBpZDogXCJkb2NrZXItY29tcG9zZSB2b2x1bWVzIHRvIHBlcnNpc3Qgc3FsaXRlIGRhdGFcIlxuY29tbWl0IGlkOiBcImltcGxlbWVudCBzcWxpdGUgcmVwb3NpdG9yeVwiXG5jb21taXQgaWQ6IFwiaWRlbnRpZnkgYSBsb2NhbCBzdHJhdGVneSB0ZXN0XCIiLCJtZXJtYWlkIjpudWxsfQ&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;identify-a-local-strategy-test&quot;&gt;Identify a local strategy test&lt;/h4&gt;
&lt;p&gt;How to prove that our workaround is working?&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Run the app on a docker container&lt;/li&gt;
  &lt;li&gt;Run a redis service on a docker container&lt;/li&gt;
  &lt;li&gt;Send a few thousand requests on the resource exposed to handle events&lt;/li&gt;
  &lt;li&gt;Check that redis queues are created and populated&lt;/li&gt;
  &lt;li&gt;Store the events in a database&lt;/li&gt;
  &lt;li&gt;Expose the database file on a docker volume (we need to have a persistent db file that is updated after each restart)&lt;/li&gt;
  &lt;li&gt;Run a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker stop CONTAINER&lt;/code&gt; command&lt;/li&gt;
  &lt;li&gt;Check that the numbers add up between the events stored in database end the events left in the queue&lt;/li&gt;
  &lt;li&gt;Restart the docker container&lt;/li&gt;
  &lt;li&gt;Check the redis queue is consumed&lt;/li&gt;
  &lt;li&gt;Re-run from step &lt;strong&gt;7&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;implement-sqlite-repository&quot;&gt;Implement sqlite repository&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Prerequisites :&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm install sqlite sqlite3&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purpose :&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Persist our events on a local database&lt;/li&gt;
  &lt;li&gt;No dependency with a distant service to persist data during test sessions on a local environment&lt;/li&gt;
  &lt;li&gt;Easily inspect results during test sessions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fortunately we did some weeks ago a refactoring work to add some abstraction and separation of concerns regarding our persistence layer.
Basically, we use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Repository&lt;/code&gt; pattern (&lt;a href=&quot;https://www.eyrolles.com/Informatique/Livre/domain-driven-design-9780321125217/&quot;&gt;See Eric Evans DDD blue book&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Thanks to this pattern and the previous work, what we needed is:&lt;/p&gt;
&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Repository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;persist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;entity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AbstractSQLiteEntitiesRepository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Repository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;persist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;entities&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
            &lt;span class=&quot;cm&quot;&gt;/*
            persist the entities
             */&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;EventsRepository&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Repository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Events&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SQLiteEventsRepository&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AbstractSQLiteEntitiesRepository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Events&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;EventsRepository&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;entities&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Events&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;cm&quot;&gt;/*
            run the query
             */&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// And then we replace the actual repository injection&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;handleEvents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;events&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;SQLiteEventsRepository&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// SQLiteEventsRepository instead of DistantEventsRepository&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;configure-docker&quot;&gt;Configure docker&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;docker-compose volumes to persist sqlite data :&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;na&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;..&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;dockerfile&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;deployments/app/Dockerfile&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;NODE_VERSION&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${NODE_VERSION}&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;NPM_VERSION&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${NPM_VERSION}&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${PORT}&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;local-agent&lt;/span&gt;

    &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;./volumes/db/data:/usr/db/data&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;unless-stopped&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;docker-compose expose agent network :&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-diff highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
  agent:
    build:
      context: ..
      dockerfile: deployments/app/Dockerfile
      args:
        NODE_VERSION: ${NODE_VERSION}
        NPM_VERSION: ${NPM_VERSION}
        PORT: ${PORT}
    target: local-agent
&lt;span class=&quot;gi&quot;&gt;+   ports:
+     - 3001:3000
+   network_mode: bridge
&lt;/span&gt;
    volumes:
      - &quot;./volumes/db/data:/usr/db/data&quot;
    restart: unless-stopped
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;docker-compose configure redis :&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;3.4&apos;&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;redis&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;redis:6.2.7-alpine&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;container_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;redis&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;healthcheck&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;redis-cli -p 6379 ping &amp;gt; /dev/null &amp;amp;&amp;amp; echo OK&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;retries&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;3s&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;6379:6379&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;./volumes/redis/data:/data&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;network_mode&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;bridge&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;unless-stopped&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;docker-compose configure main app :&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
  &lt;span class=&quot;na&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;..&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;dockerfile&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;deployments/app/Dockerfile&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;NODE_VERSION&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${NODE_VERSION}&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;NPM_VERSION&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${NPM_VERSION}&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;${PORT}&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;app&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;${PORT}:${PORT}&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;healthcheck&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;curl -f -s -o /dev/null http://localhost:${PORT}/health &amp;amp;&amp;amp; echo OK&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;retries&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;3s&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;links&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;redis&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;traefik.enable=true&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;traefik.http.routers.connector.rule=Host(`host.${BASE_DOMAIN:-localdomain}`)&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;traefik.http.routers.connector.entrypoints=websecure&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;traefik.http.routers.connector.tls.certresolver=myresolver&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;network_mode&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;bridge&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;unless-stopped&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;docker-compose configure env variable :&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-diff highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
  agent:
    build:
      context: ..
      dockerfile: deployments/app/Dockerfile
      args:
        NODE_VERSION: ${NODE_VERSION}
        NPM_VERSION: ${NPM_VERSION}
        PORT: ${PORT}
      target: local-agent
    links:
      - redis
&lt;span class=&quot;gi&quot;&gt;+   environment:
+     - NODE_ENV
+     - LOG_LEVEL
+     - SQLITE_FILEPATH
+     - QUEUE_TYPE
+     - QUEUE_CONSUMER_TYPE
+     - QUEUE_BATCH_SIZE
+     - QUEUE_AGENT_WORKER_TTL
+     - QUEUE_BATCH_TIMEOUT
+     - QUEUE_POLL_FREQ
+     - REDIS_HOST=redis
+     - REDIS_PORT=6379
&lt;/span&gt;    ports:
      - 3001:3000
    network_mode: bridge

    volumes:
      - &quot;./volumes/db/data:/usr/db/data&quot;
    restart: unless-stopped

  app:
    build:
      context: ..
      dockerfile: deployments/app/Dockerfile
      args:
        NODE_VERSION: ${NODE_VERSION}
        NPM_VERSION: ${NPM_VERSION}
        PORT: ${PORT}
      target: app
    ports:
      - &quot;${PORT}:${PORT}&quot;
    healthcheck:
      test: curl -f -s -o /dev/null http://localhost:${PORT}/health &amp;amp;&amp;amp; echo OK
      retries: 3
      timeout: 3s
    links:
      - redis
&lt;span class=&quot;gi&quot;&gt;+   environment:
+     - NODE_ENV
+     - LOG_LEVEL
+     - PORT
+     - REDIS_HOST=redis
+     - REDIS_PORT=6379
&lt;/span&gt;    labels:
      - traefik.enable=true
      - traefik.http.routers.connector.rule=Host(`host.${BASE_DOMAIN:-localdomain}`)
      - traefik.http.routers.connector.entrypoints=websecure
      - traefik.http.routers.connector.tls.certresolver=myresolver
    network_mode: bridge
    restart: unless-stopped
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So, after some hours of work, we had our local environment ready to test 🙌!&lt;/p&gt;

&lt;p&gt;… Almost. We had to troubleshoot the solution until it worked, but mainly we were doing:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Run the container, fix until ✅&lt;/li&gt;
  &lt;li&gt;POST event requests on the resource&lt;/li&gt;
  &lt;li&gt;Check the queue was filled, fix until ✅&lt;/li&gt;
  &lt;li&gt;Check the queue was consumed, fix until ✅&lt;/li&gt;
  &lt;li&gt;Check that the event was persisted, fix until ✅&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OK, we are ready to launch test sessions, observe the system and code what is missing.&lt;/p&gt;

&lt;h2 id=&quot;local-testing&quot;&gt;Local testing&lt;/h2&gt;
&lt;p&gt;I will not hold the suspense and share the improvement done with our feedback loop:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Build the docker images (3 minutes)
&lt;img src=&quot;/assets/images/2022-09-29_3.png&quot; alt=&quot;&quot; /&gt;&lt;/li&gt;
  &lt;li&gt;Run the docker containers (6 seconds)
&lt;img src=&quot;/assets/images/2022-09-29_4.png&quot; alt=&quot;&quot; /&gt;&lt;/li&gt;
  &lt;li&gt;Run K6 to perform POST requests (1.4 minutes)
&lt;img src=&quot;/assets/images/2022-09-29_5.png&quot; alt=&quot;&quot; /&gt;&lt;/li&gt;
  &lt;li&gt;Observe results:
    &lt;ul&gt;
      &lt;li&gt;Check redis queues&lt;/li&gt;
      &lt;li&gt;Check events are persisted&lt;/li&gt;
      &lt;li&gt;Stop docker agent container&lt;/li&gt;
      &lt;li&gt;Check app logs
        &lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;level&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;INFO&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1664442175682&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;command&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;stop-node-process&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;payload&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;SIGTERM received on pid 1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;level&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;INFO&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1664442175683&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;command&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;stopped-node-process&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;payload&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Node process stopped gracefully&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;level&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;INFO&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1664442175684&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;command&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;stop-node-process&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;payload&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;message received on pid 18&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;level&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;INFO&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;time&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1664442175683&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;command&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;stopped-node-process&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;payload&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:{&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Node process stopped gracefully&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
      &lt;li&gt;Check lock registry has been flushed
        &lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; 127.0.0.1:6379&amp;gt; GET workerRegistry:events
 &lt;span class=&quot;s2&quot;&gt;&quot;29&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;        &lt;/div&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What is important here is:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Number of steps before observing results have been reduced, from 7 to 3&lt;/li&gt;
  &lt;li&gt;Time spend to build and run has been reduced, from 24 minutes (at best) to a bit less than 5 minutes&lt;/li&gt;
  &lt;li&gt;Our implementation is not working as expected, we still have a lock in our registry targeting a child process that 
has not been stopped (and doing the sum up between what we have in database and what we have left in the queue confirmed it)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But that is not a problem anymore as we can deploy in less than 5 minutes.&lt;/p&gt;

&lt;p&gt;Let’s take a look at what we’ve missed. We now know that the parent process has been forked after the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SIGTERM&lt;/code&gt; has been 
received, that means we have a kind of state machine to implement:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Do not fork the parent process if a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SIGTERM&lt;/code&gt; has been received&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Implement it, test it!&lt;/p&gt;

&lt;p&gt;Doing the exact same process explained above we finally came to a solution and our test session result is:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;First Stop
    &lt;ul&gt;
      &lt;li&gt;43572 events in redis queue at start&lt;/li&gt;
      &lt;li&gt;42672 events in redis queue when docker stops&lt;/li&gt;
      &lt;li&gt;Lock registry cleaned&lt;/li&gt;
      &lt;li&gt;900 events present in database (numbers add up ✅)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Second Stop
    &lt;ul&gt;
      &lt;li&gt;42672 events in redis queue&lt;/li&gt;
      &lt;li&gt;42222 events in redis queue when docker stops&lt;/li&gt;
      &lt;li&gt;Lock registry cleaned&lt;/li&gt;
      &lt;li&gt;1350 events present in database&lt;/li&gt;
      &lt;li&gt;1350 - 900 = 450 (Youhou, all is good)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Third Stop
    &lt;ul&gt;
      &lt;li&gt;42222 events in redis queue&lt;/li&gt;
      &lt;li&gt;36972 events in redis queue when docker stops&lt;/li&gt;
      &lt;li&gt;6600 events present in database&lt;/li&gt;
      &lt;li&gt;6600 - 1350 = 5250 (number add up ✅)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Fourth Stop
    &lt;ul&gt;
      &lt;li&gt;36972 events in redis queue&lt;/li&gt;
      &lt;li&gt;25897 events in redis queue when docker stops&lt;/li&gt;
      &lt;li&gt;17675 events present in database&lt;/li&gt;
      &lt;li&gt;17675 - 6600 = 11075 (number add up ✅)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;It took us 2 days, 2 days and half to rework our local environment.&lt;/p&gt;

&lt;p&gt;At the end we succeeded to&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;reduce the feedback loop by 5&lt;/li&gt;
  &lt;li&gt;reduce the number of steps by 2&lt;/li&gt;
  &lt;li&gt;implement a solution&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Having the smallest possible feedback loop when building a software is a target to reach and think about all the time.&lt;/p&gt;

&lt;p&gt;This is one of the pillar in continuous improvement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where is the pride in all of that?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Of course, we are proud to have succeeded but there is more than this. We took the time to experiment, 
to switch uncertainty to certainty. We improved the product to first ease our colleagues work and second to be more efficient
for our users in the future, because what you do as a software developer is not only for yourself, it is for all the people
involved one day or another in the product you’ve been working on.&lt;/p&gt;

&lt;h2 id=&quot;thanks&quot;&gt;Thanks&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;To Stéfanie who took the time to read it and gave me feedbacks (the conclusion about the pride is on her 🙏)&lt;/li&gt;
  &lt;li&gt;To Marc who gave me some tricks about the look and feel&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-code&quot;&gt;The code&lt;/h2&gt;

&lt;h3 id=&quot;the-agent&quot;&gt;The agent&lt;/h3&gt;
&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Agent&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;timer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NodeJS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Timer&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;killSignalReceived&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AppConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Logger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;redisService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;RedisClientService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;checkQueue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;param1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;param2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;//...&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;killSignalReceived&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;child&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fork&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;agentFilePath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;param1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;param2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sigterm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;killSignalReceived&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;graceful-stop&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;QueueConsumer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;registerLock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;redisService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;param1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;param2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;the-process-class&quot;&gt;The Process class&lt;/h3&gt;
&lt;div class=&quot;language-typescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Processor&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cleanup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Process&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sigterm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Loggerable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Processor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;SIGTERM&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Loggerable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Processor&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;cleanup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;stop-node-process&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; received on pid &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;stopped-node-process&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Node process starting cleanup&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
              &lt;span class=&quot;nx&quot;&gt;cleanup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
              &lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;stop-node-process&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;na&quot;&gt;payload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
              &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Processor&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content><author><name>Bertrand Bougon</name></author><category term="experimentation" /><category term="XP" /><summary type="html">Sometime, even if it’s not that easy, trying hard to resolve something you are not sure about, at the end you can be proud about what you’ve done and God it’s good to feel proud about something you achieved.</summary></entry></feed>