<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>architecture - Tag - Jordan Chapuy - Blog d'un développeur passionné ❤️</title><link>https://jordanchapuy.com/tags/architecture/</link><description>architecture - Tag - Jordan Chapuy - Blog d'un développeur passionné ❤️</description><generator>Hugo -- gohugo.io</generator><language>fr</language><lastBuildDate>Fri, 19 Jan 2024 19:55:00 +0100</lastBuildDate><atom:link href="https://jordanchapuy.com/tags/architecture/" rel="self" type="application/rss+xml"/><item><title>Intégrer un SDK natif avec Flutter - Faire un passe-plat</title><link>https://jordanchapuy.com/posts/2024/01/integrer-un-sdk-natif-ios-android-avec-flutter-faire-un-passe-plat/</link><pubDate>Fri, 19 Jan 2024 19:55:00 +0100</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2024/01/integrer-un-sdk-natif-ios-android-avec-flutter-faire-un-passe-plat/</guid><description><![CDATA[<p>En ce moment, je dois intégrer des SDKs natifs Android et iOS dans une application développée avec Flutter. L&rsquo;un des SDK est distribué via un cocoapods privé, l&rsquo;autre sous la forme d&rsquo;une librairie java. C&rsquo;est un exercice intéressant. J&rsquo;ai envie de partager le cheminement que l&rsquo;on a fait avec mes pairs, et expliquer pourquoi on a terminé par faire un simple passe-plat.</p>
<h1 id="une-recette-native">Une recette native</h1>
<p>J&rsquo;enfonce peut-être une porte ouverte, mais ça me semble important à expliciter. Plutôt que de se lancer directement dans la création des pont tout en intégration les SDKs, on a décidé de commencer par <strong>tester simplement les SDKs</strong> en créant des applications natives.</p>
<p>Un nouveau projet sur iOS et un nouveau pour Android donc, qui importent chacun le SDK correspondant. Rien de plus. Deux raisons à cela.</p>
<p>Premièrement, on n&rsquo;était pas sachant sur la création du pont, c&rsquo;était la première fois qu&rsquo;on devait le faire. On voulait éviter d&rsquo;apprendre deux choses en même temps (le fonctionnement d&rsquo;un pont, le fonctionnement du SDK). Là, on reste <strong>focus</strong> sur une seule chose et on avance par <strong>petites étapes</strong>.</p>
<p>Deuxièmement, on voulait <strong>restreindre le nombre de problèmes</strong> au minimum. Lorsque ça ne marchait pas, ça pouvait venir soit de notre code natif, contenant d&rsquo;ailleurs peu de lignes, soit du SDK. On s&rsquo;est enlevé de nombreux doutes. <em>&ldquo;Est-ce que ça déconne à cause du code Flutter ? De notre façon de faire le pont ? Ou alors de notre code natif ? Ou du SDK ? Ou peut-être bien de notre projet ?&rdquo;</em>. Non, tout ce bruit, on veut l&rsquo;éviter.</p>
<p>Et on a bien fait. On a pu repérer des problèmes provenant de notre partenaire. Même si on a d&rsquo;abord douté de notre façon d&rsquo;utiliser le SDK, on a rapidement éliminé ces pistes au vu du peu de lignes de code que l&rsquo;on avait dans nos applications créées pour l&rsquo;occasion.</p>
<h1 id="un-pont-flutter--natif">Un pont Flutter &lt;&gt; Natif</h1>
<p>Vient maintenant de la recherche pour créer ce fameux pont entre du code Flutter et du code natif. Toujours dans de nouvelles applications, ET sans utiliser les SDKs pour le moment. Mêmes raisons qu&rsquo;au-dessus, on voulait se concentrer sur une chose à la fois et diminuer les sources d&rsquo;erreurs.</p>
<p>On a fouillé les internets, et on a débusqué plusieurs options pour faire discuter ensemble Flutter et le natif :</p>
<ul>
<li><a href="https://docs.flutter.dev/platform-integration/platform-channels" target="_blank" rel="noopener noreffer">Platform channels</a></li>
<li>dart:ffi (<a href="https://docs.flutter.dev/platform-integration/android/c-interop" target="_blank" rel="noopener noreffer">Android</a> et <a href="https://docs.flutter.dev/platform-integration/ios/c-interop" target="_blank" rel="noopener noreffer">iOS</a>)</li>
<li><a href="https://pub.dev/packages/pigeon" target="_blank" rel="noopener noreffer">Pigeon</a></li>
</ul>
<p>Notre préférence est allée vers les <em>Platform channels</em>, qui nous semblaient plus adaptés à notre besoin et assez simple d&rsquo;usage.</p>
<h1 id="intégration-du-sdk-dans-le-projet">Intégration du SDK dans le projet</h1>
<p>Le temps d&rsquo;intégrer les SDKs natifs directement dans notre application Flutter est ensuite arrivé. Nous étions serein avec nos expérimentations et apprentissages.</p>
<p>Pour donner un peu de contexte (simplifié), on devait intégrer un SDK de messagerie. Disons qu&rsquo;il permet d&rsquo;identifier un utilisateur via son token, d&rsquo;ouvrir un salon de discussion, d&rsquo;envoyer un message et de voir les nouveaux messages arriver.</p>
<p>On a utilisé un <code>MethodChannel</code> et un <code>EventChannel</code>. Le premier nous sert de <em><strong>donneur d&rsquo;ordres</strong></em>, il contrôle le SDK depuis notre code Flutter. Le second nous permet de faire <strong>transiter des flux de données</strong> du SDK vers Flutter - les messages du chat.</p>
<p>On a un <em>repository</em> qui cache la complexité du SDK. Les deux <em>channels</em> ne se connaissent pas, ils ne parlent qu&rsquo;à l&rsquo;instance de ce <em>repository</em>.</p>
<p>Tout fonctionne bien, on avance rapidement. Mais je commence à écrire un morceau de code côté iOS qui ne me plaît pas.</p>
<p>Pour voir les nouveaux messages arriver, il faut ouvrir un salon de discussion. Et pour ouvrir un salon, il faut être connecté. Ce séquencement, je l&rsquo;écris en swift, donc nativement sur iOS. De base, ce qui m&rsquo;intéresse fonctionnellement, c&rsquo;est de voir les messages. Le reste doit être transparent pour l&rsquo;utilisateur. Je n&rsquo;expose à Flutter qu&rsquo;un simple <code>démarrer l'écoute des messages</code>.</p>
<p>Tous ces appels de fonctions sont bien entendus asynchrones. Je target iOS 11, donc pas de <code>async/await</code>. Je ne vais pas ajouter <code>RxSwift</code>, <code>PromiseKit</code> ou une autre librairie juste pour ça non plus. Je vous laisse imaginer la cascade de <em>closure</em> qui se forme. J&rsquo;essaie d&rsquo;éclater en plusieurs fonctions, mais ce n&rsquo;est pas idéal.</p>
<p>Ah, et chaque appel peut échouer. Donc il faut gérer des erreurs à chaque niveau. Ok mais on passe pars un seul et même callback pour répondre à Flutter, comment je fais pour différencier les erreurs ? Est-ce que même j&rsquo;ai envie de différencier ?</p>
<h1 id="vers-un-passe-plat">Vers un passe-plat</h1>
<p>C&rsquo;est à ce moment que je me dis <em>&ldquo;et si on déportait tout ça vers Flutter ?&rdquo;</em>, <em>&ldquo;et si on ne faisait qu&rsquo;un passe-plat ?&rdquo;</em>. Mais oui. Tout simplement.</p>
<p>Notre pont ne sert plus que d&rsquo;interface pour parler au natif. Il fait passe-plat. Côté natif, on expose les fonctions dont a besoin uniquement et telle quelle, rien d&rsquo;autres. Côté Flutter, on orchestre, on a de la logique.</p>
<p>Ce que j&rsquo;aime bien avec cette solution, c&rsquo;est qu&rsquo;on tend vers du <strong>zéro logique côté natif</strong>.</p>
<p>On écrit <strong>moins de code en doublon</strong> (Android et iOS). Ce qui est quand même une des raisons d&rsquo;être d&rsquo;une application en Flutter, autant continuer en ce sens. S&rsquo;il y a une modification de la logique, on ne le fera qu&rsquo;à un seul endroit - côté Flutter.</p>
<p>On profite de la <strong>modernité de Dart</strong> et des <strong>packages</strong> que l&rsquo;on a ajouté à notre projet pour développer la logique. J&rsquo;ai par exemple pu jouer avec le <code>async/await</code> proposé naturellement par le langage Dart.</p>
<p>On capitalise sur <strong>l&rsquo;expertise Flutter des développeurs</strong>. Certain n&rsquo;ont jamais développé sur Android ou iOS, voire aucun des deux. Pour autant, ils maîtrisent Dart et l&rsquo;écosystème de Flutter.</p>
<p>Et c&rsquo;est enfin à ce moment-là que je me dis <em>&ldquo;et si j&rsquo;écrivais un article ?&rdquo;</em>. La boucle est bouclée.</p>
]]></description></item><item><title>Mettre à jour une application mobile sans passer par les stores - #4 Server-Driven UI</title><link>https://jordanchapuy.com/posts/2024/01/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-4-server-driven-ui/</link><pubDate>Thu, 04 Jan 2024 18:20:00 +0100</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2024/01/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-4-server-driven-ui/</guid><description><![CDATA[<p>Et si on poussait le concept de <a href="https://jordanchapuy.com/posts/2023/12/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-3-backend-for-frontend-bff" rel="">Backend for Frontend</a> encore plus loin, à l’extrême ? Un peu à l&rsquo;image de l&rsquo;Extreme Programming qui pousse des pratiques dans leurs retranchements. Qu’est-ce que ça pourrait donner pour notre histoire de backend et de front mobile ? Pourrait-on déporter jusqu&rsquo;à l&rsquo;UI de l&rsquo;application ?</p>
<p>De base, notre backend stocke des données, communique avec d&rsquo;autres services et applique de nombreuses règles métiers. Notre application, elle, va envoyer une requête pour récupérer des informations, les traiter, appliquer d&rsquo;autres règles, puis construire un rendu visuel avec divers composants UI (j&rsquo;ai une bannière, ensuite un carrousel avec trois images, puis une liste d&rsquo;articles).</p>
<p>On a vu qu&rsquo;on pouvait ajouter des traitements spécifiques au mobile en ayant un <a href="https://jordanchapuy.com/posts/2023/12/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-3-backend-for-frontend-bff" rel="">Back for Frontend</a>. Ça nous aide en déportant certaines règles côté backend, en agrégeant des données de plusieurs sources, en facilitant certains changements. Reste encore à construire le rendu visuel côté application.</p>
<p>On en arrive au cran d&rsquo;après. Bienvenue dans le <strong>Server-Driven UI</strong>.</p>
<h1 id="je-te-dis-comment-afficher">Je te dis comment afficher</h1>
<p>Avec du Server-Driven UI (aussi appelé Server-Driven Rendering, Backend-Driven UI, &hellip;), il y a un backend qui va à la fois <strong>retourner des données ET indiquer comment les présenter</strong>. Une partie de la construction de l&rsquo;interface graphique (du front mobile) est déportée côté backend.</p>
<p>Qu&rsquo;est-ce que ça veut dire, construire l&rsquo;interface ? Eh bien, le backend indique les <strong>composants</strong> à afficher (une bannière, un carrousel, une liste d&rsquo;éléments, une image, &hellip;) directement renseignés avec les <strong>données associées</strong>. De fait, la <strong>composition</strong> de l&rsquo;écran est aussi gérée (j&rsquo;ai d&rsquo;abord la bannière, ensuite le carrousel, &hellip;). Et il pourrait aussi <strong>configurer</strong> les composants (le texte de la carte est bleu, la police de 16pt, &hellip;), les <strong>actions</strong> lorsque l&rsquo;on tape sur un élément.</p>
<p>La réponse à une requête sera beaucoup plus riche. Un exemple au format JSON :</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;Accueil&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;carousel&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;image&#34;</span><span class="p">:</span> <span class="s2">&#34;https://monserveur.com/img/001.jpg&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;Arthur&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;color&#34;</span><span class="p">:</span> <span class="s2">&#34;#FFFFFF&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="p">},</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;image&#34;</span><span class="p">:</span> <span class="s2">&#34;https://monserveur.com/img/002.jpg&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;Perceval&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;color&#34;</span><span class="p">:</span> <span class="s2">&#34;#FFFFFF&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="p">},</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;image&#34;</span><span class="p">:</span> <span class="s2">&#34;https://monserveur.com/img/003.jpg&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;Lancelot&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;color&#34;</span><span class="p">:</span> <span class="s2">&#34;#FFFFFF&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="p">},</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;identifier&#34;</span><span class="p">:</span> <span class="s2">&#34;list&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;Les personnages&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;En découvrir plus sur les personnages&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;details&#34;</span><span class="p">:</span> <span class="s2">&#34;88026897-3fcb-4de8-af77-9aeb76d1e8a1&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="p">},</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;title&#34;</span><span class="p">:</span> <span class="s2">&#34;Les secrets de tournage&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;Mystère et magie !&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                    <span class="nt">&#34;details&#34;</span><span class="p">:</span> <span class="s2">&#34;1da6005c-1f57-4c95-bb1a-6fb3b3a1bde7&#34;</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">]</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>On obtient donc un nouveau moyen de mettre à jour une application mobile sans passer par les stores. On peut <strong>contrôler la construction de l&rsquo;affichage à distance</strong>. <a href="https://jordanchapuy.com/posts/2023/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-1-pourquoi" rel="">Ça nous intéresse</a> car ça nous ouvre des portes pour expérimenter, pour changer plus vite.</p>
<p>Tout cela implique <strong>un développement côté serveur et côté application</strong>.</p>
<ul>
<li>Côté serveur. Il y a une brique / un service / un backend qui construit cette réponse plus complexe. Qui doit avoir cette logique de présentation des données.</li>
<li>Côté application mobile. Il faut créer chaque composant et il faut une brique qui interprète la réponse du serveur pour la traduire dans les composants correspondants.</li>
</ul>
<p>Et vu que c&rsquo;est à notre portée, on peut aller <strong>aussi loin que nécessaire</strong> pour répondre à notre besoin. On peut avoir une présentation plutôt simple. Le serveur indiquerait seulement des composants à afficher avec leurs données. Ou au contraire, on peut pousser la configuration en détaillant des tailles de texte, des couleurs, des alignements, etc.</p>
<p>On a également le choix d&rsquo;appliquer ce concept dans les parties de l&rsquo;application qui nous intéressent. On peut avoir du Server-Driven UI <strong>uniquement sur une sous-partie de l&rsquo;application</strong>. Ce n&rsquo;est pas structurant au point de nécessiter d&rsquo;en avoir partout. Mais on peut le faire, s&rsquo;il y a le besoin. On adapte !</p>
<h2 id="quelques-cas---exemples">Quelques cas - exemples</h2>
<p>Pour illustrer et donner de l&rsquo;inspiration, voici des cas qui existent en production sur des applications grand public.</p>
<p><strong>Une campagne de satisfaction</strong>. Sous la forme d&rsquo;un simple formulaire, avec une suite de questions et plusieurs formats de réponses (choix multiple, choix unique, champs de texte libre). La complexité technique et fonctionnelle est faible. Il ne s&rsquo;agit que de donner des questions et d&rsquo;indiquer sous quelle forme on peut y répondre. Il y a un besoin de déclencher une campagne à n&rsquo;importe quel moment et de moduler le contenu.</p>
<p><strong>Un quizz</strong>. On est dans le même ordre d&rsquo;idées, c&rsquo;est au final une sorte de formulaire mais présenté sous une autre forme. Ici, le besoin est d&rsquo;avoir un parcours de questions qui change régulièrement, sans pour autant faire de mise à jour.</p>
<p><strong>Un onboarding</strong>. On entre dans un parcours bien plus complexe et lourd. C&rsquo;est une succession d&rsquo;écrans avec de nombreuses possibilités comme des formulaires, des listes, des présentation de CGU, de l&rsquo;upload de fichier, de la visualisation d&rsquo;images, etc. Les formulaires sont complexes, contiennent des règles de validation, possèdent plusieurs formes (champs libres, choix multiple, champs numéro de téléphone, &hellip;). On peut ajouter des boutons et des popups d&rsquo;aide / assistance.  Bref, un parcours complètement modulable car il y a un fort besoin de changement. À l&rsquo;autre bout, un back-office existe pour configurer tout cela.</p>
<p><strong>Une page d&rsquo;accueil</strong>. Pas de parcours mais une composition de page qui nécessite d&rsquo;être très modulable. Un jour une simple liste, un autre jour une mise en avant avec une bannière et un el suivi de la liste. Parfois des raccourcis, des cartes d&rsquo;action rapide. D&rsquo;autres fois des rappels. Et demain, un peu de tout ça en même temps. D&rsquo;ailleurs, on expérimente facilement ce qui marche le mieux en changeant à distance l&rsquo;interface.</p>
<p><strong>Un fil de contenu</strong>. Dès lors que le contenu est très dynamique, sa présentation l&rsquo;est aussi. On a besoin d&rsquo;adapter les formats.</p>
<h2 id="bénéfices">Bénéfices</h2>
<p>Outre la gestion de l&rsquo;affichage déporté sur un serveur, on peut espérer obtenir d&rsquo;autres avantages grâce au Server-Driven UI.</p>
<p>Déjà, et c&rsquo;est ce qui nous intéressait le plus par rapport à notre histoire, à <a href="https://jordanchapuy.com/posts/2023/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-1-pourquoi" rel="">cette série d&rsquo;articles</a>, on peut changer de nouveaux éléments de notre application mobile sans devoir passer par les stores : l&rsquo;interface graphique.</p>
<p>Et on est plutôt ravi de cette possibilité. On va pouvoir <strong>changer à distance</strong> plus profondément l&rsquo;application, on va pouvoir apporter des changements et des corrections plus rapidement aux utilisateurs. On aura plus de contrôle.</p>
<p>On facilite également l&rsquo;<strong>expérimentation</strong>, l&rsquo;A/B Testing. Pas besoin de <a href="https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag" rel="">Feature Flag</a>, c&rsquo;est un serveur qui génère la composition de l&rsquo;écran. C&rsquo;est déjà de la configuration à distance. On peut donc dès maintenant expérimenter.</p>
<p>Si plusieurs plateformes consomment notre serveur, on gagne une unification des interfaces. Le serveur devient <strong>une source de vérité unique</strong>, les applications clientes ne feront qu&rsquo;appliquer la présentation reçue. On a plus facilement une cohérence entre différentes plateformes. Le changement de l&rsquo;affichage ne se fera qu&rsquo;à un seul endroit.</p>
<h2 id="points-dattention">Points d&rsquo;attention</h2>
<p>Comme d&rsquo;habitude, rien n&rsquo;est magique ou parfait. Le Server-Driven UI ne fait pas exception.</p>
<p>Je commence par enfoncer une porte ouverte. Si on veut que notre serveur retourne un nouveau composant, ou une nouvelle configuration par exemple, il faut le code de notre application puisse l&rsquo;<strong>interpréter</strong>. Il faut donc soumettre une mise à jour de l&rsquo;application pour gérer ces nouveaux cas. Comme si on ajoutait une nouvelle <a href="https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag" rel="">Feature Flag</a>.</p>
<p>Je continue avec une autre porte voisine, les versions. Il faut garder en tête que dans la nature, il y a possiblement une grande variété de versions de notre application. Eh oui, pour rappel, <a href="https://jordanchapuy.com/posts/2023/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-1-pourquoi" rel="">rien n&rsquo;oblige un utilisateur à mettre à jour une application mobile</a>. Il la fera peut-être rapidement, ou dans une semaine, ou jamais.</p>
<p>On a donc une problématique de <strong>rétrocompatibilité</strong>. Admettons qu&rsquo;on ajoute un nouveau composant et qu&rsquo;on ait une nouvelle version de l&rsquo;application qui le gère, comment ça se passe pour les anciennes applications ? On peut versionner nos composants. On peut créer un mécanisme de mise à jour forcée. On peut ignorer. On a plusieurs options, mais il faut y penser.</p>
<p>Le Server-Driven UI, c&rsquo;est également une <strong>couche supplémentaire</strong> dans notre système. Ça vient avec son lot de complexité, de besoin de maintenance, de debug, etc. Et ça requiert un <strong>investissement à l&rsquo;entrée</strong>. Il y a un coût de développement plus élevé au début pour mettre en place les différentes briques et composants pour que tout fonctionne.</p>
<p>Je pense aussi à la <strong>sécurité</strong>. La surface d&rsquo;attaque de l&rsquo;application est augmentée puisqu&rsquo;elle se base davantage sur des <strong>instructions extérieures</strong>. Il est facile de modifier à la volée une réponse HTTP. Par exemple, si le serveur indique des intentions de navigation ou d&rsquo;action, l&rsquo;application devrait peut-être vérifier que l&rsquo;utilisateur a bien le droit de le faire.</p>
<h2 id="pour-se-lancer">Pour se lancer</h2>
<p>Le sujet du Server-Driven UI étant vaste et complexe, on peut chercher à en apprendre plus en s&rsquo;inspirant de retours d&rsquo;expériences de grands noms qui en font ou qui en ont fait de manière poussée : AirBnb, Instagram, Lyft, Reddit, Square.</p>
<p>On peut aussi regarder du côté de frameworks qui existent déjà. En faisant une rapide recherche, je tombe sur <a href="https://github.com/divkit/divkit" target="_blank" rel="noopener noreffer">DivKit</a> et <a href="https://github.com/ZupIT/beagle" target="_blank" rel="noopener noreffer">beagle</a> qui proposent des solutions à la fois côté serveur et côté client iOS, Android, web. J&rsquo;avais également repéré <a href="https://pub.dev/packages/rfw" target="_blank" rel="noopener noreffer">rfw (Remote Flutter Widget)</a>, mais qui me semble d&rsquo;ailleurs plus proche d&rsquo;un interpréteur de code. On le verra peut-être dans l&rsquo;épisode suivant !</p>
<hr>
<blockquote>
<p>Série d&rsquo;articles <strong>Mettre à jour une application mobile sans passer par les stores</strong> :</p>
<ul>
<li><a href="https://jordanchapuy.com/posts/2023/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-1-pourquoi" rel="">#1 Pourquoi</a></li>
<li><a href="https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag" rel="">#2 Remote config, Feature F &amp; co</a></li>
<li><a href="https://jordanchapuy.com/posts/2023/12/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-3-backend-for-frontend-bff" rel="">#3 Backend for Frontend (BFF)</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/01/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-4-server-driven-ui" rel="">#4 Server-Driven UI</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/07/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-5-interpreteur-de-code" rel="">#5 Interpréteur de code</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-6-over-the-air-update-ota" rel="">#6 Over-the-air update (OTA)</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/11/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-7-ressources" rel="">#7 Les ressources</a></li>
<li>#8 En résumé, mes options</li>
</ul>
<p>Hors-série :</p>
<ul>
<li>Accélérer le temps de review App Store d&rsquo;une application iOS</li>
<li>Forcer la mise à jour d&rsquo;une application mobile</li>
</ul>
</blockquote>
]]></description></item><item><title>Mettre à jour une application mobile sans passer par les stores - #3 Backend for Frontend (BFF)</title><link>https://jordanchapuy.com/posts/2023/12/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-3-backend-for-frontend-bff/</link><pubDate>Fri, 22 Dec 2023 19:05:00 +0100</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2023/12/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-3-backend-for-frontend-bff/</guid><description><![CDATA[<p>De nos jours, il est rare de trouver une application qui ne communique pas du tout avec l&rsquo;extérieur. <strong>La majorité des applications</strong> que l&rsquo;on utilise <strong>font des requêtes vers un ou plusieurs serveurs</strong> - pour demander des données, les afficher dynamiquement, et pour en envoyer.</p>
<p>J&rsquo;ai fait le test avec mon téléphone, j&rsquo;ai eu du mal à trouver une application qui ne faisait aucune requête (en tout cas en apparence, je n&rsquo;en suis même pas sûr à 100%). J&rsquo;ai la calculatrice qui vit sa vie dans son coin.</p>
<p>Pourquoi je raconte ça ? Parce que ces applications font très probablement des requêtes <strong>vers un serveur qui leur appartient</strong>. En d&rsquo;autres termes, l&rsquo;équipe, le département, ou l&rsquo;entreprise qui gère le développement de l&rsquo;application est également responsable du serveur.</p>
<p>Dans l&rsquo;épisode précédent, on a vu qu&rsquo;<a href="https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag" rel="">une configuration à distance permettait de changer le comportement d&rsquo;une application mobile</a>. Et que la configuration à distance, ce pouvait être simplement un fichier JSON ou une API qui exposait quelques valeurs.</p>
<p>De là à faire le rapprochement entre les données envoyées par nos serveurs et la possibilité de changer le comportement d&rsquo;une application mobile à distance, il n&rsquo;y a vraiment qu&rsquo;un petit pas. Alors faisons-le !</p>
<h1 id="vers-une-api-spécialisée">Vers une API spécialisée</h1>
<p>En général, ce qu&rsquo;on retrouve souvent, c&rsquo;est un backend qui tends vers de l&rsquo;envoi de données brutes aux fronts. Et qui s&rsquo;approche plus ou moins du REST. Pour alimenter une page, le front mobile devra effectuer une ou plusieurs requêtes puis traiter les données, appliquer un peu de logique.</p>
<p>Imaginons une page agenda sur notre application. On a envie de mettre en valeur les événements qui ont lieu aujourd&rsquo;hui, dans de jolis encarts avec un maximum d&rsquo;informations, ainsi que les 3 prochains événements. Pour le reste, on les groupe par semaine glissante et juste le titre nous suffira.</p>
<p>Notre backend nous propose une route qui retourne 100 événements, à partir du début de la semaine. Côté front mobile, on va devoir trier par date, filtrer les événements passés, mettre de côté les événements du jour et également les 3 prochains pour la mise en valeur, puis ensuite faire des groupes par semaine glissante.</p>
<p>Beaucoup de logique métier qui se retrouve côté client (l&rsquo;application). Si on décide de changer, disons par exemple la sélection des événements qui sont mis en valeur, <strong>il faut modifier l&rsquo;application et donc redéployer</strong>, ce qui implique de <a href="https://jordanchapuy.com/posts/2023/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-1-pourquoi" rel="">traverser tout le process de soumission sur les stores que l&rsquo;on aimerait éviter</a>.</p>
<p>Sans parler des données qui transitent sur le réseau : on a besoin que du titre pour une grande partie des événements. On augmente au passage la charge serveur pour rien. Bonne nouvelle, on a dit qu&rsquo;on est responsable du serveur - on peut décider d&rsquo;y <strong>déporter certaines logiques</strong>.</p>
<p>Le backend pourrait :</p>
<ul>
<li>Trier dans l’ordre adapté,</li>
<li>Ne renvoyer que les futurs événements.</li>
<li>Porter la mise en valeur en envoyant deux listes distinctes, et indiquer juste le titre pour les événements lointains.</li>
<li>Grouper par semaine glissante.</li>
<li>Aller plus loin en portant la logique de présentation. “Afficher une carte avec un titre, une description, une date pour cet événement mis en valeur, afficher un simple titre pour cet événement, etc”. On commencerait alors à parler de <a href="https://jordanchapuy.com/posts/2024/01/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-4-server-driven-ui" rel="">Server-Driven UI</a>.</li>
</ul>
<p>En fonction de ce que l&rsquo;on déporte sur le backend, on pourra <strong>modifier le comportement de l&rsquo;application à distance</strong> en déployant une nouvelle version du backend plutôt que de l&rsquo;application. Et c&rsquo;est souvent bien plus rapide.</p>
<p>Notre API, qui était généraliste, devient spécialisée pour un front.</p>
<h2 id="le-cas-graphql">Le cas GraphQL</h2>
<p>Un petit aparté sur GraphQL. Je le mettrais bien dans le panier <em>API généraliste</em> pour notre histoire. Oui, ça apporte une certaine flexibilité au front qui consomme l&rsquo;API, il peut sélectionner ce qu&rsquo;il veut, mais à la fin, <strong>c&rsquo;est toujours le front qui construit les requêtes</strong>. On veut finalement filtrer les événements passés ? Eh bien il faut redéployer l&rsquo;application.</p>
<p>Certes, c&rsquo;est une modification très simple puisque c&rsquo;est peut-être seulement un paramètre dans la requête GraphQL à ajouter ou modifier, mais cette modification est à faire côté client (notre application). Elle impliquera une soumission de la version sur les stores.</p>
<p>On n&rsquo;est pas dans la spécialisation de notre API, elle ne porte pas de la logique supplémentaire dédiée au front.</p>
<h1 id="backend-for-frontend">Backend for Frontend</h1>
<p>Avoir une API spécialisée, ça peut nous embêter dans certains cas. Si j&rsquo;ai plusieurs fronts par exemple : un site web et une application mobile. Il y a parfois une logique différente entre les deux. Le web est une autre plateforme, l&rsquo;interface est très différente. Pour l&rsquo;agenda, je veux tout afficher sous la forme d&rsquo;un calendrier mensuel.</p>
<p>On comprend donc l&rsquo;intérêt d&rsquo;avoir une API généraliste qui essaye de faire plaisir à tout le monde. Pour autant, on perçoit aussi les avantages d&rsquo;avoir une API spécialisée. C&rsquo;est là qu&rsquo;intervient le principe de Backend for Frontend : on peut avoir les deux !</p>
<p>Un Backend For Frontend, souvent connu avec l&rsquo;acronyme BFF, est une couche intermédiaire entre un backend et un frontend. Concrètement, <strong>c&rsquo;est un backend supplémentaire qui va traiter des données spécifiquement pour un type de front</strong> (une application mobile par exemple).</p>
<p>Notre front mobile va effectuer toutes ses requêtes en passant par le Back for Front, et uniquement ce dernier. <strong>C&rsquo;est le Back for Front qui appellera le backend pour obtenir les données nécessaires</strong>. Il pourra ensuite appliquer de la <strong>logique dédiée</strong> avant de renvoyer les données à l&rsquo;application mobile. Le site web aurait de son côté son propre Back for Front.</p>
<p>Vu que le Back for Front devient le point d&rsquo;entrée unique du front, il peut servir d&rsquo;<strong>agrégateur</strong>. Peut-être que pour notre agenda, on avait besoin de la liste des événements futurs et également des événements où l&rsquo;on est inscrit. Plutôt que de faire deux requêtes, le front n&rsquo;en fera qu&rsquo;une seule vers le BFF.</p>
<p>Avec cette mécanique, on voit rapidement plusieurs avantages :</p>
<ul>
<li>On sépare les logiques spécialisées. Il y a un BFF mobile, un BFF web, etc.</li>
<li>On sépare la partie spécialisée de la partie généraliste. Il y a un backend qui ne subit pas les caprices du front.</li>
<li>Un développeur mobile peut plus aisément sortir de son éco-système et effectuer des changements sur le BFF.</li>
<li>On peut regrouper plusieurs ressources en une seule route, et réfléchir en termes de page, d&rsquo;écran.</li>
<li>On cache la complexité au front. Il n&rsquo;y a pas à savoir s&rsquo;il y a plusieurs services ou même s&rsquo;il y a un partenaire externe.</li>
</ul>
<p>Et notamment, ce qui nous intéresse particulièrement dans cette série d&rsquo;articles, <strong>on déporte de la logique client (app mobile) sur un serveur distant (notre BFF)</strong>. On peut donc modifier du comportement sans passer par les stores ! On aime :)</p>
<p>C’est tout de même une décision à peser dans l’équipe. Qui dit couche supplémentaire, dit une <strong>maintenance supplémentaire</strong>. Il y a une nouvelle brique qui doit évoluer et être déployée. Déléguer davantage au Back for Front augmente au passage les possibilités d’erreurs sur l’application - elle est plus permissive. On songera à monitorer plus en profondeur ce qu’il se passe dans l’application.</p>
<hr>
<blockquote>
<p>Série d&rsquo;articles <strong>Mettre à jour une application mobile sans passer par les stores</strong> :</p>
<ul>
<li><a href="https://jordanchapuy.com/posts/2023/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-1-pourquoi" rel="">#1 Pourquoi</a></li>
<li><a href="https://jordanchapuy.com/posts/2023/09/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-2-remote-config-feature-flag" rel="">#2 Remote config, Feature Flag &amp; co</a></li>
<li><a href="https://jordanchapuy.com/posts/2023/12/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-3-backend-for-frontend-bff" rel="">#3 Backend for Frontend (BFF)</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/01/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-4-server-driven-ui" rel="">#4 Server-Driven UI</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/07/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-5-interpreteur-de-code" rel="">#5 Interpréteur de code</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/08/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-6-over-the-air-update-ota" rel="">#6 Over-the-air update (OTA)</a></li>
<li><a href="https://jordanchapuy.com/posts/2024/11/mettre-a-jour-une-application-mobile-sans-passer-par-les-stores-7-ressources" rel="">#7 Les ressources</a></li>
<li>#8 En résumé, mes options</li>
</ul>
<p>Hors-série :</p>
<ul>
<li>Accélérer le temps de review App Store d&rsquo;une application iOS</li>
<li>Forcer la mise à jour d&rsquo;une application mobile</li>
</ul>
</blockquote>
]]></description></item><item><title>Clean Architecture - Et si on passait à côté ?</title><link>https://jordanchapuy.com/posts/2020/11/clean-architecture-et-si-on-passait-a-cote/</link><pubDate>Tue, 17 Nov 2020 09:17:00 +0100</pubDate><author>Auteur</author><guid>https://jordanchapuy.com/posts/2020/11/clean-architecture-et-si-on-passait-a-cote/</guid><description><![CDATA[<p>Je vois de plus en plus la Clean Architecture comme le SCRUM. Quelque chose qui est souvent mal appliqué et mal compris. Quelque chose dont on oublie ou met de côté la philosophie, l&rsquo;essence même. Quelque chose qu&rsquo;on utilise parce que c&rsquo;est <em>à la mode</em>.</p>
<p>J&rsquo;observe un nombre grandissant de discussions autour de la Clean Architecture. C&rsquo;est davantage présent dans les projets, dans les souhaits, dans les échanges, dans les publications. Pourtant, je pense qu&rsquo;une (trop grande) partie des personnes passe à côté de concepts essentiels et ne se pose pas les bonnes questions. Malgré la bonne intention, ça peut être dangereux. J&rsquo;aimerais amorcer une prise de recul et ouvrir des questions.</p>
<h2 id="et-si-on-prenait-du-recul-">Et si on prenait du recul ?</h2>
<p>Je vois des discussions qui tournent seulement autour du pattern, du diagramme de classe. <em>&ldquo;Le Presenter fait ceci et cela. Il parle à celui-ci ou à celui-là.&rdquo;</em> Quand je demande ce qu&rsquo;est la Clean Architecture, on me répond souvent en me récitant un diagramme de classe. Pas un mot sur l&rsquo;abstraction, l&rsquo;entrée/sortie, l&rsquo;inversion de contrôle, &hellip; Et encore moins sur l&rsquo;isolation du métier.</p>
<p>J&rsquo;ai également assisté à des entretiens et des échanges avec des développeurs qui s&rsquo;acharnent avec des suites de questions pour savoir si <em>Machin</em> va plutôt dans le Router ou Interactor ou Presenter, si c&rsquo;est pas à <em>Bidule</em> de faire ça, et le rôle de <em>Truc</em> là-dedans, &hellip; Plutôt que de parler de l&rsquo;esprit de la Clean Architecture, ils ne parlent que des classes.</p>
<p>Certaines équipes utilisent la Clean Architecture comme cadre pour empêcher les développeurs d&rsquo;en sortir, en suivant un modèle à la lettre. Faire sans comprendre, sans réfléchir ne mène pas très loin. À quel point cela vaut le coup, de rendre des choses difficiles, d&rsquo;ajouter de la complexité pour empêcher des développeurs de sortir des rails ? Il y a peut-être d&rsquo;autres choix à explorer.</p>
<p>Dans tout ça, on oublie le <em>pourquoi</em>. On se concentre trop sur le <em>comment</em>. Pourquoi on l&rsquo;utilise ? <em>&ldquo;C&rsquo;est pour découper. C&rsquo;est pour pouvoir tester.&rdquo;</em> me dit-on souvent, sans trop détailler. Oui, mais pourquoi ça devient <em>&ldquo;plus découpé&rdquo;, &ldquo;plus testable&rdquo;</em> ? Quels concepts y a-t-il derrière ? Pourquoi fait-on cela ?</p>
<h2 id="et-si-on-se-recentrait-sur-le-métier-">Et si on se recentrait sur le métier ?</h2>
<p>Le métier est la partie la plus importante du produit. Sans métier, le produit n&rsquo;existerait pas, l&rsquo;équipe ne le fabriquerait pas. C&rsquo;est le cœur du programme et de l&rsquo;entreprise. Certaines règles vont au-delà du programme. La répartition des places dans un train par exemple. Cette règle peut être présente dans plusieurs programmes différents et existe même en dehors de tout ça, dans le monde réel.</p>
<p>Ces règles ne dépendent pas d&rsquo;un choix technique ou d&rsquo;un framework, elles ne sont pas affectées par un changement technique. On change de base de données ? Pas de problème. On n&rsquo;a pas encore choisi la base de données ? Pas de problème non plus. On change de framework ? Aucun souci.</p>
<p>Les règles devraient pouvoir changer aisément, le monde évolue constamment. On devrait les trouver et les comprendre facilement puisque c&rsquo;est le cœur du programme. C&rsquo;est pour toutes ces raisons qu&rsquo;il est important d&rsquo;apporter une grande attention sur cette brique. De la protéger de l&rsquo;extérieur. De la rendre compréhensible, lisible. De la tester.</p>
<p>Le schéma de Clean Architecture représenté par <a href="https://blog.cleancoder.com/uncle-bob/images/2012-08-13-the-clean-architecture/CleanArchitecture.jpg" target="_blank" rel="noopener noreffer">les 4 cercles</a> va d&rsquo;ailleurs dans ce sens. On retrouve les règles métiers et les règles applicatives au centre. Et uniquement ça. Pas de framework, pas de base de données, pas d&rsquo;interface graphique. Les frontières protègent les cercles à l&rsquo;intérieur de l&rsquo;extérieur. C&rsquo;est aussi l&rsquo;esprit de l&rsquo;architecture hexagonale et du DDD (Domain-Driven Design).</p>
<p>Le métier est au centre parce qu&rsquo;il est très important. Parce qu&rsquo;on veut le protéger. Parce qu&rsquo;on veut en prendre soin. Le reste, c&rsquo;est du détail. Du détail d&rsquo;implémentation.</p>
<h2 id="et-si-on-se-penchait-sur-les-principes-">Et si on se penchait sur les principes ?</h2>
<p>La programmation orientée-objet a son rôle à jouer, bien plus que ce que l&rsquo;on apprend souvent à l&rsquo;école (vous savez, ce fameux héritage pour classifier des animaux). Certains concepts qui gravitent autour de la POO se cachent derrière la Clean Architecture et sa séparation des couches.</p>
<p>L&rsquo;abstraction par exemple. Avec l&rsquo;abstraction, on cache les détails de l&rsquo;implémentation. On veut utiliser quelque chose sans savoir comment ça fonctionne derrière. On s&rsquo;enlève cette complexité. Je veux enregistrer un favori sans savoir de quelle manière il sera stocké.</p>
<p>L&rsquo;inversion de contrôle et l&rsquo;injection de dépendances sont un autre exemple. Ces concepts sont présents pour renforcer les frontières, pour protéger les cercles. On veut que les cercles discutent entre eux, mais sans qu&rsquo;un cercle intérieur n&rsquo;ait connaissance d&rsquo;un cercle extérieur. On découple. Un <em>Use Case</em> peut interagir avec une base de données sans que ce code ne soit à l&rsquo;intérieur du cercle, de son module. Cette brique est indépendante. Ainsi, les changements autour de la base de données ne vont pas affecter le <em>Use Case</em>. Et c&rsquo;est tout de même le <em>Use Case</em> qui est aux commandes, qui utilise la base de données.</p>
<p>On parle de modularité en programmation orientée objet. D&rsquo;autres concepts sont également là. Je vous conseille de prendre le temps de les découvrir et de les comprendre. De voir comment tout cela s&rsquo;articule, et d&rsquo;aller au-delà de la Clean Architecture. S&rsquo;ils ne vous intéressent pas, alors prenez encore plus de temps pour creuser le sujet. Mais n&rsquo;en restez pas à l&rsquo;application d&rsquo;un pattern.</p>
<h2 id="et-si-on-explorait-plus-loin-">Et si on explorait plus loin ?</h2>
<p>La Clean Architecture apporte de bonnes choses, mais ce n&rsquo;est pas une <em>silver bullet</em> pour autant. La solution miracle n&rsquo;existe pas. C&rsquo;est une solution parmi d&rsquo;autres. Il faut la comprendre, savoir ses forces et faiblesses, connaître ses principes, l&rsquo;approfondir.</p>
<p>Il faut également explorer ce qu&rsquo;il y a autour. L&rsquo;architecture hexagonale est une approche similaire par exemple. Elle accorde beaucoup d&rsquo;importance au métier, le place au centre et le protège avec un système de <em>ports</em> et d&rsquo;<em>adapters</em>. Une approche simple qui se marie très bien avec le Domain-Driven Design (un tas de choses à voir là-dedans, je recommande pleinement de s&rsquo;y plonger). Le <em>Functionnal Core, Imperative Shell</em> me semble être un autre moyen intéressant.</p>
<p>Et il faut garder en tête les différents principes de programmation. Ils sont toujours là, peu importe le choix de l&rsquo;architecture. Ils vous accompagneront pendant longtemps.</p>
<p>Cherchez à comprendre et approfondissez, n&rsquo;appliquez pas sans réfléchir. Soyez ouvert et explorateur, ne restez pas enfermé dans une vision unique. Et appréciez :)</p>
]]></description></item></channel></rss>