A place to cache linked articles (think custom and personal wayback machine)
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

index.html 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  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>Technical Solutions Poorly Solve Social Problems (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://christine.website/blog/social-quandry-devops-2022-03-17">
  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>Technical Solutions Poorly Solve Social Problems</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://christine.website/blog/social-quandry-devops-2022-03-17" title="Lien vers le contenu original">Source originale</a>
  67. </p>
  68. </nav>
  69. <hr>
  70. <p class="conversation-chat">&lt;<b>Cadey</b>&gt; I just wanna lead this article out by saying that <em>I do not have all the
  71. answers here</em>. I really wish I did, but I also feel that I shouldn't have to
  72. have an answer in mind in order to raise a question. Please also keep in mind
  73. that this is coming from someone who has been working in devops for most of
  74. their career.</p>
  75. </div>
  76. <h2>Or: The Social Quandry of Devops</h2>
  77. <p>Technology is the cornerstone of our society. As a people we have seen the
  78. catalytic things that technology has enabled us to do. Through technology and
  79. new and innovative ways of applying it, we can help solve many problems. This
  80. leads some to envision technology as a panacea, a mythical cure-all that will
  81. make all our problems go away with the right use of it.</p>
  82. <p>This does not extend to social problems. Technical fixes for social problems are
  83. how we end up with an inadequate mess that can make the problem a lot worse than
  84. it was before. You've almost certainly been able to see this in action with
  85. social media (under the belief that allowing people to connect is so morally
  86. correct that it will bring in a new age of humanity that will be objectively
  87. good for everyone). The example I want to focus on today is the Devops
  88. philosophy. Devops is a technical solution (creating a new department) that
  89. helps work around social problems in workplaces (fundamental differences in
  90. priorities and end goals), and in the process it doesn't solve either very well.</p>
  91. <p>There are a lot of skillset paths that you can end up with in tech, but the two
  92. biggest ones are development (making the computer do new things) and systems
  93. administration (making computers keep doing those things). There are many other
  94. silos in the industry (technical writing, project/product management, etc.), but
  95. the two main ones are development and systems administration. These two groups
  96. have vastly different priorities, skillsets, needs and future goals, and as a
  97. result of this there is very little natural cross-pollenation between the two
  98. silos. I have seen this evolve into cultural resentment.</p>
  99. <div class="conversation">
  100. <p class="conversation-chat">&lt;<b>Cadey</b>&gt; Not to say that this phenomenon is exclusive to inter-department ties, I've
  101. also seen it happen intra-department over choice of programming language.</p>
  102. </div>
  103. <p>As far as the main differences go, development usually sees what could be. What
  104. new things could exist and what steps you need to take to get people there. This
  105. usually involves designing and implementing new software. The systems
  106. administration side of things is more likely to see it as a matter of
  107. integrating things into an existing whole, and then ensuring that whole is
  108. reliable and proven so they don't have to worry about it constantly. This causes
  109. a slower velocity forward and can result in extra process, slow momentum and
  110. stagnation. These two forces naturally come into conflict because they are
  111. vastly different things and have vastly different requirements and expectations.</p>
  112. <p>Development may want to use a new version of the compiler to support a language
  113. feature that will eliminate a lot of repetitive boilerplate. The sysadmins may
  114. not be able to ship that compiler in production build toolstack because of
  115. conflicting dependencies elsewhere, but they may also not want to ship that
  116. compiler because of fears over trusting unproven software in production.</p>
  117. <div class="conversation">
  118. <p class="conversation-chat">&lt;<b>Cadey</b>&gt; This fear sounds really odd at first glance, but this is a paraphrased version
  119. of a problem I actually encountered in the real world at one of my first big
  120. tech jobs. This place had some unique tech choices such as making their own fork
  121. of Ubuntu for "stability reasons", and the process to upgrade tools was a huge
  122. pain on the sysadmin side because it meant retesting and deploying a lot of
  123. internal tooling, which took a lot longer than the engineering team had patience
  124. for. This may not be the best example from a technical standpoint, but things
  125. don't have to make sense for them to exist.</p>
  126. </div>
  127. <p>This tension builds over a long period of time and can cause problems when the
  128. sysadmin team is chronically underfunded (due to the idea that they are
  129. successful when nothing goes wrong, also incurring the problem of success being
  130. a negative, which can make the sysadmin team look like a money pit when they are
  131. actually the very thing that is making the money generator generate money). This
  132. can also lead to avoidable burnout, unwarranted anxiety issues and unneeded
  133. suffering on both ends of the conflict.</p>
  134. <p>So given the unstoppable force of development and the immovable wall of
  135. sysadmin, an organizational compromise was made. This started out as many things
  136. with many names, but as the idea rippled throughout people's heads the name
  137. "devops" ended up sticking. Devops is a hybrid of traditional software
  138. development and systems administration. On paper this should be great. The silos
  139. will shrink. People will understand the limits and needs of the others. Managers
  140. will be able to have more flexible employees.</p>
  141. <p>Unfortunately though, a lot of the ideas behind devops and the overall
  142. philosophy really do require you to radically burn down everything and start
  143. from scratch. This tends to really not be conducive to engineering timetables
  144. and overall system stability during the age of turbulence.</p>
  145. <div class="conversation">
  146. <p class="conversation-chat">&lt;<b>Numa</b>&gt; What's the problem with burning everything down? Fire cleanses all things and
  147. purifies away the unworthy!</p>
  148. </div>
  149. <div class="conversation">
  150. <p class="conversation-chat">&lt;<b>Cadey</b>&gt; Not when you're the one being burned!</p>
  151. </div>
  152. <div class="conversation">
  153. <p class="conversation-chat">&lt;<b>Mara</b>&gt; Wait, so what actually happens then? Does it just end up being a sysadmin team
  154. made up out of coders?</p>
  155. </div>
  156. <p>Yeah, in practice this ends up being a "new team" or a reboot of an existing
  157. team in ways that is suddenly compelling or sexy to executives because a new
  158. buzzword is on the scene. Realistically, devops did end up getting a proper
  159. definition at a buzzword conference level (being able to handle development and
  160. deployment of services from editor to production), but in practice this ends up
  161. being just some random developers that you tricked into caring about production
  162. now while also telling them that they're better than the sysadmins.</p>
  163. <div class="conversation">
  164. <p class="conversation-chat">&lt;<b>Numa</b>&gt; Two jobs for the price of one!</p>
  165. </div>
  166. <p>This ends up shafting the sysadmin team even harder because the new fancy devops
  167. team has things they can talk about as positives for their quarters, so people
  168. can more easily make a case for promotion. As a sysadmin, your "success" case is
  169. "bad things didn't happen", which means success can't stand out on reviews.
  170. Consider "scaled production above the rate of our customer acquistion rate"
  171. against "set up continuous delivery to ensure velocity on our team, saving 50
  172. hours of effort per week". Which one of those do you think gets you promoted?
  173. Which one of those do you think gets headcount for new hires?</p>
  174. <p>This has human costs too. At one of my past jobs doing more sysadmin-y things
  175. (it was marketed as a devops hybrid role, but the "hybrid" part was more of
  176. "frantically patch up the sinking ship with code" and not traditional software
  177. development). Sleep is really essential to helping you function properly to do
  178. your job. During the times when I was pager bitch, there was at least a 1/8
  179. chance that I would be woken up in the middle of the night to handle a problem.
  180. I had to change my pager tone 15 times and still get goosebumps hearing those
  181. old sounds nearly a decade later. This ended up being a huge factor in my
  182. developing anxiety issues that I still feel today. I ended up getting addicted
  183. to weed really bad for a few years. I admit that I'm really not the most robust
  184. person in the world, but these things add up.</p>
  185. <div class="conversation">
  186. <p class="conversation-chat">&lt;<b>Cadey</b>&gt; I guess "addicted to weed" isn't totally accurate or inaccurate here, it's more
  187. that I was addicted to the feeling of being high rather than dependence on the
  188. drug itself. Either way, it was bad and weed was my cope. It also probably
  189. really didn't help that I was also starting hormone replacement therapy at the
  190. time, so I was going through second puberty at the time as well. This is the
  191. kind of human capital cost when dealing with dysfunction like this. I've always
  192. been kind of afraid to speak up about this.</p>
  193. </div>
  194. <p>However, there are real technical problems that can only really be solved from a
  195. devops perspective. Tools like Docker would probably never have happened in the
  196. way they did if the devops philosophy didn't exist.</p>
  197. <p><img src="https://cdn.christine.website/file/christine-static/blog/1BDBBB94-7052-4E4C-AE32-CFEE4226CBA8.jpeg" alt="A three panel meme with an old man talking to a child. The child says &quot;it works on my machine&quot;. The old man replies with &quot;then we'll ship your machine&quot;. The last panel says &quot;and that is how docker was born&quot;."></p>
  198. <p>In a way, Docker is one of the perfect examples of the devops philosophy. It
  199. allows developers to have their own custom versions of everything. They can use
  200. custom compilers that the sysadmins don't have to integrate into everything.
  201. They can experiment with new toolstacks, languages and build systems without
  202. worrying about how they integrate into existing processes. And in the process it
  203. defaults to things that are so hilariously unsafe that you only really realize
  204. the problems when they own you. It makes it easy to ship around configurations
  205. for services yes, but it doesn't make supply chain management easy at all.</p>
  206. <div class="conversation">
  207. <p class="conversation-chat">&lt;<b>Mara</b>&gt; Wait, what about that? How does that make any sense?</p>
  208. </div>
  209. <p>Okay, let's consider this basic Dockerfile that builds a Go service. If you
  210. start from very little knowledge of what's going on, you'd probably end up with
  211. something like this:</p>
  212. <pre><code class="language-Dockerfile">
  213. <span>FROM golang:1.17
  214. </span><span>
  215. </span><span>WORKDIR /usr/src/app
  216. </span><span>
  217. </span><span>COPY go.mod go.sum ./
  218. </span><span>RUN go mod download &amp;&amp; go mod verify
  219. </span><span>
  220. </span><span>COPY . .
  221. </span><span>RUN go build -v -o /usr/local/bin/app ./...
  222. </span><span>
  223. </span><span>CMD ["app"]
  224. </span>
  225. </code></pre>
  226. <p>This allows you to pin the versions of things like the Go compiler without
  227. bothering the sysadmin team to make it available, but in the process you also
  228. don't know what version of the compiler you are actually running. Let's say that
  229. you have all your Docker images built with CI and that CI has an image cache set
  230. up (as is the default in many CI systems). On your laptop you may end up getting
  231. the latest release of Go 1.17 (at the time of writing, this is version 1.17.8),
  232. but since CI may have seen this before and may have an old version of the <code>1.17</code>
  233. tag cached. This would mean that despite your efforts at making things easy to
  234. recreate, you've just accidentally put <a href="https://github.com/golang/go/issues/50165">an ASN.1 parsing
  235. DoS</a> into production, even though
  236. your local machine will never have this issue! Not to mention if the image
  237. you're using has a glibc bug, a DNS parsing bug or any issue with one of the
  238. packages that makes up the image.</p>
  239. <div class="conversation">
  240. <p class="conversation-chat">&lt;<b>Mara</b>&gt; So as a side effect of burning down everything and starting over you don't
  241. actually get a lot of the advantages that the old system had in spite of the
  242. dysfunction?</p>
  243. </div>
  244. <div class="conversation">
  245. <p class="conversation-chat">&lt;<b>Cadey</b>&gt; Yep! Realistically though you can get around this by using exact sha256 hashes
  246. of the precise Docker image you want, however this isn't the <em>default</em> behavior
  247. so nobody will really know about it. There are ways to work around this with
  248. tools like Nix, but that is a topic for another day.</p>
  249. </div>
  250. <p>This is what the devops experience feels like, chaining together tools that
  251. require careful handling to avoid accidental security flaws in ways that the
  252. traditional sysadmin team approach fundamentally avoided by design. By
  253. sidestepping the sysadmin team's stability and process, you learn nothing from
  254. what they were doing.</p>
  255. <div class="conversation">
  256. <p class="conversation-chat">&lt;<b>Cadey</b>&gt; This is all of course assuming that at the same time as you go devops, you also
  257. avow the grandeur of the cloud. Statistics say that these two usually go hand in
  258. hand as the cloud is sold to executives as good for
  259. devops.</p>
  260. </div>
  261. <p>As for how to get out of this mess though, I'm not sure. Like I said, this is a
  262. <em>social</em> problem that is trying to be solved through a <em>business organizational</em>
  263. fix. I am a technical solutions kind of person and as such I'm really not the
  264. right person to ask about all this. I don't want to propose a solution here.
  265. I've thought out several ideas, but I got nowhere with them fast.</p>
  266. <p>I remember at one of my jobs where I was a devops I ended up also having to be
  267. the tutor on how fundamental parts of the programming language they are using
  268. work. This one service that was handling a lot of production load had issues
  269. where it would just panic and die randomly when a very large customer was trying
  270. to view a list of things that was two orders of magnitude larger than other
  271. customers that use that service. I eventually ended up figuring out where the
  272. issue was but then I had an even harder time explaining what concurrency does at
  273. a fundamental level and how race conditions can make things crash due to
  274. undefined behavior. I think it ended up being a 3 line fix too.</p>
  275. <p>I guess the thing that would really help with this is education and helping
  276. people hone their skills as developers. I understand that there's a learning
  277. curve and not everyone is going to become a programming god overnight, but every
  278. little bit sets off butterfly effects that will ripple down in other ways. Any
  279. solution that requires everyone be a programming god isn't viable for anyone,
  280. including programming gods.</p>
  281. <div class="conversation">
  282. <p class="conversation-chat">&lt;<b>Numa</b>&gt; This whole mentorship thing only really works when the company you work for
  283. doesn't de-facto punish you for mentoring people like that. If you aren't
  284. careful about how you frame this, doing that could make it difficult for you to
  285. prove yourself come review time. "Helped other people do their jobs better"
  286. doesn't really look good for a promotion committee.</p>
  287. </div>
  288. <div class="conversation">
  289. <p class="conversation-chat">&lt;<b>Mara</b>&gt; Yeah but what are you supposed to do if that kind of mentorship is what really
  290. helps motivate you as a person and is what you really enjoy doing? I don't
  291. really see "mentor" as a job title on any postings.</p>
  292. </div>
  293. <div class="conversation">
  294. <p class="conversation-chat">&lt;<b>Numa</b>&gt; There's always getting tired of trying to change things from within and then
  295. writing things out on a publicly visible blog, building up a bunch of articles
  296. over time. Then you could use that body of work as a way to meme yourself into
  297. hiring pipelines thanks to people sharing your links on aggegators like the
  298. orange site. It'd probably help if you also got a reputation as a shitposter,
  299. usually when people are able to openly joke about something that signals that
  300. they are pretty damn experienced in it.</p>
  301. </div>
  302. <div class="conversation">
  303. <p class="conversation-chat">&lt;<b>Cadey</b>&gt; You're describing this blog aren't you.</p>
  304. </div>
  305. <p>Like I said though, this is hard. A lot of the problems are actually structural
  306. problems in how companies do the science part of computer science. Structural
  307. problems cannot be solved overnight. These things take time, effort and patience
  308. to truly figure out and in the process you will fail to invent a light bulb many
  309. times over. Devops is probably a necessary evil, but I really wish that
  310. situations weren't toxic enough in the first place to require that evil.</p>
  311. </article>
  312. <hr>
  313. <footer>
  314. <p>
  315. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  316. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-home"></use>
  317. </svg> Accueil</a> •
  318. <a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
  319. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-rss2"></use>
  320. </svg> Suivre</a> •
  321. <a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
  322. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-user-tie"></use>
  323. </svg> Pro</a> •
  324. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
  325. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-mail"></use>
  326. </svg> Email</a> •
  327. <abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
  328. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-hammer2"></use>
  329. </svg> Légal</abbr>
  330. </p>
  331. <template id="theme-selector">
  332. <form>
  333. <fieldset>
  334. <legend><svg class="icon icon-brightness-contrast">
  335. <use xlink:href="/static/david/icons2/symbol-defs-2021-12.svg#icon-brightness-contrast"></use>
  336. </svg> Thème</legend>
  337. <label>
  338. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  339. </label>
  340. <label>
  341. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  342. </label>
  343. <label>
  344. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  345. </label>
  346. </fieldset>
  347. </form>
  348. </template>
  349. </footer>
  350. <script src="/static/david/js/instantpage-5.1.0.min.js" type="module"></script>
  351. <script>
  352. function loadThemeForm(templateName) {
  353. const themeSelectorTemplate = document.querySelector(templateName)
  354. const form = themeSelectorTemplate.content.firstElementChild
  355. themeSelectorTemplate.replaceWith(form)
  356. form.addEventListener('change', (e) => {
  357. const chosenColorScheme = e.target.value
  358. localStorage.setItem('theme', chosenColorScheme)
  359. toggleTheme(chosenColorScheme)
  360. })
  361. const selectedTheme = localStorage.getItem('theme')
  362. if (selectedTheme && selectedTheme !== 'undefined') {
  363. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  364. }
  365. }
  366. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  367. window.addEventListener('load', () => {
  368. let hasDarkRules = false
  369. for (const styleSheet of Array.from(document.styleSheets)) {
  370. let mediaRules = []
  371. for (const cssRule of styleSheet.cssRules) {
  372. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  373. continue
  374. }
  375. // WARNING: Safari does not have/supports `conditionText`.
  376. if (cssRule.conditionText) {
  377. if (cssRule.conditionText !== prefersColorSchemeDark) {
  378. continue
  379. }
  380. } else {
  381. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  382. continue
  383. }
  384. }
  385. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  386. }
  387. // WARNING: do not try to insert a Rule to a styleSheet you are
  388. // currently iterating on, otherwise the browser will be stuck
  389. // in a infinite loop…
  390. for (const mediaRule of mediaRules) {
  391. styleSheet.insertRule(mediaRule.cssText)
  392. hasDarkRules = true
  393. }
  394. }
  395. if (hasDarkRules) {
  396. loadThemeForm('#theme-selector')
  397. }
  398. })
  399. </script>
  400. </body>
  401. </html>