A place to cache linked articles (think custom and personal wayback machine)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

index.html 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang="fr">
  4. <!-- Has to be within the first 1024 bytes, hence before the `title` element
  5. See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
  6. <meta charset="utf-8">
  7. <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
  8. <!-- The viewport meta is quite crowded and we are responsible for that.
  9. See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
  10. <meta name="viewport" content="width=device-width,initial-scale=1">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>Keep it simple, stupid le plus longtemps possible (archive) — David Larlet</title>
  13. <meta name="description" content="Publication mise en cache pour en conserver une trace.">
  14. <!-- That good ol' feed, subscribe :). -->
  15. <link rel="alternate" type="application/atom+xml" title="Feed" href="/david/log/">
  16. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  17. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons2/apple-touch-icon.png">
  18. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons2/favicon-32x32.png">
  19. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons2/favicon-16x16.png">
  20. <link rel="manifest" href="/static/david/icons2/site.webmanifest">
  21. <link rel="mask-icon" href="/static/david/icons2/safari-pinned-tab.svg" color="#07486c">
  22. <link rel="shortcut icon" href="/static/david/icons2/favicon.ico">
  23. <meta name="msapplication-TileColor" content="#f7f7f7">
  24. <meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
  25. <meta name="theme-color" content="#f7f7f7" media="(prefers-color-scheme: light)">
  26. <meta name="theme-color" content="#272727" media="(prefers-color-scheme: dark)">
  27. <!-- Is that even respected? Retrospectively? What a shAItshow…
  28. https://neil-clarke.com/block-the-bots-that-feed-ai-models-by-scraping-your-website/ -->
  29. <meta name="robots" content="noai, noimageai">
  30. <!-- Documented, feel free to shoot an email. -->
  31. <link rel="stylesheet" href="/static/david/css/style_2021-01-20.css">
  32. <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
  33. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  34. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  35. <link rel="preload" href="/static/david/css/fonts/triplicate_t4_poly_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" crossorigin>
  36. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  37. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  38. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  39. <script>
  40. function toggleTheme(themeName) {
  41. document.documentElement.classList.toggle(
  42. 'forced-dark',
  43. themeName === 'dark'
  44. )
  45. document.documentElement.classList.toggle(
  46. 'forced-light',
  47. themeName === 'light'
  48. )
  49. }
  50. const selectedTheme = localStorage.getItem('theme')
  51. if (selectedTheme !== 'undefined') {
  52. toggleTheme(selectedTheme)
  53. }
  54. </script>
  55. <meta name="robots" content="noindex, nofollow">
  56. <meta content="origin-when-cross-origin" name="referrer">
  57. <!-- Canonical URL for SEO purposes -->
  58. <link rel="canonical" href="https://sklein.xyz/garden/020-keep-it-simple-stupid-le-plus-longtemps-possible/">
  59. <body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick" data-instant-intensity="viewport-all">
  60. <article>
  61. <header>
  62. <h1>Keep it simple, stupid le plus longtemps possible</h1>
  63. </header>
  64. <nav>
  65. <p class="center">
  66. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  67. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  68. </svg> Accueil</a> •
  69. <a href="https://sklein.xyz/garden/020-keep-it-simple-stupid-le-plus-longtemps-possible/" title="Lien vers le contenu original">Source originale</a>
  70. </p>
  71. </nav>
  72. <hr>
  73. <p>Depuis quelques années, j’utilise les mots suivants pour décrire mon mindset de développement :</p>
  74. <blockquote>
  75. <p>« Je suis au maximum le principe KISS (<a href="https://fr.wikipedia.org/wiki/Principe_KISS">Keep it simple, stupid</a>), j’écris le code le plus direct possible
  76. et quand j’ai trop de “douleur” alors je refactor mon code et j’y ajoute le minimum de sophistication indispensable »</p>
  77. </blockquote>
  78. <p>Ici j’utilise le mot “douleur” dans le sens de <a href="https://hn.algolia.com/?dateRange=all&amp;page=0&amp;prefix=false&amp;query=pain%20point&amp;sort=byPopularity&amp;type=story">“a pain point”</a> en anglais : quelque chose de casse-pieds, pénibilité, grosse difficulté…</p>
  79. <h2 id="partie-1-la-quete-du-code-parfait" tabindex="-1">Partie 1 : la quête du code “parfait” </h2>
  80. <p>Pendant la plus grande première partie de ma vie de développeur, j’ai essayé d’écrire le code le plus “propre” possible.</p>
  81. <p>Cela passait par :</p>
  82. <ul>
  83. <li>Découper le code en petites fonctions</li>
  84. <li>Éviter toute duplication de code (mon plus grand combat était le <a href="https://en.wikipedia.org/wiki/Copy-and-paste_programming">copy-and-paste programming</a>, j’ai embêté beaucoup de monde avec cela)</li>
  85. <li>Organiser le plus logiquement possible l’arborescence des dossiers</li>
  86. <li>Créer le maximum de classes (programmation objet) avec le maximum de niveau d’héritage (à l’époque c’était cool de faire de l’héritage)</li>
  87. <li>Utiliser les <a href="https://en.wikipedia.org/wiki/Design_Patterns">Design Patterns</a> (j’ai aussi creusé la <a href="https://fr.wikipedia.org/wiki/Programmation_orient%C3%A9e_aspect">programmation orientée aspect</a>…)</li>
  88. <li><a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">Don’t repeat yourself</a></li>
  89. <li>Découper mon projet en de petits projets ou librairies réutilisables</li>
  90. <li>Multiplier le nombres de repositories (Git…)</li>
  91. <li>Écrire du code pérenne dans le temps</li>
  92. <li>J’essayais d’écrire tout de suite le code dans sa version finale, devoir intervenir à nouveau sur du code était pour moi un échec, la preuve d’un mauvais choix de design.</li>
  93. </ul>
  94. <p>En résumé, un beau code était pour moi un code “intelligent” avec beaucoup de sophistication.</p>
  95. <h2 id="partie-2-la-prise-de-conscience-le-trop-de-tout" tabindex="-1">Partie 2 : la prise de conscience, le “trop de tout” </h2>
  96. <p>Il y a un peu moins de dix ans, j’ai commencé à prendre le chemin inverse, quand j’ai réalisé que je passais mon temps à chercher le code “parfait”.</p>
  97. <ul>
  98. <li>je me suis rendu compte que je passais énormément de temps à découper mon code en petites fonctions, ce qui impliquait :
  99. <ul>
  100. <li>se creuser la tête pour trouver des noms à ces fonctions</li>
  101. <li>de savoir où les placer, dans quels fichiers, dans quels sous dossiers, trouver des noms logiques à ces fichiers et ces dossiers</li>
  102. <li>de réorganiser encore et encore le découpage, le naming au fur et à mesure de l’évolution de l’application</li>
  103. </ul>
  104. </li>
  105. <li>je me suis rendu compte qu’à force d’éviter la duplication de code :
  106. <ul>
  107. <li>que j’avais un code de plus en plus difficile à comprendre</li>
  108. <li>qu’il fallait énormément de temps pour une nouvelle personne pour intervenir sur mon code</li>
  109. </ul>
  110. </li>
  111. <li>j’ai accepté (par expérience) que le code était jetable et que ce n’était pas un échec s’il avait été utile pendant une certaine durée</li>
  112. </ul>
  113. <p>Mon but était-il de faire du code ou de créer un produit rapidement tout en étant de qualité d’un point de vue fonctionnel ?</p>
  114. <h3 id="quest-ce-qui-ma-aide-a-prendre-ce-recul" tabindex="-1">Qu’est-ce qui m’a aidé à prendre ce recul ? </h3>
  115. <h4 id="des-echecs" tabindex="-1">Des échecs </h4>
  116. <p>De 2007 à 2013 j’ai poursuivi la quête du <a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">Don’t repeat yourself</a>, de <a href="https://fr.wikipedia.org/wiki/Pas_de_balle_en_argent">« la balle d’argent »</a> !</p>
  117. <p>Influencé par <a href="https://fr.wikipedia.org/wiki/Ruby_on_Rails">Ruby On Rails</a>, <a href="https://fr.wikipedia.org/wiki/Django_(framework)">Django</a>,
  118. mon rêve pour améliorer ma productivité était de générer automatiquement les applications à partir du modèle de données et des informations de paramétrages des UX.</p>
  119. <p>Ce fut un échec, un <a href="https://github.com/stephane-klein/personnal-notebook/blob/master/003-ne-tonds-pas-de-yaks.md">Yak!</a> perpétuel !</p>
  120. <p>Je passais la majorité de mon temps à :</p>
  121. <ul>
  122. <li>étudier, comprendre les Framework, sélectionner le “meilleur”</li>
  123. <li>embrasser toujours plus de complexité en écrivant des extensions, des plugins pour traiter mes cas particuliers</li>
  124. <li>modifier mes projets pour suivre la monté en version des frameworks</li>
  125. <li>trouver des solutions pour contourner les bugs des frameworks</li>
  126. </ul>
  127. <p>Je me suis trouvé de plus en plus dans des situations où je passais par exemple plus d’une semaine pour modifier un cas particulier d’un simple champ select html,
  128. chose qui m’aurait pris 30min sans framework, sans toutes les couches de magies.</p>
  129. <p>À cela s’ajoute en équipe, les heures et les heures de <a href="https://fr.wikipedia.org/wiki/Troll_(Internet)">trolls</a> de choix de framework.<br>
  130. Chaque développeur a ses préférences, pour tel ou tel framework et tout cela est parfaitement argumentable, car ils ont tous des forces et faiblesses.</p>
  131. <p>C’est suite à cette expérience que j’ai très peur de bâtir une application sur des solutions comme <a href="https://github.com/marmelab/react-admin">React Admin</a>, <a href="https://www.forestadmin.com/">Forest Admin</a> si je sais que je vais devoir les adapter (solutions qui peuvent être très bien pour faire un <a href="https://fr.wikipedia.org/wiki/Preuve_de_concept">POC</a> ou un <a href="https://fr.wikipedia.org/wiki/Produit_minimum_viable">MVP</a>), j’ai très peur de tomber dans un énorme <a href="https://github.com/stephane-klein/personnal-notebook/blob/master/003-ne-tonds-pas-de-yaks.md">Yak!</a>.</p>
  132. <h4 id="des-personnes" tabindex="-1">Des personnes </h4>
  133. <p>Des rencontres, par exemples :</p>
  134. <ul>
  135. <li><a href="https://twitter.com/athoune">Mathieu Lecarme</a> qui m’a dit une fois « j’ai besoin d’intervenir sur …, je constate que c’est de l’horlogerie fine, j’ai besoin d’aide », je me suis dit que j’avais codé quelque chose de bien trop compliqué</li>
  136. <li>Je me souviens de la quête vers le minimaliste dans le code de <a href="https://larlet.fr/david/blog/">David Larlet</a>
  137. <ul>
  138. <li>Est-ce qu’il est possible d’enlever des couches dans la stack ?</li>
  139. </ul>
  140. </li>
  141. <li><a href="https://twitter.com/plafoucriere">Philippe Lafoucrière</a> qui m’a poussé vers du minimalisme, de grosse remise en question en contribuant au code source de Gemnasium
  142. <ul>
  143. <li>Est-ce que mon ORM me fait vraiment gagner du temps ?</li>
  144. <li>Est-ce que je peux me passer de cette librairie ?</li>
  145. </ul>
  146. </li>
  147. </ul>
  148. <p>Ces deux dernières personnes m’ont poussé à réfléchir si je pouvais supprimer des couches, enlever des choses.</p>
  149. <blockquote>
  150. <p>Il semble que la perfection soit atteinte non quand il n’y a plus rien à ajouter, mais quand il n’y a plus rien à retrancher. – <a href="https://fr.wikiquote.org/wiki/Perfection">Antoine de Saint-Exupéry</a></p>
  151. </blockquote>
  152. <h4 id="linfluence-culturelle-de-technos" tabindex="-1">L’influence culturelle de technos </h4>
  153. <p>Depuis 15 ans, je suis très influencé par <a href="https://fr.wikipedia.org/wiki/Zen_de_Python">les 19 principes du Zen de Python</a>, tout particulièrement :</p>
  154. <blockquote>
  155. <ul>
  156. <li>Préfère :
  157. <ul>
  158. <li>l’explicite à l’implicite,</li>
  159. <li>le déroulé à l’imbriqué,</li>
  160. </ul>
  161. </li>
  162. <li>Prends en compte la lisibilité.</li>
  163. <li>Mais, à la pureté, privilégie l’aspect pratique.</li>
  164. <li>Face à l’ambiguïté, à deviner ne te laisse pas aller.</li>
  165. </ul>
  166. </blockquote>
  167. <p>Les choix minimalistes avec peu de sophistication du langage <a href="https://en.wikipedia.org/wiki/Go_(programming_language)">Go</a> a conforté la direction <a href="https://fr.wikipedia.org/wiki/Principe_KISS">KISS</a>.</p>
  168. <h2 id="partie-3-prise-de-decision-le-code-direct-du-code-stupide" tabindex="-1">Partie 3 : prise de décision, le code direct, du code “stupide” </h2>
  169. <p>Depuis quelques années, j’essaie d’écrire un code le plus direct possible.</p>
  170. <p>Mon objectif : diminuer au maximum ma <a href="https://fr.wikipedia.org/wiki/Charge_cognitive">charge cognitive</a>.</p>
  171. <p>J’essaie d’ajouter, une librairie, un service ou une couche d’abstraction uniquement si c’est nécessaire fonctionnellement ou si j’ai beaucoup de “douleur” avec la solution actuelle.</p>
  172. <p>J’essaie de garder un code le plus flat possible (<a href="https://www.thepythoncorner.com/2017/12/the-art-of-avoiding-nested-code/">The art of avoiding nested code</a>, <a href="https://medium.com/@ankushchoubey/clean-code-1-flat-is-better-than-nested-leave-when-not-okay-c09ba74090ef">Flat is better than nested</a>, <a href="http://matthewrocklin.com/blog/work/2019/06/23/avoid-indirection">Avoid Indirection in Code for human readability</a>)</p>
  173. <p>J’essaie de découper mon code uniquement si j’ai trop de “douleur” ou si cela apporte de la valeur fonctionnelle, exemple :</p>
  174. <ul>
  175. <li>je crée une fonction si j’ai besoin de la tester dans un test unitaire, ce qui fini par être le cas si j’ai trop de difficulté sur une section de code</li>
  176. <li>je crée une fonction pour éviter de la duplication en suivant la règle <a href="https://en.wikipedia.org/wiki/Rule_of_three_(computer_programming)">« Rule of three »</a></li>
  177. </ul>
  178. <h2>Ressources</h2>
  179. <ul>
  180. <li><a href="https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it">YAGNI</a> (You aren’t gonna need it)</li>
  181. <li><a href="https://en.wikipedia.org/wiki/Overengineering">Overengineering</a></li>
  182. <li><a href="https://en.wikipedia.org/wiki/KISS_principle">KISS principle</a></li>
  183. <li><a href="https://en.wikipedia.org/wiki/Don%27t_repeat_yourself">Don’t repeat yourself</a></li>
  184. <li><a href="https://en.wikipedia.org/wiki/Duplicate_code">Duplicate code</a></li>
  185. <li><a href="https://en.wikipedia.org/wiki/Code_reuse">Code reuse</a></li>
  186. <li><a href="https://en.wikipedia.org/wiki/Database_normalization">Database normalization</a></li>
  187. <li><a href="https://en.wikipedia.org/wiki/Rule_of_three_(computer_programming)">Rule of three (computer programming)</a></li>
  188. <li><a href="https://en.wikipedia.org/wiki/Separation_of_concerns">Separation of concerns</a></li>
  189. <li><a href="https://en.wikipedia.org/wiki/Single_source_of_truth">Single source of truth</a></li>
  190. <li><a href="https://josebrowne.com/on-coding-ego-and-attention/">On Coding, Ego and Attention</a></li>
  191. </ul>
  192. </article>
  193. <hr>
  194. <footer>
  195. <p>
  196. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  197. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  198. </svg> Accueil</a> •
  199. <a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
  200. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-rss2"></use>
  201. </svg> Suivre</a> •
  202. <a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
  203. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-user-tie"></use>
  204. </svg> Pro</a> •
  205. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
  206. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-mail"></use>
  207. </svg> Email</a> •
  208. <abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
  209. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-hammer2"></use>
  210. </svg> Légal</abbr>
  211. </p>
  212. <template id="theme-selector">
  213. <form>
  214. <fieldset>
  215. <legend><svg class="icon icon-brightness-contrast">
  216. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-brightness-contrast"></use>
  217. </svg> Thème</legend>
  218. <label>
  219. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  220. </label>
  221. <label>
  222. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  223. </label>
  224. <label>
  225. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  226. </label>
  227. </fieldset>
  228. </form>
  229. </template>
  230. </footer>
  231. <script src="/static/david/js/instantpage-5.1.0.min.js" type="module"></script>
  232. <script>
  233. function loadThemeForm(templateName) {
  234. const themeSelectorTemplate = document.querySelector(templateName)
  235. const form = themeSelectorTemplate.content.firstElementChild
  236. themeSelectorTemplate.replaceWith(form)
  237. form.addEventListener('change', (e) => {
  238. const chosenColorScheme = e.target.value
  239. localStorage.setItem('theme', chosenColorScheme)
  240. toggleTheme(chosenColorScheme)
  241. })
  242. const selectedTheme = localStorage.getItem('theme')
  243. if (selectedTheme && selectedTheme !== 'undefined') {
  244. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  245. }
  246. }
  247. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  248. window.addEventListener('load', () => {
  249. let hasDarkRules = false
  250. for (const styleSheet of Array.from(document.styleSheets)) {
  251. let mediaRules = []
  252. for (const cssRule of styleSheet.cssRules) {
  253. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  254. continue
  255. }
  256. // WARNING: Safari does not have/supports `conditionText`.
  257. if (cssRule.conditionText) {
  258. if (cssRule.conditionText !== prefersColorSchemeDark) {
  259. continue
  260. }
  261. } else {
  262. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  263. continue
  264. }
  265. }
  266. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  267. }
  268. // WARNING: do not try to insert a Rule to a styleSheet you are
  269. // currently iterating on, otherwise the browser will be stuck
  270. // in a infinite loop…
  271. for (const mediaRule of mediaRules) {
  272. styleSheet.insertRule(mediaRule.cssText)
  273. hasDarkRules = true
  274. }
  275. }
  276. if (hasDarkRules) {
  277. loadThemeForm('#theme-selector')
  278. }
  279. })
  280. </script>
  281. </body>
  282. </html>