A place to cache linked articles (think custom and personal wayback machine)
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

pirms 4 gadiem
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  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>Latence et boucle de rétroaction (archive) — 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. <meta name="robots" content="noindex, nofollow">
  28. <meta content="origin-when-cross-origin" name="referrer">
  29. <!-- Canonical URL for SEO purposes -->
  30. <link rel="canonical" href="http://mathieu.agopian.info/blog/latence-et-boucle-de-retroaction.html">
  31. <style>
  32. /* http://meyerweb.com/eric/tools/css/reset/ */
  33. html, body, div, span,
  34. h1, h2, h3, h4, h5, h6, p, blockquote, pre,
  35. a, abbr, address, big, cite, code,
  36. del, dfn, em, img, ins,
  37. small, strike, strong, tt, var,
  38. dl, dt, dd, ol, ul, li,
  39. fieldset, form, label, legend,
  40. table, caption, tbody, tfoot, thead, tr, th, td,
  41. article, aside, canvas, details, embed,
  42. figure, figcaption, footer, header, hgroup,
  43. menu, nav, output, ruby, section, summary,
  44. time, mark, audio, video {
  45. margin: 0;
  46. padding: 0;
  47. border: 0;
  48. font-size: 100%;
  49. font: inherit;
  50. vertical-align: baseline;
  51. }
  52. /* HTML5 display-role reset for older browsers */
  53. article, aside, details, figcaption, figure,
  54. footer, header, hgroup, menu, nav, section { display: block; }
  55. body { line-height: 1; }
  56. blockquote, q { quotes: none; }
  57. blockquote:before, blockquote:after,
  58. q:before, q:after {
  59. content: '';
  60. content: none;
  61. }
  62. table {
  63. border-collapse: collapse;
  64. border-spacing: 0;
  65. }
  66. /* http://practicaltypography.com/equity.html */
  67. /* https://calendar.perfplanet.com/2016/no-font-face-bulletproof-syntax/ */
  68. /* https://www.filamentgroup.com/lab/js-web-fonts.html */
  69. @font-face {
  70. font-family: 'EquityTextB';
  71. src: url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff2') format('woff2'),
  72. url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff') format('woff');
  73. font-weight: 300;
  74. font-style: normal;
  75. font-display: swap;
  76. }
  77. @font-face {
  78. font-family: 'EquityTextB';
  79. src: url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff2') format('woff2'),
  80. url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff') format('woff');
  81. font-weight: 300;
  82. font-style: italic;
  83. font-display: swap;
  84. }
  85. @font-face {
  86. font-family: 'EquityTextB';
  87. src: url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff2') format('woff2'),
  88. url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff') format('woff');
  89. font-weight: 700;
  90. font-style: normal;
  91. font-display: swap;
  92. }
  93. @font-face {
  94. font-family: 'ConcourseT3';
  95. src: url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff2') format('woff2'),
  96. url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff') format('woff');
  97. font-weight: 300;
  98. font-style: normal;
  99. font-display: swap;
  100. }
  101. /* http://practice.typekit.com/lesson/caring-about-opentype-features/ */
  102. body {
  103. /* http://www.cssfontstack.com/ Palatino 99% Win 86% Mac */
  104. font-family: "EquityTextB", Palatino, serif;
  105. background-color: #f0f0ea;
  106. color: #07486c;
  107. font-kerning: normal;
  108. -moz-osx-font-smoothing: grayscale;
  109. -webkit-font-smoothing: subpixel-antialiased;
  110. text-rendering: optimizeLegibility;
  111. font-variant-ligatures: common-ligatures contextual;
  112. font-feature-settings: "kern", "liga", "clig", "calt";
  113. }
  114. pre, code, kbd, samp, var, tt {
  115. font-family: 'TriplicateT4c', monospace;
  116. }
  117. em {
  118. font-style: italic;
  119. color: #323a45;
  120. }
  121. strong {
  122. font-weight: bold;
  123. color: black;
  124. }
  125. nav {
  126. background-color: #323a45;
  127. color: #f0f0ea;
  128. display: flex;
  129. justify-content: space-around;
  130. padding: 1rem .5rem;
  131. }
  132. nav:last-child {
  133. border-bottom: 1vh solid #2d7474;
  134. }
  135. nav a {
  136. color: #f0f0ea;
  137. }
  138. nav abbr {
  139. border-bottom: 1px dotted white;
  140. }
  141. h1 {
  142. border-top: 1vh solid #2d7474;
  143. border-bottom: .2vh dotted #2d7474;
  144. background-color: #e3e1e1;
  145. color: #323a45;
  146. text-align: center;
  147. padding: 5rem 0 4rem 0;
  148. width: 100%;
  149. font-family: 'ConcourseT3';
  150. display: flex;
  151. flex-direction: column;
  152. }
  153. h1.single {
  154. padding-bottom: 10rem;
  155. }
  156. h1 span {
  157. position: absolute;
  158. top: 1vh;
  159. left: 20%;
  160. line-height: 0;
  161. }
  162. h1 span a {
  163. line-height: 1.7;
  164. padding: 1rem 1.2rem .6rem 1.2rem;
  165. border-radius: 0 0 6% 6%;
  166. background: #2d7474;
  167. font-size: 1.3rem;
  168. color: white;
  169. text-decoration: none;
  170. }
  171. h2 {
  172. margin: 4rem 0 1rem;
  173. border-top: .2vh solid #2d7474;
  174. padding-top: 1vh;
  175. }
  176. h3 {
  177. text-align: center;
  178. margin: 3rem 0 .75em;
  179. }
  180. hr {
  181. height: .4rem;
  182. width: .4rem;
  183. border-radius: .4rem;
  184. background: #07486c;
  185. margin: 2.5rem auto;
  186. }
  187. time {
  188. display: bloc;
  189. margin-left: 0 !important;
  190. }
  191. ul, ol {
  192. margin: 2rem;
  193. }
  194. ul {
  195. list-style-type: square;
  196. }
  197. a {
  198. text-decoration-skip-ink: auto;
  199. text-decoration-thickness: 0.05em;
  200. text-underline-offset: 0.09em;
  201. }
  202. article {
  203. max-width: 50rem;
  204. display: flex;
  205. flex-direction: column;
  206. margin: 2rem auto;
  207. }
  208. article.single {
  209. border-top: .2vh dotted #2d7474;
  210. margin: -6rem auto 1rem auto;
  211. background: #f0f0ea;
  212. padding: 2rem;
  213. }
  214. article p:last-child {
  215. margin-bottom: 1rem;
  216. }
  217. p {
  218. padding: 0 .5rem;
  219. margin-left: 3rem;
  220. }
  221. p + p,
  222. figure + p {
  223. margin-top: 2rem;
  224. }
  225. blockquote {
  226. background-color: #e3e1e1;
  227. border-left: .5vw solid #2d7474;
  228. display: flex;
  229. flex-direction: column;
  230. align-items: center;
  231. padding: 1rem;
  232. margin: 1.5rem;
  233. }
  234. blockquote cite {
  235. font-style: italic;
  236. }
  237. blockquote p {
  238. margin-left: 0;
  239. }
  240. figure {
  241. border-top: .2vh solid #2d7474;
  242. background-color: #e3e1e1;
  243. text-align: center;
  244. padding: 1.5rem 0;
  245. margin: 1rem 0 0;
  246. font-size: 1.5rem;
  247. width: 100%;
  248. }
  249. figure img {
  250. max-width: 250px;
  251. max-height: 250px;
  252. border: .5vw solid #323a45;
  253. padding: 1px;
  254. }
  255. figcaption {
  256. padding: 1rem;
  257. line-height: 1.4;
  258. }
  259. aside {
  260. display: flex;
  261. flex-direction: column;
  262. background-color: #e3e1e1;
  263. padding: 1rem 0;
  264. border-bottom: .2vh solid #07486c;
  265. }
  266. aside p {
  267. max-width: 50rem;
  268. margin: 0 auto;
  269. }
  270. /* https://fvsch.com/code/css-locks/ */
  271. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  272. font-size: 1rem;
  273. line-height: calc( 1.5em + 0.2 * 1rem );
  274. }
  275. h1 {
  276. font-size: 1.9rem;
  277. line-height: calc( 1.2em + 0.2 * 1rem );
  278. }
  279. h2 {
  280. font-size: 1.6rem;
  281. line-height: calc( 1.3em + 0.2 * 1rem );
  282. }
  283. h3 {
  284. font-size: 1.35rem;
  285. line-height: calc( 1.4em + 0.2 * 1rem );
  286. }
  287. @media (min-width: 20em) {
  288. /* The (100vw - 20rem) / (50 - 20) part
  289. resolves to 0-1rem, depending on the
  290. viewport width (between 20em and 50em). */
  291. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  292. font-size: calc( 1rem + .6 * (100vw - 20rem) / (50 - 20) );
  293. line-height: calc( 1.5em + 0.2 * (100vw - 50rem) / (20 - 50) );
  294. margin-left: 0;
  295. }
  296. h1 {
  297. font-size: calc( 1.9rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  298. line-height: calc( 1.2em + 0.2 * (100vw - 50rem) / (20 - 50) );
  299. }
  300. h2 {
  301. font-size: calc( 1.5rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  302. line-height: calc( 1.3em + 0.2 * (100vw - 50rem) / (20 - 50) );
  303. }
  304. h3 {
  305. font-size: calc( 1.35rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  306. line-height: calc( 1.4em + 0.2 * (100vw - 50rem) / (20 - 50) );
  307. }
  308. }
  309. @media (min-width: 50em) {
  310. /* The right part of the addition *must* be a
  311. rem value. In this example we *could* change
  312. the whole declaration to font-size:2.5rem,
  313. but if our baseline value was not expressed
  314. in rem we would have to use calc. */
  315. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  316. font-size: calc( 1rem + .6 * 1rem );
  317. line-height: 1.5em;
  318. }
  319. p, li, pre, details {
  320. margin-left: 3rem;
  321. }
  322. h1 {
  323. font-size: calc( 1.9rem + 1.5 * 1rem );
  324. line-height: 1.2em;
  325. }
  326. h2 {
  327. font-size: calc( 1.5rem + 1.5 * 1rem );
  328. line-height: 1.3em;
  329. }
  330. h3 {
  331. font-size: calc( 1.35rem + 1.5 * 1rem );
  332. line-height: 1.4em;
  333. }
  334. figure img {
  335. max-width: 500px;
  336. max-height: 500px;
  337. }
  338. }
  339. figure.unsquared {
  340. margin-bottom: 1.5rem;
  341. }
  342. figure.unsquared img {
  343. height: inherit;
  344. }
  345. @media print {
  346. body { font-size: 100%; }
  347. a:after { content: " (" attr(href) ")"; }
  348. a, a:link, a:visited, a:after {
  349. text-decoration: underline;
  350. text-shadow: none !important;
  351. background-image: none !important;
  352. background: white;
  353. color: black;
  354. }
  355. abbr[title] { border-bottom: 0; }
  356. abbr[title]:after { content: " (" attr(title) ")"; }
  357. img { page-break-inside: avoid; }
  358. @page { margin: 2cm .5cm; }
  359. h1, h2, h3 { page-break-after: avoid; }
  360. p3 { orphans: 3; widows: 3; }
  361. img {
  362. max-width: 250px !important;
  363. max-height: 250px !important;
  364. }
  365. nav, aside { display: none; }
  366. }
  367. ul.with_columns {
  368. column-count: 1;
  369. }
  370. @media (min-width: 20em) {
  371. ul.with_columns {
  372. column-count: 2;
  373. }
  374. }
  375. @media (min-width: 50em) {
  376. ul.with_columns {
  377. column-count: 3;
  378. }
  379. }
  380. ul.with_two_columns {
  381. column-count: 1;
  382. }
  383. @media (min-width: 20em) {
  384. ul.with_two_columns {
  385. column-count: 1;
  386. }
  387. }
  388. @media (min-width: 50em) {
  389. ul.with_two_columns {
  390. column-count: 2;
  391. }
  392. }
  393. .gallery {
  394. display: flex;
  395. flex-wrap: wrap;
  396. justify-content: space-around;
  397. }
  398. .gallery figure img {
  399. margin-left: 1rem;
  400. margin-right: 1rem;
  401. }
  402. .gallery figure figcaption {
  403. font-family: 'ConcourseT3'
  404. }
  405. footer {
  406. font-family: 'ConcourseT3';
  407. display: flex;
  408. flex-direction: column;
  409. border-top: 3px solid white;
  410. padding: 4rem 0;
  411. background-color: #07486c;
  412. color: white;
  413. }
  414. footer > * {
  415. max-width: 50rem;
  416. margin: 0 auto;
  417. }
  418. footer a {
  419. color: #f1c40f;
  420. }
  421. footer .avatar {
  422. width: 200px;
  423. height: 200px;
  424. border-radius: 50%;
  425. float: left;
  426. -webkit-shape-outside: circle();
  427. shape-outside: circle();
  428. margin-right: 2rem;
  429. padding: 2px 5px 5px 2px;
  430. background: white;
  431. border-left: 1px solid #f1c40f;
  432. border-top: 1px solid #f1c40f;
  433. border-right: 5px solid #f1c40f;
  434. border-bottom: 5px solid #f1c40f;
  435. }
  436. </style>
  437. <h1>
  438. <span><a id="jumper" href="#jumpto" title="Un peu perdu ?">?</a></span>
  439. Latence et boucle de rétroaction (archive)
  440. <time>Pour la pérennité des contenus liés. Non-indexé, retrait sur simple email.</time>
  441. </h1>
  442. <section>
  443. <article>
  444. <h3><a href="http://mathieu.agopian.info/blog/latence-et-boucle-de-retroaction.html">Source originale du contenu</a></h3>
  445. <h2>Latence</h2>
  446. <p>La <a class="reference external" href="http://fr.wikipedia.org/wiki/Latence_%28informatique%29">latence</a> en informatique est un délai minimum de transmission. C'est un des
  447. principaux ennemis de la performance notamment dans le domaine du web.</p>
  448. <p>Un site web est généralement composé de multiples fichiers statiques (css,
  449. javascript, images et icônes en tout genre). Pour afficher la totalité d'une
  450. page, il faut donc faire de multiples requêtes au serveur, chacune prenant un
  451. certain temps de traitement, à quoi on rajoute la latence (le temps de
  452. transfert sur le réseau).</p>
  453. <p>On imagine facilement l'impact d'une forte latence lorsqu'il faut effectuer
  454. plusieurs dizaines voire centaines de requêtes. Même si la latence n'est que de
  455. 10ms, si on multiple ça par 100, on atteint déjà une seconde.</p>
  456. <p>Prenons un autre exemple&nbsp;: il n'est pas rare d'avoir des pages nécessitant des
  457. dizaines (des centaines, voire des milliers&nbsp;?) de requêtes SQL à une base de
  458. données. Là encore, il faut multiplier ce nombre de requête par le temps de
  459. traitement par la base de données, mais aussi par la latence.</p>
  460. <p>Étant donné la difficulté de réduire la latence, l'optimisation de la
  461. performance passe par le réduction du nombre de requêtes&nbsp;: on fait des
  462. <em>bundles</em> pour les fichiers statiques (on regroupe toutes les CSS ou les
  463. fichiers javascript, on crée des <em>image map</em> pour les icônes), on fait usage du
  464. <em>JOIN</em> pour les requêtes SQL...</p>
  465. <p></div>
  466. <div class="section" id="boucle-de-retroaction">
  467. <h2>Boucle de rétroaction</h2>
  468. <p>La <a class="reference external" href="http://fr.wikipedia.org/wiki/Boucle_de_r%C3%A9troaction">boucle de rétroaction</a> (appelée «&nbsp;feedback loop&nbsp;» en anglais) permet de
  469. raffiner un système afin d'arriver à un équilibre, à un objectif.</p>
  470. <p>Une boucle de rétroaction basée sur des mesures de position permettra à robot
  471. d'atteindre la position souhaitée&nbsp;: la vitesse et la direction seront adaptées
  472. en fonction de la distance à l'objectif.</p>
  473. <p>Plus la boucle de rétroaction sera longue, plus l'équilibre sera long a
  474. atteindre. En effet, si la mesure de position ne se fait qu'une fois toutes les
  475. 10 secondes, soit le robot devra se déplacer très lentement, soit faire de
  476. nombreux aller-retours.</p>
  477. </div>
  478. <div class="section" id="le-rapport">
  479. <h2>Le rapport&nbsp;?</h2>
  480. <p>En tant qu'informaticien, il nous arrive régulièrement d'avoir à raffiner un
  481. bout de code en fonction de différents paramètres&nbsp;: l'expression du besoin, la
  482. rapidité d'exécution, l'occupation mémoire...</p>
  483. <p>Et ce raffinage se fait par le biais d'une boucle de rétroaction qui peut
  484. prendre différentes formes&nbsp;:</p>
  485. <ul class="simple">
  486. <li>des tests automatisés (test unitaires ou fonctionnels, TDD...)</li>
  487. <li>des tests manuels</li>
  488. <li>des simulations</li>
  489. <li>des aller-retours avec l'utilisateur final, le décideur, ...</li>
  490. </ul>
  491. <p>Si la latence s'invite dans ce mécanisme, on se retrouve dans la même situation
  492. que le robot qui doit atteindre une position, mais qui n'a de retour sur sa
  493. position que rarement. Soit on avance vite et on risque les aller-retours
  494. (comprendre&nbsp;: réécriture du code), soit on avance lentement.</p>
  495. <p>Dans tous les cas, c'est un cauchemar.</p>
  496. <p>Voici quelques exemples de latence&nbsp;:</p>
  497. <ul class="simple">
  498. <li>besoin mal exprimé ou mal compris (la mesure de position n'est pas fiable)</li>
  499. <li>périmètre fonctionnel qui change (la position finale du robot change en cours
  500. de route)</li>
  501. <li>grand nombre d'aller-retours avec l'utilisateur final/décideur (nécessité de
  502. faire un très grand nombre de mesures de position)</li>
  503. <li>retours de l'utilisateur final/décideur très lents (mesure de position très
  504. rare)</li>
  505. <li>dialogue avec une API/base de données/système distant/... très lent (chaque
  506. mesure de position demande de très longs traitements)</li>
  507. <li>peu de confiance dans les résultats (nécessité de refaire plusieurs fois les
  508. mesures ou de les retraiter)</li>
  509. </ul>
  510. </div>
  511. <div class="section" id="un-exemple-concret">
  512. <h2>Un exemple concret</h2>
  513. <p>Avec mon collègue <a class="reference external" href="https://larlet.fr/david/">David</a> nous nous sommes chargés de la résolution d'un ticket
  514. pour le projet <a class="reference external" href="https://addons.mozilla.org">AMO</a>.</p>
  515. <p>Afin de pouvoir présenter des graphiques d'utilisation/téléchargement des
  516. extensions à leur auteur (comme pour <a class="reference external" href="https://addons.mozilla.org/en-US/firefox/addon/firebug/statistics/?last=30">Firebug</a>), toutes les requêtes de
  517. téléchargement et de demande de mise à jour sont enregistrées et stockées dans
  518. une base de données «&nbsp;big data&nbsp;» (pour les curieux&nbsp;: c'est stocké dans <a class="reference external" href="http://hadoop.apache.org/">Hadoop</a>
  519. et récupéré par le biais de <a class="reference external" href="https://hive.apache.org/">Hive</a>). On parle de plus d'un milliard de requête
  520. par jour, toutes requêtes confondues.</p>
  521. <p>Ce qui nous a d'abord paru simple et rapide à implémenter, s'est transformé en
  522. deux semaines de sprint (et n'est pas encore terminé).</p>
  523. <p>Nous avons subit et fait partie des différentes formes de latences listées
  524. ci-dessus&nbsp;:</p>
  525. <ul class="simple">
  526. <li>besoin mal exprimé ou mal compris&nbsp;: la répartition des tâches entre nous et
  527. notre interlocuteur a changé plusieurs fois. Par ailleurs nous n'avions
  528. aucune connaissance du système avant de nous y attaquer.</li>
  529. <li>périmètre fonctionnel qui change&nbsp;: malheureusement, arrivé au bout de la
  530. première semaine de sprint, nous avons appris qu'il nous fallait refaire la
  531. moitié de notre travail différemment suite à des contraintes non prévues.</li>
  532. <li>grand nombre d'aller-retours avec l'utilisateur final/décideur&nbsp;: à l'heure de
  533. l'écriture de ce billet, nous en sommes à 54 commentaires sur le ticket.</li>
  534. <li>retours de l'utilisateur final/décideur très lent&nbsp;: nous travaillons en
  535. France, et notre interlocuteur sur la côte ouest des USA (-9h). Il est
  536. fréquent d'avoir besoin d'attendre le lendemain pour avoir une réponse, dans
  537. un sens ou dans l'autre.</li>
  538. <li>dialogue avec un système distant très lent&nbsp;: de par le nombre de données à
  539. traiter, chaque requête à Hive (au nombre de 6) prend en moyenne 15 minutes,
  540. et la taille des données à télécharger varie entre 500Mo et 1.6Go.</li>
  541. <li>peu de confiance dans les résultats&nbsp;: nous essayions de mettre au point les
  542. requêtes Hive à exécuter, et par le même temps, le post-traitement de ces
  543. requêtes, pour coller au plus proche aux statistiques et graphiques attendus.
  544. Jouer sur deux paramètres en même temps est déjà malaisé en temps normal,
  545. mais là il nous était de plus très laborieux de confronter nos résultats avec
  546. ceux de la production.</li>
  547. </ul>
  548. </div>
  549. <div class="section" id="la-solution">
  550. <h2>La solution</h2>
  551. <p>Diminuer la latence dans la boucle de rétroaction, par tous les moyens
  552. possibles.</p>
  553. <p>De la même manière qu'il arrive régulièrement de lancer un interpréteur Python
  554. (ou un <em>ipdb</em> ;) pour bidouiller et expérimenter avec un petit bout de code
  555. et avoir des retours immédiats, il faut tout faire pour accélérer la boucle de
  556. rétroaction.</p>
  557. <ul class="simple">
  558. <li>ça paraît évident, mais connaître précisément le besoin et le contexte avant
  559. de se lancer est primordial. Nous avons facilement perdu deux à trois jours à
  560. cause de ça, en début de sprint, avec notre envie d'avancer rapidement (et de
  561. passer à quelque chose de plus fun ;)</li>
  562. <li>périmètre fonctionnel qui change&nbsp;: difficile de le prévoir ou de l'éviter,
  563. mais je pense qu'en ayant une boucle de rétroaction plus courte, nous aurions
  564. eu des résultats plus rapidement, et aurions alors plus rapidement rencontré
  565. les contraintes qui ont fait changer le périmètre.</li>
  566. <li>le nombre d'aller-retours avec l'interlocuteur, et leur lenteur&nbsp;: quand nous
  567. avons pu mettre en place un appel vidéo journalier, beaucoup de choses se
  568. sont débloquées.</li>
  569. <li>dialogue avec le système distant très lent&nbsp;: nous aurions dû <a class="reference external" href="http://www.voidspace.org.uk/python/mock/">mock</a> beaucoup
  570. plus tôt le retour des requêtes Hive. Nous aurions ensuite dû récupérer un
  571. jeu de donnée complet (plusieurs Go) le plus tôt possible pour faire des
  572. tests sur le post-traitement dans un premier temps, puis ensuite seulement
  573. essayer d'améliorer les requêtes Hive. Faire les deux en même temps est une
  574. erreur qui nous a coûté de nombreux appels à Hive (et donc de nombreuses
  575. attentes et rétro-pédalages).</li>
  576. <li>peu de confiance dans les résultats&nbsp;: encore une fois vu la taille des
  577. données à traiter, il nous était très difficile de confronter nos données à
  578. celles attendues (uniquement disponibles en production). Nous avons fini par
  579. mettre en production un post-traitement parallèle à l'actuel, et stocker les
  580. données dans d'autres tables, en attendant d'avoir la version finale et
  581. raffinée de l'algorithme et des requêtes.</li>
  582. </ul>
  583. <p>Et à ma plus grande honte, ne pas avoir de tests unitaires a été un boulet
  584. supplémentaire&nbsp;: lancer un post-traitement pour s'apercevoir 15 minutes plus
  585. tard qu'on a oublié une virgule dans le code...</p>
  586. </div></p>
  587. </article>
  588. </section>
  589. <nav id="jumpto">
  590. <p>
  591. <a href="/david/blog/">Accueil du blog</a> |
  592. <a href="http://mathieu.agopian.info/blog/latence-et-boucle-de-retroaction.html">Source originale</a> |
  593. <a href="/david/stream/2019/">Accueil du flux</a>
  594. </p>
  595. </nav>
  596. <footer>
  597. <div>
  598. <img src="/static/david/david-larlet-avatar.jpg" loading="lazy" class="avatar" width="200" height="200">
  599. <p>
  600. Bonjour/Hi!
  601. 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>
  602. 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>).
  603. </p>
  604. <p>
  605. 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>.
  606. </p>
  607. <p>
  608. Voici quelques articles choisis :
  609. <a href="/david/blog/2019/faire-equipe/" title="Accéder à l’article complet">Faire équipe</a>,
  610. <a href="/david/blog/2018/bivouac-automnal/" title="Accéder à l’article complet">Bivouac automnal</a>,
  611. <a href="/david/blog/2018/commodite-effondrement/" title="Accéder à l’article complet">Commodité et effondrement</a>,
  612. <a href="/david/blog/2017/donnees-communs/" title="Accéder à l’article complet">Des données aux communs</a>,
  613. <a href="/david/blog/2016/accompagner-enfant/" title="Accéder à l’article complet">Accompagner un enfant</a>,
  614. <a href="/david/blog/2016/senior-developer/" title="Accéder à l’article complet">Senior developer</a>,
  615. <a href="/david/blog/2016/illusion-sociale/" title="Accéder à l’article complet">L’illusion sociale</a>,
  616. <a href="/david/blog/2016/instantane-scopyleft/" title="Accéder à l’article complet">Instantané Scopyleft</a>,
  617. <a href="/david/blog/2016/enseigner-web/" title="Accéder à l’article complet">Enseigner le Web</a>,
  618. <a href="/david/blog/2016/simplicite-defaut/" title="Accéder à l’article complet">Simplicité par défaut</a>,
  619. <a href="/david/blog/2016/minimalisme-esthetique/" title="Accéder à l’article complet">Minimalisme et esthétique</a>,
  620. <a href="/david/blog/2014/un-web-omni-present/" title="Accéder à l’article complet">Un web omni-présent</a>,
  621. <a href="/david/blog/2014/manifeste-developpeur/" title="Accéder à l’article complet">Manifeste de développeur</a>,
  622. <a href="/david/blog/2013/confort-convivialite/" title="Accéder à l’article complet">Confort et convivialité</a>,
  623. <a href="/david/blog/2013/testament-numerique/" title="Accéder à l’article complet">Testament numérique</a>,
  624. et <a href="/david/blog/" title="Accéder aux archives">bien d’autres…</a>
  625. </p>
  626. <p>
  627. 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>.
  628. </p>
  629. <p>
  630. Je ne traque pas ta navigation mais mon
  631. <abbr title="Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33.184162340">hébergeur</abbr>
  632. conserve des logs d’accès.
  633. </p>
  634. </div>
  635. </footer>
  636. <script type="text/javascript">
  637. ;(_ => {
  638. const jumper = document.getElementById('jumper')
  639. jumper.addEventListener('click', e => {
  640. e.preventDefault()
  641. const anchor = e.target.getAttribute('href')
  642. const targetEl = document.getElementById(anchor.substring(1))
  643. targetEl.scrollIntoView({behavior: 'smooth'})
  644. })
  645. })()
  646. </script>