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

Meetup DevOps Toulouse : Le craft & l'infra as code

Meetup DevOps Toulouse : Le craft & l'infra as code

Alexandre RAOUL

June 28, 2018
Tweet

More Decks by Alexandre RAOUL

Other Decks in Programming

Transcript

  1. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Un peu de Craft sur l’Infra as Code Toulouse DevOps Meetup 28/06/2018 Alexandre Raoul 1
  2. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Merci à l’ENSEEIHT (!!) Merci aux orgas (!!)
  3. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Alexandre Raoul A Toulouse depuis 2 mois Pour les pyrénées ! Au début du Ruby, beaucoup de Puppet Puis pas mal de Terraform sur AWS, de l’Ansible, du Python Consultant OCTO depuis 4 ans 3 Expertise Formations Consulting Delivery
  4. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    L’infra as code : Décrire sous forme de code exécutable et testable la configuration de l’architecture technique d’infrastructure
  5. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Le code et le software craftsmanship font bon ménage... L’infra as code tourne (principalement) autour du code…
  6. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    7 Infra as Code Software Craftsmanship Voilà pour le pitch...
  7. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    “Les individus et leurs interactions plus que les processus et les outils” Agile Manifesto
  8. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    “Les individus et leurs interactions plus que les processus et les outils” Agile Manifesto Cool ta phrase, elle a 17 ans et pour le dev ça veut dire quoi par rapport à son code?
  9. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    “Le Software craftsmanship est une approche de développement de logiciels qui met l'accent sur les compétences de codage des développeurs de logiciels eux-mêmes.” Wikipedia - Software Craftsmanship
  10. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    “Le Software craftsmanship est une approche de développement de logiciels qui met l'accent sur les compétences de codage des développeurs de logiciels eux-mêmes.” Wikipedia - Software Craftsmanship En prenant soin des compétences de nos devs, on fera du meilleur code
  11. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Mais en fait derrière, c’est l’idée … … que la mauvaise qualité a (ou aura) un coût ... qu’on ne court pas un marathon comme un sprint Dette technique Qualité & code testé
  12. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Mais en fait derrière, c’est l’idée … ... qu’on peut toujours s’améliorer et apprendre ... que partager son savoir est une noble chose Faire un meetup Revue de code, pair programing ...
  13. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Au final, c’est plus un mindset qu’une méthodologie clefs en main manifesto.softwarecraftsmanship.org Mot magique qui me permet de parler de choses (agile, bon sens, XP, …) sans que ça soit stricto sensu apparu avec le craft
  14. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Coding Dojo Refactoring Pair Programming Tech Leading Boy Scout Rule Collective Code Ownership Test Driven Development (TDD) Clean Code Broken Window Software Entropy Unit Testing Idiomatic Code Egoless Programming Continuous Integration Mob Programing Code Control Keep It Simple Stupid (KISS) Code Review You Ain’t Gonna Need It (YAGNI) Legacy Code Design Patterns Style Guide Lint Test Harness Bingo
  15. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Pyramide de tests 1s - 1min 1min - 10min 10min - 30min 30min+ Durée d’éxécution Couverture Grain fin Grosse maille
  16. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    18 Boucle de feedback c’est le temps mis pour se rendre compte de sa connerie
  17. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Pyramide de tests 1s - 1min 1min - 10min 10min - 30min 30min+ Durée d’éxécution Couverture Grain fin Grosse maille Limite de flemme
  18. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Pyramide de tests 1s - 1min 1min - 10min 10min - 30min 30min+ Durée d’éxécution Couverture Grain fin Grosse maille Limite de flemme Outils de lint, sur le style > Est-ce que c’est vraiment du test? Test Kitchen, Molecule > On lance le code dans une vm DIY tools agregation
  19. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    21 If you can’t spin up a full copy of your infra and test it, you don’t actually have “infrastructure as code”. You just have ... some code, and duct tape. https://charity.wtf/2016/03/23/aws-networking-environments-and-you/
  20. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    22 Oui mais bon, on parle de l’infra là ... “Je monte une copie de mon SI pour valider ma sonde de monitoring” “Je le fais en prod - YOLO”
  21. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Pyramide de tests 1s - 1min 1min - 10min 10min - 30min 30min+ Durée d’éxécution Couverture Grain fin Grosse maille Limite de flemme Outils de lint, sur le style > Est-ce que c’est vraiment du test? Test Kitchen, Molecule > On lance le code dans une vm Faute de mieux, on va se concentrer sur cette zone
  22. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    24 Pour réduire la boucle de feedback, on isole ! --- - hosts: all roles: - role: yolo.monitoring when: ff_monitoring_active feature flipping
  23. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    25 Pour réduire la boucle de feedback, on ne teste pas l’outil lui même --- - name: install nginx yum: name: nginx state: present def test_nginx_is_installed(host): nginx = host.package("nginx") assert nginx.is_installed
  24. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    26 Pour réduire la boucle de feedback, on invente des trucs :( (ou des raccourcis) Parce que en vrai c’est dur :(
  25. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Packer permet de construire des images d’OS Par exemple des AMIs sur aws Notre but : valider que l’image est bonne Test kitchen est un outil de test qui vient du monde chef 1. on monte une vm 2. on lance des trucs (à la base, du chef) 3. on regarde le résultat (avec serverspec) 4. on détruit tout 27 Exemple 1 : Packer & Test kitchen
  26. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    28 Pseudo code packer base: je pars d’une ami “redhat” je la lance dans tel réseau bricolage: je lance un script pour passer les updates je clean les repos yum je suppr les clés (ssh host) pour qu’elle soient regen je nettoie les logs postprod: ça sera une ami qui s’appelle “maPetiteRedhat”
  27. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    require 'spec_helper' describe file('/etc/redhat-release') do it { should be_file } it { should contain 'Red Hat Enterprise Linux Server release 7.2' } end describe 'Cleanup has been done', :rhel7 do describe command("yum repolist") do its(:stdout) { should match Regexp.escape('repolist: 0') } end describe command("ls -1 /etc/yum.repos.d/") do it { expect(subject.stdout.length).to be(0) } end end 29 --- driver: name: ec2 interface: private security_group_ids: [sg-blablaEtDautreConfigDeCeGenre ] instance_type: t2.large region: eu-west-1 tags: Name: test-kitchen created-by: test-kitchen transport: name: rsync username: ec2-user platforms: - name: redhat provisioner: name: shell data_path: remote_scripts script: provision_true.sh verifier: name: shell suites: - name: RHEL7 driver: image_search: tag:git_tag: <%= ENV['CI_BUILD_REF_NAME'] ? ENV['CI_BUILD_REF_NAME'] : raise('missing CI_BUILD_REF_NAME for tag build_ref ami lookup') %> tag:product: RHEL7 verifier: command: bundle exec rspec --pattern spec/ {rhel7,rhel72}/ *_spec.rb YAML test kitchen Serverspec on se lance sur AWS dans tel réseau on lance des trucs on part de l’AMI qu’on vient de construire on lance des tests
  28. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Molecule vient du monde Ansible et est très comparable à test kitchen Ce qui est top : tout est construit à base playbooks Ansible ! La cli au final c’est ๏ un générateur de squelette ๏ un orchestrateur qui sait enchaîner les étapes du test à partir des commandes a. create b. converge c. verify d. destroy 30 Exemple 2 : Molecule et les checks prometheus
  29. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Et sinon prom? Il y a 2 fonctionnalités un peu originales dans Molecule : ๏ La notion de topologie : on peut lancer plusieurs machines et faire des choses sur les unes et les autres ๏ La notion de scénario : on peut facilement mutualiser du code sur notre setup et au final avoir un scénario sur la voix royale, et un sur une panne spécifique Avec la topologie + scénario on peut créer un test qui : 1. installe prometheus sur une instance 2. un “exporter” sur une autre 3. pose une alerte 4. pourrie l’instance avec l’exporter pour provoquer l’alerte 5. vérifie que l’alerte a vu le truc 31 Exemple 2 : Molecule et les checks prometheus
  30. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Terraform c’est cool, mais le langage n’est pas des plus élégants et surtout quand on veut refactorer une (ou des) topologie, on est un peu seuls... Mon exemple : une centaine de topologies, une convention de tag qui évolue, comment on sait quelles topologies sont à mettre à retravailler et si c’est fait? La solution, un peu de magie ruby et du rspec 1. on récupère tous les tfstate dans les buckets S3 2. c’est du json donc on les parse 3. on parcourt tous les objets “aws_instance” et on match des attributs Limite : faut déjà qu’il y ait un déploiement pour le jouer 32 Exemple 3 : Terraform, remote state et rspec
  31. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    require 'spec_helper' require 'aws-sdk' require 'json' require 'logger' require 'yaml' require 'hashie' CACHE_FILE_NAME = 'cache.yml' aws_region = ENV.fetch('AWS_REGION', aws_region) logger = Logger.new(STDOUT) logger.level = Logger::INFO tf_states = {} if File.file?(CACHE_FILE_NAME ) logger.info("Using cache ' #{CACHE_FILE_NAME} '") tf_states = YAML::load_file(CACHE_FILE_NAME ) else logger.info("Create cache ' #{CACHE_FILE_NAME} '") iam_client = Aws::IAM::Client.new(region: aws_region) client = Aws::S3::Client.new(region: aws_region) state_buckets = client.list_buckets.buckets.map do |bucket| bucket.name if bucket.name =~ Regexp.new(Regexp.escape('tfstate-')) end state_buckets .compact!.sort! state_buckets .each do |state_bucket_name| logger.info("Bucket found : ' #{state_bucket_name} '") end 33 Exemple 3 : Le bout de code maison state_buckets .each do |state_bucket_name| tf_states[state_bucket_name ] = {} bucket = Aws::S3::Resource.new(client: client).bucket(state_bucket_nam current_bucket_tf_states = {} bucket.objects.each do |object| if object.key =~ Regexp.new(Regexp.escape('terraform.tfstate')) current_bucket_tf_states [object.key] = JSON.parse(object.get.body. end end current_bucket_tf_states .each do |k,v| logger.info("Tfstate found : 's3:// #{state_bucket_name} /#{k}'") end tf_states[state_bucket_name ] = current_bucket_tf_states end File.open(CACHE_FILE_NAME , 'w') {|f| f.write tf_states.to_yaml } logger.info("Cache '#{CACHE_FILE_NAME} ' created") end On boucle sur les buckets S3 qui commencent par “tfstate-” On y cheche les “tfstate”
  32. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    34 Exemple 3 : Et les assertions describe "TFStates looks ok" do tf_states.each do |bucket_name, tf_state_hash| context "in '#{bucket_name} '" do tf_state_hash .each do |tf_state_name , tf_state_content| tf_state_content .extend Hashie::Extensions::DeepLocate context "in '#{tf_state_name} '" do describe 'sg is good' do # snippet_for_sg security_groups = tf_state_content .deep_locate -> (k,v,o) { k == 'type' && v == "aws_security_group" } security_groups .each do |sg| context "in sg '#{sg['primary']['id']}'" do describe 'checks tags' do let (:subject) { sg['primary']['attributes'] } it { is_expected.to have_key("tags.Environment") } it { is_expected.to have_key("tags.Kind") } it { is_expected.to have_key("tags.Name") } it { is_expected.to have_key("tags.Zone") } end end end end end end end end end end On boucle sur les tfstate On cherche les objets de type security group On vérifie les tags dessus
  33. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    35 Exemple 3 : Et les assertions describe "TFStates looks ok" do tf_states.each do |bucket_name, tf_state_hash| context "in '#{bucket_name} '" do tf_state_hash .each do |tf_state_name , tf_state_content| tf_state_content .extend Hashie::Extensions::DeepLocate context "in '#{tf_state_name} '" do describe 'vpc is good' do # snippet_for_vpc vpcs = tf_state_content .deep_locate -> (k,v,o) { k == 'type' && v == "aws_vpc" } vpcs .each do |vpc| context "in vpc '#{vpc['primary']['id']}'" do describe 'checks tags' do let (:subject) { vpc['primary']['attributes'] } it { is_expected.to have_key("tags.Environment") } it { is_expected.to have_key("tags.Zone") } end end end end end end end end end end Pareil mais pour les VPC
  34. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    $ rspec spec/all_in_one_spec.rb I, [2018-06-11T15:51:40.296266 #3106] INFO -- : Using cache 'cache.yml' TFStates looks ok in 'tfstate-eu-west-1-dev-anotherdemotime' in 'hosted_zone_dev/terraform.tfstate' tfstate content vpc is good in vpc 'vpc-03ee5d65' checks tags should have key "tags.Environment" should have key "tags.Zone" in 'tfstate-eu-west-1-dev-demotime' in 'network/terraform.tfstate' tfstate content sg is good in sg 'sg-16d96e34' checks tags should have key "tags.Environment" should have key "tags.Kind" should have key "tags.Name" should have key "tags.Zone" in sg 'sg-e6l74180' checks tags should have key "tags.Environment" should have key "tags.Kind" should have key "tags.Name" should have key "tags.Zone" Finished in 0.01884 seconds (files took 0.28763 seconds to load) 10 examples, 0 failures 36 Exemple 3 : dans le shell ça donne ça
  35. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    $ rspec spec/all_in_one_spec.rb I, [2018-06-11T15:51:40.296266 #3106] INFO -- : Using cache 'cache.yml' TFStates looks ok in 'tfstate-eu-west-1-dev-anotherdemotime' in 'hosted_zone_dev/terraform.tfstate' tfstate content vpc is good in vpc 'vpc-03ee5d65' checks tags should have key "tags.Environment" should have key "tags.Zone" in 'tfstate-eu-west-1-dev-demotime' in 'network/terraform.tfstate' tfstate content sg is good in sg 'sg-16d96e34' checks tags should have key "tags.Environment" should have key "tags.Kind" should have key "tags.Name" should have key "tags.Zone" in sg 'sg-e6l74180' checks tags should have key "tags.Environment" should have key "tags.Kind" should have key "tags.Name" should have key "tags.Zone" (FAILED - 1) 37 Exemple 3 : dans le shell ça donne ça quand ça plante Failures: 1) TFStates looks ok in 'tfstate-eu-west-1-dev-demotime' in 'network/terraform.tfstate' tfstate content sg is good in sg 'sg-e6l74180' checks tags should have key "tags.Zone" Failure/Error: it { is_expected.to have_key( "tags.Zone") } expected #has_key?("tags.Zone") to return true, got false # ./spec/all_in_one_spec.rb:75:in `block (11 levels) in <top (required)>' Finished in 0.03136 seconds (files took 0.36419 seconds to load) 10 examples, 1 failure Failed examples: rspec ./spec/all_in_one_spec.rb[1:2:2:1:1:2:1:4] # TFStates looks ok in 'tfstate-eu-west-1-dev-demotime' in 'network/terraform.tfstate' tfstate content sg is good in sg 'sg-e6l74180' checks tags should have key "tags.Zone" Ici ça fail Le résumé dit exactement où chercher
  36. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    ๏ Le code fait des choses, mais il est surtout lu par des humains ! ๏ Cela passe par des pratiques très “classiques” < Bien nommer ses fichiers, ses roles, … < “Style guide” ๏ Formatage : simple alignement du code, règles communes < Allège un peu la charge de lecture de code < Pas de débat sur tab ou double espace... < terraform fmt ๏ Lint : vient du monde C, va plus loin que le simple alignement < Fait des choix sur du style < Implémente parfois des règles pour éviter certains bugs < ansible-lint 39 Du code lu par des humains
  37. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Le setup de lint du mec en face de moi quand on faisait du Puppet + = +
  38. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Mon setup de lint quand je faisais du Puppet Les setups sont différent, mais donnent du feedback super vite ! Faites votre propre assemblage ou copiez celui du voisin … mais prennez le temps de le faire ! + =
  39. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Dans Ansible on peut mettre des variables dans 250 endroits entre vault, les groups vars, les machins vars, trololo vars … Mais on essaye de limiter cette dispersion, pour simplifier la lecture 1. on se mets d’accord dans l’équipe 2. on fait un effort 3. au bout de 3 jours, tout le monde a oublié Bats est un framework de test pour du bash, quel rapport? Il va nous permettre de wrapper des oneliner shell type grep & find pour valider nos standards en mode easy peasy 43 “mon standard n’est pas dans l’outil XY” : batman Bats à la rescousse
  40. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    #!/usr/bin/env bats @test "Ansible cfg does not mention ansible user" { run grep --quiet --extended-regexp '^remote_user' ansible.cfg [ "$status" -eq 1 ] } @test "Vars in group_vars shall be '.yml' except for vault" { for file in $(find group_vars - type f ! -name "*.yml"); do echo "Testing '${file}' ..." >&2 run grep -q 'ANSIBLE_VAULT ' $file [ "$status" -eq 0 ] done } @test "Vars in group_vars shall be in its own sub-folder" { result="$(find group_vars -type f -depth 1 | wc -l)" [ "$result" -eq 0 ] } 44 En bats par exemple # You shall explain why you dare using host_vars @test "Grep for mandatory comment in host_vars" { for file in $(find host_vars -name "*.yml" -type f); do echo "Testing '${file}' ..." >&2 run grep --quiet --extended-regexp '^# .+$' $file [ "$status" -eq 0 ] done } @test "We dont use 'inventory' folder (we are using 'inventories')" { run test -d inventory [ "$status" -eq 1 ] } @test "No subfolder in inventories" { result="$(find inventories -type d | wc -l)" [ "$result" -eq 1 ] } $ bats ansible_practices.bats ✓ Ansible cfg does not mention ansible user ✓ Vars in group_vars shall be '.yml' except for vault ✓ Vars in group_vars shall be in its own sub-folder ✓ Grep for mandatory comment in host_vars ✓ We dont use 'inventory' folder (we are using 'inventories') ✓ No subfolder in inventories 6 tests, 0 failures
  41. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    ๏ Tous les tests dans la CI, tout le temps (sauf si ça vous coûte un bras) ๏ Jenkins, Gitlab CI, whatever, il n’y a pas de CI “d’Infra” ๏ une CI rouge ne doit quasiment jamais arriver < Smell : c’est vécu comme une “contrainte” pas comme une “aide” < Tests probablement pas lancés en local? 46 L’outil dans lequel vous faites votre intégration continue
  42. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Module ready Change Puppet Module Run Static Analysis Run Test-Kitchen Tests Run RSpec Tests Dev Commit Module Change Trigger Job Run Static Analysis Run RSpec Tests Run Test-Kitchen Tests Tag Module X.Y on Continous Integration Server on Developer’s workstation Module ready Un exemple de pipeline Puppet
  43. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    ๏ Bienveillance ๏ Un peu de préparation < Checkout du code, le lire et noter les trucs bizarres + L’interface de merge request de gitlab est TOP ๏ Ne pas hésiter à diverger sur un mini cours si besoin < Par exemple à quoi sert SELinux ou le fonctionnement d’un SSH Agent ๏ Si il y a des corrections à faire, ça ne veut pas forcément dire une autre revue formelle ๏ Evitez les corrections en live < Si c’est trop long et lourd vous ne les ferez plus ... ๏ “ah je savais pas qu’on faisait comme ça” est une opportunité pour améliorer les standards de l’équipe : mettez vous d’accord sur l’évolution directement ๏ Bienveillance 50 Comment faire une bonne revue de code ?
  44. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    ๏ Le format, tous devant la télé et un qui code ๏ Idéal < au bootstrap d’un projet < quand on ne sait pas faire un truc beau < quand on ne sait pas trop où on va ๏ Visez 1h, 2h max 51 Mob programing, encore un truc pour être moins productif
  45. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    ๏ Un seul à la fois, mais on utilise son poste < il y a trop de tricks dans vim/atom/sublime/intelliJ/emacs/nano < et de clavier azerty/qwerty/qwerty CA/bépo étranges pour chaque poste de dev... ๏ Essayez de tourner toutes les 15 min, mais privilégiez la rotation sur un commit marquant plutôt que sur le chrono ! < Pour basculer le code : passez par Git < Pour basculer une session SSH : tmux & screen ๏ Des fois le pair programming c’est du “pair troubleshooting” ou du “pair exploration” < C’est pas parce que je viens d’inventer ces mots que c’est interdit ;) ๏ Si il y a une grosse différence d'expérience : pas grave si on est pas sur du 50/50 ou que le quart du temps est passé sur de la formation < dans les limites du raisonnable : une tâche sur un profil apparmor où on doit reprendre les bases des gestions de droits sur les fichiers unix, ça fait un trop gros gap ! 52 Pair programing, quelques tips
  46. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    ๏ Disclaimer : je décris mon mode de fonctionnement perso ๏ 30 min sanctuarisé tous les jours < entre 13h30-14h par exemple < attention à ne pas exploser le timing ๏ sorte de revue collective, sauf que l’objectif est de passer le savoir dans l’équipe ๏ Sujet choisis au standup le matin ๏ En moyenne, annulé 1 fois par semaine ๏ 1 fois sur 2, ne dure que 10 min ๏ On y parle < Standard de code < Tâche tordue dont tout le monde doit connaître le fonctionnement < Choix d’architecture < Ou tout simplement revue collective 53 Un point tech pour partager et décider
  47. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    55 Le super héros Résout vos problèmes mais … casse tout autour pour le faire Le moine codeur Le grand architecte Fait un dossier d’archi pour chaque évolution mais … il se retrouve périmé après chaque implem’ Le critique A des convictions sur tout mais … n’a jamais rien implémenté de concret L’archiviste Refactore le code tout le temps mais … ne fait rien de nouveau Implémente tout ce que vous voulez mais … dans son coin
  48. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    56 Le super héros Tests automatisés Le moine codeur Revue de code, Pair programing ... Le grand architecte Documentation as code Le critique Rétrospectives L’archiviste Definition of done & tests d’acceptance
  49. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    Gérer l’Infra-as-code comme du code Focus sur le feedback Bricolez adaptez vos outils Concevez votre code pour qu’il soit lu Relisez le code du voisin Détectez les stéréotypes WIN WIN WIN WIN WIN WIN
  50. OCTO © 2018 - Reproduction interdite sans autorisation écrite préalable

    59 Culture Code Software Craftsmanship : Better Places with Better Code http://www.octo.com/fr/publications/20-culture-code Culture DevOps : Les ingrédients secrets d'une organisation DevOps équitable et durable https://www.octo.com/fr/publications/30-culture-devops-vol-01 Pour aller plus loin ... Merci, des questions?