Ce billet se veut une introduction au meetup du Paris Salesforce Developer Group, le 27 novembre 2014 chez Neoxia, intitulé “Versionning et travail en équipe avec Salesforce”.

Après quelques projets Force.com mettant en scène plusieurs développeurs et plusieurs instances, la question concernant le versionning du code source s’est forcément imposée à toute équipe de développement. De la simple gestion de version à l’automatisation des tests unitaires en passant par la classique question “c’est bien toi le dernier à avoir travaillé sur tel trigger ?”, il y a toujours une bonne raison de mettre en place une solide méthode de gestion du code source.

La particularité qui nous intéresse ici, c’est la double synchronisation qu’un tel système occasionne pour l’environnement Force.com : d’un côté, le code source doit être synchronisé avec le serveur de gestion du versions (ci-après noté CVS) ; de l’autre, le code source est synchronisé entre les développeurs via les instances lorsqu’ils touchent à une même ressource.

Salesforce préconise de posséder une sandbox par développeur (http://www.salesforce.com/us/developer/docs/dev_lifecycle/Content/lifecycle_adv_sandbox_env.htm). Cependant, ce n’est pas toujours possible, souvent pour des raisons logistiques. Par exemple, rafraîchir un environnement de développement avec des données ou une structure de production peut être une opération coûteuse. En rafraîchir plusieurs multiplie les coûts et les délais.

Nous souhaitions donc mettre en place un système qui nous permettrait de synchroniser le code avec notre CVS tout en n’étant pas gênés par la synchronisation avec une unique instance de développement.

 

Règles

Notre démarche s’est appuyé sur plusieurs règles et/ou conventions classiques posées dès le début :

  1. le code source présent sur le CVS prime sur les autres versions
  2. un seul repository par projet, indépendamment du nombre d’environnements à gérer
  3. le contenu de chaque instance est isolé sur une branche indépendante des autres
  4. le contenu de certaines instances (production, pré-production, …), et donc certaines branches, doit être protégé.

Et enfin, la plus importante : ce doit être simple. Dans le cas contraire, après quelques tests, ce serait vite abandonné par les développeurs. Malheureusement, la particularité de la “double synchronisation” et l’éventuelle richesse des environnements sont deux éléments qui ont tendance à compliquer les choses.

Contexte et prérequis

La démarche est adaptée à un environnement classique, que l’on trouve chez la grande majorité de nos clients. Cette infrastructure est généralement de l’un des 2 types ci-dessous.

img-1

Figure 1 – Environnements Salesforce

 

Pour la partie liée au code (triggers, controllers, pages…), nos développeurs utilisent le Force.com IDE (https://developer.salesforce.com/page/Force.com_IDE) ou bien Mavensmate (http://mavensmate.com).

Si le choix d’un IDE ou d’un autre n’a pas d’impact, il faut veiller à ce que la Tooling API (https://developer.salesforce.com/page/Tooling_API) soit bien l’API utilisée par défaut par l’IDE.

Si son IDE utilise la metadata API, lorsqu’un développeur fera une action de Pull sur une ressource depuis le CVS, il sera obligé de la rafraîchir manuellement depuis le sandbox, car les versions locales et distantes seront différentes pour l’IDE (le dernier modificateur et la date de modification seront différents), même si le contenu est identique.

L’aspect CVS est propre à chaque équipe. Chez Neoxia, nous avons une préférence pour Git, que ce soit à travers Github (https://github.com/neoxia) ou bien notre serveur Gitlab pour certains projets internes. Pour nos développements Force.com, afin d’organiser nos développements en local, nous utilisons Gitflow (voir l’excellent article à ce sujet : http://nvie.com/posts/a-successful-git-branching-model).

L’organisation de nos projets est représentée ci-dessous. Un repository concerne un projet et est composé de plusieurs branches, une par environnement cible. Les développeurs ont accès à la branche DEV en Pull et Push. Les autres branches nécessitent des autorisations supplémentaires, ce qui permet d’isoler les autres environnements de celui de développement. La branche “master” est la branche de production.

img-2Figure 2 – Organisation “Git” d’un projet

 

 

En pratique…

La pratique est très classique et ne s’éloigne pas de l’utilisation “normale” d’un CVS : Pulls réguliers, Commits réguliers, Pushs cohérents, etc.
Nous allons tout de même développer deux cas qui nous intéressent particulièrement : comment un développeur peut-il faire des pull et des push sur le repository distant malgré la double synchronisation ? Et comment peut-on livrer une version dans un autre environnement ?

Cas 1 : Pull & Push des développeurs

C’est dans ce cas que la Tooling API prend son importance. Cette API est utilisée dans les versions récentes du Force.com IDE. Il est aussi possible de modifier la configuration de Mavensmate afin de l’utiliser (http://mavensmate.com/Plugins/Sublime_Text/Compiling). Grâce à elle, les modifications effectuées en local sur un fichier sont synchronisées avec le serveur, sans vérifier que vous êtes bien le dernier modificateur du dit fichier.

Sans cette API (c’est à dire avec la Metadata API utilisée jusqu’alors), un développeur a besoin de dérouler les étapes suivantes :

  1. Faire un Pull de la dernière version ;
  2. Rafraîchir chaque fichier local à partir de la sandbox afin d’être identifié comme dernier modificateur de ces fichiers et acquérir le droit de les modifier ;
  3. Modifier l’un de ces fichiers ;
  4. Ce fichier est alors, automatiquement ou manuellement, synchronisé avec la sandbox.

L’utilisation de cette API supprime donc un élément de sécurisation du code mais simplifie ce process. A charge donc aux développeurs de faire attention lorsqu’ils sont amenés à travailler sur des ressources identiques.

 

Cas 2 : Livraisons

Dans notre organisation de repository, les développeurs n’ont accès qu’à la branche DEV, celle qui est lié à l’instance de développement. En effet, il n’est pas possible de développer directement en production. Pour mettre en place ce fonctionnement, nous avons “protégé” les autres branches : tout le monde y a accès en mode Pulls mais seuls certains profils peuvent exécuté des Pushs.

Cette protection est possible sur Gitlab à partir de la page de gestion des branches. A ma connaissance, il n’est pas possible de protéger une branche sur Github.

img-3Figure 3 – Mise en production d’un projet

 

Une livraison dans un environnement stable (recette, pré-production, production) nécessite donc un profil spécial de “validateur”. Hormis cette spécificité de protection, la procédure de livraison est classique (Pull, Merge puis Push) et représentée sur le schéma ci-dessus.

 

Conclusion

Les principaux points d’amélioration obtenus grâce à cette démarche ont été :

  • un pilotage plus fin des environnements SF au sein d’un même projet ;
  • une responsabilité accrue des développeurs (notamment sur la qualité du code et des tests) ;
  • un meilleure qualité des livraisons sur chaque instance.

En outre, cette démarche nous ouvre de nouvelles possibilités d’industrialisation des développements, notamment grâce à la mise en place d’un serveur d’intégration continue permettant d’automatiser l’exécution des tests et des déploiements. Nous en reparlerons dans un prochain billet.

Billet en collaboration avec Gil Gourevitch.