Repository with sources and generator of https://larlet.fr/david/ https://larlet.fr/david/
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 37KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang=en>
  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>Inclusive Python — 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. <!-- Canonical URL for SEO purposes -->
  28. <link rel="canonical" href="https://larlet.fr/david/blog/2017/inclusive-python/">
  29. <!-- SEO/Semantic metadata -->
  30. <meta name="description" content="Making your code resilient requires empathy." />
  31. <meta name="twitter:description" property="og:description" itemprop="description" content="Making your code resilient requires empathy." />
  32. <meta name="twitter:title" property="og:title" itemprop="name" content="Inclusive Python" />
  33. <meta name="twitter:card" content="summary" />
  34. <meta name="twitter:creator" content="@davidbgk" />
  35. <meta name="twitter:url" property="og:url" content="https://larlet.fr/david/blog/2017/inclusive-python/" />
  36. <meta property="og:type" content="article" />
  37. <meta property="og:site_name" content="David Larlet (@davidbgk)" />
  38. <meta name="twitter:image" property="og:image" itemprop="image" content="https://larlet.fr/static/david/blog/2017/inclusive-python.jpg" />
  39. <style>
  40. /* http://meyerweb.com/eric/tools/css/reset/ */
  41. html, body, div, span,
  42. h1, h2, h3, h4, h5, h6, p, blockquote, pre,
  43. a, abbr, address, big, cite, code,
  44. del, dfn, em, img, ins,
  45. small, strike, strong, tt, var,
  46. dl, dt, dd, ol, ul, li,
  47. fieldset, form, label, legend,
  48. table, caption, tbody, tfoot, thead, tr, th, td,
  49. article, aside, canvas, details, embed,
  50. figure, figcaption, footer, header, hgroup,
  51. menu, nav, output, ruby, section, summary,
  52. time, mark, audio, video {
  53. margin: 0;
  54. padding: 0;
  55. border: 0;
  56. font-size: 100%;
  57. font: inherit;
  58. vertical-align: baseline;
  59. }
  60. /* HTML5 display-role reset for older browsers */
  61. article, aside, details, figcaption, figure,
  62. footer, header, hgroup, menu, nav, section { display: block; }
  63. body { line-height: 1; }
  64. blockquote, q { quotes: none; }
  65. blockquote:before, blockquote:after,
  66. q:before, q:after {
  67. content: '';
  68. content: none;
  69. }
  70. table {
  71. border-collapse: collapse;
  72. border-spacing: 0;
  73. }
  74. /* http://practicaltypography.com/equity.html */
  75. /* https://calendar.perfplanet.com/2016/no-font-face-bulletproof-syntax/ */
  76. /* https://www.filamentgroup.com/lab/js-web-fonts.html */
  77. @font-face {
  78. font-family: 'EquityTextB';
  79. src: url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff2') format('woff2'),
  80. url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff') format('woff');
  81. font-weight: 300;
  82. font-style: normal;
  83. font-display: swap;
  84. }
  85. @font-face {
  86. font-family: 'EquityTextB';
  87. src: url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff2') format('woff2'),
  88. url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff') format('woff');
  89. font-weight: 300;
  90. font-style: italic;
  91. font-display: swap;
  92. }
  93. @font-face {
  94. font-family: 'EquityTextB';
  95. src: url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff2') format('woff2'),
  96. url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff') format('woff');
  97. font-weight: 700;
  98. font-style: normal;
  99. font-display: swap;
  100. }
  101. @font-face {
  102. font-family: 'ConcourseT3';
  103. src: url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff2') format('woff2'),
  104. url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff') format('woff');
  105. font-weight: 300;
  106. font-style: normal;
  107. font-display: swap;
  108. }
  109. /* http://practice.typekit.com/lesson/caring-about-opentype-features/ */
  110. body {
  111. /* http://www.cssfontstack.com/ Palatino 99% Win 86% Mac */
  112. font-family: "EquityTextB", Palatino, serif;
  113. background-color: #f0f0ea;
  114. color: #07486c;
  115. font-kerning: normal;
  116. -moz-osx-font-smoothing: grayscale;
  117. -webkit-font-smoothing: subpixel-antialiased;
  118. text-rendering: optimizeLegibility;
  119. font-variant-ligatures: common-ligatures contextual;
  120. font-feature-settings: "kern", "liga", "clig", "calt";
  121. }
  122. pre, code, kbd, samp, var, tt {
  123. font-family: 'TriplicateT4c', monospace;
  124. }
  125. em {
  126. font-style: italic;
  127. color: #323a45;
  128. }
  129. strong {
  130. font-weight: bold;
  131. color: black;
  132. }
  133. nav {
  134. background-color: #323a45;
  135. color: #f0f0ea;
  136. display: flex;
  137. justify-content: space-around;
  138. padding: 1rem .5rem;
  139. }
  140. nav:last-child {
  141. border-bottom: 1vh solid #2d7474;
  142. }
  143. nav a {
  144. color: #f0f0ea;
  145. }
  146. nav abbr {
  147. border-bottom: 1px dotted white;
  148. }
  149. h1 {
  150. border-top: 1vh solid #2d7474;
  151. border-bottom: .2vh dotted #2d7474;
  152. background-color: #e3e1e1;
  153. color: #323a45;
  154. text-align: center;
  155. padding: 5rem 0 4rem 0;
  156. width: 100%;
  157. font-family: 'ConcourseT3';
  158. display: flex;
  159. flex-direction: column;
  160. }
  161. h1.single {
  162. padding-bottom: 10rem;
  163. }
  164. h1 span {
  165. position: absolute;
  166. top: 1vh;
  167. left: 20%;
  168. line-height: 0;
  169. }
  170. h1 span a {
  171. line-height: 1.7;
  172. padding: 1rem 1.2rem .6rem 1.2rem;
  173. border-radius: 0 0 6% 6%;
  174. background: #2d7474;
  175. font-size: 1.3rem;
  176. color: white;
  177. text-decoration: none;
  178. }
  179. h2 {
  180. margin: 4rem 0 1rem;
  181. border-top: .2vh solid #2d7474;
  182. padding-top: 1vh;
  183. }
  184. h3 {
  185. text-align: center;
  186. margin: 3rem 0 .75em;
  187. }
  188. hr {
  189. height: .4rem;
  190. width: .4rem;
  191. border-radius: .4rem;
  192. background: #07486c;
  193. margin: 2.5rem auto;
  194. }
  195. time {
  196. display: bloc;
  197. margin-left: 0 !important;
  198. }
  199. ul, ol {
  200. margin: 2rem;
  201. }
  202. ul {
  203. list-style-type: square;
  204. }
  205. a {
  206. text-decoration-skip-ink: auto;
  207. text-decoration-thickness: 0.05em;
  208. text-underline-offset: 0.09em;
  209. }
  210. article {
  211. max-width: 50rem;
  212. display: flex;
  213. flex-direction: column;
  214. margin: 2rem auto;
  215. }
  216. article.single {
  217. border-top: .2vh dotted #2d7474;
  218. margin: -6rem auto 1rem auto;
  219. background: #f0f0ea;
  220. padding: 2rem;
  221. }
  222. article p:last-child {
  223. margin-bottom: 1rem;
  224. }
  225. p {
  226. padding: 0 .5rem;
  227. margin-left: 3rem;
  228. }
  229. p + p,
  230. figure + p {
  231. margin-top: 2rem;
  232. }
  233. blockquote {
  234. background-color: #e3e1e1;
  235. border-left: .5vw solid #2d7474;
  236. display: flex;
  237. flex-direction: column;
  238. align-items: center;
  239. padding: 1rem;
  240. margin: 1.5rem;
  241. }
  242. blockquote cite {
  243. font-style: italic;
  244. }
  245. blockquote p {
  246. margin-left: 0;
  247. }
  248. figure {
  249. border-top: .2vh solid #2d7474;
  250. background-color: #e3e1e1;
  251. text-align: center;
  252. padding: 1.5rem 0;
  253. margin: 1rem 0 0;
  254. font-size: 1.5rem;
  255. width: 100%;
  256. }
  257. figure img {
  258. max-width: 250px;
  259. max-height: 250px;
  260. border: .5vw solid #323a45;
  261. padding: 1px;
  262. }
  263. figcaption {
  264. padding: 1rem;
  265. line-height: 1.4;
  266. }
  267. aside {
  268. display: flex;
  269. flex-direction: column;
  270. background-color: #e3e1e1;
  271. padding: 1rem 0;
  272. border-bottom: .2vh solid #07486c;
  273. }
  274. aside p {
  275. max-width: 50rem;
  276. margin: 0 auto;
  277. }
  278. /* https://fvsch.com/code/css-locks/ */
  279. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  280. font-size: 1rem;
  281. line-height: calc( 1.5em + 0.2 * 1rem );
  282. }
  283. h1 {
  284. font-size: 1.9rem;
  285. line-height: calc( 1.2em + 0.2 * 1rem );
  286. }
  287. h2 {
  288. font-size: 1.6rem;
  289. line-height: calc( 1.3em + 0.2 * 1rem );
  290. }
  291. h3 {
  292. font-size: 1.35rem;
  293. line-height: calc( 1.4em + 0.2 * 1rem );
  294. }
  295. @media (min-width: 20em) {
  296. /* The (100vw - 20rem) / (50 - 20) part
  297. resolves to 0-1rem, depending on the
  298. viewport width (between 20em and 50em). */
  299. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  300. font-size: calc( 1rem + .6 * (100vw - 20rem) / (50 - 20) );
  301. line-height: calc( 1.5em + 0.2 * (100vw - 50rem) / (20 - 50) );
  302. margin-left: 0;
  303. }
  304. h1 {
  305. font-size: calc( 1.9rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  306. line-height: calc( 1.2em + 0.2 * (100vw - 50rem) / (20 - 50) );
  307. }
  308. h2 {
  309. font-size: calc( 1.5rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  310. line-height: calc( 1.3em + 0.2 * (100vw - 50rem) / (20 - 50) );
  311. }
  312. h3 {
  313. font-size: calc( 1.35rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  314. line-height: calc( 1.4em + 0.2 * (100vw - 50rem) / (20 - 50) );
  315. }
  316. }
  317. @media (min-width: 50em) {
  318. /* The right part of the addition *must* be a
  319. rem value. In this example we *could* change
  320. the whole declaration to font-size:2.5rem,
  321. but if our baseline value was not expressed
  322. in rem we would have to use calc. */
  323. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  324. font-size: calc( 1rem + .6 * 1rem );
  325. line-height: 1.5em;
  326. }
  327. p, li, pre, details {
  328. margin-left: 3rem;
  329. }
  330. h1 {
  331. font-size: calc( 1.9rem + 1.5 * 1rem );
  332. line-height: 1.2em;
  333. }
  334. h2 {
  335. font-size: calc( 1.5rem + 1.5 * 1rem );
  336. line-height: 1.3em;
  337. }
  338. h3 {
  339. font-size: calc( 1.35rem + 1.5 * 1rem );
  340. line-height: 1.4em;
  341. }
  342. figure img {
  343. max-width: 500px;
  344. max-height: 500px;
  345. }
  346. }
  347. figure.unsquared {
  348. margin-bottom: 1.5rem;
  349. }
  350. figure.unsquared img {
  351. height: inherit;
  352. }
  353. @media print {
  354. body { font-size: 100%; }
  355. a:after { content: " (" attr(href) ")"; }
  356. a, a:link, a:visited, a:after {
  357. text-decoration: underline;
  358. text-shadow: none !important;
  359. background-image: none !important;
  360. background: white;
  361. color: black;
  362. }
  363. abbr[title] { border-bottom: 0; }
  364. abbr[title]:after { content: " (" attr(title) ")"; }
  365. img { page-break-inside: avoid; }
  366. @page { margin: 2cm .5cm; }
  367. h1, h2, h3 { page-break-after: avoid; }
  368. p3 { orphans: 3; widows: 3; }
  369. img {
  370. max-width: 250px !important;
  371. max-height: 250px !important;
  372. }
  373. nav, aside { display: none; }
  374. }
  375. ul.with_columns {
  376. column-count: 1;
  377. }
  378. @media (min-width: 20em) {
  379. ul.with_columns {
  380. column-count: 2;
  381. }
  382. }
  383. @media (min-width: 50em) {
  384. ul.with_columns {
  385. column-count: 3;
  386. }
  387. }
  388. ul.with_two_columns {
  389. column-count: 1;
  390. }
  391. @media (min-width: 20em) {
  392. ul.with_two_columns {
  393. column-count: 1;
  394. }
  395. }
  396. @media (min-width: 50em) {
  397. ul.with_two_columns {
  398. column-count: 2;
  399. }
  400. }
  401. .gallery {
  402. display: flex;
  403. flex-wrap: wrap;
  404. justify-content: space-around;
  405. }
  406. .gallery figure img {
  407. margin-left: 1rem;
  408. margin-right: 1rem;
  409. }
  410. .gallery figure figcaption {
  411. font-family: 'ConcourseT3'
  412. }
  413. footer {
  414. font-family: 'ConcourseT3';
  415. display: flex;
  416. flex-direction: column;
  417. border-top: 3px solid white;
  418. padding: 4rem 0;
  419. background-color: #07486c;
  420. color: white;
  421. }
  422. footer > * {
  423. max-width: 50rem;
  424. margin: 0 auto;
  425. }
  426. footer a {
  427. color: #f1c40f;
  428. }
  429. footer .avatar {
  430. width: 200px;
  431. height: 200px;
  432. border-radius: 50%;
  433. float: left;
  434. -webkit-shape-outside: circle();
  435. shape-outside: circle();
  436. margin-right: 2rem;
  437. padding: 2px 5px 5px 2px;
  438. background: white;
  439. border-left: 1px solid #f1c40f;
  440. border-top: 1px solid #f1c40f;
  441. border-right: 5px solid #f1c40f;
  442. border-bottom: 5px solid #f1c40f;
  443. }
  444. </style>
  445. <h1 class="single">
  446. <span><a id="jumper" href="#jumpto" title="Un peu perdu ?">?</a></span>
  447. Inclusive Python
  448. <time>Publié le 29 mai 2017</time>
  449. </h1>
  450. <article class="single">
  451. <blockquote>
  452. <p>After 12 years of hacking in Python, what did I learn the hard way? From biology to the web, across startups and now French government, I realized one thing: making your code resilient requires empathy.</p>
  453. </blockquote>
  454. <p><em>It is the subject of a <a href="/david/talks/">talk</a> (<a href="/static/david/talks/inclusive-python.pdf">slides</a>) I gave at the <a href="http://montrealpython.org/en/">Montreal-Python</a> <a href="https://www.meetup.com/fr-FR/Montreal-Python/events/240094945/">meetup</a>.</em></p>
  455. <p>I’ve been using Python for more than a decade now. Such a ride. And still, time doesn’t really matter. It’s more the diversity of projects and interactions that made me who I am <a href="/david/blog/2016/inclusive-developer/">as a developer</a>. As such, I’m more and more concerned about the life of the code than ever. The transmission of the associated knowledge is the key to success of a project and to achieve this you have to think as a team. <strong>Lone wolves are burning out with their products.</strong> And it’s a real loss of energy. And happiness. And that sucks.</p>
  456. <p>But first, let’s define <em>inclusive</em>. Given the <a href="https://en.wiktionary.org/wiki/inclusive">Wiktionary</a> the first definition is:</p>
  457. <blockquote>
  458. <p>Including (almost) everything within its scope.</p>
  459. </blockquote>
  460. <p>For this article, I would like to slightly rephrase that definition:</p>
  461. <blockquote>
  462. <p>Including (almost) every<em>body</em> within its scope. </p>
  463. </blockquote>
  464. <p>I prefer that definition because <strong>coding is a social and political act.</strong> As such, each and every line of Python you produce should be put into that context. With whom. And why.</p>
  465. <p>So, how do you make everybody capable of working with you(r Python code)?</p>
  466. <h2>Include yourself</h2>
  467. <blockquote>
  468. <p>Yesterday I was clever, so I wanted to change the world. Today I am wise, so I am changing myself. — Jalaluddin Rumi</p>
  469. </blockquote>
  470. <p>That might seem obvious but do yourself a favour and do not reject yourself from your own code! We all have (please confirm :p) a project with no tests, no docs and yet critical and running in production that you have to maintain. Reshaping the project is not an option because you are short on attention/budget so it became a patchwork of ugly bug fixes. At that point, even you are unable to fix something without a week of procrastination to avoid that painful task. <strong>The challenge is not technical but the amount of motivation required is tremendous.</strong></p>
  471. <p>Try to be empathetic with a <strike>older</strike> wiser self. Ease the installation process, reduce dependencies, have fixtures. Document, automate, speed up the feedback loop when you are modifying something. All <a href="/david/blog/2015/collaboration-technique/">basic things</a> that I rarely saw well implemented (including my projects).</p>
  472. <h2>Include your colleagues</h2>
  473. <blockquote>
  474. <p>— “But if all of our programmers are pairing, won’t they write half as much code?”<br />
  475. — “No, hopefully they’ll write even less than that.”</p>
  476. <p><cite><em><a href="https://twitter.com/benrady/status/817430925176958977">Ben Rady</a></em></cite></p>
  477. </blockquote>
  478. <p>Being part of a team is a way to duplicate the knowledge around the project. And that’s clearly not a lack of time or energy when you see the turn-over within our profession. I see three ways to do it:</p>
  479. <ol>
  480. <li><strong>before</strong>: discussing strategies all together regularly, your mileage may vary on the frequency. The whole team needs to have a clear picture of what will be developed and <em>why</em>.</li>
  481. <li><strong>during</strong>: pair-programming and/or quick sessions to discuss a particular issue mainly focused on the <em>how</em>.</li>
  482. <li><strong>after</strong>: performing code-reviews and user-testing on each and every pull/merge-request. Check that the “why” of point 1. has been addressed and tested. Do not hesitate to trash everything at that point if it’s not relevant anymore.</li>
  483. </ol>
  484. <p>Besides that, newcomers are a chance to rethink together a better process to onboard people. It only happens once per people, do not miss it and block at least half a day dedicated to that task. <em>Observe</em> them installing your project and trying to figure out how to make it run. <strong>Observe, do not help, do not say anything, let them find out alone.</strong> It’s not a user-testing session but a developer one. Collect everything to improve the developer experience later. Once the task is performed or worse your colleague is stuck, it’s time to discuss of the improvements. Is that a documentation issue? Or an environment one? Are you really explaining the purpose of your project? Which are the communication channels? And so on. We all have an <em>illusion</em> of the simplicity of our processes until they confront the diversity of others’ experiences.</p>
  485. <p><strong>The knowledge of your product is in your team, not in your code.</strong> We probably need new practices to get rid of that situation, it’s still too hard to find the right cursor between documenting and delivering value. Not only sharing how it works but why it failed and how do we addressed it at that time.</p>
  486. <h2>Include your (re)users</h2>
  487. <blockquote>
  488. <p>My suggestions can be expensive in time, money and energy. When you’re building something for the first time, all of this comes down to you. Focus on the documentation in the beginning. By doing that, you’ll create a welcoming place for others and then they can start helping you with the rest of it.</p>
  489. <p><cite><em><a href="https://the-pastry-box-project.net/charlotte-spencer/2015-september-16">Lowering the barriers</a></em> (<a href="/david/cache/3cfbe249e4ec23ee28c6c3af7633e5b1/">cache</a>)</cite></p>
  490. </blockquote>
  491. <p>This is a particular case that might be biased by my situation but when you are open-sourcing your developments and working for <strike>a government</strike> citizens you want people to be able to contribute to your work one way or another. Lowering the barriers of the contributions is still very hard.</p>
  492. <p><a href="https://medium.com/@kentcdodds/first-timers-only-78281ea47455">Labelling some easy-picking issues</a> (<a href="/david/cache/51ba770c8e8142bac33da33354fad29b/">cache</a>) might be worth it and your reactivity to answer to declared issues is key. Especially by people who just created an account just to submit them. Which does happen more than I expected in my case! Performing pedagogic reviews might be worth it on the long term to help contributors level up and produce better code with you.</p>
  493. <p>Note: if your project only runs on top-of-the-market computers and requires to download megabytes of dependencies, you are closing the door to a lot of potential contributors.</p>
  494. <h2>Include maintainers</h2>
  495. <blockquote>
  496. <p>While I empathize with maintainers burning out and asking for support, trying to tackle sustainability from a maintainer centric view is a to paddle against the flow of the river. We continue to see barriers to adoption and participation fall away, enabling a new generation of contributors to be involved as long as we can view them as part of the solution rather than the problem itself.</p>
  497. <p>Developers like to think they code their way out of any problem. We know how to scale servers but most of us are inexperienced with scaling people.</p>
  498. <p><cite><em><a href="https://medium.com/open-source-communities/maintainer-vs-community-97edc28387ad">Maintainer vs. Community</a></em> (<a href="/david/cache/4d5851d18f4b3e893490b3910de2597f/">cache</a>)</cite></p>
  499. </blockquote>
  500. <p>Each and every time you contribute to an open-source project, you give your technical debt to a maintainer. Sad but true so help them with tests and documentation too! Lowering the barriers to other contributors is a way to increase the sustainability of the project which directly benefits to you.</p>
  501. <p>As a maintainer, try to involve more people in the governance and maintenance of your project (I’m terrible at this…). This is somehow your escape lane because interest in projects will vanish from time to time. If you are the only one keeping the keys it will be lost forever once abandoned. At least, be a <a href="https://brson.github.io/2017/04/05/minimally-nice-maintainer">Minimally-nice Open Source Software Maintainer</a> (<a href="/david/cache/f86b54bf25411c04eb538befd6ebc856/">cache</a>).</p>
  502. <h2>Include beginners</h2>
  503. <blockquote>
  504. <p>Write code for complex logic so elegantly simple that it won’t make you look smart.</p>
  505. </blockquote>
  506. <p>Think about it each and every time you plan to add a metaclass, a signal, a decorator or introduce the latest hyped lib to name a few. The beauty of your code is somewhat ugly to somebody having a hard time understanding these concepts. Really, nobody will blame you for writing dumb code that anyone understand at first sight. Not to mention yourself when you are stressed by a deadline or reopening this code six months later.</p>
  507. <p><strong>The best programmers write code beginners understand.</strong> It is as simple as this. You can write idiomatic Python and still be readable by a developer using another programming language. Make it a target and enjoy <a href="/david/blog/2016/code-reviews-croisees/">crossed code-reviews</a> to identify these issues.</p>
  508. <p>Document tools you use for your project (<a href="http://pycodestyle.pycqa.org/en/latest/">pycodestyle</a>, <a href="http://timothycrosley.github.io/isort/">isort</a> to name a few), you can even add pre-commit hooks or automated checks <em>via</em> the pull/merge-request.</p>
  509. <h2>Include citizens</h2>
  510. <blockquote>
  511. <p>In an ever-more intricate and connected world, where software plays a larger and larger role in everyday life, it’s irresponsible to speak of coding as a lightweight activity. Software is not simply lines of code, nor is it blandly technical. In just a few years, understanding programming will be an indispensable part of active citizenship.</p>
  512. <p><cite><em><a href="https://aeon.co/ideas/coding-is-not-fun-it-s-technically-and-ethically-complex">Coding is not ‘fun’, it’s technically and ethically complex</a></em> (<a href="/david/cache/8b81a17dd00142dd98a251d2ca723716/">cache</a>)</cite></p>
  513. </blockquote>
  514. <p>I’m not only talking about fixing typos in documentation here. How do you include people in the process of building the product? How do you make them aware that they can have a direct impact on what is done with their taxes? That part is yet to be experimented because it requires a shift in minds. A <a href="/david/blog/2016/delivery-values/">nation is a cooperative that scaled</a> and as such each individual should act as part of a community.</p>
  515. <p>Maybe some day, micro-payments will be available to remunerate the time spent by citizens on collective projects but — apart from the technical issue — the complexity to evaluate the value of each contribution is a real problem.</p>
  516. <h2>Include conclusion</h2>
  517. <blockquote>
  518. <p>An important point of maturity as a developer is realizing that writing code is a relatively insignificant part of software development.</p>
  519. <p><cite><em><a href="https://twitter.com/srbaker/status/831990107586646018">Steven R. Baker</a></em></cite></p>
  520. </blockquote>
  521. <p>Embrace the diversity of others point of views, make them count. <strong>Your code is not a book, it’s a continuous discussion on a given goal.</strong> You are maybe familiar with the concept of <a href="https://en.wikipedia.org/wiki/Progressive_enhancement">progressive enhancement</a>, you can push the first draft of your code/documentation as a proof of concept and then progressively enhance the inclusivity of your project too. As for <a href="https://learning.mozilla.org/en-US/web-literacy">Web literacy</a>, it’s a matter of Python literacy. We have the chance to use a language that is easy to learn, let’s be worthy of it.</p>
  522. <p>I had to confess that I’m not doing half of the things I described, it is mostly self-criticism here. And that’s OK, really, because <strong>inclusiveness is a journey</strong>. Just be sure to keep moving toward a direction that makes you feel good at the end of each and every day.</p>
  523. <h2>Include discussions</h2>
  524. <blockquote>
  525. <p>What makes a good pull-request for a developer and a good code review from a maintainer?</p>
  526. </blockquote>
  527. <p>On the developer side, documenting clearly what is the aim of your contribution is key. It looks obvious but that’s not always the case. Adding clean code, tests and documentation is great. We use to add an entry in the changelog with every pull-request nowadays to ease the communication with our international team.</p>
  528. <p>A good code review is a one that is both respectful and engaging. You can <a href="https://blog.alphasmanifesto.com/2016/11/17/how-to-perform-a-good-code-review/">be inspired</a> (<a href="/david/cache/4f5f1314047ae271ac5f080f6c43bff4/">cache</a>) by <a href="http://blog.fogcreek.com/increase-defect-detection-with-our-code-review-checklist-example/">a checklist</a> (<a href="/david/cache/3177652e7a1a4808cc303cb58246cbf3/">cache</a>) but once again, don’t take it too dogmatically. It’s up on your team to define its own check points.</p>
  529. <blockquote>
  530. <p>How do you handle technical debt and contributions?</p>
  531. </blockquote>
  532. <p>We actually (and sadly) don’t have pull-requests related to technical debt clean up. We mostly initiate that kind of change during workweeks (about twice per year) when everybody is in the same room to coordinate and evaluate alternatives together.</p>
  533. </article>
  534. <figure class="image" property="schema:image">
  535. <img src="/static/david/blog/2017/inclusive-python.jpg" alt="" />
  536. </figure>
  537. <nav id="jumpto">
  538. <p>
  539. <a rel=prev href="/david/blog/2017/espace-temps/">← Espace et temps</a> | <a href="/david/blog/" title="Retour à la liste des expériences">↑</a> | <a rel=next href="/david/blog/2017/sur-la-route/">Sur la route →</a>
  540. </p>
  541. </nav>
  542. <footer>
  543. <div>
  544. <img src="/static/david/david-larlet-avatar.jpg" loading="lazy" class="avatar" width="200" height="200">
  545. <p>
  546. Bonjour/Hi!
  547. 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>
  548. 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>).
  549. </p>
  550. <p>
  551. 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>.
  552. </p>
  553. <p>
  554. Les dernières publications hebdomadaires sont :
  555. </p>
  556. <ul class="with_columns">
  557. <li>
  558. <a href="/david/stream/2019/12/31/">Merci</a>
  559. </li>
  560. <li>
  561. <a href="/david/stream/2019/12/27/">Intemporels</a>
  562. </li>
  563. <li>
  564. <a href="/david/stream/2019/12/24/">Outils</a>
  565. </li>
  566. <li>
  567. <a href="/david/stream/2019/12/17/">Origines</a>
  568. </li>
  569. <li>
  570. <a href="/david/stream/2019/12/10/">Publier</a>
  571. </li>
  572. <li>
  573. <a href="/david/stream/2019/12/03/">En forêt</a>
  574. </li>
  575. <li>
  576. <a href="/david/stream/2019/11/26/">Ecocentric</a>
  577. </li>
  578. <li>
  579. <a href="/david/stream/2019/11/19/">Se livrer</a>
  580. </li>
  581. <li>
  582. <a href="/david/stream/2019/11/12/">Dépendances</a>
  583. </li>
  584. <li>
  585. <a href="/david/stream/2019/11/05/">Positif</a>
  586. </li>
  587. <li>
  588. <a href="/david/stream/2019/10/29/">Dettes</a>
  589. </li>
  590. <li>
  591. <a href="/david/stream/2019/10/22/">Privilèges</a>
  592. </li>
  593. <li>
  594. <a href="/david/stream/2019/10/15/">Discrétion</a>
  595. </li>
  596. <li>
  597. <a href="/david/stream/2019/10/08/">Désespérance</a>
  598. </li>
  599. <li>
  600. <a href="/david/stream/2019/10/01/">Présent</a>
  601. </li>
  602. <li>
  603. <a href="/david/stream/2019/09/24/">Manifester</a>
  604. </li>
  605. <li>
  606. <a href="/david/stream/2019/09/17/">Arpenter</a>
  607. </li>
  608. <li>
  609. <a href="/david/stream/2019/09/10/">Nostalgie</a>
  610. </li>
  611. <li>
  612. <a href="/david/stream/2019/09/03/">Déconstruire</a>
  613. </li>
  614. <li>
  615. <a href="/david/stream/2019/08/27/">Documenter</a>
  616. </li>
  617. <li>
  618. <a href="/david/stream/2019/08/20/">Frustration</a>
  619. </li>
  620. <li>
  621. <a href="/david/stream/2019/08/13/">Holisme</a>
  622. </li>
  623. <li>
  624. <a href="/david/stream/2019/08/06/">1%</a>
  625. </li>
  626. <li>
  627. <a href="/david/stream/2019/07/30/">Exemplarité</a>
  628. </li>
  629. <li>
  630. <a href="/david/stream/2019/07/23/">Timelines</a>
  631. </li>
  632. <li>
  633. <a href="/david/stream/2019/07/16/">Écoute</a>
  634. </li>
  635. <li>
  636. <a href="/david/stream/2019/07/02/">Anxiété</a>
  637. </li>
  638. <li>
  639. <a href="/david/stream/2019/06/21/">À lier</a>
  640. </li>
  641. <li>
  642. <a href="/david/stream/2019/06/14/">Pauvreté</a>
  643. </li>
  644. <li>
  645. <a href="/david/stream/2019/06/07/">Amateur</a>
  646. </li>
  647. <li>
  648. <a href="/david/stream/2019/05/31/">Pollution</a>
  649. </li>
  650. <li>
  651. <a href="/david/stream/2019/05/24/">Apaisement</a>
  652. </li>
  653. <li>
  654. <a href="/david/stream/2019/05/10/">Folie</a>
  655. </li>
  656. <li>
  657. <a href="/david/stream/2019/05/03/">Sympathie</a>
  658. </li>
  659. <li>
  660. <a href="/david/stream/2019/04/12/">Péremption</a>
  661. </li>
  662. <li>
  663. <a href="/david/stream/2019/04/05/">Définitions</a>
  664. </li>
  665. <li>
  666. <a href="/david/stream/2019/03/29/">Acceptation</a>
  667. </li>
  668. <li>
  669. <a href="/david/stream/2019/03/22/">Dissonance</a>
  670. </li>
  671. <li>
  672. <a href="/david/stream/2019/03/15/">Reconnaissance</a>
  673. </li>
  674. <li>
  675. <a href="/david/stream/2019/03/08/">Lecture</a>
  676. </li>
  677. <li>
  678. <a href="/david/stream/2019/03/01/">Journaux</a>
  679. </li>
  680. <li>
  681. <a href="/david/stream/2019/02/22/">Écriture</a>
  682. </li>
  683. <li>
  684. <a href="/david/stream/2019/02/15/">Kyriarchie</a>
  685. </li>
  686. <li>
  687. <a href="/david/stream/2019/02/08/">Mots-serrures</a>
  688. </li>
  689. <li>
  690. <a href="/david/stream/2019/02/01/">Sans voie</a>
  691. </li>
  692. <li>
  693. <a href="/david/stream/2019/01/25/">Auto-diagnostic</a>
  694. </li>
  695. <li>
  696. <a href="/david/stream/2019/01/18/">Agilité</a>
  697. </li>
  698. <li>
  699. <a href="/david/stream/2019/01/11/">Métaphores</a>
  700. </li>
  701. <li>
  702. <a href="/david/stream/2019/01/04/">Balbutiements</a>
  703. </li>
  704. </ul>
  705. <p>
  706. Voici quelques articles choisis :
  707. <a href="/david/blog/2019/faire-equipe/" title="Accéder à l’article complet">Faire équipe</a>,
  708. <a href="/david/blog/2018/bivouac-automnal/" title="Accéder à l’article complet">Bivouac automnal</a>,
  709. <a href="/david/blog/2018/commodite-effondrement/" title="Accéder à l’article complet">Commodité et effondrement</a>,
  710. <a href="/david/blog/2017/donnees-communs/" title="Accéder à l’article complet">Des données aux communs</a>,
  711. <a href="/david/blog/2016/accompagner-enfant/" title="Accéder à l’article complet">Accompagner un enfant</a>,
  712. <a href="/david/blog/2016/senior-developer/" title="Accéder à l’article complet">Senior developer</a>,
  713. <a href="/david/blog/2016/illusion-sociale/" title="Accéder à l’article complet">L’illusion sociale</a>,
  714. <a href="/david/blog/2016/instantane-scopyleft/" title="Accéder à l’article complet">Instantané Scopyleft</a>,
  715. <a href="/david/blog/2016/enseigner-web/" title="Accéder à l’article complet">Enseigner le Web</a>,
  716. <a href="/david/blog/2016/simplicite-defaut/" title="Accéder à l’article complet">Simplicité par défaut</a>,
  717. <a href="/david/blog/2016/minimalisme-esthetique/" title="Accéder à l’article complet">Minimalisme et esthétique</a>,
  718. <a href="/david/blog/2014/un-web-omni-present/" title="Accéder à l’article complet">Un web omni-présent</a>,
  719. <a href="/david/blog/2014/manifeste-developpeur/" title="Accéder à l’article complet">Manifeste de développeur</a>,
  720. <a href="/david/blog/2013/confort-convivialite/" title="Accéder à l’article complet">Confort et convivialité</a>,
  721. <a href="/david/blog/2013/testament-numerique/" title="Accéder à l’article complet">Testament numérique</a>,
  722. et <a href="/david/blog/" title="Accéder aux archives">bien d’autres…</a>
  723. </p>
  724. <p>
  725. 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>.
  726. </p>
  727. <p>
  728. Je ne traque pas ta navigation mais mon
  729. <abbr title="Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33.184162340">hébergeur</abbr>
  730. conserve des logs d’accès.
  731. </p>
  732. </div>
  733. </footer>
  734. <script type="text/javascript">
  735. ;(_ => {
  736. const jumper = document.getElementById('jumper')
  737. jumper.addEventListener('click', e => {
  738. e.preventDefault()
  739. const anchor = e.target.getAttribute('href')
  740. const targetEl = document.getElementById(anchor.substring(1))
  741. targetEl.scrollIntoView({behavior: 'smooth'})
  742. })
  743. })()
  744. </script>
  745. <script>
  746. /* Service workers */
  747. if (navigator.serviceWorker) {
  748. window.addEventListener('load', function () {
  749. var selector = 'a[href^="/david/cache/"], a[rel=prev], a[rel=next]'
  750. function sendLinks (selector) {
  751. var links = [].slice.call(document.querySelectorAll(selector)).map(function (link) {
  752. return link.getAttribute('href')
  753. })
  754. links.push(location.pathname) // Put the current page in cache too.
  755. navigator.serviceWorker.controller.postMessage({ links: links })
  756. }
  757. navigator.serviceWorker.getRegistration()
  758. .then(function (registration) {
  759. if (!registration || !navigator.serviceWorker.controller) {
  760. return navigator.serviceWorker.register('/serviceworker.js')
  761. .then(navigator.serviceWorker.ready)
  762. .then(function () {
  763. console.log('[ServiceWorker] Ready to go!')
  764. })
  765. .catch(console.error.bind(console))
  766. } else {
  767. console.log('[ServiceWorker] Send links via registration')
  768. sendLinks(selector)
  769. }
  770. })
  771. navigator.serviceWorker.addEventListener('controllerchange', function () {
  772. console.log('[ServiceWorker] Send links via controller change')
  773. sendLinks(selector)
  774. })
  775. navigator.serviceWorker.addEventListener('message', function (event) {
  776. var link = document.querySelector('a[href="' + event.data.link + '"]')
  777. if (event.data.status && link) {
  778. link.style.backgroundColor = '#2d7474'
  779. link.style.color = '#f0f0ea'
  780. link.setAttribute('title', 'En cache pour consultation sans connexion')
  781. }
  782. })
  783. })
  784. } else {
  785. console.warn('[ServiceWorker] No cache for old browsers.')
  786. }
  787. </script>