A place to cache linked articles (think custom and personal wayback machine)
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  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>Consistency (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://localshred.github.io/consistency.html">
  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. Consistency (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://localshred.github.io/consistency.html">Source originale du contenu</a></h3>
  445. <p>In July of 2010 I was hired at a tiny startup known as MoneyDesktop (now <a href="http://mx.com">MX</a>). We had a legacy PHP+Flex app inherited from a previous company, and as you can imagine, it was not pretty. One of the great things about working at a brand new startup is that you actually don't have any customers yet, so the tech is about as green field as it gets. This is also one of the worst things, because at this stage you don't know what you don't know. We decided from day one to build a service-oriented architecture with Protocol Buffers running the intra-service communication. We ditched the PHP and ported the Flex to run on top of a Rails API service. So sue me.</p>
  446. <p>Naturally, at first we got a lot more things wrong than we got right, but the seed of the architecture that we started was solid and it enabled us to move very quickly to produce a product that customers wanted. We created a system that in just over 12 months was starting to get out of hand. We used Rails for all of the "front-end" services but decided to use Sinatra to power others because they were "lighter weight". At one point I started writing a custom event service, only later to find RabbitMQ (thank the heavens we found it before I'd gotten very far). We had a lot of duplication and not a lot of established patterns for how to be consistent. We were really good at clever solutions, but didn't understand how damaging that was to the long term health of our software.</p>
  447. <h3>Finding Coal</h3>
  448. <p>In late 2011 we acquired a tiny startup and brought on their technical co-founder as our VP of Engineering, Brandon Dewitt. Brandon's an incredibly smart engineer, and I feel truly blessed to have been able to code under his guidance and leadership.</p>
  449. <p>For an entire month after the acquisition there was near-total radio silence from him from a leadership perspective. I started getting super antsy wondering what was going on, worried he was freaking out about our app or our team or the color of the paint on the walls. We had recently gone through some engineering management swing-and-miss situations, so we were really hoping things were going to work out with Brandon.</p>
  450. <p>After about a month he finally opened up that he had some major concerns about the lack of consistency in our software practices, specifically how much technical debt we'd already accumulated in such a short period of time. Sure, we'd done a good job producing a working product, and we were clearly gaining traction in our industry, but at what cost? I remember well Brandon's critique of one of our critical internal services, which had basically had one engineer working on it from day one. We'll call that dev Hank. Hank was no longer with our company, for related reasons:</p>
  451. <blockquote><p>"It's like, Hank has a house right next to a power plant. Hank wants to get power to his house so he can run the lights and the dishwasher and all that.</p>
  452. <p>"But instead of plugging into the power station next door, he walks out into his front yard with a shovel, and he starts digging for coal. And he digs, and he digs, and he digs some more. He spends an incredible amount of time digging.</p>
  453. <p>"And you know what's the craziest part? <strong>He fucking found coal!!!</strong>"</p></blockquote>
  454. <p>A lot of our services were like that, we dug for coal when we had a power plant next door.</p>
  455. <p>Over the next couple years we evolved the platform into a set of services that were cohesive and well-formed. Working at any layer of the stack was simple because every app was built with the same set of principles and style. We standardized using Rails for every service. We worked hard to solidify the patterns and tooling that enabled us to iterate quickly and produce good code. It's easy for me to say that in 12 years coding, MoneyDesktop had by far the best codebase I've ever worked in. Of course the system wasn't perfect by any stretch of the imagination, but it had "good bones", and <a href="https://vimeo.com/43774443">many of the engineers</a> MoneyDesktop has employed over the years have <a href="https://www.youtube.com/watch?v=efwZwalqTP0">vouched for its elegance</a>.</p>
  456. <p>Would we have gotten there without Brandon's guidance? Maybe. I've worked for a lot of other companies where consistentcy wasn't even a conversation, and it's my belief that the focus on discoverability and consistency is what made that codebase work well.</p>
  457. <h3>Finding Consistency</h3>
  458. <p>A focus on discoverability and consistency should be an intentional and public decision that you make in your software organization. Your developers should know about it, and should hold each other to the standards you agree to.</p>
  459. <p>What does discoverability and consistency mean? It means producing software (hopefully) free from the artifacts of bias, as agreed upon by your team. Do you have to use Rails or protobuf to be discoverable and consistent? Of course not. But you should seek to gain consensus. Here is a simple guide to becoming more consistent and discoverable in your codebase.</p>
  460. <h3>1. Get a Style Guide</h3>
  461. <p>I don't blame you if you just rolled your eyes, I know I did when we got our first style guides at MoneyDesktop. But hear me out.</p>
  462. <p>Style guides abound on github and other places for the language and framework you are using. Find the most idiomatic style guide you can, tweak it at a minimum, and preach it to your team. Get consensus. Get buy-in. Get a style guide.</p>
  463. <p>The style guide really is one of the best things you can have. You will hire plenty of developers who have different opinions about bracing, spacing, how to name methods, size of methods, size of classes, feature X over feature Y... etc. Which one is "right", or does "right" even exist?</p>
  464. <p><strong>The "right" style guide is the one whereby following it, your team can consistently produce relatively bug-free software in a timely manner.</strong></p>
  465. <p>A trivial example is bracing. Many languages allow you to omit braces for single line <code>if</code>/<code>else</code> blocks, but if you want to execute multiple statements per block, you've got to use braces (<a href="https://en.wikipedia.org/wiki/Heartbleed">Hearbleed</a> anyone?).</p>
  466. <div class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">if</span> <span class="p">(</span><span class="n">foo</span><span class="p">.</span><span class="n">IsValid</span><span class="p">())</span>
  467. <span class="n">DoStuff</span><span class="p">();</span>
  468. <span class="k">else</span>
  469. <span class="nf">DoOtherStuff</span><span class="p">();</span>
  470. <span class="n">DoMoreOtherStuff</span><span class="p">();</span> <span class="c1">// spacing makes me think this should be part of the else</span></code></pre></div>
  471. <p>In this example spacing doesn't save you (unless you're in python), so you've got to use braces on the <code>else</code> if you want to execute both method calls. But now what do you do with the <code>if</code> statement?</p>
  472. <div class="highlight"><pre><code class="language-csharp" data-lang="csharp"><span class="k">if</span> <span class="p">(</span><span class="n">foo</span><span class="p">.</span><span class="n">isValid</span><span class="p">())</span>
  473. <span class="n">doStuff</span><span class="p">();</span>
  474. <span class="k">else</span>
  475. <span class="p">{</span>
  476. <span class="n">doOtherStuff</span><span class="p">();</span>
  477. <span class="n">doMoreOtherStuff</span><span class="p">();</span>
  478. <span class="p">}</span></code></pre></div>
  479. <p>You <em>could</em> leave braces off the <code>if</code> statement, but to be most consistent with the rest of your codebase, why not always use braces? Of course the language allows omitting braces <em>in certain situations</em>, but <em>not in all situations</em>.</p>
  480. <p>Another example comes from ruby, and it's one I wish the community would figure out. Ruby 1.9 introduced a new hash key syntax when your keys are symbols:</p>
  481. <div class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="c1"># 1.8 symbol keys are same as symbols everywhere else</span>
  482. <span class="n">i_am_a_symbol</span> <span class="o">=</span> <span class="ss">:hello</span>
  483. <span class="n">toys</span> <span class="o">=</span> <span class="p">{</span> <span class="ss">:woody</span> <span class="o">=&gt;</span> <span class="ss">:cowboy</span><span class="p">,</span> <span class="ss">:buzz</span> <span class="o">=&gt;</span> <span class="ss">:space_ranger</span> <span class="p">}</span>
  484. <span class="c1"># ... but in 1.9 you can use a different syntax for _the same thing_</span>
  485. <span class="n">toys</span> <span class="o">=</span> <span class="p">{</span> <span class="ss">woody</span><span class="p">:</span> <span class="ss">:cowboy</span><span class="p">,</span> <span class="ss">buzz</span><span class="p">:</span> <span class="ss">:space_ranger</span> <span class="p">}</span></code></pre></div>
  486. <p>In both cases, the hash keys are symbols, but in 1.9 you may encounter either one. When I go to change a file with these keys, which do I use? Probably the same as what's in the file, assuming their isn't mixed usage. If there is mixed usage, or I'm creating an entirely new file... what then?</p>
  487. <p>Pick style guide rules that help your team to be consistent now and in the future, regardless of the whims or fancies of Joe, Jane, or Janet Developer (or even fancy new fangled language constructs). I am <em>not</em> saying don't use new language features. I'm saying question the consistency value of new features. I am also <em>not</em> saying how you should use braces or symbol syntax, these are just examples of discussions I have been a part of.</p>
  488. <p>I have had individual developers complain to me about the usage of a style guide and I'll be honest, it boggles my mind. If you find negative value in adhering to a style guide, what you're saying is that your preferences are more important than the health of the codebase over time. Yes, I believe adherence to a style guide produces a healthy codebase.</p>
  489. <p>Your style guide shouldn't contain every possible rule anyone can conceive, merely the preferences which are generally controversial or tend to be confusing to your team. Preferences that drive Sally to produce code that <em>feels</em> different than Jeff's. Everyone has their own style, and that style should never be discouraged as "wrong". Just try to find a common ground that's consistent and discoverable.</p>
  490. <h3>2. Use Trusted/Tested Community Libraries</h3>
  491. <p>Beginning developers want to write a solution for every problem that they can imagine. Experienced developers want to use everyone else's battle-tested solutions wherever possible. Neither are wrong, but context is pretty important. If the problem you're solving for has a well-tested and well-trusted solution produced by your language community, you really should be using it in your production system. If it doesn't, produce it and then give it back to the community!</p>
  492. <p>That being said, there's a certain amount of taking for granted attitude that we would do well to squash out of our industry. Don't go re-invent the wheel, but you should definitely <em>study wheels</em>. Read often. Learn a new software language every year. Subscribe to weekly mailing lists. Hop on that library's IRC and ask questions. Stay familiar with the trends of the language and framework you are using. Go to user group meetings.</p>
  493. <p>No software project is an island, so you should stand on the shoulders of those who've come before. Just don't be ignorant about why they made the decisions they did.</p>
  494. <h3>3. Write Tests (and run them!)</h3>
  495. <p>Please, for the love of all that is holy, write tests for your software. Write tests when you add code. Write tests when you're fixing bugs. Remove practices, processes, and roadblocks that stop your developers from testing.</p>
  496. <p>Once you have those tests, run them during your development and release processes.</p>
  497. <h3>4. Get Feedback Often</h3>
  498. <p>Talk to your team weekly about how things are going (not necessarily the "what", but the "why" and "how"). Talk about your style guides, the libraries you're using (or should be using). Talk about your methods and processes. Hold weekly brown bag discussions. Teach others on your team about past experiences you've had. Start a book club and meet regularly.</p>
  499. <p>Getting feedback will empower your developers to feel like there's a reason they accepted the job offer. Give them a reason to stay, a reason to get or remain passionate about what it is you're doing.</p>
  500. <hr/>
  501. <p>Finding consistency for your team is a valuable process you can go through. You'll empower your developers to write better code and enjoy what they do. Your project's health will thank you for it.</p>
  502. </article>
  503. </section>
  504. <nav id="jumpto">
  505. <p>
  506. <a href="/david/blog/">Accueil du blog</a> |
  507. <a href="http://localshred.github.io/consistency.html">Source originale</a> |
  508. <a href="/david/stream/2019/">Accueil du flux</a>
  509. </p>
  510. </nav>
  511. <footer>
  512. <div>
  513. <img src="/static/david/david-larlet-avatar.jpg" loading="lazy" class="avatar" width="200" height="200">
  514. <p>
  515. Bonjour/Hi!
  516. 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>
  517. 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>).
  518. </p>
  519. <p>
  520. 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>.
  521. </p>
  522. <p>
  523. Voici quelques articles choisis :
  524. <a href="/david/blog/2019/faire-equipe/" title="Accéder à l’article complet">Faire équipe</a>,
  525. <a href="/david/blog/2018/bivouac-automnal/" title="Accéder à l’article complet">Bivouac automnal</a>,
  526. <a href="/david/blog/2018/commodite-effondrement/" title="Accéder à l’article complet">Commodité et effondrement</a>,
  527. <a href="/david/blog/2017/donnees-communs/" title="Accéder à l’article complet">Des données aux communs</a>,
  528. <a href="/david/blog/2016/accompagner-enfant/" title="Accéder à l’article complet">Accompagner un enfant</a>,
  529. <a href="/david/blog/2016/senior-developer/" title="Accéder à l’article complet">Senior developer</a>,
  530. <a href="/david/blog/2016/illusion-sociale/" title="Accéder à l’article complet">L’illusion sociale</a>,
  531. <a href="/david/blog/2016/instantane-scopyleft/" title="Accéder à l’article complet">Instantané Scopyleft</a>,
  532. <a href="/david/blog/2016/enseigner-web/" title="Accéder à l’article complet">Enseigner le Web</a>,
  533. <a href="/david/blog/2016/simplicite-defaut/" title="Accéder à l’article complet">Simplicité par défaut</a>,
  534. <a href="/david/blog/2016/minimalisme-esthetique/" title="Accéder à l’article complet">Minimalisme et esthétique</a>,
  535. <a href="/david/blog/2014/un-web-omni-present/" title="Accéder à l’article complet">Un web omni-présent</a>,
  536. <a href="/david/blog/2014/manifeste-developpeur/" title="Accéder à l’article complet">Manifeste de développeur</a>,
  537. <a href="/david/blog/2013/confort-convivialite/" title="Accéder à l’article complet">Confort et convivialité</a>,
  538. <a href="/david/blog/2013/testament-numerique/" title="Accéder à l’article complet">Testament numérique</a>,
  539. et <a href="/david/blog/" title="Accéder aux archives">bien d’autres…</a>
  540. </p>
  541. <p>
  542. 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>.
  543. </p>
  544. <p>
  545. Je ne traque pas ta navigation mais mon
  546. <abbr title="Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33.184162340">hébergeur</abbr>
  547. conserve des logs d’accès.
  548. </p>
  549. </div>
  550. </footer>
  551. <script type="text/javascript">
  552. ;(_ => {
  553. const jumper = document.getElementById('jumper')
  554. jumper.addEventListener('click', e => {
  555. e.preventDefault()
  556. const anchor = e.target.getAttribute('href')
  557. const targetEl = document.getElementById(anchor.substring(1))
  558. targetEl.scrollIntoView({behavior: 'smooth'})
  559. })
  560. })()
  561. </script>