Ceci est un résumé de mon intervention à Confoo, vous pouvez retrouver le code associé sur le dépôt dédié.
Simplicity-Oriented Design starts with a realization: we do not know what we have to make until after we start making it. Coming up with ideas, or large-scale designs isn’t just wasteful, it’s directly toxic to designing the truly accurate solutions. The really juicy problems are hidden like far valleys, and any activity except active scouting creates a fog that hides those distant valleys. You need to keep mobile, pack light, and move fast.
Cette conférence devait parler de Python et des API mais au cours de sa préparation le sujet a évolué pour élargir la problématique. J’ai préféré parler de minimalisme plus que de GraphQL et d’esthétique plus que de versionnement ou de performances. J’ai pris conscience de l’urgence (cache) de montrer de la simplicité et cela est parti de plusieurs constats.
Épuisement technique
Ultimately, the problem is that by choosing React (and inherently JSX), you’ve unwittingly opted into a confusing nest of build tools, boilerplate, linters, & time-sinks to deal with before you ever get to create anything.
Il y a eu des réponses (cache), des trolls (cache) et des vidéos là-dessus. Les développeurs web se sont rendu compte pendant la semaine de Noël qu’ils allaient passer à côté de 3 nouveaux concepts JS et 2 nouvelles façons d’organiser ses CSS. L’effervescence des communautés est si prompte à réinventer la roue, plusieurs fois, qu’il est difficile de suivre le fil même pour un core-stack developer. Comment utiliser des technologies modernes sans passer sa vie dans des fichiers de configuration ? Comment prendre le temps de se focaliser sur une technologie quelques mois sans rendre ses connaissances obsolètes ?
Initiateurs et mainteneurs
There are two roles for any project: starters and maintainers. People may play both roles in their lives, but for some reason I’ve found that for a single project it’s usually different people. Starters are good at taking a big step in a different direction, and maintainers are good at being dedicated to keeping the code alive.
[…]
I am definitely a starter. I tend to be interested in a lot of various things, instead of dedicating myself to a few concentrated areas. I’ve maintained libraries for years, but it’s always a huge source of guilt and late Friday nights to catch up on a backlog of issues.
Je suis également un initiateur. J’aime créer de nouvelles choses en expérimentant des usages et des techniques. Lorsque je me retrouve dans un rôle de mainteneur, j’ai tendance à complexifier l’existant et à le rendre moins stable par ma soif d’apprendre de nouvelles choses. Or l’apprentissage nait de l’échec et du test des limites. C’est assez désastreux pour les projets et je pense que l’engouement pour les microservices est un complot des initiateurs en mal d’expérimentations au sein d’applications à maintenir. À moins que la maintenance soit un vestige du passé (cache).
Matériel pédagogique
La fonction première d’un enseignant, ou d’un formateur, est de faire apprendre. Étant donné que l’apprenant est seul à pouvoir apprendre, l’enseignant ne peut que créer les conditions pour qu’il puisse apprendre. Comme je le souligne souvent, apprendre se doit d’être un acte conscient, autonome, volontaire et social.
[…]
Ces solutions seront certainement nouvelles, car si elles existaient on les utiliserait déjà. C’est ce qui rend stimulant la profession d’enseignant, faire face à de nouveaux défis et être en constant changement. Mais pour changer, il faut sortir de sa zone de confort et se mettre à la place du bénéficiaire, ou victime, de nos pratiques.
Je donne des cours à l’IUT d’Arles depuis deux ans. C’est peut-être ce qui m’a le plus ouvert les yeux sur la complexité de notre profession qui rend les concepts aussi difficile à appréhender. Si l’on veut que les nouveaux venus aient une chance d’avoir une vue d’ensemble avant de se spécialiser, il va nous falloir des outils adéquats qui ne masquent pas la complexité mais la réduisent.
Et cela ne s’applique pas qu’aux étudiants mais aux nouvelles personnes intégrant une équipe. Combien de temps faut-il à un arrivant pour pouvoir comprendre votre architecture ? Pour pouvoir installer l’ensemble des dépendances ? Pour reproduire facilement un bug ? À quel point votre équipe est-elle inclusive ?
Scalable POC
An MVP is a process that you repeat over and over again: Identify your riskiest assumption, find the smallest possible experiment to test that assumption, and use the results of the experiment to course correct.
A Minimum Viable Product Is Not a Product, It’s a Process (cache)
Cela fait un moment que l’on cherche avec scopyleft un agrégat de technologies qui nous permettrait de faire de tous petits services qui permettent d’aller vers l’utilisateur afin de vérifier leur pertinence avant même d’envisager une mise en production. L’erreur de base en innovation est de vouloir aller trop loin avant de tester le besoin réel de son produit et de passer à l’échelle un truc complètement inutile.
Small libs loosely joined
A system where you can delete parts without rewriting others is often called loosely coupled, but it’s a lot easier to explain what one looks like rather than how to build it in the first place.
Even hardcoding a variable once can be loose coupling, or using a command line flag over a variable. Loose coupling is about being able to change your mind without changing too much code.
Write code that is easy to delete, not easy to extend (cache)
Partant de ce constat, j’ai essayé de produire une stack minimaliste qui comportent très peu de dépendances qui peuvent évoluer en fonction du besoin. De cette manière, on accède à un LEAN technique : l’ajout de complexité architecturale en fonction du besoin uniquement.
Le code produit accorde une place importante à l’esthétique et à la modularité sans endommager la compréhension de l’ensemble grâce à la documentation et aux tests.
Falcon = API HTTP Python
Falcon is a minimalist WSGI library for building speedy web APIs and app backends. We like to think of Falcon as the Dieter Rams of web frameworks.
Avec Falcon, il faut aimer le bas niveau sachant qu’il est de votre responsabilité de retourner le bon status code ou content type par exemple. Une fois cela accepté, il y a très peu de magie pour exécuter le contrat requête/réponse classique. L’explicite permet aux personnes intégrant le projet de comprendre ce qu’il se passe sans passer par une quinzaine de (meta)classes et autant de fichiers.
Servi par livereload, chaque mise à jour de code relance le serveur et la page dans votre navigateur.
J’ai finalement inclus les dépendances directement sur le dépôt pour que ce soit plus facile à installer en session donc pas de requirements.txt
. Hérésie ! Cela fait 500Ko au total à télécharger contre un virtualenv
de 10Mo…
TinyDB = données en JSON
TinyDB aims to be simple and fun to use. Therefore two key values are simplicity and elegance of interfaces and code. These values will contradict each other from time to time. In these cases , try using as little magic as possible.
J’ai enfin trouvé la petite pépite que je cherchais depuis longtemps qui est encore plus légère que SQLite
et qui permet d’aller explorer le fichier à tout moment pour savoir ce qu’il se passe dans les données. Le language pour effectuer des requêtes est plutôt bien fait et permet de faire des recherches.
Le système est portable et ne nécessite aucune dépendance ce qui réduit la barrière à l’entrée et à la contribution.
Silk = documentation et tests
Markdown based document-driven web API testing.
La rapidité d’exécution d’un outil écrit en Go est toujours surprenante, j’ai eu besoin de vérifier que les tests étaient bien passés pour être sûr de son bon fonctionnement… Mon expérience me montre qu’une documentation qui n’est pas testée/proche du code n’est jamais synchronisée et conduit à des frustrations pour les utilisateurs. Silk est un moyen de faire cela directement depuis votre markdown, ça me rappelle d’une certaine manière le couple docutils/reStructuredText. En rapide. Et je ne saurais trop insister sur l’importance d’avoir une suite de tests rapide pour qu’elle reste pertinente.
Raconter une histoire dans vos tests est plus verbeux mais assurément plus intéressant pour la personne qui cherchera à comprendre ce que vous avez implémenté. Il y a de grandes chances que ce soit vous. Le README
du dépôt est un exemple de ce qui peut être réalisé.
RiotJS = composants web
The frontend space is indeed crowded, but we honestly feel the solution is still “out there”. We believe Riot offers the right balance for solving the great puzzle. While React seems to do it, they have serious weak points that Riot will solve.
Pour la partie JavaScript, mon objectif est de ne pas avoir à utiliser de package.json
également. Hérésie ! (bis) npm install riot mocha
génère un dossier node_modules
de 10 Mo. Mes besoins au final sont de 280 Ko lorsque je ne récupère à la main que ce dont j’ai besoin pour ce proof-of-concept. Quand même… En bonus, je peux avoir une estimation du poids réel de mes dépendances et explorer le code facilement. C’est aussi la raison pour laquelle je n’utilise pas Webpack à cette étape qui est dirigée par les besoins.
La beauté de Riot est d’avoir une approche composant avec le triptyque HTML/CSS/JS au même endroit et sans avoir l’un qui réécrit l’autre pour mieux saborder le dernier… De plus, quasiment tous les évènements sont explicites ici aussi.
Mocha = tests inclus
Mocha is a feature-rich JavaScript test framework running on […] the browser, making asynchronous testing simple and fun.
Je n’ai pas trouvé l’outil que je cherchais sur ce plan là alors je me suis rabattu sur le moins pire qui permet d’avoir une exécution dans le navigateur. La boucle de feedback est rapide et favorise la conception émergente. La syntaxe reste élégante.
Passage à l’échelle
In the end you should be aiming to design your application to depend on Flask as little as possible. The framework shouldn’t dictate your application design, and microframeworks in particular try to avoid doing this as much as possible.
Falcon ne devrait pas souffrir niveau performances, c’est plus la manière dont il est servi qui importe ici. Remplacer livereload par gunicorn par exemple. Pour une approche orientée service Nameko serait peut-être davantage approprié et pour de l’asynchrone aiohttp reste minimaliste.
Au niveau des données, TinyDB n’est clairement pas fait pour passer à l’échelle. Il faudra se pencher sur des solutions type dataset pour des données en CSV/JSON ou Walrus si l’on veut utiliser Redis en backend.
Côté front, le polyfill document-register-element permet de faire des Web Components nativement si l’on ne supporte pas RiotJS, basic-web-components est une piste à explorer (cache). Éventuellement intégrer un framework CSS comme Bulma pour utiliser Flexbox mais il faudrait que les frameworks CSS commencent à adopter l’approche par composants web dans leur modularité afin de pouvoir les inclure de manière « scopée » plus facilement.
Challengers
Right now, using React requires cobbling together multiple bricks: React itself, its plugins, Webpack, some kind of data management system, to say nothing of a whole back-end stack. But Meteor is in a unique position to solve that challenge for you, and in essence become the best possible platform to build React apps.
Je me suis demandé un moment si je n’étais pas en train de refaire Meteor ou le plus moderne Meatier qui semble être fait pour être plus modulaire. La complexité de prise en main reste quand même assez élevée de mon point de vue.
Preact garde malheureusement l’approche de React avec toute sa logique de cycle de vie d’un composant qui vient complexifier le moindre Hello World.
GraphQL pourrait remplacer notre API orientée ressources mais j’ai l’impression que tout le monde se rue dessus pour de mauvaises raisons. Si vous voulez laisser le choix aux clients de ne récupérer que les champs qui les intéressent c’est possible avec les sparse fieldsets de JSON API ou les fields masks. Vous n’avez pas besoin de toute la complexité de GraphQL pour autant et de son single endpoint… je ne limite pas GraphQL à cette fonctionnalité mais c’est souvent ce qui est mis en avant pour motiver une réécriture pour des systèmes qui n’ont pas forcément les problématiques rencontrées par Facebook.
Support et communauté
C’est le principal travers de ne pas utiliser les bibliothèques les plus populaires, le support et les communautés sont réduits. Les outils pré-cités reposent bien souvent sur l’effort d’une seule personne et les extensions sont rares donc on en arrive à faire plus de choses à la main. C’est le prix à payer d’un artisanat qui se questionne davantage sur la qualité et qui ne cherche pas forcément la quantité.
Équipe
If this garden bed is an open place that everyone can work in. A community garden instead of a protected and isolated botanical garden. Then that is where they will work. Instead of cultivating their own little gardens. Where they try to match the latest bloom in the 2016 Botanical Garden catalogue. They will work in the community garden. Together.
Bien sûr cette approche ne saurait trouver son sens que si elle est initiée, développée et soutenue par l’ensemble de l’équipe (cache). Il ne s’agit pas ici d’appliquer les vues d’un directeur technique mais de choisir ensemble ce qui semble pertinent afin que le produit génère le plus de valeur possible pour l’utilisateur final tout en conservant une expérience développeur intéressante pour l’équipe.
Stratégie
Thus teams are often confronting the uncomfortable choice between a risky refactoring operation and clean amputation. The best developers can be positively gleeful about amputating a diseased piece of code (even when it’s their own baby, so to speak), recognizing that it’s often the best choice for the overall health of the project. Better a single module should die than continue to bog down the rest of the project.
[…]
The organic, evolutionary nature of code also highlights the importance of getting your APIs right. By virtue of their public visibility, APIs can exert a lot of influence on the future growth of the codebase. A good API acts like a trellis, coaxing the code to grow where you want it. A bad API is like a cancer, and it will metastasize all over your codebase.
L’intérêt de partir d’un périmètre aussi restreint est de pouvoir se ré-interroger à chaque nouvel ajout sur sa pertinence, cela constitue une base itérative sans renoncer au plaisir technique. Le code est lisible et explicable en quelques heures pour des personnes ayant un faible niveau et il n’y a pas besoin de télécharger la moitié d’internet pour faire tourner une page web. Ma démarche est de renoncer à la complexité par défaut qui est prônée par tous les frameworks actuels, l’ajout de dépendances doit se faire au moment du besoin.
La durée de vie d’une composition de technologies est forcément réduite et demande de se ré-interroger à échéances régulières sur sa pertinence. Toute la difficulté actuelle est de pouvoir allonger ces échéances pour trouver le bon ratio entre focus et exploration. Plus vous bâtirez sur des concepts simples, universels et standardisés, plus vous aurez de chances de pouvoir être conservateur dans votre choix technique. Et plus vous serez inclusif auprès des potentiels contributeurs.
Pour aller plus loin, il serait intéressant d’aller vers du offline-first (cache) mais il n’y a pas encore de framework permettant de l’exploiter de manière simple. Je rêve de pouvoir manipuler des offline web components qui se synchronisent à la demande. C’est ce qui arrive avec Kinto ou PouchDB mais ça reste encore assez inaccessible. L’étape suivante étant de pouvoir échanger les données en pair à pair, on pourrait même imaginer que chaque composant dispose de sa propre blockchain et mine sa vie indépendamment de l’application mais je vais trop loin.
Il y avait 9 personnes durant la session et voici les retours proposés par Confoo dans l’heure qui suit (!) par email.
Une suite à cette intervention intitulée Simplicité par défaut a été donnée lors de Mix-IT 2016.