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

Livraison continue, simplement

martinsson
January 14, 2020

Livraison continue, simplement

Les astuces pour faire du trunk based development et de la livraison continue simplement.

Présenté à Human Talks Grenoble jan 2020

martinsson

January 14, 2020
Tweet

More Decks by martinsson

Other Decks in Programming

Transcript

  1. Intégration continue : trunk based dev Livraison continue : déploiement

    auto Dev/QA Déploiement continue : déploiement en Prod
  2. Les parties faciles mais souvent negligées • Trunk based development

    • Parallell change - supporter deux versions • Feature Flags & Dark Launch • Branch by abstraction • Déploiement indépendant sans coordination
  3. Parallell change - supporter deux versions export function doSomething(arg1, arg2)

    { } // new method with slightly modified behavior // no need for synchronising with changes to existing usages export function doSomethingV2(arg1, arg2, arg3) { // duplicated logic and tests (or not) } app.get('/doSomething', doSomething) // publish a new route with a new name app.get('/doSomethingV2', doSomethingV2) Modification non compatible? 
 => créer nouvelle méthode temporairement Et pourquoi pas au niveau public ici REST Quand plus personne utilise l’ancienne version, supprimer
  4. Feature flag class SomeService { // inject the flag on

    boot constructor(private newFeature) {} youNameIt(arg1) { // logic... if (this.newFeature) { // new code } else { // possibly there's some existing behavior } // logic... } }
  5. Feature flag Mais si on a 10 ifs pour une

    feature? => Branch by abstraction
  6. Branch By Abstraction Ex changement de fournisseur d’envoi email //

    usage class WelcomeEmailer { sendWelcomeEmail(email, name) { checkEmailNotSentAlreadyTo(email) // specific to current lib let emailContent = "to: " + email + "\n\n" + "Hi " + name + "\n\n" + "welcome to our new platform!" // specific to current lib send(emailContent) logger.log("email sent to " + email) } } // existing lib export function send(emailContent: string) { } Déplacer le code spécifique vers un nouvel objet EmailAdapter // new lib export function sendEmail(to, from, content: string) { }
  7. Branch By Abstraction class WelcomeEmailerUsingAbstraction { constructor(private emailAdapter) { }

    sendWelcomeEmail(email) { checkEmailNotSentAlreadyTo(email) let content = "Hi " + name + "\n" + "\n" + "welcome to our new platform!" this.emailAdapter.send(email, content) logger.log("email sent to " + email) } } Injecter la strategie d’EmailAdapter voulue
  8. Feature flags with many ifs // basic approach requiring many

    ifs class SomethingMoreComplex { constructor(private newFeature) {} youNameIt(arg1) { if (this.newFeature) { doNewThing_1() } // logic ... if (this.newFeature) { doNewThing_2() } // logic... } } // approach using branch by abstraction class SomethingMoreComplexInjection { // instead of injecting the feature flag, inject the strategy/command object constructor(private strategy: ICoolFeature) {} youNameIt(arg1) { this.strategy.doNewThing_1() // logic ... this.strategy.doNewThing_2() // logic... } } // booting the application : only one if necessary let coolFeature = newFeature? new CoolFeature() : new OldFeature() const toto = new SomethingMoreComplexInjection(coolFeature) Use branch by abstraction
  9. Database change 1. Script de création de colonne + remplissage

    non bloquant 2. Nouveau code gérant les deux modes avec le feature flag OFF 3. Script de remplissage du delta bloquant + feature flag ON 4. Suppression ancien code + feature flag (+ colonne / table?) En plusieurs étapes …. Si vraiment on a besoin d’une haute dispo