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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  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>Making world-class docs takes effort (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://daniel.haxx.se/blog/2021/09/04/making-world-class-docs-takes-effort/">
  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>Making world-class docs takes effort</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.svg#icon-home"></use>
  65. </svg> Accueil</a> •
  66. <a href="https://daniel.haxx.se/blog/2021/09/04/making-world-class-docs-takes-effort/" title="Lien vers le contenu original">Source originale</a>
  67. </p>
  68. </nav>
  69. <hr>
  70. <p>Here are six requirements that I have on a project for it to reach my gold approval for stellar docs. Then something about what I’ve done recently to further improve the docs for curl.</p>
  71. <h2>Your docs belong in the code repository</h2>
  72. <p>It needs to be next to the code so that authors and contributors can update/read the docs while working on the code or docs. Providing it in a separate repository or otherwise separated will undoubtedly lead to discrepancies sooner or later. Similar to how <em>all wikis are always wrong</em>.</p>
  73. <h2>Your docs is not extracted from code</h2>
  74. <p>Admit it. If you browse around you will realize that the best documented projects you find never provide that docs generated directly from code. Such generated docs can still provide value, but you will not reach gold level without more effort.</p>
  75. <p>Separated docs encourage more writing and writing by people who are otherwise scared of touching the code or thinking that fixing spelling errors in the docs isn’t worth patching the code for. It also allows for other and better formatting on the docs.</p>
  76. <h2>Your docs features examples</h2>
  77. <p>Users always ask for (more) examples. You can never go wrong by providing examples. If your docs don’t have enough examples, you’re not doing the docs good enough yet.</p>
  78. <h2>You document every API call you provide</h2>
  79. <p>Fewer things make me sigh more than when I have to dig up the source code and from that try to figure out exactly how an external and publicly provided API works. Yet this still happens regularly even for libraries that have been released and maintained for decades.</p>
  80. <p>In one fairly recent instance I reported such an omission in a popular library. It took them over two years to add it.</p>
  81. <p>Long-living libraries should also provide information about from which versions certain functionality or options exist or can be expected to work or not work.</p>
  82. <h2>Your docs is easily accessible and browsed</h2>
  83. <p>Good docs means that we can <em>find</em> what we’re looking for and that the documentation flows and is easily read and understood. Ideally, even simple google searches for API details in your library should lead us to suitable entry points.</p>
  84. <p>Preferably, the documentation should also be provided for proper off-line reading, meaning man pages or something similar that can be browsed when disconnected from the Internet.</p>
  85. <h2>Your docs should be easy to contribute to</h2>
  86. <p>The docs should be easy for contributors to help out with (independently from the code if desired). That also includes that they should be easy for contributors to build and render locally so that they can test and view their updates while working on them.</p>
  87. <h2>Documentation in the curl project</h2>
  88. <p>I want the documentation for curl and libcurl to be known, recognized and widely admitted to be world-class.</p>
  89. <p>I want the curl documentation to be of a quality and content to make users not able to find competitors or similar projects with better docs.</p>
  90. <p>Documentation in curl is not an after-thought. It is not a second-tier component. It is a crucial and important foundation that allows users to use, trust and rely on our products. We require that new changes or improved functionality are provided with the corresponding updated and accurate documentation.</p>
  91. <p>We also try to verify and check the docs as much as possible with scanners , tests and tools.</p>
  92. <h2>Non-stop iterating is key</h2>
  93. <p>I maintain that our documentation is as good as it is today a lot thanks to us very rigidly sticking to our guiding principles: <em>compatibility</em> and <em>not breaking existing behavior</em>. Documentation we wrote decades ago is still valid. It gives us plenty of time to keep refining and polishing the documentation of a feature that doesn’t change. No documentation was perfect already at the first attempt, but after numerous iterations and improvements chances are it is better. Time is on our side. And we are never done, documentation can always be improved.</p>
  94. <h2>I’m putting in the work</h2>
  95. <p>A few days ago I talked documentation with someone and when doing so I thought about what guiding principles I think we should put on project documentation. What I’ve listed above basically.</p>
  96. <p>In then dawned on me that the current man curl.1 man page is actually not featuring that many examples, in spite of it being <strong>3535</strong> lines long. I pondered a little bit on how best add some, and then dove in and extended our system that generates it from the hundreds of individual files that each describe a single command line option. They should of course all offer at least one example!</p>
  97. <p>Having <strong>242</strong> command line options (as of right now, it will be more soon), that sudden idea that seemed simple enough turned into a quite gruesome work and I spent many hours walking over the options to make up examples. I also made sure that our build system now returns an error if there’s a command option without an example in the documentation! This way, we can be sure that also all future command line options will have examples in the man page.</p>
  98. <p>This made the curl.1 man page grew with over 1200 lines!</p>
  99. <h2>libcurl options too</h2>
  100. <p>A few years ago I did a manual effort and made sure most man pages for libcurl options include examples, but I never made that into a test or anything so there’s nothing that forces us to stick to this.</p>
  101. <p>Having started this journey, I decided now was the time to add that requirement to the scripts. I extended test case 1173, which already scans all man pages to verify some basic syntax, to also check that man pages for options feature an <code>EXAMPLE</code> section.</p>
  102. <p>There are at this moment <strong>374</strong> stand-alone man pages for libcurl options. Only ten of them were detected to not feature good enough examples and it wasn’t very hard to fix this.</p>
  103. <h2>Consistency is good</h2>
  104. <p>Having just extended the man page checker, another idea came up.</p>
  105. <p>I made the script also check that each man page features the correct set of sections, in the required order! I’m a true believer in consistency and that using the same set in the same order will make the docs easier to read and find information in, and checking for these things will make sure that all future additions will be forced stick to the same.</p>
  106. <p>The mandatory sections for libcurl option man pages are right now, in this order:</p>
  107. <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate" title="">
  108. NAME
  109. SYNOPSIS
  110. DESCRIPTION
  111. PROTOCOLS
  112. EXAMPLE
  113. AVAILABILITY
  114. RETURN VALUE
  115. SEE ALSO
  116. </pre></div>
  117. <p>These man pages are allowed to have other sections as well, and they can be placed anywhere among the mandatory ones, but the eight section headers that has to be there has to be in that order.</p>
  118. <h2>Cross-references</h2>
  119. <p>While at it, I also extended the man page scanner to check that all references in all curl man pages to libcurl options are verified to actually refer to existing options, to find typos. Ironically this extra check turned out finding exactly <strong>no</strong> such typos in the current <strong>463</strong> man pages!</p>
  120. <h2>Future</h2>
  121. <p>The outcome of the work I write about here will of course be merged asap and will be part of future releases and on the website.</p>
  122. <p>We should keep thinking of more ways to improve the documentation and for more ways to verify and cross-reference things mentioned in the docs to increase its accuracy and detect typos.</p>
  123. <p>If you find a problem, an inferior wording or just something you think we should improve in any curl documentation, <a href="https://github.com/curl/curl/issues/new/choose">file a bug</a> or a <a href="https://github.com/curl/curl/pulls">PR</a>! We also try to make this as easy as possible for users to do directly from the <a href="https://curl.se/">curl website</a> by providing bug-reporting direct links from the documentation pages.</p>
  124. <h2>Updates</h2>
  125. <p>I added the sixth “rule” days after the initial post after Willy Tarreau’s feedback.</p>
  126. </article>
  127. <hr>
  128. <footer>
  129. <p>
  130. <a href="/david/" title="Aller à l’accueil"><svg class="icon icon-home">
  131. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-home"></use>
  132. </svg> Accueil</a> •
  133. <a href="/david/log/" title="Accès au flux RSS"><svg class="icon icon-rss2">
  134. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-rss2"></use>
  135. </svg> Suivre</a> •
  136. <a href="http://larlet.com" title="Go to my English profile" data-instant><svg class="icon icon-user-tie">
  137. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-user-tie"></use>
  138. </svg> Pro</a> •
  139. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel"><svg class="icon icon-mail">
  140. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-mail"></use>
  141. </svg> Email</a> •
  142. <abbr class="nowrap" title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340"><svg class="icon icon-hammer2">
  143. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-hammer2"></use>
  144. </svg> Légal</abbr>
  145. </p>
  146. <template id="theme-selector">
  147. <form>
  148. <fieldset>
  149. <legend><svg class="icon icon-brightness-contrast">
  150. <use xlink:href="/static/david/icons2/symbol-defs.svg#icon-brightness-contrast"></use>
  151. </svg> Thème</legend>
  152. <label>
  153. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  154. </label>
  155. <label>
  156. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  157. </label>
  158. <label>
  159. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  160. </label>
  161. </fieldset>
  162. </form>
  163. </template>
  164. </footer>
  165. <script src="/static/david/js/instantpage-5.1.0.min.js" type="module"></script>
  166. <script>
  167. function loadThemeForm(templateName) {
  168. const themeSelectorTemplate = document.querySelector(templateName)
  169. const form = themeSelectorTemplate.content.firstElementChild
  170. themeSelectorTemplate.replaceWith(form)
  171. form.addEventListener('change', (e) => {
  172. const chosenColorScheme = e.target.value
  173. localStorage.setItem('theme', chosenColorScheme)
  174. toggleTheme(chosenColorScheme)
  175. })
  176. const selectedTheme = localStorage.getItem('theme')
  177. if (selectedTheme && selectedTheme !== 'undefined') {
  178. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  179. }
  180. }
  181. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  182. window.addEventListener('load', () => {
  183. let hasDarkRules = false
  184. for (const styleSheet of Array.from(document.styleSheets)) {
  185. let mediaRules = []
  186. for (const cssRule of styleSheet.cssRules) {
  187. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  188. continue
  189. }
  190. // WARNING: Safari does not have/supports `conditionText`.
  191. if (cssRule.conditionText) {
  192. if (cssRule.conditionText !== prefersColorSchemeDark) {
  193. continue
  194. }
  195. } else {
  196. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  197. continue
  198. }
  199. }
  200. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  201. }
  202. // WARNING: do not try to insert a Rule to a styleSheet you are
  203. // currently iterating on, otherwise the browser will be stuck
  204. // in a infinite loop…
  205. for (const mediaRule of mediaRules) {
  206. styleSheet.insertRule(mediaRule.cssText)
  207. hasDarkRules = true
  208. }
  209. }
  210. if (hasDarkRules) {
  211. loadThemeForm('#theme-selector')
  212. }
  213. })
  214. </script>
  215. </body>
  216. </html>