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 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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>Modern Health, frameworks, performance, and harm (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. <!-- Documented, feel free to shoot an email. -->
  28. <link rel="stylesheet" href="/static/david/css/style_2021-01-20.css">
  29. <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
  30. <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>
  31. <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>
  32. <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>
  33. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  34. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  35. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  36. <script>
  37. function toggleTheme(themeName) {
  38. document.documentElement.classList.toggle(
  39. 'forced-dark',
  40. themeName === 'dark'
  41. )
  42. document.documentElement.classList.toggle(
  43. 'forced-light',
  44. themeName === 'light'
  45. )
  46. }
  47. const selectedTheme = localStorage.getItem('theme')
  48. if (selectedTheme !== 'undefined') {
  49. toggleTheme(selectedTheme)
  50. }
  51. </script>
  52. <meta name="robots" content="noindex, nofollow">
  53. <meta content="origin-when-cross-origin" name="referrer">
  54. <!-- Canonical URL for SEO purposes -->
  55. <link rel="canonical" href="https://ericwbailey.website/published/modern-health-frameworks-performance-and-harm/">
  56. <body class="remarkdown h1-underline h2-underline h3-underline em-underscore hr-center ul-star pre-tick" data-instant-intensity="viewport-all">
  57. <article>
  58. <header>
  59. <h1>Modern Health, frameworks, performance, and harm</h1>
  60. </header>
  61. <nav>
  62. <p class="center">
  63. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  64. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  65. </svg> Accueil</a> •
  66. <a href="https://ericwbailey.website/published/modern-health-frameworks-performance-and-harm/" title="Lien vers le contenu original">Source originale</a>
  67. </p>
  68. </nav>
  69. <hr>
  70. <p>I would like to thank <a href="https://www.modernhealth.com/">Modern Health</a>. It was not their intent, but using their service broke me out of a deep depression by launching me into an incandescent rage.</p>
  71. <p>I’ve read enough on <a href="https://osmihelp.org/">destigmatizing mental health</a> that I feel no shame in discussing this. In fact, in this regard I feel twice fortunate. The first is to know enough about myself to know I need help and not feel bad about it, and the second is that I have an employer-offered benefit to take advantage of.</p>
  72. <p>You need to use every resource you can for things like this, and there is no shame in doing so. Mental health resources, like physical health resources, are in incredibly short supply right now.</p>
  73. <p>I signed up for Modern Health’s service earlier this week. After signing my rights away by clicking an impressive number of checkboxes, I was greeted with this experience:</p>
  74. <p><img alt="An almost entirely blank white screen. In the top lefthand corner is the Modern Health log, and navigation options for 'Explore', 'Circles', and 'FAQ'. On the top righthand corner is navigation options for 'Messages' and my profile. In the center of the screen is a small loading spinner. Screenshot." loading="lazy" src="https://ericwbailey.website/img/posts/modern-health-frameworks-performance-and-harm/modern-health-routing-failure.png"></p>
  75. <p>Since I make digital experiences for a living, I immediately knew what happened. The signup user flow failed to transition me over to the onboarding user flow.</p>
  76. <p>In addition to <a href="https://builtwith.com/advanced?back=joinmodernhealth.com">a terrifying amount of telemetry</a>, Modern Health’s customer-facing experience is delivered using React and Webpack.</p>
  77. <p>If you are familiar with how the web is built, what happened is pretty obvious: A website that over-relies on JavaScript to power its experience had its logic collide with one or more other errant pieces of logic that it summons. This created a deadlock.</p>
  78. <p>If you do not make digital experiences for a living, what happened is not obvious at all. All you see is a tiny fake loading spinner that never stops.</p>
  79. <p>Experiences on the web are so poor that many people have developed coping strategies for getting what they need. I <a href="https://filecamp.com/support/problem-solving/hard-refresh/">hard refreshed the tab</a> and was unceremoniously dumped into my homepage dashboard. Many others may know to do the same.</p>
  80. <p>However, many others is not everyone. I also need to point out that people are visiting sites like this because they are not in a good place. Depression and stress lowers your executive function. Furthermore, <a href="https://alistapart.com/article/paint-the-picture-not-the-frame/">people internalize technology’s failures as their own</a>.</p>
  81. <p>What if I was suicidal?</p>
  82. <p>I used an up-to-date operating system to access this website on a top of the line laptop, browsing with an <a href="https://css-tricks.com/evergreen-does-not-mean-immediately-available/">evergreen</a> Chromium browser with no setting adjustments or extensions to interfere with things. Can you imagine what chance for success <a href="https://css-tricks.com/test-your-product-on-a-crappy-laptop/">someone using something other than that</a> will have?</p>
  83. <p><a href="https://timkadlec.com/remembers/2019-01-09-the-ethics-of-performance/">Technology choices have ethical ramifications</a>.</p>
  84. <p>A person seeking help in a time of crisis does not care about TypeScript, tree shaking, hot module replacement, A/B tests, burndown charts, NPS, OKRs, KPIs, or other startup jargon. <a href="https://andy-bell.co.uk/speed-for-who/">Developer experience does not count for shit</a> if the person using the thing they built can’t actually get what they need.</p>
  85. <p>There is also the very real possibility that the developers responsible for making this experience do actually care. However, they may be structurally unable to deny stakeholders demanding an onslaught of non-features, in an attempt to parrot other startups in hopes of reproducing their perceived success.</p>
  86. <p>I felt compelled to write this because explaining the situation is a fractal of absurdity. I’d be laughing if I wasn’t so furious.</p>
  87. <p>I mean it. Take some time today to try and verbally explain the totality of what went wrong here to someone who doesn’t make digital experiences.</p>
  88. <p>Try to justify the architectural choices made compared to an intended audience. Then try to re-justify it through the lens of power dynamics and and a vulnerable population.</p>
  89. <p>An experience like Modern Health should be as lean and fault-tolerant as possible. It should not make 162 requests transferring ~15 MB just to hope it can show me two <a href="https://beaconagency.co.uk/post/does-big-tech-design-have-an-authenticity-problem">sanitized Corporate Memphis blob humans</a> promoting a gamified growth funnel.</p>
  90. <figure role="figure" aria-label="Screaming.">
  91. <img alt="A card component with a title that reads, 'Resilience, it's a family thing'. There is a subtitle that reads, 'Learn strategies to make resilience part of yoour family make up.', a call-to-action link that says, 'Take a pause.' and a smaller sub-call-to-action link that says, 'Start a new streak!' There is also a cartoon illustration of two happy, ethnically-ambiguous men, one an older man and one younger. The illustration style is simple, geometric shapes and soft pastel colors that neatly side-steps having to do actual representation." loading="lazy" src="https://ericwbailey.website/img/posts/modern-health-frameworks-performance-and-harm/resilience-its-a-family-thing.png">
  92. <figcaption>
  93. Screaming.
  94. </figcaption>
  95. </figure>
  96. <p>I don’t want the underlying concept behind Modern Health to fail. I want more people to get the help they need in a reliable and safe way. However, I wish we as an industry would stop <a href="https://joshcollinsworth.com/blog/self-fulfilling-prophecy-of-react">promoting and rewarding the wrong things</a>.</p>
  97. <p>We’ve lost the plot. Performance, accessibility, and usability are more than inconvenient truths you can pretend don’t exist. They have a direct impact on the quality of someone’s life.</p>
  98. </article>
  99. <hr>
  100. <footer>
  101. <p>
  102. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  103. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  104. </svg> Accueil</a> •
  105. <a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
  106. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-rss2"></use>
  107. </svg> Suivre</a> •
  108. <a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
  109. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-user-tie"></use>
  110. </svg> Pro</a> •
  111. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
  112. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-mail"></use>
  113. </svg> Email</a> •
  114. <abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
  115. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-hammer2"></use>
  116. </svg> Légal</abbr>
  117. </p>
  118. <template id="theme-selector">
  119. <form>
  120. <fieldset>
  121. <legend><svg class="icon icon-brightness-contrast">
  122. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-brightness-contrast"></use>
  123. </svg> Thème</legend>
  124. <label>
  125. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  126. </label>
  127. <label>
  128. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  129. </label>
  130. <label>
  131. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  132. </label>
  133. </fieldset>
  134. </form>
  135. </template>
  136. </footer>
  137. <script src="/static/david/js/instantpage-5.1.0.min.js" type="module"></script>
  138. <script>
  139. function loadThemeForm(templateName) {
  140. const themeSelectorTemplate = document.querySelector(templateName)
  141. const form = themeSelectorTemplate.content.firstElementChild
  142. themeSelectorTemplate.replaceWith(form)
  143. form.addEventListener('change', (e) => {
  144. const chosenColorScheme = e.target.value
  145. localStorage.setItem('theme', chosenColorScheme)
  146. toggleTheme(chosenColorScheme)
  147. })
  148. const selectedTheme = localStorage.getItem('theme')
  149. if (selectedTheme && selectedTheme !== 'undefined') {
  150. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  151. }
  152. }
  153. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  154. window.addEventListener('load', () => {
  155. let hasDarkRules = false
  156. for (const styleSheet of Array.from(document.styleSheets)) {
  157. let mediaRules = []
  158. for (const cssRule of styleSheet.cssRules) {
  159. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  160. continue
  161. }
  162. // WARNING: Safari does not have/supports `conditionText`.
  163. if (cssRule.conditionText) {
  164. if (cssRule.conditionText !== prefersColorSchemeDark) {
  165. continue
  166. }
  167. } else {
  168. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  169. continue
  170. }
  171. }
  172. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  173. }
  174. // WARNING: do not try to insert a Rule to a styleSheet you are
  175. // currently iterating on, otherwise the browser will be stuck
  176. // in a infinite loop…
  177. for (const mediaRule of mediaRules) {
  178. styleSheet.insertRule(mediaRule.cssText)
  179. hasDarkRules = true
  180. }
  181. }
  182. if (hasDarkRules) {
  183. loadThemeForm('#theme-selector')
  184. }
  185. })
  186. </script>
  187. </body>
  188. </html>