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

5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  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,minimum-scale=1,initial-scale=1,shrink-to-fit=no">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>BETTER LEARNING THROUGH CODE REVIEWS (archive) — 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. <meta name="robots" content="noindex, nofollow">
  28. <meta content="origin-when-cross-origin" name="referrer">
  29. <!-- Canonical URL for SEO purposes -->
  30. <link rel="canonical" href="http://capgemini.github.io/learning/better-learning-code-reviews/">
  31. <style>
  32. /* http://meyerweb.com/eric/tools/css/reset/ */
  33. html, body, div, span,
  34. h1, h2, h3, h4, h5, h6, p, blockquote, pre,
  35. a, abbr, address, big, cite, code,
  36. del, dfn, em, img, ins,
  37. small, strike, strong, tt, var,
  38. dl, dt, dd, ol, ul, li,
  39. fieldset, form, label, legend,
  40. table, caption, tbody, tfoot, thead, tr, th, td,
  41. article, aside, canvas, details, embed,
  42. figure, figcaption, footer, header, hgroup,
  43. menu, nav, output, ruby, section, summary,
  44. time, mark, audio, video {
  45. margin: 0;
  46. padding: 0;
  47. border: 0;
  48. font-size: 100%;
  49. font: inherit;
  50. vertical-align: baseline;
  51. }
  52. /* HTML5 display-role reset for older browsers */
  53. article, aside, details, figcaption, figure,
  54. footer, header, hgroup, menu, nav, section { display: block; }
  55. body { line-height: 1; }
  56. blockquote, q { quotes: none; }
  57. blockquote:before, blockquote:after,
  58. q:before, q:after {
  59. content: '';
  60. content: none;
  61. }
  62. table {
  63. border-collapse: collapse;
  64. border-spacing: 0;
  65. }
  66. /* http://practicaltypography.com/equity.html */
  67. /* https://calendar.perfplanet.com/2016/no-font-face-bulletproof-syntax/ */
  68. /* https://www.filamentgroup.com/lab/js-web-fonts.html */
  69. @font-face {
  70. font-family: 'EquityTextB';
  71. src: url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff2') format('woff2'),
  72. url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff') format('woff');
  73. font-weight: 300;
  74. font-style: normal;
  75. font-display: swap;
  76. }
  77. @font-face {
  78. font-family: 'EquityTextB';
  79. src: url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff2') format('woff2'),
  80. url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff') format('woff');
  81. font-weight: 300;
  82. font-style: italic;
  83. font-display: swap;
  84. }
  85. @font-face {
  86. font-family: 'EquityTextB';
  87. src: url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff2') format('woff2'),
  88. url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff') format('woff');
  89. font-weight: 700;
  90. font-style: normal;
  91. font-display: swap;
  92. }
  93. @font-face {
  94. font-family: 'ConcourseT3';
  95. src: url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff2') format('woff2'),
  96. url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff') format('woff');
  97. font-weight: 300;
  98. font-style: normal;
  99. font-display: swap;
  100. }
  101. /* http://practice.typekit.com/lesson/caring-about-opentype-features/ */
  102. body {
  103. /* http://www.cssfontstack.com/ Palatino 99% Win 86% Mac */
  104. font-family: "EquityTextB", Palatino, serif;
  105. background-color: #f0f0ea;
  106. color: #07486c;
  107. font-kerning: normal;
  108. -moz-osx-font-smoothing: grayscale;
  109. -webkit-font-smoothing: subpixel-antialiased;
  110. text-rendering: optimizeLegibility;
  111. font-variant-ligatures: common-ligatures contextual;
  112. font-feature-settings: "kern", "liga", "clig", "calt";
  113. }
  114. pre, code, kbd, samp, var, tt {
  115. font-family: 'TriplicateT4c', monospace;
  116. }
  117. em {
  118. font-style: italic;
  119. color: #323a45;
  120. }
  121. strong {
  122. font-weight: bold;
  123. color: black;
  124. }
  125. nav {
  126. background-color: #323a45;
  127. color: #f0f0ea;
  128. display: flex;
  129. justify-content: space-around;
  130. padding: 1rem .5rem;
  131. }
  132. nav:last-child {
  133. border-bottom: 1vh solid #2d7474;
  134. }
  135. nav a {
  136. color: #f0f0ea;
  137. }
  138. nav abbr {
  139. border-bottom: 1px dotted white;
  140. }
  141. h1 {
  142. border-top: 1vh solid #2d7474;
  143. border-bottom: .2vh dotted #2d7474;
  144. background-color: #e3e1e1;
  145. color: #323a45;
  146. text-align: center;
  147. padding: 5rem 0 4rem 0;
  148. width: 100%;
  149. font-family: 'ConcourseT3';
  150. display: flex;
  151. flex-direction: column;
  152. }
  153. h1.single {
  154. padding-bottom: 10rem;
  155. }
  156. h1 span {
  157. position: absolute;
  158. top: 1vh;
  159. left: 20%;
  160. line-height: 0;
  161. }
  162. h1 span a {
  163. line-height: 1.7;
  164. padding: 1rem 1.2rem .6rem 1.2rem;
  165. border-radius: 0 0 6% 6%;
  166. background: #2d7474;
  167. font-size: 1.3rem;
  168. color: white;
  169. text-decoration: none;
  170. }
  171. h2 {
  172. margin: 4rem 0 1rem;
  173. border-top: .2vh solid #2d7474;
  174. padding-top: 1vh;
  175. }
  176. h3 {
  177. text-align: center;
  178. margin: 3rem 0 .75em;
  179. }
  180. hr {
  181. height: .4rem;
  182. width: .4rem;
  183. border-radius: .4rem;
  184. background: #07486c;
  185. margin: 2.5rem auto;
  186. }
  187. time {
  188. display: bloc;
  189. margin-left: 0 !important;
  190. }
  191. ul, ol {
  192. margin: 2rem;
  193. }
  194. ul {
  195. list-style-type: square;
  196. }
  197. a {
  198. text-decoration-skip-ink: auto;
  199. text-decoration-thickness: 0.05em;
  200. text-underline-offset: 0.09em;
  201. }
  202. article {
  203. max-width: 50rem;
  204. display: flex;
  205. flex-direction: column;
  206. margin: 2rem auto;
  207. }
  208. article.single {
  209. border-top: .2vh dotted #2d7474;
  210. margin: -6rem auto 1rem auto;
  211. background: #f0f0ea;
  212. padding: 2rem;
  213. }
  214. article p:last-child {
  215. margin-bottom: 1rem;
  216. }
  217. p {
  218. padding: 0 .5rem;
  219. margin-left: 3rem;
  220. }
  221. p + p,
  222. figure + p {
  223. margin-top: 2rem;
  224. }
  225. blockquote {
  226. background-color: #e3e1e1;
  227. border-left: .5vw solid #2d7474;
  228. display: flex;
  229. flex-direction: column;
  230. align-items: center;
  231. padding: 1rem;
  232. margin: 1.5rem;
  233. }
  234. blockquote cite {
  235. font-style: italic;
  236. }
  237. blockquote p {
  238. margin-left: 0;
  239. }
  240. figure {
  241. border-top: .2vh solid #2d7474;
  242. background-color: #e3e1e1;
  243. text-align: center;
  244. padding: 1.5rem 0;
  245. margin: 1rem 0 0;
  246. font-size: 1.5rem;
  247. width: 100%;
  248. }
  249. figure img {
  250. max-width: 250px;
  251. max-height: 250px;
  252. border: .5vw solid #323a45;
  253. padding: 1px;
  254. }
  255. figcaption {
  256. padding: 1rem;
  257. line-height: 1.4;
  258. }
  259. aside {
  260. display: flex;
  261. flex-direction: column;
  262. background-color: #e3e1e1;
  263. padding: 1rem 0;
  264. border-bottom: .2vh solid #07486c;
  265. }
  266. aside p {
  267. max-width: 50rem;
  268. margin: 0 auto;
  269. }
  270. /* https://fvsch.com/code/css-locks/ */
  271. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  272. font-size: 1rem;
  273. line-height: calc( 1.5em + 0.2 * 1rem );
  274. }
  275. h1 {
  276. font-size: 1.9rem;
  277. line-height: calc( 1.2em + 0.2 * 1rem );
  278. }
  279. h2 {
  280. font-size: 1.6rem;
  281. line-height: calc( 1.3em + 0.2 * 1rem );
  282. }
  283. h3 {
  284. font-size: 1.35rem;
  285. line-height: calc( 1.4em + 0.2 * 1rem );
  286. }
  287. @media (min-width: 20em) {
  288. /* The (100vw - 20rem) / (50 - 20) part
  289. resolves to 0-1rem, depending on the
  290. viewport width (between 20em and 50em). */
  291. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  292. font-size: calc( 1rem + .6 * (100vw - 20rem) / (50 - 20) );
  293. line-height: calc( 1.5em + 0.2 * (100vw - 50rem) / (20 - 50) );
  294. margin-left: 0;
  295. }
  296. h1 {
  297. font-size: calc( 1.9rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  298. line-height: calc( 1.2em + 0.2 * (100vw - 50rem) / (20 - 50) );
  299. }
  300. h2 {
  301. font-size: calc( 1.5rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  302. line-height: calc( 1.3em + 0.2 * (100vw - 50rem) / (20 - 50) );
  303. }
  304. h3 {
  305. font-size: calc( 1.35rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  306. line-height: calc( 1.4em + 0.2 * (100vw - 50rem) / (20 - 50) );
  307. }
  308. }
  309. @media (min-width: 50em) {
  310. /* The right part of the addition *must* be a
  311. rem value. In this example we *could* change
  312. the whole declaration to font-size:2.5rem,
  313. but if our baseline value was not expressed
  314. in rem we would have to use calc. */
  315. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  316. font-size: calc( 1rem + .6 * 1rem );
  317. line-height: 1.5em;
  318. }
  319. p, li, pre, details {
  320. margin-left: 3rem;
  321. }
  322. h1 {
  323. font-size: calc( 1.9rem + 1.5 * 1rem );
  324. line-height: 1.2em;
  325. }
  326. h2 {
  327. font-size: calc( 1.5rem + 1.5 * 1rem );
  328. line-height: 1.3em;
  329. }
  330. h3 {
  331. font-size: calc( 1.35rem + 1.5 * 1rem );
  332. line-height: 1.4em;
  333. }
  334. figure img {
  335. max-width: 500px;
  336. max-height: 500px;
  337. }
  338. }
  339. figure.unsquared {
  340. margin-bottom: 1.5rem;
  341. }
  342. figure.unsquared img {
  343. height: inherit;
  344. }
  345. @media print {
  346. body { font-size: 100%; }
  347. a:after { content: " (" attr(href) ")"; }
  348. a, a:link, a:visited, a:after {
  349. text-decoration: underline;
  350. text-shadow: none !important;
  351. background-image: none !important;
  352. background: white;
  353. color: black;
  354. }
  355. abbr[title] { border-bottom: 0; }
  356. abbr[title]:after { content: " (" attr(title) ")"; }
  357. img { page-break-inside: avoid; }
  358. @page { margin: 2cm .5cm; }
  359. h1, h2, h3 { page-break-after: avoid; }
  360. p3 { orphans: 3; widows: 3; }
  361. img {
  362. max-width: 250px !important;
  363. max-height: 250px !important;
  364. }
  365. nav, aside { display: none; }
  366. }
  367. ul.with_columns {
  368. column-count: 1;
  369. }
  370. @media (min-width: 20em) {
  371. ul.with_columns {
  372. column-count: 2;
  373. }
  374. }
  375. @media (min-width: 50em) {
  376. ul.with_columns {
  377. column-count: 3;
  378. }
  379. }
  380. ul.with_two_columns {
  381. column-count: 1;
  382. }
  383. @media (min-width: 20em) {
  384. ul.with_two_columns {
  385. column-count: 1;
  386. }
  387. }
  388. @media (min-width: 50em) {
  389. ul.with_two_columns {
  390. column-count: 2;
  391. }
  392. }
  393. .gallery {
  394. display: flex;
  395. flex-wrap: wrap;
  396. justify-content: space-around;
  397. }
  398. .gallery figure img {
  399. margin-left: 1rem;
  400. margin-right: 1rem;
  401. }
  402. .gallery figure figcaption {
  403. font-family: 'ConcourseT3'
  404. }
  405. footer {
  406. font-family: 'ConcourseT3';
  407. display: flex;
  408. flex-direction: column;
  409. border-top: 3px solid white;
  410. padding: 4rem 0;
  411. background-color: #07486c;
  412. color: white;
  413. }
  414. footer > * {
  415. max-width: 50rem;
  416. margin: 0 auto;
  417. }
  418. footer a {
  419. color: #f1c40f;
  420. }
  421. footer .avatar {
  422. width: 200px;
  423. height: 200px;
  424. border-radius: 50%;
  425. float: left;
  426. -webkit-shape-outside: circle();
  427. shape-outside: circle();
  428. margin-right: 2rem;
  429. padding: 2px 5px 5px 2px;
  430. background: white;
  431. border-left: 1px solid #f1c40f;
  432. border-top: 1px solid #f1c40f;
  433. border-right: 5px solid #f1c40f;
  434. border-bottom: 5px solid #f1c40f;
  435. }
  436. </style>
  437. <h1>
  438. <span><a id="jumper" href="#jumpto" title="Un peu perdu ?">?</a></span>
  439. BETTER LEARNING THROUGH CODE REVIEWS (archive)
  440. <time>Pour la pérennité des contenus liés. Non-indexé, retrait sur simple email.</time>
  441. </h1>
  442. <section>
  443. <article>
  444. <h3><a href="http://capgemini.github.io/learning/better-learning-code-reviews/">Source originale du contenu</a></h3>
  445. <p>One of the main reasons I wanted to join a big company was the opportunity to learn. I wanted the chance to work on bigger projects with colleagues who’ve been there and done that, and to benefit from their experience.</p>
  446. <p>In the 4 years I’ve been at Capgemini, I’ve been lucky enough to get those opportunities, and for me, the thing that has been the most helpful in terms of my own learning has probably been code reviews - both other people reviewing my code, and me reviewing other people’s code.</p>
  447. <h2 id="why">Why?</h2>
  448. <p>Some people say <a href="https://ihofmann.wordpress.com/2012/10/12/five-reasons-why-structured-code-reviews-are-waste-of-money/">code reviews are a waste of time</a>, and if they’re talking about what code reviews used to be, I’d be inclined to agree. The idea of scheduling <a href="https://en.wikipedia.org/wiki/Fagan_inspection">a set of formal meetings</a> where a bunch of developers get together and go through a file line by line seems ludicrous nowadays.</p>
  449. <p>Thankfully, it doesn’t have to be like that any more. With modern tools, code reviews are far more efficient. They’re an integral part of our workflow at Capgemini, and are <a href="http://www.tsphethean.co.uk/blog/2013/11/28/Reviewing-code-reviews/">vital in improving the quality of our code</a>.</p>
  450. <h3 id="more-haste-less-speed">More haste, less speed</h3>
  451. <p>Velocity is a term that gets used a lot, and it’s generally agreed that high velocity is a good thing. But sometimes, when a team of developers gets into their stride, they can resemble a team of galloping horses. Too much change in a short space of time can be overwhelming, and it can sometimes be good to create a bottleneck to slow down the pace of change and make sure that the change is appropriate. Besides, code reviews and the improvement in quality they bring about can actually <a href="http://blog.codinghorror.com/code-reviews-just-do-it/">increase productivity</a>.</p>
  452. <h3 id="keep-it-clean">Keep it clean</h3>
  453. <p>Once bad code has entered the code base, it can be very difficult to get rid of it. You may think that you can take care of coding standards and unit tests once you’ve got a few more high-priority tickets out of the way, and got your project manager off your back, but the truth is that <a href="http://on-agile.blogspot.co.uk/2007/04/why-you-wont-fix-it-later.html">you probably won’t get round to tidying up later</a>.</p>
  454. <p>Code reviews are the ideal place to ask questions like:</p>
  455. <ul>
  456. <li>Does this code actually solve the right problem?</li>
  457. <li>Does it solve the problem in an appropriate way?</li>
  458. <li>Is there unit-test coverage?</li>
  459. <li>Is the code secure?</li>
  460. <li>Is it likely to introduce any bugs?</li>
  461. <li>Does it comply with relevant standards?</li>
  462. <li>Are there any relevant accessibility considerations?</li>
  463. </ul>
  464. <p>Don’t imagine that you can rely on the QA team to catch any bugs that might be lurking, or that the developers are too busy for this sort of thing. The test team have got enough to do already, without devs deploying shoddy code onto the test environment.</p>
  465. <h3 id="pour-encourager-les-autres">Pour encourager les autres</h3>
  466. <p>Code reviews are an ideal place to encourage a mindset of <a href="http://tech.trivago.com/2015/08/31/culture_of_quality/">caring about quality</a>. They’re an opportunity to reinforce positive values within the development team, and get everyone thinking about how the code base can be improved.</p>
  467. <p>The code review can also be a springboard for conversation, and an opportunity to explain the thinking behind a code change (although beware of the temptation to <a href="https://en.wikipedia.org/wiki/Parkinson%27s_law_of_triviality">bikeshed</a>).</p>
  468. <p>For these reasons, the reviewers shouldn’t just be the senior devs - quality is everybody’s responsibility. Similarly, the senior members of the team shouldn’t imagine that <a href="http://blog.8thcolor.com/en/2014/04/5-reasons-you-are-not-doing-code-reviews/">their code doesn’t need to be reviewed</a>. Reviewers don’t need to be the subject matter experts for that feature. Even if the review comments are “I don’t understand this code” - that’s a sign that the code may need more comments. In fact, code reviews are a great way to ease people into learning about new areas of your codebase.</p>
  469. <h3 id="lessons-learned">Lessons learned</h3>
  470. <p>Everyone makes mistakes, and if you don’t realise that it’s a mistake, you’ll never be able to learn.
  471. For junior developers, or even those with more experience, it’s easy to get into bad habits, especially if you’re used to working on your own. Pull requests can be a fantastic learning resource - a chance to see the workings of your colleagues’ minds, to consider alternative approaches to solving problems, and to ask why a particular approach has been chosen.</p>
  472. <h2 id="how">How?</h2>
  473. <p>Hopefully you see the value of doing code reviews, and either they’re part of your workflow already, or you’re planning to start doing them. So I’d like to share a few ideas about improving the quality of the code reviews, and hopefully that will help to improve the quality of the code itself.</p>
  474. <p>When we moved from SVN to Git a couple of years ago, we had the opportunity to put a system in place. By using a feature branch workflow, pull requests become part of the process, and in theory no piece of code should go live unless it’s been reviewed. So it’s important that your tools support you.</p>
  475. <p>Github pull requests are good as far as they go, but code review tools like <a href="https://www.atlassian.com/software/stash">Stash</a> provide more advanced features, which we’ve found to be really useful. For example:</p>
  476. <h4 id="approvals">Approvals</h4>
  477. <p>Reviewing isn’t just a case of looking at code, but of signing off that you’re happy for it to go live. Stash includes the notion of approvals, and allows you to require a certain number of approvals before the pull request can be merged.
  478. One important thing to check is whether the repo is set up so that approvals are cancelled when more changes are pushed to the branch - annoyingly, this doesn’t seem to be the default.</p>
  479. <h4 id="granular-permissions">Granular permissions</h4>
  480. <p>Per-branch permissions can be set up so that only certain members of the team can merge to the main branches - this helps to keep team leads aware of what changes are going to go live.</p>
  481. <h4 id="tasks">Tasks</h4>
  482. <p>Another nice feature of Stash is tasks - you can add a checkbox to a comment, and set your repo up so that pull requests can’t be merged while they have tasks outstanding. For instance, you can approve the pull request with the caveat that something needs to be fixed before it gets merged.</p>
  483. <p>One of the drawbacks of Github pull requests is that when someone pushes changes, the diff view will no longer show comments from previous versions, whereas Stash will still show comments on lines that haven’t changed since the comment was made. The other nice thing is that you can easily see which changes you’ve already viewed - especially useful in pull requests that go through a lot of iterations. A useful feature that was in Crucible (Atlassian’s SVN code review tool) but not in Stash, is an indicator of what percentage of the review each reviewer has viewed, so you could get an idea of whether you need to chase up the reviewers. Nice, but not enough to make me want to go back to SVN.</p>
  484. <h4 id="integration-and-automation">Integration and automation</h4>
  485. <p>The other good thing about Stash is that it plays nicely with our issue tracker. We have quite a granular workflow set up in Jira, and a lot of the transitions are automated. For example, when a pull request is created, the relevant ticket goes into “Code Review” status, and when the pull request is merged or declined, the status is updated again. We also have integration between Jenkins and Jira so that when the test environments are built, it updates the status of tickets pending build, and the QA team can see which tickets are ready for testing.</p>
  486. <p>This is great, because it means no more nagging people to update the status of their tickets - it’s easy to see the current state of play for any of our projects, and to trust that the status reflects the truth.</p>
  487. <p><a href="http://www.cgpgrey.com/blog/humans-need-not-apply">Computers are better at boring jobs than humans</a>. Boring jobs like checking that code comments are correctly punctuated and indented. I’ve written before about <a href="http://www.red-route.org/articles/keeping-clean-why-coding-standards-are-important">the importance of coding standards</a>, and while it may come across as pedantic, when code is written according to standards, it’s much easier to debug.</p>
  488. <p>Tools like <a href="https://github.com/brigade/overcommit">overcommit</a> make it simple to integrate code linters into your workflow, and in our <a href="/devops/developer-automation">standard Vagrant box</a>, there are pre-commit hooks in place to prevent commits which violate Drupal coding standards. So hopefully this saves reviewers (and the author of the code) from the dispiriting experience of dozens of comments about indentation - much better to get the machine to do the nagging for you.</p>
  489. <p>More importantly, you can set up a continuous integration server to make sure that the change isn’t breaking any tests. For example, whenever a developer pushes to our repos, it triggers Jenkins to run unit test builds on that branch. If your pull request has failed builds, it can’t be merged.</p>
  490. <h3 id="check-yourself-before-you-wreck-yourself">Check yourself before you wreck yourself</h3>
  491. <p>When (or even before) you create a pull request, look at the diff in the code review tool. Before your colleagues look at the change, you should be your own first reviewer. The context switch from editing to reviewing can help you to see the code you’ve written in a different light, and this can sometimes highlight errors or omissions.</p>
  492. <h3 id="little-things-please-little-minds-while-bigger-fools-look-on">Little things please little minds, while bigger fools look on</h3>
  493. <p>Ideally, pull requests are small - <a href="https://twitter.com/iamdevloper/status/397664295875805184">attention fatigue</a> means it’s almost impossible to thoroughly review large changes. When the diff view is a sea of red and green, it’s really hard to be sure that you’ve got your head around everything. In extreme cases in Stash, you’ll see “This pull request is too large to render. Showing the first 1000 files.” Seeing that message gives me the fear.</p>
  494. <p>When a pull request is bigger than a couple of files, it can be a sign that you might not be splitting your tasks into small enough units. Sometimes it can help if developers create a feature branch, and branch off that for smaller tasks, so that when you come to do the big merge into the main branch, the code has already been reviewed in small chunks.</p>
  495. <h3 id="dont-just-look-at-the-code">Don’t just look at the code</h3>
  496. <p>If in doubt, check out the branch and test it yourself. It’s a really good habit to get into, especially for larger changes that may need a bit more consideration. It may seem time-consuming, but it’s much quicker to find problems <em>before</em> they get into a code branch that will be going live.</p>
  497. <h3 id="its-good-to-talk">It’s good to talk</h3>
  498. <p>Sometimes online comments aren’t the best way to communicate. Especially when changes are complex, or if a pull request needs a lot of work, talk them through together. Nobody wants to be on the receiving end of a big pile of negative comments. If it seems like someone needs a lot of guidance, maybe <a href="/development/pair-programming-budo">pair programming</a> would be a better approach.</p>
  499. <h3 id="sharing-is-caring">Sharing is caring</h3>
  500. <p>When you’re making a comment, don’t just tell your colleague that their code is bad. It’s really helpful to give examples of how it could be improved, or link to useful articles that will help people understand why you’re making that comment. For instance, when I’m reviewing CSS by junior developers, I very often find myself linking to the <a href="https://www.drupal.org/node/1887862">Drupal coding standards</a>, or an explanation of <a href="http://www.456bereastreet.com/archive/201004/whenever_you_use_hover_also_use_focus/">why hover styles should be accompanied by focus styles</a>.</p>
  501. <h3 id="love-the-sinner-hate-the-sin">Love the sinner, hate the sin</h3>
  502. <p>Some developers dread code reviews. I think we’re lucky in that the atmosphere within our team is very supportive, but I can imagine in some organisations a code review could feel like a trial by fire. It should go without saying, but code review comments should never get personal. The aim is to improve the quality of the team’s code, not prove that you’re cleverer than your colleagues.</p>
  503. <p>The other thing to remember is that criticism isn’t just about pointing out things that are wrong. It can have a really beneficial effect on morale to make positive comments about something someone has done well.</p>
  504. <h2 id="were-getting-there">We’re getting there</h2>
  505. <p>Over the last few years, code reviews have really helped our team to improve and learn a lot, and we’ve come a long way towards a culture of quality, but there’s always room for improvement. There are more quality checks that we can automate, but top of my wish list would be to <a href="https://www.lullabot.com/articles/github-pull-request-builder-for-drupal">spin up a test environment for each pull request</a>. I’d also like to get more front-end quality checks automated, perhaps including performance metrics using a tool like <a href="https://github.com/gmetais/grunt-devperf">devperf</a>, or visual regression testing using <a href="https://github.com/BBC-News/wraith">Wraith</a> or <a href="http://garris.github.io/BackstopJS/">Backstop</a>.</p>
  506. <p>But even if you don’t have robots doing all that clever stuff, if code review is part of your process, you’re going in the right direction. And besides, no matter how much you automate, you’ll still need someone to use their judgement.</p>
  507. </article>
  508. </section>
  509. <nav id="jumpto">
  510. <p>
  511. <a href="/david/blog/">Accueil du blog</a> |
  512. <a href="http://capgemini.github.io/learning/better-learning-code-reviews/">Source originale</a> |
  513. <a href="/david/stream/2019/">Accueil du flux</a>
  514. </p>
  515. </nav>
  516. <footer>
  517. <div>
  518. <img src="/static/david/david-larlet-avatar.jpg" loading="lazy" class="avatar" width="200" height="200">
  519. <p>
  520. Bonjour/Hi!
  521. 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>
  522. 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>).
  523. </p>
  524. <p>
  525. 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>.
  526. </p>
  527. <p>
  528. Voici quelques articles choisis :
  529. <a href="/david/blog/2019/faire-equipe/" title="Accéder à l’article complet">Faire équipe</a>,
  530. <a href="/david/blog/2018/bivouac-automnal/" title="Accéder à l’article complet">Bivouac automnal</a>,
  531. <a href="/david/blog/2018/commodite-effondrement/" title="Accéder à l’article complet">Commodité et effondrement</a>,
  532. <a href="/david/blog/2017/donnees-communs/" title="Accéder à l’article complet">Des données aux communs</a>,
  533. <a href="/david/blog/2016/accompagner-enfant/" title="Accéder à l’article complet">Accompagner un enfant</a>,
  534. <a href="/david/blog/2016/senior-developer/" title="Accéder à l’article complet">Senior developer</a>,
  535. <a href="/david/blog/2016/illusion-sociale/" title="Accéder à l’article complet">L’illusion sociale</a>,
  536. <a href="/david/blog/2016/instantane-scopyleft/" title="Accéder à l’article complet">Instantané Scopyleft</a>,
  537. <a href="/david/blog/2016/enseigner-web/" title="Accéder à l’article complet">Enseigner le Web</a>,
  538. <a href="/david/blog/2016/simplicite-defaut/" title="Accéder à l’article complet">Simplicité par défaut</a>,
  539. <a href="/david/blog/2016/minimalisme-esthetique/" title="Accéder à l’article complet">Minimalisme et esthétique</a>,
  540. <a href="/david/blog/2014/un-web-omni-present/" title="Accéder à l’article complet">Un web omni-présent</a>,
  541. <a href="/david/blog/2014/manifeste-developpeur/" title="Accéder à l’article complet">Manifeste de développeur</a>,
  542. <a href="/david/blog/2013/confort-convivialite/" title="Accéder à l’article complet">Confort et convivialité</a>,
  543. <a href="/david/blog/2013/testament-numerique/" title="Accéder à l’article complet">Testament numérique</a>,
  544. et <a href="/david/blog/" title="Accéder aux archives">bien d’autres…</a>
  545. </p>
  546. <p>
  547. 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>.
  548. </p>
  549. <p>
  550. Je ne traque pas ta navigation mais mon
  551. <abbr title="Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33.184162340">hébergeur</abbr>
  552. conserve des logs d’accès.
  553. </p>
  554. </div>
  555. </footer>
  556. <script type="text/javascript">
  557. ;(_ => {
  558. const jumper = document.getElementById('jumper')
  559. jumper.addEventListener('click', e => {
  560. e.preventDefault()
  561. const anchor = e.target.getAttribute('href')
  562. const targetEl = document.getElementById(anchor.substring(1))
  563. targetEl.scrollIntoView({behavior: 'smooth'})
  564. })
  565. })()
  566. </script>