<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Avalon Lab</title>
    <description>The latest articles on DEV Community by Avalon Lab (@avalon-lab).</description>
    <link>https://dev.to/avalon-lab</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1423%2Fe67c1313-2eb9-4681-947e-09abf726a941.png</url>
      <title>DEV Community: Avalon Lab</title>
      <link>https://dev.to/avalon-lab</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/avalon-lab"/>
    <language>en</language>
    <item>
      <title>Pourquoi écrire des Documents de Choix d'Architecture ? (Architecture Decision Record)</title>
      <dc:creator>Jean-François Le Foll</dc:creator>
      <pubDate>Wed, 16 Jun 2021 13:50:22 +0000</pubDate>
      <link>https://dev.to/avalon-lab/pourquoi-ecrire-des-documents-de-choix-d-architecture-architecture-decision-record-101c</link>
      <guid>https://dev.to/avalon-lab/pourquoi-ecrire-des-documents-de-choix-d-architecture-architecture-decision-record-101c</guid>
      <description>&lt;h2&gt;
  
  
  Tout d'abord qu'est-ce qu'un ADR ?
&lt;/h2&gt;

&lt;p&gt;La base de notre métier est de faire des choix : choix de technologie, choix d'architecture, choix d'implémentation...&lt;br&gt;
Certains sont plus impactants que d'autres.&lt;/p&gt;

&lt;p&gt;Le but d'un ADR est de documenter et de tracer le raisonnement derrière ces choix, en gardant le contexte du niveau de connaissance et de maîtrise du sujet au moment de ce choix.&lt;br&gt;
Quel était mon problème ? Quelles étaient les différentes solutions envisagées ? Quels éléments nous ont amenés vers ce choix ?&lt;/p&gt;

&lt;h2&gt;
  
  
  Quel formalisme pour un ADR ?
&lt;/h2&gt;

&lt;p&gt;Un ADR, c'est un document texte, facile à partager au sein de l'équipe (dans un wiki ou dans un repository par exemple).&lt;/p&gt;

&lt;p&gt;C'est un document immuable, il n'a pas vocation à être mis à jour, au mieux le statut peut changer si cette décision est remplacée par une autre.&lt;/p&gt;

&lt;p&gt;Le titre de l'ADR doit être explicite : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;choix_langage_backend&lt;/li&gt;
&lt;li&gt;choix_base_de_données&lt;/li&gt;
&lt;li&gt;gestion_des_dates&lt;/li&gt;
&lt;li&gt;format_des_logs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Décrivez clairement le contexte, pourquoi cette décision se pose, quel problème / contrainte essayons nous de résoudre ?&lt;/p&gt;

&lt;p&gt;Décrivez le raisonnement qui vous amène à votre décision, n’hésitez pas à lister les expérimentations que vous avez faites, les articles sur lesquels vous vous êtes basés, tout ce qui vous permettra de comprendre votre décision si vous relisez l'ADR dans 6 mois.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Ce sont pour moi, les trois parties les plus importantes d'un ADR : titre, contexte, raisonnement/décision&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Vous pouvez également décrire les conséquences qu'aura ce choix (par exemple nouvelle contrainte ou nouvelle complexité).&lt;br&gt;
Vous pouvez aussi ajouter un statut à votre ADR (accepté, rejeté, déprécié, remplacé...).&lt;/p&gt;

&lt;p&gt;Vous pouvez trouver des modèles d'ADR beaucoup plus détaillés sur internet, mais au final c'est vous et votre équipe qui allez les écrire et les lire donc choisissez les rubriques qui sont pertinentes pour vous.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Dans un contexte en constante évolution, où nous apprenons de nouvelles choses régulièrement (sur les besoins des utilisateurs, sur les technos, ...), pouvoir pourquoi et comment tel ou tel choix a été fait est important pour une équipe et sa compréhension de son produit.&lt;br&gt;
C'est aussi une source d'information pratique pour les nouveaux arrivants dans l'équipe.&lt;/p&gt;




&lt;p&gt;D'un point de vue personnel, chez Avalon Lab, nous sommes des prestataires, nous accompagnons des entreprises et porteurs de projets qui n'ont pas forcément d'équipe technique.&lt;br&gt;
Dans ce cas, les ADR nous permettent de documenter tous les choix technologiques et d'architectures que nous prenons, car finalement ce n'est pas nous qui allons vivre avec ces choix, mais bien les développeurs·euses qui seront recruté·e·s plus tard par le client. &lt;br&gt;
Les ADR leurs permettrons de comprendre comment et pourquoi le produit est ce qu'il est.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Pour aller plus loin sur le sujet des ADR : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://adr.github.io/"&gt;ADR GitHub organization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/joelparkerhenderson/architecture-decision-record"&gt;Architecture decision record (ADR)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Cover Photo by &lt;a href="https://unsplash.com/@kaleidico?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Kaleidico&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>architecture</category>
      <category>documentation</category>
      <category>adr</category>
    </item>
    <item>
      <title>Setting up a typescript project in 2021</title>
      <dc:creator>Marceau "XioRcaL" Lacroix</dc:creator>
      <pubDate>Wed, 28 Apr 2021 07:48:50 +0000</pubDate>
      <link>https://dev.to/avalon-lab/setting-up-a-typescript-project-in-2021-4cfg</link>
      <guid>https://dev.to/avalon-lab/setting-up-a-typescript-project-in-2021-4cfg</guid>
      <description>&lt;p&gt;This post will describe how to create a project in typescript from scratch. The final project include some basic code, tests, commit hooks to enforce code formating, automatic tests on push and more ! I hope you'll enjoy it :)&lt;/p&gt;

&lt;h1&gt;
  
  
  TL; DR
&lt;/h1&gt;

&lt;p&gt;find the code &lt;a href="https://github.com/xiorcal/ts-demo"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Basics
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Before you start
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;you should have node/npm (latest lts should do the trick)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm init&lt;/code&gt; was run. So you have a &lt;code&gt;package.json&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting up typescript
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Typescript itself
&lt;/h3&gt;

&lt;p&gt;Pretty straight-forward : &lt;code&gt;npm install typescript --save-dev&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now check if that worked ; create a file &lt;code&gt;src/demo.ts&lt;/code&gt; and fill it with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;greeter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;person&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;person&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;greeter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;World&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And run... Wait... what should I run ? Meh that JS, a &lt;code&gt;node src/demo.ts&lt;/code&gt; will do it !&lt;br&gt;
...&lt;br&gt;
Oh no... Why does it complains about some unexpected ':' ?&lt;br&gt;
:-/&lt;/p&gt;
&lt;h3&gt;
  
  
  Configuring typescript itself
&lt;/h3&gt;

&lt;p&gt;I like to use a recommended default setting for tsc (typescript compiler) : &lt;code&gt;npm install --save-dev @tsconfig/recommended&lt;/code&gt; then create a file named &lt;code&gt;tsconfig.json&lt;/code&gt; and fill it with :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"extends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"@tsconfig/recommended/tsconfig.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"outDir"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./dist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"include"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"src/**/*"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"exclude"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"node_modules"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dist"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in your package.json add a script for build : &lt;code&gt;"build": "tsc",&lt;/code&gt;&lt;br&gt;
you should be able to run &lt;code&gt;npm run build&lt;/code&gt; then &lt;code&gt;node dist/demo.js&lt;/code&gt;&lt;br&gt;
Nice !&lt;/p&gt;
&lt;h3&gt;
  
  
  Speeding things up
&lt;/h3&gt;

&lt;p&gt;well I'm the kind of person that does not like to have to type 2 commands everytime my code changes. So lets spend some time automating it a bit&lt;/p&gt;

&lt;p&gt;first add tsc-watch to the project: &lt;code&gt;npm install tsc-watch --save-dev&lt;/code&gt;&lt;br&gt;
then add a watch script to the package:&lt;br&gt;
&lt;code&gt;"watch": "tsc-watch --onSuccess \"node ./dist/demo.js\"",&lt;/code&gt;&lt;br&gt;
now you can run &lt;code&gt;npm watch&lt;/code&gt; and every change you made will imediately be complied and run ! &lt;/p&gt;
&lt;h2&gt;
  
  
  Enforce the "2 spaces or GTFO" law !
&lt;/h2&gt;

&lt;p&gt;formatting will be done with eslint and prettier, enforcing formatting will be done with husky and its pre-commit hooks &lt;/p&gt;
&lt;h3&gt;
  
  
  configuring style tools
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-config-prettier eslint-plugin-import prettier
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;in &lt;code&gt;.eslintrc.js&lt;/code&gt; file :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@typescript-eslint/parser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;parserOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tsconfig.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;sourceType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;module&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@typescript-eslint/eslint-plugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;extends&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;eslint:recommended&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;plugin:@typescript-eslint/recommended&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;prettier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in &lt;code&gt;.eslintignore&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node_modules
dist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in &lt;code&gt;.prettierrc.js&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;trailingComma&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;all&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;tabWidth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;singleQuote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;add a &lt;code&gt;lint&lt;/code&gt; script to package.json :&lt;br&gt;
&lt;code&gt;"lint": "eslint src --ext .js,.jsx,.ts,.tsx"&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Automate it
&lt;/h3&gt;

&lt;p&gt;Once again, I'm lazy, so I need those tools to run automatically for me. That's where husky commes to play!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; husky pretty-quick
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;add a prepare script : &lt;code&gt;"prepare": "husky install"&lt;/code&gt;&lt;br&gt;
run it : &lt;code&gt;npm run prepare&lt;/code&gt;&lt;br&gt;
you should see a .husky directory now.&lt;br&gt;
create a file nammed &lt;code&gt;pre-commit&lt;/code&gt; in this directory and fill it with :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/_/husky.sh"&lt;/span&gt;

npx &lt;span class="nt"&gt;--no-install&lt;/span&gt; pretty-quick &lt;span class="nt"&gt;--staged&lt;/span&gt;
npm run lint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;now your formatting will be fixed on commit \o/&lt;/p&gt;

&lt;h2&gt;
  
  
  enforce the "meaningful commit or GTFO" law !
&lt;/h2&gt;

&lt;p&gt;this will be done with commit-lint &lt;br&gt;
&lt;code&gt;npm install --save-dev @commitlint/config-conventional @commitlint/cli&lt;/code&gt;&lt;br&gt;
then create a &lt;code&gt;commit-msg&lt;/code&gt; file in .husky directory with :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/_/husky.sh"&lt;/span&gt;

npx &lt;span class="nt"&gt;--no-install&lt;/span&gt; commitlint &lt;span class="nt"&gt;--edit&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and a &lt;code&gt;commitlint.config.js&lt;/code&gt; with &lt;code&gt;module.exports = {extends: ['@commitlint/config-conventional']}&lt;/code&gt; in it.&lt;br&gt;
Now your commit messages are force to obey the law !&lt;/p&gt;
&lt;h2&gt;
  
  
  Prevent your friends to break the law
&lt;/h2&gt;

&lt;p&gt;husky take care of that for you :)&lt;/p&gt;
&lt;h2&gt;
  
  
  These are not the tests you are looking for
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Set-up
&lt;/h3&gt;

&lt;p&gt;I use jest so we need to install it first: &lt;code&gt;npm install -D jest ts-jest @types/jest&lt;/code&gt;&lt;br&gt;
then config, &lt;code&gt;jest.config.js&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;preset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ts-jest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;testEnvironment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;add a test script : &lt;code&gt;"test": "jest"&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Your very first test
&lt;/h3&gt;

&lt;p&gt;in &lt;code&gt;demo.spec.ts&lt;/code&gt; we are going to ensure that our greeter is really polite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;greeter&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./demo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;greeter function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a greet should start with Hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;greeter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bob&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;try it with &lt;code&gt;npm run test&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Guess what...? AUTOMATION
&lt;/h3&gt;

&lt;p&gt;This time no external deps nor manual tweaking ! jest took care of that for us. simply run &lt;code&gt;jest --watch&lt;/code&gt; ! Your tests should run on source edit. Alternatively you can use an extension in your ide to do it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up your dev env
&lt;/h2&gt;

&lt;p&gt;I'm using vscode so this is the one that will be covered by this section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extensions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=Orta.vscode-jest"&gt;Jest (orta.vscode-jest)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint"&gt;ESLint (dbaeumer.vscode-eslint)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode"&gt;Prettier - Code formatter (esbenp.prettier-vscode)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I suggest enabling code coverage overlay for jest (io.orta.jest.coverage.toggle).&lt;br&gt;
Using prettier as formatter directly in editor will instantanely format your code correctly rather than on commit.&lt;/p&gt;
&lt;h2&gt;
  
  
  Time for release ?
&lt;/h2&gt;

&lt;p&gt;Ok so your greeter is now ready for its first release ! Lets take advantage of our strict commit message policy to have a nice changelog ! standard-version will help us do so &lt;br&gt;
&lt;code&gt;npm i --save-dev standard-version&lt;/code&gt;&lt;br&gt;
and a release script : &lt;code&gt;"release": "standard-version"&lt;/code&gt;&lt;br&gt;
finally run &lt;code&gt;npm run release -- --first-release&lt;/code&gt; to do your... first release !&lt;/p&gt;
&lt;h1&gt;
  
  
  automate it, noob !
&lt;/h1&gt;

&lt;p&gt;using github actions because those are pretty neat. create a &lt;code&gt;.github/workflows/&lt;/code&gt; directory to setup those actions.&lt;/p&gt;
&lt;h2&gt;
  
  
  auto test on commit
&lt;/h2&gt;

&lt;p&gt;This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node&lt;br&gt;
&lt;a href="https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions"&gt;For more information&lt;/a&gt;&lt;br&gt;
&lt;code&gt;node.js.yml&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;
&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Node.js CI&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;12.x&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;14.x&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use Node.js ${{ matrix.node-version }}&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v1&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.node-version }}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build --if-present&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  auto publish on release
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;npmPublish.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish package on npm&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;created&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;publish-npm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;
          &lt;span class="na"&gt;registry-url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://registry.npmjs.org/&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cache node modules&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/cache@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/.npm&lt;/span&gt; &lt;span class="c1"&gt;# npm cache files are stored in `~/.npm` on Linux/macOS&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}&lt;/span&gt;
          &lt;span class="na"&gt;restore-keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;${{ runner.os }}-build-${{ env.cache-name }}-&lt;/span&gt;
            &lt;span class="s"&gt;${{ runner.os }}-build-&lt;/span&gt;
            &lt;span class="s"&gt;${{ runner.os }}-&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;if [ ${{ github.event.release.action }} = "prereleased" ]; then&lt;/span&gt;
            &lt;span class="s"&gt;npm publish --tag beta&lt;/span&gt;
          &lt;span class="s"&gt;else&lt;/span&gt;
            &lt;span class="s"&gt;npm publish&lt;/span&gt;
          &lt;span class="s"&gt;fi&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;NODE_AUTH_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{secrets.npm_token}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;NPM_TOKEN&lt;/code&gt; is a &lt;strong&gt;repository secret&lt;/strong&gt; holding an access token with publish rights from npm. get your own at &lt;a href="https://www.npmjs.com/settings/%7BYOUR_USER%7D/tokens"&gt;https://www.npmjs.com/settings/{YOUR_USER}/tokens&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  fun stuff
&lt;/h1&gt;

&lt;p&gt;haha you whish&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>CTO d'amorçage / Team as a Service, qu'est-ce que c'est ?</title>
      <dc:creator>Jean-François Le Foll</dc:creator>
      <pubDate>Wed, 13 May 2020 14:57:45 +0000</pubDate>
      <link>https://dev.to/avalon-lab/cto-d-amorcage-team-as-a-service-qu-est-ce-que-c-est-42jd</link>
      <guid>https://dev.to/avalon-lab/cto-d-amorcage-team-as-a-service-qu-est-ce-que-c-est-42jd</guid>
      <description>&lt;p&gt;Le principe du CTO d'amorçage / Team as a Service est d'intervenir, à minima en binôme, dans une structure sans compétence disponible en développement logiciel (développement, gestion de projet, etc ...) afin de démarrer un projet, d'accompagner le client sur le développement et la conception de son produit ou MVP, de poser les bases d'une architecture saine et éventuellement de l'aider dans son recrutement de développeurs.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j273nhM0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/dfokm7boeba8w6aslb4i.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j273nhM0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/dfokm7boeba8w6aslb4i.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nous avons abordé notre action de CTO d'amorçage / Team as a Service suivant trois axes : tout d'abord d'un point de vue apprentissage fonctionnel, puis d'un point de vue méthodologique et enfin d'un point de vue technique.&lt;/p&gt;

&lt;h1&gt;
  
  
  Apprentissage fonctionnel
&lt;/h1&gt;

&lt;p&gt;Le métier de ce client était quelque chose de nouveaux pour nous, nous avons donc fait plusieurs ateliers d'Event Storming avec l'expert métier.  &lt;/p&gt;

&lt;p&gt;Le but de ces ateliers est multiple :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Découvrir le langage métier de l'expert (et donc partager le même langage entre le code et la réalité métier)&lt;/li&gt;
&lt;li&gt;Découvrir le fonctionnement de l'outil, le process métier, les besoins&lt;/li&gt;
&lt;li&gt;Avoir une première idée / ébauche de la conception du logiciel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ceci s'inscrit dans une approche Domain-Driven Design (DDD) ou Conception pilotée par le domaine (métier).&lt;/p&gt;

&lt;p&gt;Ces ateliers sont refaits régulièrement, par exemple pour présenter un nouveau use case afin d'en explorer le fonctionnement.&lt;/p&gt;

&lt;h1&gt;
  
  
  Méthodologie
&lt;/h1&gt;

&lt;p&gt;Chez Avalon Lab, nous sommes convaincus par les principes de développement agile.&lt;br&gt;&lt;br&gt;
Nous avons un fonctionnement assez proche de la méthode eXtrem Programming :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contact étroit avec l'expert métier&lt;/li&gt;
&lt;li&gt;Livraison fréquente&lt;/li&gt;
&lt;li&gt;Feedback régulier&lt;/li&gt;
&lt;li&gt;Binômage&lt;/li&gt;
&lt;li&gt;Développement piloté par les tests (TDD)&lt;/li&gt;
&lt;li&gt;Intégration et déploiement continue&lt;/li&gt;
&lt;li&gt;Rythme soutenable&lt;/li&gt;
&lt;li&gt;Conception simple&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Intervenant dans un contexte "remote" dès le départ, l'expert métier n'étant pas localisé avec l'équipe de développement, nous avons mis en place plusieurs outils afin de collaborer efficacement en fonction des contraintes client :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gitlab (gitlab.com), pour la gestion de projets (user stories, bug tracker, milestone)&lt;/li&gt;
&lt;li&gt;Miro (miro.com), un tableau blanc collaboratif (schémas, atelier post-it)&lt;/li&gt;
&lt;li&gt;Skype ou autre, notamment pour faire des démos, via le partage d'écran.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Technique
&lt;/h1&gt;

&lt;p&gt;L'approche DDD, notamment au travers d'ateliers type Event Storming, nous permet de mieux concevoir l'application.&lt;br&gt;&lt;br&gt;
L'application est découpée en domaine, unités logiques correspondant à un regroupement logique de sens métier.&lt;/p&gt;

&lt;p&gt;Pour implémenter ces domaines, nous avons suivi les principes de l'architecture hexagonale où tout le code, correspondant aux règles métier, est correctement isolé de l'extérieur (base de données, web services, interface utilisateur) et n'est pas "pollué" par du code provenant d'un quelconque framework ce qui rend les choix de solutions type framework moins définitive et impactant.&lt;/p&gt;

&lt;p&gt;Aujourd'hui, on sait que les fonctions principales d'un logiciel concernent principalement de la présentation de données (certains parlent de 80 % lecture de données et 20 % écriture de données).&lt;/p&gt;

&lt;p&gt;Partant de ce constant, nous avons adopté le pattern CQRS (Command Query Responsibility Segregation) qui sépare les tâches d'écriture (command), des tâches de lecture (query) et ayant des modèles de donnés séparés.&lt;br&gt;
&lt;strong&gt;&lt;em&gt;[Ce pattern peut être étendu avec le principe d'Event Sourcing lorsque le métier requiert un traçage / audit des différentes actions.]&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Toutes les décisions d'architectures / de choix techniques sont tracés dans des documents de décision d'architecture (Architecture decision record - &lt;a href="https://github.com/joelparkerhenderson/architecture_decision_record"&gt;ADR&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture SI
&lt;/h3&gt;

&lt;p&gt;L'architecture physique du SI évolue en fonction des besoins métier, tout en se basant sur les principes généraux des &lt;a href="https://12factor.net/fr/"&gt;12 factors&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Nous avons d'un côté un frontal web (SPA) et de l'autre un backend métier.&lt;/p&gt;

&lt;p&gt;Pour le backend métier, notre principe de base est de démarrer avec un monolithe, comme nous adoptons une démarche DDD, ce monolithe embarque nos domaines qui eux sont indépendants et correctement séparés.&lt;br&gt;&lt;br&gt;
L'avantage est de simplifier la phase de construction de l'application ainsi que sont déploiement et son monitoring tout en gardant la flexibilité de pouvoir sortir un domaine afin de répondre à un nouveau besoin ou à des contraintes de charges spécifiques.&lt;/p&gt;

&lt;p&gt;De plus, cette architecture est déclinée en deux versions :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test/intégration =&amp;gt; construite directement depuis les sources, à chaque modification (Continuous Deployement), permet aux développeurs et à l'expert métier de tester sur un environnement déployé.&lt;/li&gt;
&lt;li&gt;Production =&amp;gt; construite et déployée à la demande, ouverte aux clients.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Technologie
&lt;/h3&gt;

&lt;p&gt;Dans l'optique d'aider le client à recruter des développeurs et un CTO, nous sommes partis sur des technologies fiables, connues et pour lesquelles il est facile de recruter tout en respectant nos critères de qualités.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VueJS / Web Component (lit-element)&lt;/li&gt;
&lt;li&gt;Java 11&lt;/li&gt;
&lt;li&gt;Gitlab : gestion de code et ci/cd&lt;/li&gt;
&lt;li&gt;Datadog : collecte et analyse des logs applicatives / monitoring &lt;strong&gt;&lt;em&gt;[peut être remplacé par Elastic Stack]&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Clever Cloud : gestion de l'infrastructure&lt;/li&gt;
&lt;li&gt;Izanami : Configuration partagée, features flipping&lt;/li&gt;
&lt;li&gt;Warp10 : Base de données de séries temporelles&lt;/li&gt;
&lt;li&gt;Cellar / AWS S3 : stockage de fichiers&lt;/li&gt;
&lt;li&gt;SonarCloud : Analyse qualité du code
&lt;/li&gt;
&lt;/ul&gt;




&lt;blockquote&gt;
&lt;p&gt;Cet article vous a intéressé, vous avez envie d'en savoir plus ou par rapport à vos besoins ?&lt;br&gt;&lt;br&gt;
N'hésitez pas à nous envoyer un mail à &lt;a href="mailto:contact@avalon-lab.coop"&gt;contact@avalon-lab.coop&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>cto</category>
      <category>esn</category>
      <category>service</category>
    </item>
    <item>
      <title>Server-Sent Events démystifiés, avec un cas concret.</title>
      <dc:creator>Jean-François Le Foll</dc:creator>
      <pubDate>Wed, 11 Mar 2020 16:18:28 +0000</pubDate>
      <link>https://dev.to/avalon-lab/server-sent-events-demystifies-avec-un-cas-concret-402</link>
      <guid>https://dev.to/avalon-lab/server-sent-events-demystifies-avec-un-cas-concret-402</guid>
      <description>&lt;h1&gt;
  
  
  Préface
&lt;/h1&gt;

&lt;p&gt;Avant d'aller plus loin, expliquons d'abord ce que sont les Server-sent Events (SSE pour les intimes).&lt;/p&gt;

&lt;p&gt;Il s'agit d'un canal unidirectionnel permettant au serveur d'envoyer des messages à un navigateur.&lt;/p&gt;

&lt;p&gt;C'est une techno ancienne, qui date de 2009-2010 et est disponible au grand public depuis les versions 6 de Chrome et Firefox, mais qui a été un peu mise de coté à l'arrivée des WebSockets.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2TCgqWag--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nw4l78nremv2lpsn8502.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2TCgqWag--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nw4l78nremv2lpsn8502.JPG" alt="Alt Text" width="880" height="269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Objectif ?
&lt;/h1&gt;

&lt;p&gt;Le but de cette démo est de construire un cas concret d'utilisation de SSE.&lt;br&gt;
Beaucoup d'articles ou de démos que j'ai pu trouver ne montrent guère autre chose qu'un event pré-construit envoyé à intervalle régulier, pas grand-chose à voir avec la réalité.&lt;/p&gt;

&lt;p&gt;Dans cette démo, nous allons construire une API Rest, qui poussera un message dans un RabbitMQ en mode Fan-out.&lt;br&gt;
De l'autre coté, nous aurons un serveur nodejs qui écoutera les messages et poussera un SSE au bon client de la webapp servi par le nodejs.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mY9zZemB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3nugak40uy99zb18827b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mY9zZemB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3nugak40uy99zb18827b.png" alt="Alt Text" width="880" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dans l'objet poussé sur l'endpoint, nous avons un client ID, ce qui permet d'avoir plusieurs onglets ouverts sur la web app et ainsi voir que les SSE arrivent seulement au bon client.&lt;/p&gt;
&lt;h1&gt;
  
  
  Le code :
&lt;/h1&gt;
&lt;h3&gt;
  
  
  L'API Rest
&lt;/h3&gt;

&lt;p&gt;Je ne vais pas entrer ici dans les détails de l'API Rest, c'est une API Java (&lt;a href="https://jooby.io"&gt;Jooby 2&lt;/a&gt;) qui sert de producer RabbitMQ.&lt;/p&gt;
&lt;h3&gt;
  
  
  La Web App
&lt;/h3&gt;

&lt;p&gt;Il s'agit d'une simple page html avec un Web Component (les dépendances sont chargées directement avec &lt;a href="https://www.pika.dev/"&gt;Pika&lt;/a&gt;, cela peut prendre quelques secondes).&lt;/p&gt;

&lt;p&gt;Pour se connecter à un endpoint SSE, rien de plus simple, il suffit de définir un &lt;a href="https://developer.mozilla.org/fr/docs/Web/API/EventSource"&gt;&lt;code&gt;EventSource&lt;/code&gt;&lt;/a&gt; qui prend en paramètre l'url de la source.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sseSource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;EventSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/event-stream/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Dans notre cas, nous ajoutons dans l'url le clientId du client connecté.&lt;/p&gt;

&lt;p&gt;Sur cet objet EventSource nous allons venir définir un event listener, le but est de ne réagir qu'aux messages de type &lt;code&gt;notif&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="nx"&gt;sseSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;notif&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;notifications&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Ce code nous permet d'incrémenter un compteur et d’alimenter un tableau avec le message de l’événement. &lt;br&gt;
C'est tout pour la partie front.&lt;/p&gt;
&lt;h3&gt;
  
  
  La partie serveur NodeJs
&lt;/h3&gt;
&lt;h4&gt;
  
  
  1) Le point d'entrée SSE
&lt;/h4&gt;

&lt;p&gt;Ici on utilise ExpressJS car il n'y rien de particulier à faire pour mettre en place la ressource SSE :&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/event-stream/:clientId&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;clientId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/event-stream&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cache-Control&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no-cache&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;keep-alive&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;connections&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Connection open for client : &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="nx"&gt;connections&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Ici nous définissons notre ressource &lt;code&gt;GET "/event-stream/:clientId"&lt;/code&gt; avec un paramètre &lt;code&gt;clientId&lt;/code&gt; qui nous permet de stocker l'objet &lt;code&gt;response&lt;/code&gt; sur lequel envoyer les messages :&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="nx"&gt;connections&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Mais avant de stocker cette réponse, il faut la "configurer" pour le SSE :&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;writeHead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text/event-stream&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cache-Control&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no-cache&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;Connection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;keep-alive&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Pour résumer cette partie, à chaque fois qu'un client fait un &lt;code&gt;GET&lt;/code&gt; sur notre ressource SSE, nous stockons dans un objet sont &lt;code&gt;clientId&lt;/code&gt; et l'objet &lt;code&gt;response&lt;/code&gt; afin de lui pousser des messages ultérieurement.&lt;/p&gt;
&lt;h4&gt;
  
  
  2) Le consumer RabbitMQ
&lt;/h4&gt;

&lt;p&gt;Afin de pouvoir se connecter sur le RabbitMQ, nous allons avoir besoin de la dépendance vers la librairie &lt;code&gt;amqplib&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;amqp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;amqplib/callback_api&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// =&amp;gt; fonctionne avec des callback&lt;/span&gt;
&lt;span class="c1"&gt;// ou&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;amqp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;amqplib&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// =&amp;gt; fonctionne avec des promesses&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Au démarrage du serveur nodejs, on ouvre une connexion vers RabbitMQ&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;amqp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;amqp://localhost&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Dans cette connexion, on va créer un channel sur notre Exchange et une Queue (Cf dépôt Github pour le code de cette partie).&lt;/p&gt;

&lt;p&gt;Ce qui nous intéresse ici, c'est de voir comment on consomme les messages.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;      &lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;consume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New message for client : &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;clientRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;connections&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientRes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nx"&gt;clientRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`event: notif\n`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
              &lt;span class="nx"&gt;clientRes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`data: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n\n`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;noAck&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;On va parser le message pour en récupérer le contenu, grâce au &lt;code&gt;clientId&lt;/code&gt; du message, on récupère notre objet &lt;code&gt;response&lt;/code&gt; qui correspond.&lt;br&gt;
Si elle existe, on vient écrire une première ligne avec le type d'événement &lt;code&gt;clientRes.write('event: notif\n');&lt;/code&gt; (pour rappel notre front n'écoute que les messages &lt;code&gt;notif&lt;/code&gt;).&lt;br&gt;
Puis une seconde ligne avec le contenu du message &lt;code&gt;clientRes.write('data: ${data.content}\n\n');&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Et voilà, nous avons poussé notre message dans notre stream d'événements.&lt;br&gt;
Le front réagi, incrémente le compteur et affiche le message !&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T7DS3eBB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/s4kwhq47efy8hcu13w52.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T7DS3eBB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/s4kwhq47efy8hcu13w52.JPG" alt="Alt Text" width="642" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;J'espère que maintenant l'utilisation des SSE est un peu plus claire et concrète pour vous aussi :)&lt;/p&gt;



&lt;p&gt;Le code de la démo complète est disponible sur GitHub : &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Avalon-Lab"&gt;
        Avalon-Lab
      &lt;/a&gt; / &lt;a href="https://github.com/Avalon-Lab/realtime-webapp-sse-rabbitmq"&gt;
        realtime-webapp-sse-rabbitmq
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Demo WebApp temps réel avec SSE et RabbitMQ
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



</description>
      <category>sse</category>
      <category>rabbitmq</category>
      <category>reactivewebapp</category>
      <category>usecase</category>
    </item>
    <item>
      <title>Utiliser les Futures avec Vavr</title>
      <dc:creator>Mathieu Marchadour</dc:creator>
      <pubDate>Wed, 13 Nov 2019 15:20:44 +0000</pubDate>
      <link>https://dev.to/avalon-lab/utiliser-les-futures-avec-vavr-406k</link>
      <guid>https://dev.to/avalon-lab/utiliser-les-futures-avec-vavr-406k</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Dans le cadre d’un projet chez l’un de nos clients, on nous a chargé de réaliser une API. Celle-ci avait la responsabilité d’agréger différentes données venant de plusieurs API.&lt;/p&gt;

&lt;p&gt;À des fins de performance, nous avons choisi de paralléliser les appels et d’utiliser les Futures.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Présentation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;La librairie Vavr est utilisable à partir de la version 8 de Java.&lt;br&gt;&lt;br&gt;
Cette librairie a pour but d’améliorer le coté programmation fonctionnelle de Java 8 en ajoutant notamment des types de données immuables et des structures de contrôles orientés fonctionnelles.&lt;/p&gt;

&lt;p&gt;C'est parmi ces types de données immuables que nous trouvons notre Future, objet de cet article.&lt;/p&gt;

&lt;p&gt;Une Future va permettre de réaliser une action dont le résultat sera disponible dans le futur.&lt;/p&gt;

&lt;p&gt;Lorsque l'action de la Future est terminée, trois états de celle-ci sont possibles :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;completed&lt;/em&gt;: lorsque la Future s'est terminée&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;success&lt;/em&gt;: lorsque la Future s'est terminée avec succès&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;failure&lt;/em&gt;: lorsque la Future s'est terminée en erreur&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Il est possible d'ajouter des callbacks afin d'intercepter ces trois états.&lt;/p&gt;

&lt;p&gt;Chez notre client, cela permettait de lancer X actions (Futures) permettant de récupérer des données, attendre le résultat de chacune et agréger toutes les données. Pour mettre en place ceci, nous avons créé une liste de Futures, les avons packagées dans une séquence. Nous devons attendre le résultat de toutes les Futures et avons donc bloqué les différents Thread grâce à la méthode .await(). Ensuite, la méthode .get() nous permet d’obtenir le résultat de la Future.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Illustration : la course d'animaux&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Afin de lancer la course et de vous présenter les Futures, nous allons réaliser un test unitaire.&lt;/p&gt;

&lt;p&gt;Création de la classe Java Animal avec son nom, sa famille, son type et vitesse moyenne. L'annotation @Data vient du projet Lombok : une librairie de génération de code. Ce projet fera l'objet d'un autre article.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;Ici, nous initialisons 5 animaux qui sont de famille et de vitesse différentes.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;Le test unitaire:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;Résultat du test unitaire :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3Dr-sWPo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A-CVF6alZYl2MtAQvImBhAA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3Dr-sWPo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A-CVF6alZYl2MtAQvImBhAA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Grâce à ce test unitaire, nous avons utilisé la librairie Vavr, disponible à partir de Java 8, afin de paralléliser des traitements. Cette librairie ne permet pas uniquement l’utilisation de Future mais elle implémente aussi des Collections, List, Map, Option, Try …&lt;/p&gt;

&lt;p&gt;La documentation de Vavr est disponible ci-dessous afin d’approfondir cette librairie.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Documentation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://www.vavr.io/"&gt;Site officiel Vavr&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.baeldung.com/vavr-future"&gt;Introduction to Future in Vavr | Baeldung&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Premiers pas avec AutoHotkey</title>
      <dc:creator>Marceau "XioRcaL" Lacroix</dc:creator>
      <pubDate>Wed, 06 Nov 2019 14:58:13 +0000</pubDate>
      <link>https://dev.to/avalon-lab/premiers-pas-avec-autohotkey-4ffg</link>
      <guid>https://dev.to/avalon-lab/premiers-pas-avec-autohotkey-4ffg</guid>
      <description>&lt;h2&gt;
  
  
  Trop long / Pas lu
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Avalon-Lab/tooling/tree/master/akh_scripts/show_my_console"&gt;le code est là&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Problématique de base
&lt;/h2&gt;

&lt;p&gt;Suite à changement d'environnement de boulot (poste de dev linux -&amp;gt; windows) j'ai besoin de retrouver certaines habitudes et notamment&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6jk9ZbaF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://extensions.gnome.org/extension-data/screenshots/screenshot_1411_8MWYILj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6jk9ZbaF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://extensions.gnome.org/extension-data/screenshots/screenshot_1411_8MWYILj.png" alt="Tilix quake like console"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oui je fais partie de ces gens qui ont besoin d'un terminal à portée d'une touche de clavier. Sauf qu’apparemment sous Windows ce fonctionnement n'existe pas. Depuis j'ai appris que c'était plus ou moins possible, voir la section alternative en bas de l'article.&lt;/p&gt;

&lt;h2&gt;
  
  
  C'est quoi AutoHotkey ?
&lt;/h2&gt;

&lt;p&gt;D'après leur site web c'est &lt;code&gt;The ultimate automation scripting language for Windows&lt;/code&gt;. Ça a l'air plutôt cool présenté comme ça ! Et effectivement ahk permet aussi bien de simuler un clic souris que d'utiliser des dll windows. Sur le papier ça devrait permettre de résoudre le problème.&lt;/p&gt;

&lt;h2&gt;
  
  
  Le script
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cibler la touche de déclenchement
&lt;/h3&gt;

&lt;p&gt;En temps normal c'est assez facile avec akh, il suffit d'écrire &lt;code&gt;Matouche::&lt;/code&gt; pour déclencher une action&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;j::
MsgBox, "vous avez appuyé sur 'j'"
return
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Sauf que moi j'ai envie d'utiliser ma touche ². Naïvement j'ai essayé&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;²::
MsgBox, "vous avez appuyé sur '²'"
return
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;qui produit un joli &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HWfMUT5y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/2cu25efrbfjpvz5rchkj.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HWfMUT5y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/2cu25efrbfjpvz5rchkj.PNG" alt="Erreur"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Il faut donc trouver un moyen d'identifier le code correspondant à la touche; la &lt;a href="https://www.autohotkey.com/docs/KeyList.htm#SpecialKeys"&gt;doc ahk&lt;/a&gt; sur le sujet est assez claire; il suffit d'ajouter &lt;code&gt;#InstallKeybdHook&lt;/code&gt; dans mon script et de regarder les logs. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f-0CNUtk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/29csvafmd7jkcv26my0c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f-0CNUtk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/29csvafmd7jkcv26my0c.png" alt="capture des frappes clavier"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Le code de la touche ² est donc &lt;code&gt;SC029&lt;/code&gt;; essayons ça :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SC029::
MsgBox, "vous avez appuyé sur '²'"
return
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;et ça marche! (il faut utiliser un encodage utf8 avec BOM pour avoir les caractères spéciaux affichés correctement)&lt;/p&gt;

&lt;h3&gt;
  
  
  La base : basculer sur une fenêtre existante
&lt;/h3&gt;

&lt;p&gt;Maintenant il faut identifier la fenêtre cible et la rendre active. Pour ça le mode 'Window Spy' est très pratique, il permet d'afficher le titre, la classe, l'executable et le pid de la fenêtre active.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CUj4or5t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/y2jkit0jtg69daz2npcr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CUj4or5t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/y2jkit0jtg69daz2npcr.png" alt="window spy du terminal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;L'algo qu'on cherche à implémenter en pseudo code donnerait quelque chose comme&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Si fenêtre active = terminal
  minimiser
  réactiver ancienne fenêtre
sinon
  sauvegarder ancienne fenêtre
  activer la fenêtre terminal

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Pour ça on va se servir des fonctions ahk suivantes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.autohotkey.com/docs/commands/WinActive.htm"&gt;WinActive&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.autohotkey.com/docs/commands/WinMinimize.htm"&gt;WinMinimize&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.autohotkey.com/docs/commands/WinActivate.htm"&gt;WinActivate&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;previous_active := ""

SC029::
  if WinActive("ahk_exe WindowsTerminal.exe") {
      WinMinimize, ahk_exe WindowsTerminal.exe
      if (previous_active) {
          WinActivate, ahk_id %previous_active%
      }
  } else {
      previous_active := WinExist("A")
      WinActivate, ahk_exe WindowsTerminal.exe
  }
return
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Et si mon terminal est fermé ?
&lt;/h3&gt;

&lt;p&gt;Là encore c'est assez simple, &lt;code&gt;run, C:\PATH_TO_MY_APP\app.exe&lt;/code&gt; devrait faire le job. Mais comme mon terminal vient du &lt;a href="https://www.microsoft.com/fr-fr/p/windows-terminal-preview/9n0dx20hk701"&gt;windows store&lt;/a&gt;, je n'ai pas de lien direct pour l’exécutable. J'ai trouvé une astuce qui consiste à créer un raccourci pour l'appli en question et référencer le raccourci dans le script. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Win + R &lt;code&gt;shell:appsFolder&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;clic droit créer un raccourci&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;run, path\to\raccourci&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;previous_active := ""

SC029::
if WinExist("ahk_exe WindowsTerminal.exe") {
    if WinActive("ahk_exe WindowsTerminal.exe") {
        WinMinimize, ahk_exe WindowsTerminal.exe
        if (previous_active) {
            WinActivate, ahk_id %previous_active%
        }
    } else {
        previous_active := WinExist("A")
        WinActivate, ahk_exe WindowsTerminal.exe
    }
} else{
    previous_active := WinExist("A")
    run, C:\PATH_TO\terminal_shortcut
}
return
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Pratique, mais si j'ai besoin de taper un ² ?
&lt;/h3&gt;

&lt;p&gt;Ajoutons un deuxième raccourci : Maj + ²&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+SC029::
Send ²
return
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;La liste des modificateurs est &lt;a href="https://www.autohotkey.com/docs/Tutorial.htm#s21"&gt;ici&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;une icône plus jolie :
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I_Icon = C:\PATH_TO\icon.ico
IfExist, %I_Icon%
  Menu, Tray, Icon, %I_Icon%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Alernatives
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;En épinglant une appli à la barre des taches il est possible de reproduire l'ouverture/basculement. Il suffit d'appuyer sur Win + 1..9 correspondant au "numéro" de l'app dans la barre des taches&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>autohotkey</category>
      <category>beginners</category>
      <category>french</category>
    </item>
    <item>
      <title>Retour sur SoCraTesDay à Rennes</title>
      <dc:creator>Jean-François Le Foll</dc:creator>
      <pubDate>Wed, 06 Nov 2019 14:56:36 +0000</pubDate>
      <link>https://dev.to/avalon-lab/retour-sur-socratesday-a-rennes-3ofg</link>
      <guid>https://dev.to/avalon-lab/retour-sur-socratesday-a-rennes-3ofg</guid>
      <description>&lt;p&gt;Vendredi 14 juin, j'ai eu la chance de participer à la première SoCraTesDay à Rennes.&lt;br&gt;&lt;br&gt;
Un forum ouvert d'une journée, autour du développement logiciel, des tests, de la qualité du code et du software craftsmanship.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Un forum ouvert ? Qu'est-ce que c'est ?
&lt;/h2&gt;

&lt;p&gt;Un forum ouvert est une façon de structurer une conférence, sans speakers, où les participants construisent eux-mêmes leurs programmes en fonction de leurs connaissances et de ce qu'ils ont envie d'apprendre / échanger.  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Une conférence dont vous êtes le héros !  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Chacun affiche le(s) sujet(s), dont il a envie de parler sur un tableau (appelé Marketplace), aux intersections entre des créneaux horaires et des espaces nommés.  &lt;/p&gt;

&lt;p&gt;Marketplace du SoCraTes Rennes :  &lt;/p&gt;

&lt;p&gt;Liquid error: internal&lt;/p&gt;

&lt;p&gt;Cet &lt;em&gt;"agenda"&lt;/em&gt; continu de se construire au fil de la journée. En fonction des discussions, de nouveaux post-it vont être ajoutés pour approfondir certains sujets par exemple ou parce qu'une session a fait émerger une nouvelle idée à sur laquelle un groupe a envie de discuter.  &lt;/p&gt;

&lt;p&gt;Les règles de ce genre d'événement sont assez simples. En plus du respect et de la bienveillance, on retrouve également :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Quand c'est fini, c'est fini&lt;/em&gt; : il est important, à la fin de son créneau horaire, de s'arrêter pour laisser la place au groupe suivant. Ça ne veut pas dire pour autant qu'il faille arrêter la discussion, au contraire, il suffit simplement de trouver un espace libre pour continuer&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;La loi des deux pieds&lt;/em&gt; : à tous moments, vous êtes libre de suivre vos deux pieds pour quitter une session afin de rejoindre une autre session ou autre.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  SoCraTesDay, on y parle de quoi ?
&lt;/h2&gt;

&lt;p&gt;Et bien c'est ça qui est vraiment intéressant c'est qu'on y parle de tout ce dont les participants ont envie.   &lt;/p&gt;

&lt;p&gt;Personnellement, j'ai tendance à découper les sujets en trois catégories.  &lt;/p&gt;

&lt;h2&gt;
  
  
  La technique, les outils
&lt;/h2&gt;

&lt;p&gt;Lors de ce SoCraTest, il y a eu des sessions d'introductions à ELM et Rust, des katas de refacto de code legacy, des discussions autour des backends js, du code source de spring boot, de la gestion des logs avec ELK.  &lt;/p&gt;

&lt;h2&gt;
  
  
  La conception, l'architecture, les méthodes
&lt;/h2&gt;

&lt;p&gt;Il y a des sessions sur le BDD (pas les bases de données, mais le Behaviour Driven Development), sur le DDD en mode introduction sur les concepts stratégiques puis comment démarrer concrètement après, sur le TDD (voilà on fait le tour des xDD ;) ), sur les archis hexagonales, les archis micro-frontend, sur les tests e2e, sur la stabilité des logiciels, sur l'agilité (notamment sur les Scrum Masters qui ne font pas de dev).  &lt;/p&gt;

&lt;h2&gt;
  
  
  La pratique, le métier, l'éthique
&lt;/h2&gt;

&lt;p&gt;Enfin, il y a eu des discussions autour de la veille, du bonheur au travail, de qu'est-ce qu'un bon développeur, sur le mentoring, alternative au salariat ? (indépendant, monter sa boite), sur l'impact écologique des logiciels et le low tech et un retour d'expérience sur une organisation horizontale.  &lt;/p&gt;

&lt;h2&gt;
  
  
  À quoi a ressemblé ton SoCraTesDay ?
&lt;/h2&gt;

&lt;p&gt;Le temps de discuter un peu, de regarder la construction du market place, je suis arrivé sur la fin de la discussion concernant le principe de micro-frontend.  &lt;/p&gt;

&lt;p&gt;J'ai enchaîné ensuite sur la session DDD que j'avais proposé, car c'est mon intérêt du moment, remettre le métier du client au cœur de notre pratique et de notre code, parler le même langage que l'expert métier, sont des choses que je trouve importantes et presque toute ma veille du moment tourne autour de ce sujet.&lt;br&gt;&lt;br&gt;
Cette session était plutôt basée sur les concepts stratégiques : comment exprimer les domaines, contextes métiers, notamment via des Event Storming. Elle a suscité une deuxième session, plus "tactique" où on a parlé d'User Stories Mapping, de slicing horizontal, d'architecture à Uses Cases.  &lt;/p&gt;

&lt;p&gt;J'ai terminé la matinée par les sessions sur les Object Calisthenics et comment construire une roadmap dans une approche MVP.  &lt;/p&gt;

&lt;p&gt;L'après-midi, j'ai participé à la session sur les alternatives au salariat. Le groupe était assez hétérogène avec des salariés de boites classiques, de boites "un peu plus ouvertes", des indépendants (ou ex-indé) et moi en SCOP.&lt;br&gt;&lt;br&gt;
On a eu beaucoup d'échanges très constructifs, des retours d'expériences enrichissants car on n'avait pas tous le même vécu, rencontré les mêmes problématiques.  &lt;/p&gt;

&lt;p&gt;Au-delà du market place, il y a aussi toutes les discussions impromptues dans l'espace commun, l'occasion de faire plein de rencontres intéressantes.  &lt;/p&gt;

&lt;h2&gt;
  
  
  En conclusion ?
&lt;/h2&gt;

&lt;p&gt;Il s'agissait de ma seconde journée de forum ouvert après NewCrafts Bordeaux de l'année dernière et je dois dire que j'apprécie vraiment beaucoup ce format de conférence qui est vraiment basé sur les discussions, les échanges contrairement à une conférence traditionnelle où on écoute un speaker pendant 45 minutes.  &lt;/p&gt;

&lt;p&gt;Rendez-vous à &lt;a href="https://bordeaux.ncrafts.io/"&gt;NewCrafts Bordeaux&lt;/a&gt; en octobre maintenant ;)  &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Article publié originellement sur &lt;a href="https://medium.com/avalonlab/retour-sur-socrates-day-rennes-23d0d988dec4"&gt;Medium&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>socrates</category>
      <category>unconference</category>
      <category>softwaredevelopment</category>
      <category>french</category>
    </item>
    <item>
      <title>Qui sommes-nous ?</title>
      <dc:creator>Jean-François Le Foll</dc:creator>
      <pubDate>Wed, 06 Nov 2019 14:32:23 +0000</pubDate>
      <link>https://dev.to/avalon-lab/qui-sommes-nous-afe</link>
      <guid>https://dev.to/avalon-lab/qui-sommes-nous-afe</guid>
      <description>&lt;p&gt;Nous sommes &lt;strong&gt;un studio de développement logiciel&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Nous sommes &lt;strong&gt;trois développeurs passionnés&lt;/strong&gt; qui travaillent ensemble depuis déjà plusieurs années et qui ont décidé de monter leur structure afin de mettre en pratique leur conception du métier de développeur et de la façon de construire des logiciels.&lt;/p&gt;

&lt;p&gt;Nous considérons qu'apprendre est notre métier, apprendre de nouvelles technologies mais également une ouverture d'esprit et une curiosité pour comprendre le métier de nos interlocuteurs et échanger avec eux. Au fil des années nous avons travaillé dans des domaines très variés et fait de nombreuses rencontres humaines : pour nous, c'est aussi ce qui rend notre travail intéressant.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2ijK7X0j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/yk6zuuc69hh5y1o25gyk.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2ijK7X0j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/yk6zuuc69hh5y1o25gyk.jpeg" alt="L’équipe Avalon Lab" width="880" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Que fait-on ?
&lt;/h2&gt;

&lt;p&gt;Nous réalisons vos projets logiciels avec vous, en mettant en place une &lt;strong&gt;co-construction&lt;/strong&gt; itérative et agile, basée sur les principes d'&lt;strong&gt;&lt;a href="https://ronjeffries.com/xprog/what-is-extreme-programming/"&gt;eXtrem Programming&lt;/a&gt;&lt;/strong&gt; et du &lt;strong&gt;Software Craftsmanship&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Nous vous accompagnons également vos équipes sur la mise en place de bonnes pratiques agiles et techniques issues d'XP (développement itératif, livraison constante de valeur, TDD, pair programming, ...).&lt;/p&gt;

&lt;p&gt;Pour nous, la meilleure façon de construire un logiciel passe par une bonne communication entre les différents acteurs ainsi que par la mise en place d'équipes de développeurs auto-organisés, responsables, ayant le contrôle/pouvoir sur leur travail de tous les jours.&lt;/p&gt;

&lt;p&gt;En nous basant sur ce principe qui nous est cher, nous nous sommes constitués sous forme de &lt;strong&gt;Société COopérative et Participative&lt;/strong&gt; (SCOP), afin de laisser à chacun la possibilité de prendre part aux décisions de l'entreprise, dans la transparence la plus totale.&lt;/p&gt;

&lt;p&gt;Jean-François, Mathieu, Jérémy.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Article publié originellement sur &lt;a href="https://medium.com/avalonlab/qui-sommes-nous-c4a72c91cf6d"&gt;Medium&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>scop</category>
      <category>développementlogiciel</category>
      <category>nossii</category>
      <category>french</category>
    </item>
  </channel>
</rss>
