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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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,initial-scale=1">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>A short introduction to building digital services in the Canadian government (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="#f0f0ea">
  24. <meta name="msapplication-config" content="/static/david/icons2/browserconfig.xml">
  25. <meta name="theme-color" content="#f0f0ea">
  26. <!-- Documented, feel free to shoot an email. -->
  27. <link rel="stylesheet" href="/static/david/css/style_2020-06-19.css">
  28. <!-- See https://www.zachleat.com/web/comprehensive-webfonts/ for the trade-off. -->
  29. <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>
  30. <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>
  31. <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>
  32. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_regular.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  33. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_bold.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  34. <link rel="preload" href="/static/david/css/fonts/triplicate_t3_italic.woff2" as="font" type="font/woff2" media="(prefers-color-scheme: dark)" crossorigin>
  35. <script type="text/javascript">
  36. function toggleTheme(themeName) {
  37. document.documentElement.classList.toggle(
  38. 'forced-dark',
  39. themeName === 'dark'
  40. )
  41. document.documentElement.classList.toggle(
  42. 'forced-light',
  43. themeName === 'light'
  44. )
  45. }
  46. const selectedTheme = localStorage.getItem('theme')
  47. if (selectedTheme !== 'undefined') {
  48. toggleTheme(selectedTheme)
  49. }
  50. </script>
  51. <meta name="robots" content="noindex, nofollow">
  52. <meta content="origin-when-cross-origin" name="referrer">
  53. <!-- Canonical URL for SEO purposes -->
  54. <link rel="canonical" href="https://sboots.ca/2020/06/16/building-digital-services-in-the-canadian-government/">
  55. <body class="remarkdown h1-underline h2-underline h3-underline hr-center ul-star pre-tick">
  56. <article>
  57. <header>
  58. <h1>A short introduction to building digital services in the Canadian government</h1>
  59. </header>
  60. <nav>
  61. <p class="center">
  62. <a href="/david/" title="Aller à l’accueil" tabindex="1">🏠</a>
  63. </p>
  64. </nav>
  65. <hr>
  66. <h2><a href="https://sboots.ca/2020/06/16/building-digital-services-in-the-canadian-government/">Source originale du contenu</a></h2>
  67. <main>
  68. <p>Back in March, some friends from the Ottawa civic tech community reached out. The pandemic was <a href="/2020/03/25/look-out-for-one-another/">ramping up</a>, and they were interested in volunteering their developer skills to help government departments respond to the crisis. Building digital services and IT systems in a government environment is complicated. The federal government in particular has a lot of rules to navigate, and it’s easy for these to overwhelm people and (at the least) siphon their time away from designing and building user-friendly software.</p>
  69. <p>Here’s what I wrote, on a Sunday evening – none of this constitutes formal policy advice, but it was meant to give an introduction to which rules really do deserve a lot of attention, and potential landmines to avoid. (Note that some of the links below were added to this blog post after the fact, for extra context or further reading.)</p>
  70. <p>You’ll notice that this skips over some of the most important practical steps in designing, delivering, and iterating on good digital services – doing research with actual users, using <a href="https://digital.canada.ca/2018/06/27/tools-to-do-good-work/">modern software development tools</a> and best practices, deploying early and frequently, etc. This was written for an audience that’s used to building digital products in the private sector, to better understand what’s new and different in a government context. Enjoy!</p>
  71. <p><img src="/img/2020/parliament-feb-2020-cropped.jpg" class="img-fluid" alt="A photo from near Parliament Hill looking west at the Confederation Building and other buildings along Wellington, on a sunny February day."/></p>
  72. <h2 id="a-short-introduction">A short introduction</h2>
  73. <p>In case it’s useful, here’s a few suggestions on typical government implementation details – trying to focus here on the ones that really matter, not the seemingly-endless lists of rules that <a href="/2020/02/27/user-needs-not-government-needs/">ultimately don’t affect users</a>. These are the ones that government teams get accidentally crushed over when they screw them up (e.g. lawsuits or public shaming, etc.).</p>
  74. <p>From a tech standpoint, anything you build is <a href="/2020/05/26/why-are-there-so-few-senior-developers-in-government/">almost guaranteed</a> to be higher-quality than most existing GC systems and services. Use what you’re familiar with and what you trust. Most of these suggestions ultimately have to do with the front-end/public-facing aspect of services, not back-end engineering decisions (where the GC norm is, y’know, <a href="https://www.macleans.ca/politics/ottawa/pulling-off-a-bureaucratic-miracle-how-the-cerb-got-done/">40-year-old COBOL</a> or dicey ASP.NET applications).</p>
  75. <p><em>GC = Government of Canada; sorry in advance for any acronyms</em></p>
  76. <h2 id="official-languages">Official Languages</h2>
  77. <p>Anything that constitutes a Government of Canada service or communications product needs to be available in English and French, “<a href="https://www.tbs-sct.gc.ca/pol/doc-eng.aspx?id=26164">simultaneously and of equal quality</a>”. Ideally your departmental partner would have translation capabilities on standby so you wouldn’t need to translate things yourself – but you definitely need to build EN/FR internationalization support into everything from the start. Speaking from experience it’s a pain to add in after the fact. Publicly launching a service only in English, then adding French later, would be a huge (political) catastrophe.</p>
  78. <p>Also count on at least one full business day for any translation request to come back, even ones that are marked super urgent. Write as much of your public-facing content as early as possible (e.g. in parallel to your software work) so that you can send it translation ASAP.</p>
  79. <h2 id="accessibility">Accessibility</h2>
  80. <p>Any Government of Canada service (and ones delivered and built by third parties) needs to meet <strong><a href="https://www.w3.org/TR/WCAG20/">WCAG 2.0 AA</a></strong> accessibility standards. This is mostly the basics e.g. keyboard navigable, has sufficient colour contrast, has good headings and image alt-text, etc.</p>
  81. <p>Not meeting WCAG 2.0 AA is a semi-frequent source of lawsuits that the Government of Canada always loses. Run your service through at least two or three different online testing tools that check for WCAG compliance and save a copy of the results somewhere, send them to your departmental partners for posterity, etc. Your departmental partner should be doing much more extensive, ongoing accessibility testing (the <a href="https://digital.canada.ca/a11y/">CDS accessibility handbook</a> can help).</p>
  82. <h2 id="federal-identity-program">Federal Identity Program</h2>
  83. <p>Certain government types are <em>very</em> particular about how the government’s logos and visuals are used. The very short answer is: put the <a href="https://raw.githubusercontent.com/cds-snc/node-starter-app/master/public/img/sig-blk-en.svg">“Government of Canada / Gouvernement du Canada” signature</a> in the top left of the page, and the <a href="https://raw.githubusercontent.com/cds-snc/node-starter-app/master/public/img/wmms-blk.svg">“Canada” wordmark</a> in the bottom right, and don’t be too outlandish with fonts and colours. (The formal <a href="https://www.canada.ca/en/treasury-board-secretariat/services/government-communications/federal-identity-program/manual.html">Federal Identity Program requirements</a> are from the 1990s and mostly apply to government letterhead, building signs, and vehicle decals – there’s a lot of interpretation and debate about how to apply them to websites, and it’s best to avoid those debates if you can.)</p>
  84. <p>On the French version of your website or service, the signature should use the <a href="https://raw.githubusercontent.com/cds-snc/node-starter-app/master/public/img/sig-blk-fr.svg">French-first “Gouvernement du Canada / Government of Canada” version</a>.</p>
  85. <p>CDS has <a href="https://github.com/cds-snc/node-starter-app">a “starter app” repository</a> that you can use for inspiration (and logo files) but don’t worry too much if you’re using a different front-end library, etc.</p>
  86. <h2 id="domain-names">Domain names</h2>
  87. <p>The government is pretty inconsistent here, but in a perfect world everything run by the GC would have domain names ending in <code>*.canada.ca</code> or <code>*.gc.ca</code>.</p>
  88. <p>When Global Affairs Canada sent out notifications to a bunch of international travellers last week [mid-March] and used bitly links, people freaked out because <a href="https://twitter.com/xdr/status/1240710656841486336">it looked like a scam</a>.</p>
  89. <p>There’s a <a href="https://alpha.canada.ca/en/instructions.html">DNS setup</a> that CDS operates at <code>alpha.canada.ca</code> and can spin up a subdomain off of it relatively quickly, if that’s useful (and if your departmental partner doesn’t already have some specific URL in mind). It can be pointed at whatever cloud provider you need and it’s faster than going through the gauntlet of SSC + TBS + ServiceCanada that normally has to approve GC subdomains. It’d be better than something that isn’t clearly GC-operated.</p>
  90. <h2 id="inclusive-design">Inclusive design</h2>
  91. <p>Practically speaking, this is probably the hardest area to figure out (but <a href="/2020/02/25/our-services-arent-working/#why-this-matters">incredibly important</a>). Think about situations like: people applying for a service on behalf of their elderly non-tech-savvy parents; band councils trying to apply on behalf of everyone on their First Nations reserve; people applying on behalf of hospitalized family members or friends.</p>
  92. <p>One notable mishap here last year was IRCC’s redesigned program to apply for family reunification visas; the team built a cloud service (for the first time) and it scaled really well to handle the giant surge of requests when the application period opened (compared to, well, IRCC’s normal, more fragile IT systems). But, the program was designed “first come, first serve” and as a result, <a href="https://www.cbc.ca/news/politics/ircc-parent-grandparent-sponsorship-filled-2019-1.4995806">inadvertently prioritized whoever could get through the complicated online application form fastest</a> (disadvantaging people with disabilities or accessibility requirements, people with slow bandwidth or computers, etc.).</p>
  93. <p>People acting on behalf of other people is the most complicated area (and a bunch of GC services don’t handle it well, although the CRA and ESDC do have some online services that include delegating to family members / power of attorney contacts or, say, tax professionals). Whatever you build might not need to handle these edge cases, but figuring out ahead of time which ones you can and which ones you can’t (and clearly documenting why, and making sure that your departmental partners know) is important.</p>
  94. <h2 id="shipping">Shipping</h2>
  95. <p>In government, the hardest part of any IT-related project is <a href="/2020/01/10/shipping/">literally getting it out the door</a>. Under normal circumstances there’s a whole gauntlet of approval processes (security, privacy, quality control, infrastructure) usually all done by separate groups or committees. For a brand new online service, getting through these processes could typically take 6-24 months. (This is one reason why people say that tech implementation is only a small part of digital government work – the rest is, either <a href="/2020/01/28/introducing-agile-to-large-organizations-is-a-subtractive-process-not-an-additive-one/">navigating through or getting rid of all these waterfall processes</a>).</p>
  96. <p>In an emergency situation like the COVID pandemic, the typical approval processes for something to get shipped (“go live” or “go into production”) could potentially be skipped – but in place of them, you would definitely need some kind of written confirmation from a senior public servant (e.g. assistant deputy minister or deputy minister) from the department in question. An email from them saying “I authorize the operation of this service” is sufficient.</p>
  97. <p><strong>There is a whole graveyard littered with amazing digital products in government that never made it out the door.</strong> I can think of probably a dozen examples. Don’t be one of them. World-class tech implementation won’t get you through this; you need the backing from a public servant at the highest leadership level possible to fight through any potential gatekeepers and to give the green light to go live. Having a close relationship between the product team and that senior public servant from as early on as possible helps (direct communications, regular progress updates). I’d say, this is the biggest risk to any project – that you build something phenomenal, and then your partner department gets cold feet and it never ships. This happens frequently.</p>
  98. <p><em>Thanks to <a href="https://twitter.com/rossferg">Ross Ferguson</a> for suggesting that I publish this as a blog post. If you’re a public servant working to navigate these rules in your department, <a href="https://twitter.com/sboots">don’t hesitate to reach out</a>! The rules here – and the long tail of other government requirements – can definitely be a challenge, and you’re not alone.</em></p>
  99. </main>
  100. </article>
  101. <hr>
  102. <footer>
  103. <p>
  104. <a href="/david/" title="Aller à l’accueil">🏠</a> •
  105. <a href="/david/log/" title="Accès au flux RSS">🤖</a> •
  106. <a href="http://larlet.com" title="Go to my English profile" data-instant>🇨🇦</a> •
  107. <a href="mailto:david%40larlet.fr" title="Envoyer un courriel">📮</a> •
  108. <abbr title="Hébergeur : Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33184162340">🧚</abbr>
  109. </p>
  110. <template id="theme-selector">
  111. <form>
  112. <fieldset>
  113. <legend>Thème</legend>
  114. <label>
  115. <input type="radio" value="auto" name="chosen-color-scheme" checked> Auto
  116. </label>
  117. <label>
  118. <input type="radio" value="dark" name="chosen-color-scheme"> Foncé
  119. </label>
  120. <label>
  121. <input type="radio" value="light" name="chosen-color-scheme"> Clair
  122. </label>
  123. </fieldset>
  124. </form>
  125. </template>
  126. </footer>
  127. <script type="text/javascript">
  128. function loadThemeForm(templateName) {
  129. const themeSelectorTemplate = document.querySelector(templateName)
  130. const form = themeSelectorTemplate.content.firstElementChild
  131. themeSelectorTemplate.replaceWith(form)
  132. form.addEventListener('change', (e) => {
  133. const chosenColorScheme = e.target.value
  134. localStorage.setItem('theme', chosenColorScheme)
  135. toggleTheme(chosenColorScheme)
  136. })
  137. const selectedTheme = localStorage.getItem('theme')
  138. if (selectedTheme && selectedTheme !== 'undefined') {
  139. form.querySelector(`[value="${selectedTheme}"]`).checked = true
  140. }
  141. }
  142. const prefersColorSchemeDark = '(prefers-color-scheme: dark)'
  143. window.addEventListener('load', () => {
  144. let hasDarkRules = false
  145. for (const styleSheet of Array.from(document.styleSheets)) {
  146. let mediaRules = []
  147. for (const cssRule of styleSheet.cssRules) {
  148. if (cssRule.type !== CSSRule.MEDIA_RULE) {
  149. continue
  150. }
  151. // WARNING: Safari does not have/supports `conditionText`.
  152. if (cssRule.conditionText) {
  153. if (cssRule.conditionText !== prefersColorSchemeDark) {
  154. continue
  155. }
  156. } else {
  157. if (cssRule.cssText.startsWith(prefersColorSchemeDark)) {
  158. continue
  159. }
  160. }
  161. mediaRules = mediaRules.concat(Array.from(cssRule.cssRules))
  162. }
  163. // WARNING: do not try to insert a Rule to a styleSheet you are
  164. // currently iterating on, otherwise the browser will be stuck
  165. // in a infinite loop…
  166. for (const mediaRule of mediaRules) {
  167. styleSheet.insertRule(mediaRule.cssText)
  168. hasDarkRules = true
  169. }
  170. }
  171. if (hasDarkRules) {
  172. loadThemeForm('#theme-selector')
  173. }
  174. })
  175. </script>
  176. </body>
  177. </html>