• Ce blog — désormais archivé — est en lecture seule.
    Nouveau blog: William Durand.

Feature branch, Feature toggle pattern

Bonsoir,

Hier c’était devops meetup, 5ème du nom, où j’ai pu voir que JMX, ce n’était pas ma vie mais que ça semble tout de même cool !

JMX c’est un outil de monitoring Java plutôt mal connu et de mauvaise réputation alors qu’au contraire, il est très intéressant (enfin, pour ceux qui font du Java). La présentation était excellente et rondement bien menée.

Ce qui m’a poussé à écrire cet article, c’est la partie sur le Feature toggle Pattern. Oui ça en jette grave mais au fond, c’est un concept que tout le monde devrait connaître. Ce patron vise à activer de nouvelles fonctionnalités d’un service en production. Il y a plusieurs manières de le faire avec des attentes différentes.

Déployer en production

  • Sauce Weka : on pousse en prod, on regarde Pinba (ou tout autre outil de monitoring) et là : il s’affole et on rollback ou tout est ok, Next !
  • Sauce plus traditionnelle : la preprod contient la nouvelle fonctionnalité et tout a été testé (le top c’est avec des données de prod répliquées à J-1, une preprod quoi…), on déploie le code versionné de preprod sur la prod, normalement pas de soucis. Au pire on rollback.
  • Sauce Facebook : on déploie par groupe, ce qui permet de tester en situation réelle sans pour autant compromettre toute l’application.
  • Sauce random : On ouvre la nouvelle fonctionnalité aléatoirement sur un délai donné avant de l’ouvrir à tout le monde.

Pour…

  • Améliorer/Faire évoluer l’existant.
  • Ajouter une nouveauté.
  • A/B testing
  • Canary testing (test du canari, provient d’une sombre histoire de mines) : soit ça marche, soit t’as perdu.
  • Tester la viabilité d’une fonctionnalité : si elle plait ou non, si elle est rentable, si elle est acceptée.

Le Feature toggle pattern est une solution qui répond principalement aux trois dernières attentes. Il s’agit de rendre possible l’activation mais surtout la désactivation d’une fonctionnalité en instantanée sans rollback lourd et contraignant (les gens qui font du Java savent ce que c’est que redéployer).

 J’en viens donc à la partie technique, comment fait-on ?

Il nous faut deux implémentations d’une même interface, un dispatcher et une variable/propriété en guise d’interrupteur. Le dispatcher va lire cette variable et renvoyer vers l’une ou l’autre des deux implémentations, ce n’est pas bien compliqué et Martin Fowler l’illustre parfaitement bien dans son article sur le Feature toggle.

Mais au fait, pourquoi un titre qui parle de Feature Branch ?

C’est plus ou moins lié. Vous connaissez surement l’article A successful Git branching model, il ne fait qu’exposer ce principe. Chaque nouvelle fonctionnalité est développée dans une branche à part et soit on merge par la suite, soit non.

On peut donc utiliser ce modèle pour développer notre feature toggle :

  • une branche master : le code stable.
  • une branche new_feature : le code de la nouvelle fonctionnalité.
  • une branche new_feature_toggle : l’intégration de la nouvelle fonctionnalité dans le code stable avec le dispatcher et l’interrupteur qui va bien.

On déploie notre branche new_feature_toggle et on valide nos objectifs. Si c’est ok, on pourra merger new_feature dans le master et tout restera propre. Je dis cela parce que, lors de la soirée, des gens ont évoqué la propreté du code et la présentation évoquait la duplication du code. Ce système de trois branches amenuise ces problèmes.

Je ne l’ai pas dit avant mais le système de feature toggle a une durée de vie limitée. Il ne s’agit pas d’avoir en permanence la possibilité d’activer ou de désactiver des fonctionnalités même si dans l’absolu, « why not ?! ».

Symfony2, encore.

En discutant avec mon pote @Fabpom, nous avons pu faire l’analogie Java/Symfony2 assez aisément. Mettre en oeuvre le principe de feature toggle avec Symfony2, ce n’est ni plus ni moins que charger un service ou l’autre lors du boot de l’application. On peut imaginer la lecture d’une valeur dans un fichier YAML et le tour est joué.

So ?

L’idée est là, le concept est en place et fait son job. Il ne faut pas hésiter à se poser la question lorsque l’on développe et que l’on nous impose un certain « sans filet ». C’est un pattern à connaître et qui peut faire gagner pas mal de temps… et d’argent ;)

  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Twitter
  • Google Bookmarks
  • FriendFeed
  • LinkedIn
  • MySpace
  • Netvibes
  • PDF
  • Ping.fm
  • RSS
  • Technorati
  • viadeo FR
  • Wikio
  • Yahoo! Buzz
Publié dans ParisDevops | Mots-clefs : , , , | Commentaires fermés

#ParisJS – 7ème édition en bref

Bonsoir,

Je reviens juste de la 7ème édition du ParisJS et j’ai adoré.

Pourquoi ? Pour les conférences de bon niveau, les gens sympathiques avec certains bien calés et l’ambiance générale (+ les pizzas…:-D). En gros, un bon univers qui me correspond bien et voici mon résumé.

Développement web pour TV connectées

En rapide, c’est un vaste sketch, rien de normé, rien de compatible, chacun fait ce qu’il veut, etc. J’avais déjà eu l’aperçu au pôle dédié chez e-TF1 mais là c’était encore plus démonstratif.

Pour autant, les TV connectées représentent 40 millions de télés mais seulement 20% sont réellement connectées. A noter que Google (1 million de TV) et Apple (250k télés) ne sont pas les plus véloces. Les acteurs majeurs sont les créateurs de télés (LG, Samsung, …), les set-top box (Boxee, AppleTV, …) et les box opérateurs (Free, SFR, Orange, …).

Le cas Samsung a servi de fil d’ariane sur cette présentation. Je passe les détails mais ce n’est pas la panacée, il faut même patcher jQuery (problème de innerHTML inutilisable). J’ai appris le nom d’un outil utile : easy-XDM permettant notamment de dialoguer entre frames de domaines différents.

Pour conclure, il vaut mieux développer from scratch plutôt que de tenter d’adapter des existants. Le mieux reste de se constituer une couche d’abstraction ou de voir du côté de Sencha Touch. Une librairie devrait sortir et répondra au doux nom de Joshfire, du nom de la boite qui l’a créée. On a également évoqué les noms de lime et de hbbtv dans l’assemblée.

CouchDB

Une bonne pratique lorsqu’on veut modifier une « vue » aka Map/Reduce est de créer une nouvelle vue, de laisser l’indexation se faire et d’ensuite mettre à jour le code qui utilise cette nouvelle vue. La raison à cela est le temps de recalcule de l’index qui peut être très long.

HTML5 et vidéo

L’intérêt était ici de présenter la vidéo pour utiliser une webcam en HTML5 afin de prendre des photos, vidéos, … En vrac, il faut voir du côté du Device Api and Policy Working Group du W3C et du WHATWG (HTML living standard.

Des implémentations existent dans Android Stock Browser et PhoneGap. BlackBerry utilise sa propre implémentation : Webworks BB, tout comme Nokia avec : Nokia WRT. Mozilla a créé une extension nommée Rainbow pour pouvoir faire des trucs sympas.

Expressivité en JavaScript

En voilà une conf qui fait plaisir, normal le gars vient d’af83

Utiliser la librairie underscore.js parce que ça ne mange pas de pain et ça fait plaisir :-D Mais également parce qu’elle permet de rendre notre code JS lisible et là, c’est une bonne chose ! (Même si tout le monde n’était pas de cet avis…)

Pour éviter la soupe des callbacks, on peut compter sur Futures par exemple et de manière générale à tout ce qui répond à Promises/Futures.

Dernière chose, avec Firefox qui respecte bien la spec JS on peut faire:

var [a, b]  = func();

Cool non ? Et dernier truc: http://code.google.com/p/traceur-compiler/.

Les slides de François de Metz sont sur son profil Github.

Pacmaze experiment

http://pacmaze.com/.

Voilà pour le résumé, court mais avec de bonnes pistes à explorer :)

  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Twitter
  • Google Bookmarks
  • FriendFeed
  • LinkedIn
  • MySpace
  • Netvibes
  • PDF
  • Ping.fm
  • RSS
  • Technorati
  • viadeo FR
  • Wikio
  • Yahoo! Buzz
Publié dans Non classé, ParisJS | Mots-clefs : , | Commentaires fermés

Tests unitaires et fonctionnels sur un Bundle en Symfony2

Bonjour,

Depuis quelques temps maintenant je travaille à temps complet avec Symfony2. J’ai écrit quelques bundles puisque, à l’heure actuelle, il n’y a pas autant d’outils fournis avec Symfony2 qu’avec symfony 1.4.

Ecrire un bundle n’est pas très compliqué mais pour bien le tester, on peut vite rencontrer des problèmes. Jusqu’à présent, j’utilisais une manière naïve d’exécuter mes tests PHPUnit. Mes fichiers bootstrap.php allaient chercher le fichier autoload.php dans le projet courant.

Oui, projet courant = forte dépendance.

Aucun moyen de tester mon bundle en « vase clos » et c’est fort dommage. J’ai cherché un petit peu et j’ai trouvé une solution de contournement grâce à l’ami Kris Wallsmith qui explique comment il teste son bundle Symfony2. La solution est bonne puisque il me suffit d’avoir une arborescence de ce type pour tester aisément mes bundles:

projects
  |
  |_ Symfony2 (sources)
  |_ Bundle 1
  |_ Bundle 2
  |_ etc

Ainsi, je configure un phpunit.xml pour chaque bundle qui modifie la variable $_SEVER['SYMFONY'] de la sorte:

<php>
    <server name="SYMFONY" value="../Symfony2/src" />
</php>

Cette configuration permet de s’affranchir d’un projet complet pour les tests unitaires. Seulement j’ai rencontré deux problèmes:

  • Impossible de faire des tests fonctionnels.
  • Impossible de tester le bundle en intégration continue.

Or, l’intégration continue pour moi, c’est vital (ou presque). J’ai donc cherché une meilleure solution qui prend en compte les deux problèmes ci-dessus.

Tests unitaires d’un bundle

Pour les tests unitaires, c’est assez simple et assez proche de la méthode de Kris. La différence vient du fait que le bundle embarque les sources de Symfony2 en fixtures.

Le fichier phpunit.xml.dist prend cette forme:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
   backupStaticAttributes="false"
   colors="true"
   convertErrorsToExceptions="true"
   convertNoticesToExceptions="true"
   convertWarningsToExceptions="true"
   processIsolation="false"
   stopOnFailure="false"
   syntaxCheck="false"
   bootstrap="./Tests/bootstrap.php">
    <php>
        <server name="SYMFONY" value="./Fixtures/symfony/src" />
    </php>
    <testsuites>
        <testsuite name="MyBundle Test Suite">
            <directory suffix="Test.php">./Tests</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist>
            <directory>./</directory>
            <exclude>
                <directory>./Tests</directory>
            </exclude>
        </whitelist>
    </filter>
</phpunit>

Le fichier Tests/bootstrap.php par défaut est celui-ci:

<?php

require_once $_SERVER['SYMFONY'].'/Symfony/Component/ClassLoader/UniversalClassLoader.php';

use Symfony\Component\ClassLoader\UniversalClassLoader;

$loader = new UniversalClassLoader();
$loader->registerNamespace('Symfony', $_SERVER['SYMFONY']);
$loader->register();

spl_autoload_register(function($class)
{
    if (0 === strpos($class, 'My\\Bundle\')) {
        $path = implode('
/', array_slice(explode('\', $class), 2)).'.php';
        require_once __DIR__.'
/../'.$path;
        return true;
    }
});

Et pour terminer, il faudra ajouter le repo Git de Symfony2 en submodule du bundle dans Fixtures/symfony:

git submodule add git://github.com/symfony/symfony.git  Fixtures/symfony

Pour lancer les tests unitaires, nous n’avons plus qu’à faire:

git submodule update --init
phpunit -c phpunit.xml.dist

Si l’on souhaite tester son bundle sur la dernière version de Symfony2 en permanence, ce qui semble une bonne idée pour avoir un bundle à jour, on peut intercaler la commande suivante entre les deux précédentes:

git submodule foreach git pull origin master

Voilà pour cette partie, un aperçu avec le JqueryUiBundle:

Tests fonctionnels

Pour les tests fonctionnels, il nous faut un projet en fixtures comme on le faisait en symfony 1.x. Mais ce qui est bien, c’est que nous n’avons pas besoin de tout et que l’on peut customiser son projet de test. On peut probablement enlever les dossiers web/ et src/ et retirer le plus de vendors possible. L’important est d’avoir la console qui fonctionne, signe que le projet reste cohérent.

Pour cela, on va créer un projet dans Fixtures/testProject. Ce projet pourra être modifié à votre guise mais n’oubliez pas que c’est le projet qui sert pour les tests ! Pour rester à jour au niveau des vendors (Symfony, Twig, …) le mieux est de les ajouter en submodules du bundle. Ainsi, on exécutera les mêmes commandes pour lancer nos tests.

Note: Ce projet de test ne doit pas embarquer le bundle dans lequel il se trouve.

Le fichier phpunit.xml.dist va rester celui préconisé dans la documentation officielle de Symfony2.

Mais le fichier Tests/bootstrap.php va changer:

<?php

require_once __DIR__.'/../Fixtures/testProject/app/autoload.php';

$filesystem = new \Symfony\Component\HttpKernel\Util\Filesystem();
$filesystem->remove(__DIR__.'/../Fixtures/testProject/app/cache');
$filesystem->remove(__DIR__.'/../Fixtures/testProject/app/logs');
$filesystem->mkdir(__DIR__.'/../Fixtures/testProject/app/cache');
$filesystem->mkdir(__DIR__.'/../Fixtures/testProject/app/logs');

Celui-ci va permettre de réinitialiser le cache et les logs avant chaque phase de tests.

Dernière modification à effectuer sur le fichier Fixtures/testProject/app/autoload.php du projet de test en ajoutant le code ci-dessous à la fin:

spl_autoload_register(function($class) {
    if (0 === strpos($class, 'My\Bundle\')) {
        $path = implode('
/', array_slice(explode('\', $class), 2)).'.php';
        require_once __DIR__.'
/../../../'.$path;
        return true;
    }
});

Voilà, avec cette configuration, nous pouvons lancer nos tests fonctionnels sans soucis et de manière propre puisque l’environnement qui sera créé est bien celui de notre projet de test que nous maîtrisons bien. On peut ajouter de la configuration dans ce projet de test comme le chargement de routes, le paramétrage du bundle, etc…

Exemple d’utilisation avec le ExposeRoutingBundle:

Avec ces deux astuces, tout bundle peut être testé de manière autonome et dans la vision « à la Symfony2″, c’est plutôt intéressant :-)

  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Twitter
  • Google Bookmarks
  • FriendFeed
  • LinkedIn
  • MySpace
  • Netvibes
  • PDF
  • Ping.fm
  • RSS
  • Technorati
  • viadeo FR
  • Wikio
  • Yahoo! Buzz
Publié dans Symfony2 | Mots-clefs : , , , | Commentaires fermés

Symfony, Jenkins & co

Bonjour,

Depuis quelques temps j’ai repris mes travaux déjà énoncés symfony rencontre Hudson, Mantis et les autres. J’ai mis à disposition un template générique d’un build.xml pour Phing exclusivement, accessible sur mon Github : jenkins-phing-symfony. Il permet d’analyser son code symfony 1.x avec à peu près tous les outils en vogue du moment.

A ce propos, PHPLoc ne comporte pas de tâche Phing mais Raphael Stolt en a écrit une qui semble fonctionner : phploc-phing.

A noter également qu’il faut passer une variable à ce script pour indiquer le nom du projet:

    phing main -DprojectName=$JOB_NAME

Plusieurs targets sont disponibles :

  • main : Lance tout ce qui suit ;
  • clean ;
  • pdepend : Lance l’analyse de code statique avec PHP Depend ;
  • phpcpd : Lance l’analyse de code dupliqué PHPCPD ;
  • phpcs : Lance l’analyse checkstyle avec PHP_CodeSniffer ;
  • phpdoc : Lance la génération de la documentation avec phpDocumentor ;
  • phploc : Lance l’analyse PHPLoc ;
  • phpmd : Lance l’analyse PHP Mess Detector.

D’autre part, j’ai mis à jour mes règles Checkstyle (PHP_CodeSniffer) pour symfony 1.x : phpcs-symfony.

    <?xml version="1.0"?>
    <ruleset name="Symfony">
      <description>symfony coding standard</description>
      <!-- Tab indentation -->
      <rule ref="Generic.WhiteSpace.DisallowTabIndent"/>
      <!-- symfony uses 2 spaces to indent -->
      <rule ref="Symfony.WhiteSpace.ScopeIndent"/>
      <!-- -->
      <rule ref="Generic.ControlStructures.InlineControlStructure"/>
      <!-- -->
      <rule ref="Symfony.ControlStructures.ControlSignature"/>
      <!-- ensures there is no space after cast tokens -->
      <rule ref="Generic.Formatting.SpaceAfterCast"/>
      <!-- ensures that variables are not passed by reference when calling a function -->
      <rule ref="Generic.Functions.CallTimePassByReference"/>
      <!-- PHP constants should be lowercase -->
      <rule ref="Generic.PHP.LowerCaseConstant"/>
      <!-- No spaces on square brackets -->
      <rule ref="Squiz.Arrays.ArrayBracketSpacing"/>
      <!-- Don't allow ELSEIF, just ELSE IF -->
      <rule ref="Squiz.ControlStructures.ElseIfDeclaration"/>
      <!-- Ensures there is a space between each condition of foreach loops -->
      <rule ref="Squiz.ControlStructures.ForEachLoopDeclaration"/>
      <!-- Ensures there is a space between each condition of for loops -->
      <rule ref="Squiz.ControlStructures.ForLoopDeclaration"/>
      <!-- Ensures all control structure keyworkds are lowercase -->
      <rule ref="Squiz.ControlStructures.LowercaseDeclaration"/>
      <!-- Ensures all calls to inbuilt PHP functions are lowercase -->
      <rule ref="Squiz.PHP.LowercasePHPFunctions"/>
      <!-- Verifies that class members have scope modifiers -->
      <rule ref="Squiz.Scope.MemberVarScope"/>
      <!-- Verifies that class members have scope modifiers -->
      <rule ref="Squiz.Scope.MethodScope"/>
    </ruleset>

Après exécution sur mes projets, ces règles permettent de bien respecter les standards imposés par symfony 1.x (uniquement).

Voilà pour les nouvelles :-)

  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Twitter
  • Google Bookmarks
  • FriendFeed
  • LinkedIn
  • MySpace
  • Netvibes
  • PDF
  • Ping.fm
  • RSS
  • Technorati
  • viadeo FR
  • Wikio
  • Yahoo! Buzz
Publié dans symfony | Mots-clefs : , , , , , , , | Commentaires fermés

Symfony live 2011 – Journée 2

 Symfony2 from the trenches

Bon, c’était une liste des features de Sf2, les slides suffisent à expliquer ce qui a été dit.

 Introducting Assetics

« If you haven’t optimized frontend, you haven’t optimized. »

Beaucoup d’outils existent pour gérer ses assets : yui compressor, sass, less, jsmin, coffeScript, cssEmbed, sprockets, stylus, pcaker, … Aucun n’est écrit en PHP ⇒ Assetic ! (Viens du mot « asceticism »).

AsseticBundle

Assetic : dump –watch

HTTP Cache

Lire la documentation HTTP (la RFC là, vous savez ;-) ).

Deux types de cache existent :

http expiration : cache-control, expires

  • expires : utilise les dates spécifiées dans la RFC C1123 ⇒ gmdate()
  • cache-control : à utiliser contrairement à expires.
  • L’expiration permet d’accroître le nombre de requêtes possible sur son serveur.

http validation : last-modified, etags

  • 304 not motified, last-modified/ if-modified-since
  • La validation préserve la bande passante !

PHP ajoute un header de ce type dès lors qu’il y a une session :

    cache-control : no-store, no-data, must-revalidate, pre-check=0,post-check=0

Proxy cache

Shared cache, client side

Gateway cache

~proxy but server side, CDNs

Varnish

    cache-control : s-maxage=99 (shared max age)

Symfony2 en pièces détachées

  • Escaping enlevé de Sf2
  • transChoice() permet de gérer la pluralisation

Avis global

Génial, vraiment. J’ai pu rencontré pas mal de gens intéressants. Les conférences étaient toutes sympathiques et le cadre agréable. J’ai vraiment passé deux bonnes journées et je remercie Sensio de m’y avoir invité. Vivement l’année prochaine !

  • Print
  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Twitter
  • Google Bookmarks
  • FriendFeed
  • LinkedIn
  • MySpace
  • Netvibes
  • PDF
  • Ping.fm
  • RSS
  • Technorati
  • viadeo FR
  • Wikio
  • Yahoo! Buzz
Publié dans SfLive, symfony | Mots-clefs : , , | Commentaires fermés