Repository with sources and generator of https://larlet.fr/david/ https://larlet.fr/david/
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 46KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900
  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>
  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,minimum-scale=1,initial-scale=1,shrink-to-fit=no">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>Minimalisme et esthétique — David Larlet</title>
  13. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  14. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons/apple-touch-icon.png">
  15. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons/favicon-32x32.png">
  16. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons/favicon-16x16.png">
  17. <link rel="manifest" href="/manifest.json">
  18. <link rel="mask-icon" href="/static/david/icons/safari-pinned-tab.svg" color="#5bbad5">
  19. <link rel="shortcut icon" href="/static/david/icons/favicon.ico">
  20. <meta name="apple-mobile-web-app-title" content="David Larlet">
  21. <meta name="application-name" content="David Larlet">
  22. <meta name="msapplication-TileColor" content="#da532c">
  23. <meta name="msapplication-config" content="/static/david/icons/browserconfig.xml">
  24. <meta name="theme-color" content="#f0f0ea">
  25. <!-- That good ol' feed, subscribe :p. -->
  26. <link rel=alternate type="application/atom+xml" title=Feed href="/david/log/">
  27. <!-- Canonical URL for SEO purposes -->
  28. <link rel="canonical" href="https://larlet.fr/david/blog/2016/minimalisme-esthetique/">
  29. <!-- SEO/Semantic metadata -->
  30. <meta name="description" content="Cela constitue une base itérative sans renoncer au plaisir technique." />
  31. <meta name="twitter:description" property="og:description" itemprop="description" content="Cela constitue une base itérative sans renoncer au plaisir technique." />
  32. <meta name="twitter:title" property="og:title" itemprop="name" content="Minimalisme et esthétique" />
  33. <meta name="twitter:card" content="summary" />
  34. <meta name="twitter:creator" content="@davidbgk" />
  35. <meta name="twitter:url" property="og:url" content="https://larlet.fr/david/blog/2016/minimalisme-esthetique/" />
  36. <meta property="og:type" content="article" />
  37. <meta property="og:site_name" content="David Larlet (@davidbgk)" />
  38. <meta name="twitter:image" property="og:image" itemprop="image" content="https://larlet.fr/static/david/blog/2016/minimalisme-esthetique.jpg" />
  39. <style>
  40. /* http://meyerweb.com/eric/tools/css/reset/ */
  41. html, body, div, span,
  42. h1, h2, h3, h4, h5, h6, p, blockquote, pre,
  43. a, abbr, address, big, cite, code,
  44. del, dfn, em, img, ins,
  45. small, strike, strong, tt, var,
  46. dl, dt, dd, ol, ul, li,
  47. fieldset, form, label, legend,
  48. table, caption, tbody, tfoot, thead, tr, th, td,
  49. article, aside, canvas, details, embed,
  50. figure, figcaption, footer, header, hgroup,
  51. menu, nav, output, ruby, section, summary,
  52. time, mark, audio, video {
  53. margin: 0;
  54. padding: 0;
  55. border: 0;
  56. font-size: 100%;
  57. font: inherit;
  58. vertical-align: baseline;
  59. }
  60. /* HTML5 display-role reset for older browsers */
  61. article, aside, details, figcaption, figure,
  62. footer, header, hgroup, menu, nav, section { display: block; }
  63. body { line-height: 1; }
  64. blockquote, q { quotes: none; }
  65. blockquote:before, blockquote:after,
  66. q:before, q:after {
  67. content: '';
  68. content: none;
  69. }
  70. table {
  71. border-collapse: collapse;
  72. border-spacing: 0;
  73. }
  74. /* http://practicaltypography.com/equity.html */
  75. /* https://calendar.perfplanet.com/2016/no-font-face-bulletproof-syntax/ */
  76. /* https://www.filamentgroup.com/lab/js-web-fonts.html */
  77. @font-face {
  78. font-family: 'EquityTextB';
  79. src: url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff2') format('woff2'),
  80. url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff') format('woff');
  81. font-weight: 300;
  82. font-style: normal;
  83. font-display: swap;
  84. }
  85. @font-face {
  86. font-family: 'EquityTextB';
  87. src: url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff2') format('woff2'),
  88. url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff') format('woff');
  89. font-weight: 300;
  90. font-style: italic;
  91. font-display: swap;
  92. }
  93. @font-face {
  94. font-family: 'EquityTextB';
  95. src: url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff2') format('woff2'),
  96. url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff') format('woff');
  97. font-weight: 700;
  98. font-style: normal;
  99. font-display: swap;
  100. }
  101. @font-face {
  102. font-family: 'ConcourseT3';
  103. src: url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff2') format('woff2'),
  104. url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff') format('woff');
  105. font-weight: 300;
  106. font-style: normal;
  107. font-display: swap;
  108. }
  109. /* http://practice.typekit.com/lesson/caring-about-opentype-features/ */
  110. body {
  111. /* http://www.cssfontstack.com/ Palatino 99% Win 86% Mac */
  112. font-family: "EquityTextB", Palatino, serif;
  113. background-color: #f0f0ea;
  114. color: #07486c;
  115. font-kerning: normal;
  116. -moz-osx-font-smoothing: grayscale;
  117. -webkit-font-smoothing: subpixel-antialiased;
  118. text-rendering: optimizeLegibility;
  119. font-variant-ligatures: common-ligatures contextual;
  120. font-feature-settings: "kern", "liga", "clig", "calt";
  121. }
  122. pre, code, kbd, samp, var, tt {
  123. font-family: 'TriplicateT4c', monospace;
  124. }
  125. em {
  126. font-style: italic;
  127. color: #323a45;
  128. }
  129. strong {
  130. font-weight: bold;
  131. color: black;
  132. }
  133. nav {
  134. background-color: #323a45;
  135. color: #f0f0ea;
  136. display: flex;
  137. justify-content: space-around;
  138. padding: 1rem .5rem;
  139. }
  140. nav:last-child {
  141. border-bottom: 1vh solid #2d7474;
  142. }
  143. nav a {
  144. color: #f0f0ea;
  145. }
  146. nav abbr {
  147. border-bottom: 1px dotted white;
  148. }
  149. h1 {
  150. border-top: 1vh solid #2d7474;
  151. border-bottom: .2vh dotted #2d7474;
  152. background-color: #e3e1e1;
  153. color: #323a45;
  154. text-align: center;
  155. padding: 5rem 0 4rem 0;
  156. width: 100%;
  157. font-family: 'ConcourseT3';
  158. display: flex;
  159. flex-direction: column;
  160. }
  161. h1.single {
  162. padding-bottom: 10rem;
  163. }
  164. h1 span {
  165. position: absolute;
  166. top: 1vh;
  167. left: 20%;
  168. line-height: 0;
  169. }
  170. h1 span a {
  171. line-height: 1.7;
  172. padding: 1rem 1.2rem .6rem 1.2rem;
  173. border-radius: 0 0 6% 6%;
  174. background: #2d7474;
  175. font-size: 1.3rem;
  176. color: white;
  177. text-decoration: none;
  178. }
  179. h2 {
  180. margin: 4rem 0 1rem;
  181. border-top: .2vh solid #2d7474;
  182. padding-top: 1vh;
  183. }
  184. h3 {
  185. text-align: center;
  186. margin: 3rem 0 .75em;
  187. }
  188. hr {
  189. height: .4rem;
  190. width: .4rem;
  191. border-radius: .4rem;
  192. background: #07486c;
  193. margin: 2.5rem auto;
  194. }
  195. time {
  196. display: bloc;
  197. margin-left: 0 !important;
  198. }
  199. ul, ol {
  200. margin: 2rem;
  201. }
  202. ul {
  203. list-style-type: square;
  204. }
  205. a {
  206. text-decoration-skip-ink: auto;
  207. text-decoration-thickness: 0.05em;
  208. text-underline-offset: 0.09em;
  209. }
  210. article {
  211. max-width: 50rem;
  212. display: flex;
  213. flex-direction: column;
  214. margin: 2rem auto;
  215. }
  216. article.single {
  217. border-top: .2vh dotted #2d7474;
  218. margin: -6rem auto 1rem auto;
  219. background: #f0f0ea;
  220. padding: 2rem;
  221. }
  222. article p:last-child {
  223. margin-bottom: 1rem;
  224. }
  225. p {
  226. padding: 0 .5rem;
  227. margin-left: 3rem;
  228. }
  229. p + p,
  230. figure + p {
  231. margin-top: 2rem;
  232. }
  233. blockquote {
  234. background-color: #e3e1e1;
  235. border-left: .5vw solid #2d7474;
  236. display: flex;
  237. flex-direction: column;
  238. align-items: center;
  239. padding: 1rem;
  240. margin: 1.5rem;
  241. }
  242. blockquote cite {
  243. font-style: italic;
  244. }
  245. blockquote p {
  246. margin-left: 0;
  247. }
  248. figure {
  249. border-top: .2vh solid #2d7474;
  250. background-color: #e3e1e1;
  251. text-align: center;
  252. padding: 1.5rem 0;
  253. margin: 1rem 0 0;
  254. font-size: 1.5rem;
  255. width: 100%;
  256. }
  257. figure img {
  258. max-width: 250px;
  259. max-height: 250px;
  260. border: .5vw solid #323a45;
  261. padding: 1px;
  262. }
  263. figcaption {
  264. padding: 1rem;
  265. line-height: 1.4;
  266. }
  267. aside {
  268. display: flex;
  269. flex-direction: column;
  270. background-color: #e3e1e1;
  271. padding: 1rem 0;
  272. border-bottom: .2vh solid #07486c;
  273. }
  274. aside p {
  275. max-width: 50rem;
  276. margin: 0 auto;
  277. }
  278. /* https://fvsch.com/code/css-locks/ */
  279. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  280. font-size: 1rem;
  281. line-height: calc( 1.5em + 0.2 * 1rem );
  282. }
  283. h1 {
  284. font-size: 1.9rem;
  285. line-height: calc( 1.2em + 0.2 * 1rem );
  286. }
  287. h2 {
  288. font-size: 1.6rem;
  289. line-height: calc( 1.3em + 0.2 * 1rem );
  290. }
  291. h3 {
  292. font-size: 1.35rem;
  293. line-height: calc( 1.4em + 0.2 * 1rem );
  294. }
  295. @media (min-width: 20em) {
  296. /* The (100vw - 20rem) / (50 - 20) part
  297. resolves to 0-1rem, depending on the
  298. viewport width (between 20em and 50em). */
  299. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  300. font-size: calc( 1rem + .6 * (100vw - 20rem) / (50 - 20) );
  301. line-height: calc( 1.5em + 0.2 * (100vw - 50rem) / (20 - 50) );
  302. margin-left: 0;
  303. }
  304. h1 {
  305. font-size: calc( 1.9rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  306. line-height: calc( 1.2em + 0.2 * (100vw - 50rem) / (20 - 50) );
  307. }
  308. h2 {
  309. font-size: calc( 1.5rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  310. line-height: calc( 1.3em + 0.2 * (100vw - 50rem) / (20 - 50) );
  311. }
  312. h3 {
  313. font-size: calc( 1.35rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  314. line-height: calc( 1.4em + 0.2 * (100vw - 50rem) / (20 - 50) );
  315. }
  316. }
  317. @media (min-width: 50em) {
  318. /* The right part of the addition *must* be a
  319. rem value. In this example we *could* change
  320. the whole declaration to font-size:2.5rem,
  321. but if our baseline value was not expressed
  322. in rem we would have to use calc. */
  323. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  324. font-size: calc( 1rem + .6 * 1rem );
  325. line-height: 1.5em;
  326. }
  327. p, li, pre, details {
  328. margin-left: 3rem;
  329. }
  330. h1 {
  331. font-size: calc( 1.9rem + 1.5 * 1rem );
  332. line-height: 1.2em;
  333. }
  334. h2 {
  335. font-size: calc( 1.5rem + 1.5 * 1rem );
  336. line-height: 1.3em;
  337. }
  338. h3 {
  339. font-size: calc( 1.35rem + 1.5 * 1rem );
  340. line-height: 1.4em;
  341. }
  342. figure img {
  343. max-width: 500px;
  344. max-height: 500px;
  345. }
  346. }
  347. figure.unsquared {
  348. margin-bottom: 1.5rem;
  349. }
  350. figure.unsquared img {
  351. height: inherit;
  352. }
  353. @media print {
  354. body { font-size: 100%; }
  355. a:after { content: " (" attr(href) ")"; }
  356. a, a:link, a:visited, a:after {
  357. text-decoration: underline;
  358. text-shadow: none !important;
  359. background-image: none !important;
  360. background: white;
  361. color: black;
  362. }
  363. abbr[title] { border-bottom: 0; }
  364. abbr[title]:after { content: " (" attr(title) ")"; }
  365. img { page-break-inside: avoid; }
  366. @page { margin: 2cm .5cm; }
  367. h1, h2, h3 { page-break-after: avoid; }
  368. p3 { orphans: 3; widows: 3; }
  369. img {
  370. max-width: 250px !important;
  371. max-height: 250px !important;
  372. }
  373. nav, aside { display: none; }
  374. }
  375. ul.with_columns {
  376. column-count: 1;
  377. }
  378. @media (min-width: 20em) {
  379. ul.with_columns {
  380. column-count: 2;
  381. }
  382. }
  383. @media (min-width: 50em) {
  384. ul.with_columns {
  385. column-count: 3;
  386. }
  387. }
  388. ul.with_two_columns {
  389. column-count: 1;
  390. }
  391. @media (min-width: 20em) {
  392. ul.with_two_columns {
  393. column-count: 1;
  394. }
  395. }
  396. @media (min-width: 50em) {
  397. ul.with_two_columns {
  398. column-count: 2;
  399. }
  400. }
  401. .gallery {
  402. display: flex;
  403. flex-wrap: wrap;
  404. justify-content: space-around;
  405. }
  406. .gallery figure img {
  407. margin-left: 1rem;
  408. margin-right: 1rem;
  409. }
  410. .gallery figure figcaption {
  411. font-family: 'ConcourseT3'
  412. }
  413. footer {
  414. font-family: 'ConcourseT3';
  415. display: flex;
  416. flex-direction: column;
  417. border-top: 3px solid white;
  418. padding: 4rem 0;
  419. background-color: #07486c;
  420. color: white;
  421. }
  422. footer > * {
  423. max-width: 50rem;
  424. margin: 0 auto;
  425. }
  426. footer a {
  427. color: #f1c40f;
  428. }
  429. footer .avatar {
  430. width: 200px;
  431. height: 200px;
  432. border-radius: 50%;
  433. float: left;
  434. -webkit-shape-outside: circle();
  435. shape-outside: circle();
  436. margin-right: 2rem;
  437. padding: 2px 5px 5px 2px;
  438. background: white;
  439. border-left: 1px solid #f1c40f;
  440. border-top: 1px solid #f1c40f;
  441. border-right: 5px solid #f1c40f;
  442. border-bottom: 5px solid #f1c40f;
  443. }
  444. </style>
  445. <h1 class="single">
  446. <span><a id="jumper" href="#jumpto" title="Un peu perdu ?">?</a></span>
  447. Minimalisme et esthétique
  448. <time>Publié le 25 février 2016</time>
  449. </h1>
  450. <article class="single">
  451. <p><em>Ceci est un résumé de mon intervention à <a href="https://confoo.ca">Confoo</a>, vous pouvez retrouver le code associé sur <a href="https://github.com/davidbgk/confoo">le dépôt dédié</a>.</em></p>
  452. <blockquote>
  453. <p>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.</p>
  454. <p><cite><em><a href="http://hintjens.com/blog:19">How to Design Perfect (Software) Products</a></em> (<a href="/david/cache/2bfa30e8d911bac28aa4844302437c6c/">cache</a>)</cite></p>
  455. </blockquote>
  456. <p>Cette conférence devait parler <a href="/david/stream/2015/10/19/">de Python et des API</a> mais <a href="https://gist.github.com/davidbgk/e459577c241e5b905571">au cours de sa préparation</a> 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 <a href="http://tinyclouds.org/rant.html">l’urgence</a> (<a href="/david/cache/b932828a2ee51364e222b82b9ba4e870/">cache</a>) de montrer de la simplicité et cela est parti de plusieurs constats.</p>
  457. <h2>Épuisement technique</h2>
  458. <blockquote>
  459. <p>Ultimately, the problem is that by choosing React (and inherently JSX), you’ve unwittingly opted into a confusing nest of build tools, boilerplate, linters, &amp; time-sinks to deal with before you ever get to create anything.</p>
  460. <p><cite><em><a href="https://medium.com/@ericclemmons/javascript-fatigue-48d4011b6fc4">Javascript Fatigue</a></em> (<a href="/david/cache/f41d0be1b419e16d37b415958dab7339/">cache</a>)</cite></p>
  461. </blockquote>
  462. <p>Il y a eu des <a href="http://www.2ality.com/2016/02/js-fatigue-fatigue.html">réponses</a> (<a href="/david/cache/ad4989ebdcbb68611415e359c2564adb/">cache</a>), des <a href="http://www.foreverscape.com/art/2016/byte-me-javascript-fatigue/">trolls</a> (<a href="/david/cache/c70709eae0bbfc38b7bd73b447e3a14f/">cache</a>) et des <a href="https://www.youtube.com/watch?v=18DdpKtOSXo">vidéos</a> 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 <a href="/david/stream/2015/10/07/">core-stack developer</a>. 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 ?</p>
  463. <h2>Initiateurs et mainteneurs</h2>
  464. <blockquote>
  465. <p>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.</p>
  466. <p>[…]</p>
  467. <p>I am definitely a starter. I tend to be interested in a <em>lot</em> 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.</p>
  468. <p><cite><em><a href="http://jlongster.com/Starters-and-Maintainers">Starters and Maintainers</a></em> (<a href="/david/cache/0d7137e32d5ec9d0c301a72282e97c01/">cache</a>)</cite></p>
  469. </blockquote>
  470. <p>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 <em>microservices</em> est un complot des initiateurs en mal d’expérimentations au sein d’applications à maintenir. À moins que la maintenance soit <a href="https://18f.gsa.gov/2016/02/23/software-maintenance-is-an-anti-pattern/">un vestige du passé</a> (<a href="/david/cache/e6f00d9b489f69b28250cd43e33b96d2/">cache</a>).</p>
  471. <h2>Matériel pédagogique</h2>
  472. <blockquote>
  473. <p>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.</p>
  474. <p>[…]</p>
  475. <p>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.</p>
  476. <p><cite><em><a href="https://didapro.me/2016/02/15/sortir-de-sa-zone-de-confort-2/">Sortir de sa zone de confort</a></em> (<a href="/david/cache/6ac2fbe56771be20dafafd8452d4141b/">cache</a>)</cite></p>
  477. </blockquote>
  478. <p>Je donne <a href="/david/pro/enseignement/">des cours à l’IUT d’Arles</a> 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.</p>
  479. <p>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 ?</p>
  480. <h2>Scalable POC</h2>
  481. <blockquote>
  482. <p>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.</p>
  483. <p><cite><em><a href="http://www.themacro.com/articles/2016/01/minimum-viable-product-process/">A Minimum Viable Product Is Not a Product, It’s a Process</a></em> (<a href="/david/cache/6b495183abd78323ceafac6cdc12cc57/">cache</a>)</cite></p>
  484. </blockquote>
  485. <p>Cela fait un moment que l’on cherche avec <a href="http://scopyleft.fr/">scopyleft</a> un agrégat de technologies qui nous permettrait de faire de tous petits services qui permettent d’aller vers l’utilisateur afin de <a href="/david/pro/produits-essentiels/">vérifier leur pertinence</a> 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.</p>
  486. <h2>Small libs loosely joined</h2>
  487. <blockquote>
  488. <p>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.</p>
  489. <p>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.</p>
  490. <p><cite><em><a href="http://programmingisterrible.com/post/139222674273/write-code-that-is-easy-to-delete-not-easy-to">Write code that is easy to delete, not easy to extend</a></em> (<a href="/david/cache/7cd1ba7e421234316758516bff8be157/">cache</a>)</cite></p>
  491. </blockquote>
  492. <p>Partant de ce constat, j’ai essayé de produire une <em>stack</em> minimaliste qui comportent très peu de dépendances qui peuvent évoluer en fonction du besoin. <strong>De cette manière, on accède à un LEAN technique : l’ajout de complexité architecturale en fonction du besoin uniquement.</strong></p>
  493. <p>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.</p>
  494. <h2>Falcon = API HTTP Python</h2>
  495. <blockquote>
  496. <p>Falcon is a minimalist WSGI library for building speedy web APIs and app backends. We like to think of Falcon as the <em>Dieter Rams</em> of web frameworks.</p>
  497. <p><cite><em><a href="http://falcon.readthedocs.org/en/stable/">Falcon</a></em></cite></p>
  498. </blockquote>
  499. <p>Avec Falcon, il faut aimer le bas niveau sachant qu’il est de votre responsabilité de retourner le bon <em>status code</em> ou <em>content type</em> 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.</p>
  500. <p>Servi par <a href="https://pypi.python.org/pypi/livereload">livereload</a>, chaque mise à jour de code relance le serveur et la page dans votre navigateur.</p>
  501. <p>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 <code>requirements.txt</code>. Hérésie ! Cela fait 500Ko au total à télécharger contre un <code>virtualenv</code> de 10Mo…</p>
  502. <h2>TinyDB = données en JSON</h2>
  503. <blockquote>
  504. <p>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.</p>
  505. <p><cite><em><a href="http://tinydb.readthedocs.org/en/latest/">TinyDB</a></em></cite></p>
  506. </blockquote>
  507. <p>J’ai enfin trouvé la petite pépite que je cherchais depuis longtemps qui est encore plus légère que <code>SQLite</code> 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.</p>
  508. <p>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.</p>
  509. <h2>Silk = documentation et tests</h2>
  510. <blockquote>
  511. <p>Markdown based document-driven web API testing.</p>
  512. <p><cite><em><a href="https://github.com/matryer/silk">Silk</a></em></cite></p>
  513. </blockquote>
  514. <p>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 <em>markdown</em>, ç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.</p>
  515. <p>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 <code>README</code> du dépôt est un exemple de ce qui peut être réalisé.</p>
  516. <h2>RiotJS = composants web</h2>
  517. <blockquote>
  518. <p>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.</p>
  519. <p><cite><em><a href="http://riotjs.com/">RiotJS</a></em></cite></p>
  520. </blockquote>
  521. <p>Pour la partie JavaScript, mon objectif est de ne pas avoir à utiliser de <code>package.json</code> également. Hérésie ! (bis) <code>npm install riot mocha</code> génère un dossier <code>node_modules</code> 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 <em>proof-of-concept</em>. 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 <a href="https://webpack.github.io/">Webpack</a> à cette étape qui est dirigée par les besoins.</p>
  522. <p>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.</p>
  523. <h2>Mocha = tests inclus</h2>
  524. <blockquote>
  525. <p>Mocha is a feature-rich JavaScript test framework running on […] the browser, making asynchronous testing simple and fun.</p>
  526. <p><cite><em><a href="http://mochajs.org/">Mocha</a></em></cite></p>
  527. </blockquote>
  528. <p>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 <em>feedback</em> est rapide et favorise la <a href="/david/blog/2013/tdd-conception-emergente/">conception émergente</a>. La syntaxe reste élégante.</p>
  529. <h2>Passage à l’échelle</h2>
  530. <blockquote>
  531. <p>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.</p>
  532. <p><cite><em><a href="https://etscrivner.github.io/posts/2014/10/building-large-flask-apps-in-the-real-world/">Building Large Flask Apps In The Real World</a></em> (<a href="/david/cache/23a57db93ad36a37f40e1ff30b5dea2d/">cache</a>)</cite></p>
  533. </blockquote>
  534. <p>Falcon ne devrait pas souffrir niveau performances, c’est plus la manière dont il est servi qui importe ici. Remplacer <a href="http://livereload.readthedocs.org/en/latest/">livereload</a> par <a href="http://gunicorn.org/">gunicorn</a> par exemple. Pour une approche orientée service <a href="http://nameko.readthedocs.org/en/stable/">Nameko</a> serait peut-être davantage approprié et pour de l’asynchrone <a href="http://aiohttp.readthedocs.org/en/stable/">aiohttp</a> reste minimaliste.</p>
  535. <p>Au niveau des données, TinyDB n’est clairement pas fait pour passer à l’échelle. Il faudra se pencher sur des solutions type <a href="https://dataset.readthedocs.org/en/latest/">dataset</a> pour des données en CSV/JSON ou <a href="https://walrus.readthedocs.org/en/latest/">Walrus</a> si l’on veut utiliser Redis en <em>backend</em>.</p>
  536. <p>Côté <em>front</em>, le <em>polyfill</em> <a href="https://github.com/WebReflection/document-register-element">document-register-element</a> permet de faire des <em>Web Components</em> nativement si l’on ne supporte pas RiotJS, <a href="https://github.com/basic-web-components/basic-web-components">basic-web-components</a> est une <a href="https://component.kitchen/blog/posts/a-new-release-of-basic-web-components-based-on-plain-javascript-component-mixins">piste à explorer</a> (<a href="/david/cache/3647ff17fdec1f87799f7a1282fa5c92/">cache</a>). Éventuellement intégrer un <em>framework</em> CSS comme <a href="http://bulma.io/">Bulma</a> 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.</p>
  537. <h2>Challengers</h2>
  538. <blockquote>
  539. <p>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.</p>
  540. <p><cite><em><a href="https://www.discovermeteor.com/blog/the-state-of-meteor-part-2-what-happens-next/">The State Of Meteor Part 2: What Happens Next</a></em> (<a href="/david/cache/c42e26d79ef2a72748850ca7d7f98d64/">cache</a>)</cite></p>
  541. </blockquote>
  542. <p>Je me suis demandé un moment si je n’étais pas en train de refaire <a href="https://www.meteor.com/">Meteor</a> ou le plus moderne <a href="https://github.com/mattkrick/meatier">Meatier</a> 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.</p>
  543. <p><a href="http://developit.github.io/preact/">Preact</a> garde malheureusement l’approche de <a href="http://facebook.github.io/react/">React</a> avec toute sa logique de cycle de vie d’un composant qui vient complexifier le moindre <em>Hello World</em>.</p>
  544. <p><a href="http://graphql.org/">GraphQL</a> 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 <a href="http://jsonapi.org/format/#fetching-sparse-fieldsets">sparse fieldsets</a> de JSON API ou les <a href="http://flask-restplus.readthedocs.org/en/latest/mask.html">fields masks</a>. Vous n’avez pas besoin de toute la complexité de GraphQL pour autant et de son <em>single endpoint</em>… 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.</p>
  545. <h2>Support et communauté</h2>
  546. <p>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. <strong>C’est le prix à payer d’un artisanat qui se questionne davantage sur la qualité et qui ne cherche pas forcément la quantité.</strong></p>
  547. <h2>Équipe</h2>
  548. <blockquote>
  549. <p>If this garden bed is an open place that everyone can work <em>in</em>. 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.</p>
  550. <p><cite><em><a href="http://ludwig.nz/2016/01/25/together/">Together</a></em> (<a href="/david/cache/e284347d93a0fb4388d4d1428c79a0d5/">cache</a>)</cite></p>
  551. </blockquote>
  552. <p>Bien sûr cette approche ne saurait trouver son sens que si elle est initiée, développée et soutenue par <a href="http://ludwig.nz/2016/02/06/not-just-pattern-libraries/">l’ensemble de l’équipe</a> (<a href="/david/cache/0cd26f943ba3f729a99d05160ecd2196/">cache</a>). Il ne s’agit pas ici d’appliquer les vues d’un directeur technique mais de choisir ensemble ce qui semble pertinent <strong>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.</strong></p>
  553. <h2>Stratégie</h2>
  554. <blockquote>
  555. <p>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.</p>
  556. <p>[…]</p>
  557. <p>The organic, evolutionary nature of code also highlights the importance of <strong>getting your APIs right</strong>. 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.</p>
  558. <p><cite><em><a href="http://www.meltingasphalt.com/a-codebase-is-an-organism/">A Codebase is an Organism</a></em> (<a href="/david/cache/7d25593fd8739da9608a0fdae30f5345/">cache</a>)</cite></p>
  559. </blockquote>
  560. <p>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, <strong>cela constitue une base itérative sans renoncer au plaisir technique.</strong> 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 <em>complexité par défaut</em> qui est prônée par tous les <em>frameworks</em> actuels, l’ajout de dépendances doit se faire au moment du besoin.</p>
  561. <p>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.</p>
  562. <p>Pour aller plus loin, il serait intéressant d’aller vers du <a href="http://hood.ie/blog/say-hello-to-offline-first.html">offline-first</a> (<a href="/david/cache/32bfd094aa8514985578ea493c6c3aea/">cache</a>) mais il n’y a pas encore de <em>framework</em> permettant de l’exploiter de manière simple. <strong>Je rêve de pouvoir manipuler des offline web components qui se synchronisent à la demande.</strong> C’est ce qui arrive avec <a href="http://kintojs.readthedocs.org/">Kinto</a> ou <a href="http://pouchdb.com/">PouchDB</a> mais ça reste encore assez inaccessible. L’étape suivante étant de pouvoir échanger les données en <a href="https://github.com/buckket/twtxt">pair à pair</a>, on pourrait même imaginer que chaque composant dispose de sa propre <em>blockchain</em> et mine sa vie indépendamment de l’application mais je vais trop loin.</p>
  563. <p><em>Il y avait 9 personnes durant la session et voici <a href="/static/david/blog/minimalisme-esthetique-retours.pdf">les retours</a> proposés par Confoo dans l’heure qui suit (!) par email.</em></p>
  564. <p>Une suite à cette intervention intitulée <a href="/david/blog/2016/simplicite-defaut/">Simplicité par défaut</a> a été donnée lors de <a href="/david/blog/2016/mixit-2016/">Mix-IT 2016</a>.</p>
  565. </article>
  566. <figure class="image" property="schema:image">
  567. <img src="/static/david/blog/2016/minimalisme-esthetique.jpg" alt="" />
  568. </figure>
  569. <nav id="jumpto">
  570. <p>
  571. <a rel=prev href="/david/blog/2016/rencontres-conviviales/">← Rencontres conviviales</a> | <a href="/david/blog/" title="Retour à la liste des expériences">↑</a> | <a rel=next href="/david/blog/2016/opendata-liens-casses/">Opendata et liens cassés →</a>
  572. </p>
  573. </nav>
  574. <footer>
  575. <div>
  576. <img src="/static/david/david-larlet-avatar.jpg" loading="lazy" class="avatar" width="200" height="200">
  577. <p>
  578. Bonjour/Hi!
  579. Je suis <a href="/david/" title="Profil public">David&nbsp;Larlet</a>, je vis actuellement à Montréal et j’alimente cet espace depuis 15 ans. <br>
  580. Si tu as apprécié cette lecture, n’hésite pas à poursuivre ton exploration. Par exemple via les <a href="/david/blog/" title="Expériences bienveillantes">réflexions bimestrielles</a>, la <a href="/david/stream/2019/" title="Pensées (dés)articulées">veille hebdomadaire</a> ou en t’abonnant au <a href="/david/log/" title="S’abonner aux publications via RSS">flux RSS</a> (<a href="/david/blog/2019/flux-rss/" title="Tiens c’est quoi un flux RSS ?">so 2005</a>).
  581. </p>
  582. <p>
  583. Je m’intéresse à la place que je peux avoir dans ce monde. En tant qu’humain, en tant que membre d’une famille et en tant qu’associé d’une coopérative. De temps en temps, je fais aussi des <a href="https://github.com/davidbgk" title="Principalement sur Github mais aussi ailleurs">trucs techniques</a>. Et encore plus rarement, <a href="/david/talks/" title="En ce moment je laisse plutôt la place aux autres">j’en parle</a>.
  584. </p>
  585. <p>
  586. Les dernières publications hebdomadaires sont :
  587. </p>
  588. <ul class="with_columns">
  589. <li>
  590. <a href="/david/stream/2019/12/31/">Merci</a>
  591. </li>
  592. <li>
  593. <a href="/david/stream/2019/12/27/">Intemporels</a>
  594. </li>
  595. <li>
  596. <a href="/david/stream/2019/12/24/">Outils</a>
  597. </li>
  598. <li>
  599. <a href="/david/stream/2019/12/17/">Origines</a>
  600. </li>
  601. <li>
  602. <a href="/david/stream/2019/12/10/">Publier</a>
  603. </li>
  604. <li>
  605. <a href="/david/stream/2019/12/03/">En forêt</a>
  606. </li>
  607. <li>
  608. <a href="/david/stream/2019/11/26/">Ecocentric</a>
  609. </li>
  610. <li>
  611. <a href="/david/stream/2019/11/19/">Se livrer</a>
  612. </li>
  613. <li>
  614. <a href="/david/stream/2019/11/12/">Dépendances</a>
  615. </li>
  616. <li>
  617. <a href="/david/stream/2019/11/05/">Positif</a>
  618. </li>
  619. <li>
  620. <a href="/david/stream/2019/10/29/">Dettes</a>
  621. </li>
  622. <li>
  623. <a href="/david/stream/2019/10/22/">Privilèges</a>
  624. </li>
  625. <li>
  626. <a href="/david/stream/2019/10/15/">Discrétion</a>
  627. </li>
  628. <li>
  629. <a href="/david/stream/2019/10/08/">Désespérance</a>
  630. </li>
  631. <li>
  632. <a href="/david/stream/2019/10/01/">Présent</a>
  633. </li>
  634. <li>
  635. <a href="/david/stream/2019/09/24/">Manifester</a>
  636. </li>
  637. <li>
  638. <a href="/david/stream/2019/09/17/">Arpenter</a>
  639. </li>
  640. <li>
  641. <a href="/david/stream/2019/09/10/">Nostalgie</a>
  642. </li>
  643. <li>
  644. <a href="/david/stream/2019/09/03/">Déconstruire</a>
  645. </li>
  646. <li>
  647. <a href="/david/stream/2019/08/27/">Documenter</a>
  648. </li>
  649. <li>
  650. <a href="/david/stream/2019/08/20/">Frustration</a>
  651. </li>
  652. <li>
  653. <a href="/david/stream/2019/08/13/">Holisme</a>
  654. </li>
  655. <li>
  656. <a href="/david/stream/2019/08/06/">1%</a>
  657. </li>
  658. <li>
  659. <a href="/david/stream/2019/07/30/">Exemplarité</a>
  660. </li>
  661. <li>
  662. <a href="/david/stream/2019/07/23/">Timelines</a>
  663. </li>
  664. <li>
  665. <a href="/david/stream/2019/07/16/">Écoute</a>
  666. </li>
  667. <li>
  668. <a href="/david/stream/2019/07/02/">Anxiété</a>
  669. </li>
  670. <li>
  671. <a href="/david/stream/2019/06/21/">À lier</a>
  672. </li>
  673. <li>
  674. <a href="/david/stream/2019/06/14/">Pauvreté</a>
  675. </li>
  676. <li>
  677. <a href="/david/stream/2019/06/07/">Amateur</a>
  678. </li>
  679. <li>
  680. <a href="/david/stream/2019/05/31/">Pollution</a>
  681. </li>
  682. <li>
  683. <a href="/david/stream/2019/05/24/">Apaisement</a>
  684. </li>
  685. <li>
  686. <a href="/david/stream/2019/05/10/">Folie</a>
  687. </li>
  688. <li>
  689. <a href="/david/stream/2019/05/03/">Sympathie</a>
  690. </li>
  691. <li>
  692. <a href="/david/stream/2019/04/12/">Péremption</a>
  693. </li>
  694. <li>
  695. <a href="/david/stream/2019/04/05/">Définitions</a>
  696. </li>
  697. <li>
  698. <a href="/david/stream/2019/03/29/">Acceptation</a>
  699. </li>
  700. <li>
  701. <a href="/david/stream/2019/03/22/">Dissonance</a>
  702. </li>
  703. <li>
  704. <a href="/david/stream/2019/03/15/">Reconnaissance</a>
  705. </li>
  706. <li>
  707. <a href="/david/stream/2019/03/08/">Lecture</a>
  708. </li>
  709. <li>
  710. <a href="/david/stream/2019/03/01/">Journaux</a>
  711. </li>
  712. <li>
  713. <a href="/david/stream/2019/02/22/">Écriture</a>
  714. </li>
  715. <li>
  716. <a href="/david/stream/2019/02/15/">Kyriarchie</a>
  717. </li>
  718. <li>
  719. <a href="/david/stream/2019/02/08/">Mots-serrures</a>
  720. </li>
  721. <li>
  722. <a href="/david/stream/2019/02/01/">Sans voie</a>
  723. </li>
  724. <li>
  725. <a href="/david/stream/2019/01/25/">Auto-diagnostic</a>
  726. </li>
  727. <li>
  728. <a href="/david/stream/2019/01/18/">Agilité</a>
  729. </li>
  730. <li>
  731. <a href="/david/stream/2019/01/11/">Métaphores</a>
  732. </li>
  733. <li>
  734. <a href="/david/stream/2019/01/04/">Balbutiements</a>
  735. </li>
  736. </ul>
  737. <p>
  738. Voici quelques articles choisis :
  739. <a href="/david/blog/2019/faire-equipe/" title="Accéder à l’article complet">Faire équipe</a>,
  740. <a href="/david/blog/2018/bivouac-automnal/" title="Accéder à l’article complet">Bivouac automnal</a>,
  741. <a href="/david/blog/2018/commodite-effondrement/" title="Accéder à l’article complet">Commodité et effondrement</a>,
  742. <a href="/david/blog/2017/donnees-communs/" title="Accéder à l’article complet">Des données aux communs</a>,
  743. <a href="/david/blog/2016/accompagner-enfant/" title="Accéder à l’article complet">Accompagner un enfant</a>,
  744. <a href="/david/blog/2016/senior-developer/" title="Accéder à l’article complet">Senior developer</a>,
  745. <a href="/david/blog/2016/illusion-sociale/" title="Accéder à l’article complet">L’illusion sociale</a>,
  746. <a href="/david/blog/2016/instantane-scopyleft/" title="Accéder à l’article complet">Instantané Scopyleft</a>,
  747. <a href="/david/blog/2016/enseigner-web/" title="Accéder à l’article complet">Enseigner le Web</a>,
  748. <a href="/david/blog/2016/simplicite-defaut/" title="Accéder à l’article complet">Simplicité par défaut</a>,
  749. <a href="/david/blog/2016/minimalisme-esthetique/" title="Accéder à l’article complet">Minimalisme et esthétique</a>,
  750. <a href="/david/blog/2014/un-web-omni-present/" title="Accéder à l’article complet">Un web omni-présent</a>,
  751. <a href="/david/blog/2014/manifeste-developpeur/" title="Accéder à l’article complet">Manifeste de développeur</a>,
  752. <a href="/david/blog/2013/confort-convivialite/" title="Accéder à l’article complet">Confort et convivialité</a>,
  753. <a href="/david/blog/2013/testament-numerique/" title="Accéder à l’article complet">Testament numérique</a>,
  754. et <a href="/david/blog/" title="Accéder aux archives">bien d’autres…</a>
  755. </p>
  756. <p>
  757. On peut <a href="mailto:david%40larlet.fr" title="Envoyer un courriel">échanger par courriel</a>. Si éventuellement tu souhaites que l’on travaille ensemble, tu devrais commencer par consulter le <a href="http://larlet.com">profil dédié à mon activité professionnelle</a> et/ou contacter directement <a href="http://scopyleft.fr/">scopyleft</a>, la <abbr title="Société coopérative et participative">SCOP</abbr> dont je fais partie depuis six ans. Je recommande au préalable de lire <a href="/david/blog/2018/cout-site/" title="Attention ce qui va suivre peut vous choquer">combien coûte un site</a> et pourquoi je suis plutôt favorable à une <a href="/david/pro/devis/" title="Discutons-en !">non-demande de devis</a>.
  758. </p>
  759. <p>
  760. Je ne traque pas ta navigation mais mon
  761. <abbr title="Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33.184162340">hébergeur</abbr>
  762. conserve des logs d’accès.
  763. </p>
  764. </div>
  765. </footer>
  766. <script type="text/javascript">
  767. ;(_ => {
  768. const jumper = document.getElementById('jumper')
  769. jumper.addEventListener('click', e => {
  770. e.preventDefault()
  771. const anchor = e.target.getAttribute('href')
  772. const targetEl = document.getElementById(anchor.substring(1))
  773. targetEl.scrollIntoView({behavior: 'smooth'})
  774. })
  775. })()
  776. </script>
  777. <script>
  778. /* Service workers */
  779. if (navigator.serviceWorker) {
  780. window.addEventListener('load', function () {
  781. var selector = 'a[href^="/david/cache/"], a[rel=prev], a[rel=next]'
  782. function sendLinks (selector) {
  783. var links = [].slice.call(document.querySelectorAll(selector)).map(function (link) {
  784. return link.getAttribute('href')
  785. })
  786. links.push(location.pathname) // Put the current page in cache too.
  787. navigator.serviceWorker.controller.postMessage({ links: links })
  788. }
  789. navigator.serviceWorker.getRegistration()
  790. .then(function (registration) {
  791. if (!registration || !navigator.serviceWorker.controller) {
  792. return navigator.serviceWorker.register('/serviceworker.js')
  793. .then(navigator.serviceWorker.ready)
  794. .then(function () {
  795. console.log('[ServiceWorker] Ready to go!')
  796. })
  797. .catch(console.error.bind(console))
  798. } else {
  799. console.log('[ServiceWorker] Send links via registration')
  800. sendLinks(selector)
  801. }
  802. })
  803. navigator.serviceWorker.addEventListener('controllerchange', function () {
  804. console.log('[ServiceWorker] Send links via controller change')
  805. sendLinks(selector)
  806. })
  807. navigator.serviceWorker.addEventListener('message', function (event) {
  808. var link = document.querySelector('a[href="' + event.data.link + '"]')
  809. if (event.data.status && link) {
  810. link.style.backgroundColor = '#2d7474'
  811. link.style.color = '#f0f0ea'
  812. link.setAttribute('title', 'En cache pour consultation sans connexion')
  813. }
  814. })
  815. })
  816. } else {
  817. console.warn('[ServiceWorker] No cache for old browsers.')
  818. }
  819. </script>