Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Constance et qualité du code dans une équipe

Constance et qualité du code dans une équipe

Depuis plusieurs années, chez Mirego, nous recherchons constamment l’équilibre parfait entre la qualité des produits que nous bâtissons et celle du code qui les propulse.

8c4cee1129bc11fbe9a0b9379dce2cb1?s=128

Rémi Prévost

April 11, 2018
Tweet

Transcript

  1. Constance et qualité du code dans une équipe Rémi Prévost

    Web à Québec 2018
  2. Rémi Prévost Lead Développement Web chez Mirego

  3. Sondage ✋

  4. Constance et qualité de code dans une équipe La quête

    ultime
  5. Abstrait Pourquoi? Concret Comment?

  6. Code de qualité La philosophie derrière les outils

  7. Constance Constance → Prévisibilité → Productivité

  8. Fierté Code clever vs. code maintenable

  9. Conventions Communautés + conventions internes

  10. Focus Se poser le moins de questions possible

  11. Concrètement Linters et formatters

  12. Linters Analyse du code → Règles strictes → Avertissements

  13. Démo eslint

  14. { "type": "Program", "body": [ { "type": "VariableDeclaration", "kind": "const",

    "declarations": [ { "type": "VariableDeclarator", "id": { "type": "Identifier", "name": "foo" }, "init": { "type": "Literal", "value": "hello world", "raw": "'hello world'" } } ] } ], "sourceType": "script" } const foo = 'hello world';
  15. Linters (avancés) Analyse du code → Règles inférées → Avertissements

  16. Démo credo

  17. Formatters Analyse du code → Règles strictes → Ré-écriture du

    code
  18. Démo prettier

  19. Le reste Ce qui ne s’analyse pas (yet!)

  20. Extraire les cas d’exceptions pour les rendre très visibles

  21. class ArticleFetcher { constructor(baseUrl) { this.baseUrl = baseUrl; } fetchArticles(sectionKey)

    { return fetch(this.baseUrl) .then(response => response.json()) .then(response => response.articles) .then(articles => articles.map(article => this.processArticle(article))); } processArticle(article) { const tags = article.sectionKey === 'sports' ? article.sportsTags : article.tags; return { ...article, tags: tags}; } }
  22. const extractTags = (article) => { return article.sectionKey === 'sports'

    ? article.sportsTags : article.tags; }; class ArticleFetcher { constructor(baseUrl) { this.baseUrl = baseUrl; } fetchArticles(sectionKey) { return fetch(this.baseUrl) .then(response => response.json()) .then(response => response.articles) .then(articles => articles.map(article => this.processArticle(article))); } processArticle(article) { const tags = extractTags(article); return { ...article, tags: tags}; } }
  23. Contrôler le flow avec des guard clauses

  24. storeLocale() { const result = []; if (this.isEnglish) { result.push('en');

    } else { result.push('fr'); if (this.isCanada) { result.push('ca'); } else { result.push('us'); } } return result; }
  25. storeLocale() { if (this.isActive) { this.locale = true; this.alternateLocale =

    false; return this; } } storeLocale() { if (!this.isActive) return; this.locale = true; this.alternateLocale = false; return this; }
  26. def store_locale(%{active: false} = thing) do thing end def store_locale(%{active:

    true} = thing) do thing |> Map.put(:locale, true) |> Map.put(:alterate_locale, false) end
  27. Éviter les abbréviations

  28. articleProxy(id) { this.fetch(id).then(a => { if (!a.isPublished) return; return {

    title: a.fullTitle, description: a.description.toUpperCase(), authorName: a.author.name }; }); }
  29. articleProxy(id) { this.fetch(id).then(article => { if (!article.isPublished) return; return {

    title: article.fullTitle, description: article.description.toUpperCase(), authorName: article.author.name }; }); }
  30. Nommer les choses de la façon la plus neutre possible

  31. MeteomediaDataFetcher WeatherReportFetcher vs. Service

  32. GoogleDoubleClickForPublishers Advertisements vs. Contexte

  33. Faire la différence entre DRY et over-engineering

  34. class FooComponent { handleFirstEvent(data) { this.data = data.toUpperCase(); this.name =

    'foo'; } } class BarComponent { handleSecondEvent(data) { this.data = data.toUpperCase(); this.name = 'bar'; } }
  35. class ParentComponent { setStuff(data, name) { this.data = data.toUpperCase(); this.name

    = name; } } class FooComponent extends ParentComponent { handleFirstEvent(data) { this.setStuff(data, 'foo'); } } class BarComponent extends ParentComponent { handleSecondEvent(data) { this.setStuff(data, 'bar'); } }
  36. Ordonner et grouper les éléments

  37. alias Ecto.Query alias Accent.Endpoint alias Dataloader.Ecto alias GraphQL.Projects.Resolver alias GraphQL.Users.Resolver

    alias Web.Helpers alias GraphQL.Translations.Resolver alias Search.Configuration alias Absinthe.Plugin alias Accent.Repo alias GraphQL.Pages.Resolver
  38. alias Absinthe.Plugin alias Accent.Endpoint alias Accent.Repo alias Dataloader.Ecto alias Ecto.Query

    alias GraphQL.Pages.Resolver alias GraphQL.Projects.Resolver alias GraphQL.Users.Resolver alias GraphQL.Translations.Resolver alias Search.Configuration alias Web.Helpers
  39. import * as React from 'react'; import Button from 'material-ui/Button';

    import withStyles, {WithStylesProps} from 'material-ui/styles/withStyles'; import Zoom from 'material-ui/transitions/Zoom'; import {translate} from 'react-i18next'; import {compose} from 'recompose'; import AccentIcon from './components/accent-icon'; import {i18n} from 'i18next'; interface Props {}; interface TranslatedProps { i18n: i18n; } type EnhancedProps = Props & WithStylesProps & TranslatedProps;
  40. // Vendor import * as React from 'react'; // Vendor

    components import Button from 'material-ui/Button'; import withStyles, {WithStylesProps} from 'material-ui/styles/withStyles'; import Zoom from 'material-ui/transitions/Zoom'; import {compose} from 'recompose'; import {translate} from 'react-i18next'; // Components import AccentIcon from './components/accent-icon'; // Vendor types import {i18n} from 'i18next'; // Interfaces interface Props {}; interface TranslatedProps {i18n: i18n} // Types type EnhancedProps = Props & WithStylesProps & TranslatedProps;
  41. OK! Ce que j’aimerais que vous reteniez

  42. Merci! Questions? Rémi Prévost @remi