lundi 28 janvier 2013

5 Bonnes raisons du MDA pour le développement mobile

 
Article co-écrit par Florent Dupont et Lamia Gaouar, qui prépare actuellement un doctorat SIC autour des développements Android et MDA à l'université de Tlemcen.

La démocratisation des plateformes nomades (mobiles et tablettes) poussent les entreprises à proposer toujours plus de services aux utilisateurs. Elles ont, en effet, bien compris tous les enjeux qui se trament derrière les applications mobile : communication améliorée, nouveaux services aux utilisateurs, régie publicitaire, avantage concurrentiel, etc.

Cet engouement pour les plateformes nomades offre de nouvelles perspectives de marché, notamment pour les entreprises éditrices (que ce soient des Mobile Agencies, des Web Agencies ou encore des SSII) qui peuvent proposer leur expertise de développement. Depuis 2011, le marché des ventes de mobile dépasse les ventes de PC et offre donc des perspectives de marché de développement d’applications mobile très importantes.

Ces éditeurs doivent cependant s’adapter aux plateformes de développement mobile qui sont foncièrement différentes de celle des applications Desktop. En effet, ces plateformes imposent des contraintes fortes, les ressources étant limitées : taille d’écran réduite, processeur faible, stockage limité, connexion lente et intermittente, RAM limitée. Toutes ces limitations impliquent une discipline de développement particulière pour que l’expérience utilisateur soit toujours efficace.

Au niveau logiciel, de multiples OS (Android, iOS, BlackBerry, Windows Phone) se disputent le marché de la mobilité. A chaque OS correspond une plateforme de téléchargement d’applications, des outils de développement et un langage de programmation permettant le développement et la distribution des applications :

 


Cette hétérogénéité des outils de développement et des langages, rend difficile le développement d’applications mobile multiplateformes. Elle pousse les développeurs à faire un choix sur la plateforme, tout en assurant la plus grande distribution possible.

Des outils pour aider les développeurs ?

Google a récemment apporté un élément de réponse avec le projet J2ObjC qui permet de convertir du code Java (Android) en code Objective-C (iOS). L’intérêt d’une telle démarche est de pouvoir récupérer le code fonctionnel d’une application Android afin de faciliter la conversion vers la plateforme iOS.
Mais cette approche pose encore de nombreuses questions :
  • Qu’en est-il de la conversion Objective-C vers Java ? Et vers d’autres OS  ?
  • Et plus généralement, comment capitaliser sur le fonctionnel d’une application indépendamment des préoccupations techniques afin d’en faciliter la migration ?  

Une réponse avec le MDA

L’approche MDA a su faire ses preuves pour le développement d’applications d’entreprise et peut également apporter beaucoup pour les applications mobile. Au travers de 5 points, nous allons voir pourquoi et comment l’approche MDA peut nous aider à assurer la pérennité des savoir-faire, le gain de productivité tout en répondant aux problématiques de fragmentation des plateformes mobile.

1. Réduire les problématiques de fragmentation

Chaque OS mobile détient une part du marché, et donc chacun possède sa communauté d’utilisateurs et de développeurs. Cette fragmentation pose un souci pour les entreprises désireuses de toucher un large public car le développement des applications multiplateformes est très coûteux en temps et en argent. Les entreprises se trouvent face à un dilemme :
  • Développer une application de qualité en un temps efficace et limiter sa distribution à une plateforme spécifique. 
  • Développer une application aux fonctionnalités réduites, mais proposée sur plusieurs plateformes et à un large panel d'utilisateurs.
Des solutions hybrides existent comme Cordova (application native construite à partir de vue Web et Html5) ou Flex 4.6 (exécution sous plateforme Flash) et permettent d’assurer du multiplateformes, mais leur prise en charge reste techniquement partielle. En réalité, une application native restera plus adaptée pour plusieurs raisons :
  • L’utilisateur dispose d’un environnement adapté à sa plateforme et à ses spécificités : l’expérience utilisateur reste optimale.
  • Le développeur tire profit de l’architecture spécifique et optimise l’application en fonction de la plateforme.
  • L’application peut évoluer et éventuellement tirer parti des fonctionnalités spécifiques à une plateforme ou OS.

L’approche MDA peut répondre à ces problématiques : décrire les besoins fonctionnels d’une application indépendamment de la plateforme d’exécution, et respecter les spécificités techniques de chaque plateforme. MDA permet de générer le code sans valeur ajoutée (boilerplate code) spécifique à chaque plateforme. On assure ainsi un gain de productivité, même sur des applications natives.

2. Capitaliser sur les concepts proches

Chaque OS mobile utilise son propre langage de programmation et arbore ses propres APIs mais les concepts généraux restent standards et communs. On peut se permettre de capitaliser des concepts communs entre différentes plateformes permettant de modéliser une application de manière générique, citons par exemple :
  • Activité : correspond à une page de l’application, elle est une notion commune à tous les OS. Une application est composée d’une ou de plusieurs activités.
  • Gestion des données de l’application : en séparant le code de l’interface graphique et le code fonctionnel.
  • Vues et actions associées : une vue est un objet graphique par lequel l’utilisateur interagit avec l’application ce qui provoque une action liée à la vue. Nous retrouvons la plupart des vues sur tous les OS mobile : bouton, saisie de texte, label, barre de navigation, bouton radio, case à cocher, etc.
  • Type d’évènements : une application doit prendre en charge certains évènements susceptibles d’apparaitre durant son exécution tels que les appels téléphoniques, les SMS, etc.
  • Applications natives : les applications natives telles que le calendrier, les contacts, les alarmes, le lecteur média sont communs à tous les OS.
L’approche MDA divise la conception de l’application en deux points de vue :
  • Un point de vue "fonctionnel" indépendant des détails liés à la plateforme d’exécution. On définit ce que l’on veut générer (le quoi). Dans cette partie, on modélise des notions abstraites telles que des écrans, boutons, objets métier, DAO, mais en restant indépendant de leur implémentation technique. Modéliser le fonctionnel de l’application assure la pérennité des savoir-faire.
  • Un point de vue "technique" dans lequel sera décrit l’architecture de la plateforme d’exécution. On définit comment on veut le générer (le comment). Dans cette partie, on spécifie comment la notion fonctionnelle doit être générée : quel langage (Objective C, Java), quelle version (Android 4.1 par exemple), quelle implémentation de BDD. Modéliser l’architecture technique assure la prise en compte de la plateforme d’exécution.
L’étape qui suit la description fonctionnelle et technique d’une application est la génération du code source, c’est le rôle du générateur (ex. MIA Studio, Acceleo). Il s’appuie sur le modèle fonctionnel et technique de l’application pour générer du code source que le développeur pourra enrichir manuellement (le traitement algorithmique et les ressources qui ne peuvent pas être déduits du modèle). La modélisation nous assure une pérennisation du savoir fonctionnel. La génération de code assure un gain de temps considérable entrainant un gain de productivité.

3. Elargir l’écosystème mobile

L’écosystème - tout ce qui vit autour d’une plateforme pour en faciliter le développement - existant sous JavaEE/.NET est large, mais sur plateforme mobile, cet écosystème est encore réduit. L’utilisation de librairies tierces dans les applications mobile est limitée par les différents OS pour plusieurs raisons :
  • Une taille d’application importante : l’utilisation massive de librairies est au contraire des bonnes pratiques pour le développement mobile (problématique d’espace mémoire).
  • Corrolaire du point précédent : une taille d’application trop importante peut être un frein à son téléchargement (debit limité et frais des réseaux 3G).
  • Le manque de visibilité des développements des librairies. Alors que les librairies pour applications JEE/.Net sont portées par de grands éditeurs (JBoss, Spring, Microsoft, etc.), les librairies mobile existantes sont quasi-exclusivement développées par des développeurs tiers. Le suivi et la maintenance ne sont donc pas toujours assurés.
  • Les éditeurs Google, Apple, Microsoft gardent la main sur les évolutions des SDK et ne garantissent donc pas la compatibilité des librairies tierces avec les nouvelles versions des plateformes.
Pour assurer la pérennité du code et élargir son périmètre de compatibilité à plusieurs versions, il est donc préférable d’être indépendant au maximum des librairies tierces et d’avoir un code standard au SDK. L'approche MDA réduit le temps de développement en générant du code standard au SDK, en respectant les bonnes pratiques d’architecture et de qualité.

4. Industrialiser le développement

La mise en place d’une approche MDA, conjointement avec les différents composants d’une usine logicielle (construction, Intégration continue, analyse qualimétrique), industrialise le développement et assure une bonne qualité au code.
L’industrialisation avec le MDA nécessite plusieurs éléments clés :
  • La mise en place d’un POC par une équipe d’architectes logiciels. Ce POC servira de base de code attendu pour faciliter la réalisation du générateur.
  • Un code généré ne doit pas être source d’erreurs et doit rester compatible avec les niveaux de qualimétrie logicielle (qualité, architecture).
  • Une formation des développeurs à l’utilisation du DSL et du générateur.
  • Un support technique permettant d’accompagner les développeurs sur les outils afin d’assurer un bon démarrage du projet.
  • Une communauté autour du générateur qui remonte les bugs. L’amélioration en continue du générateur profite aux développements en cours et aux prochains projets.
  • Une capitalisation sur les bonnes pratiques de développement afin de développer des futures applications encore plus rapidement.
Sur le marché, il y a encore peu de développeurs avec des compétences “mobile”. L’industrialisation des développements mobile par l’approche MDA, a encore plus de sens dans ce contexte, car il permet d’avoir un meilleur accompagnement et un meilleur suivi.

5. Réduire le coût de possession

Avec des budgets toujours plus serrés, les entreprises veulent réduire le coût de possession de leurs applications. L’approche MDA, et plus spécifiquement le DSL et le générateur de code ont une grande valeur de capitalisation et de réutilisabilité. Elles permettent ainsi de réduire les coûts de possession, notamment sur l’investissement initial et le coût de maintenance  :
  • Une conception facilitée par un DSL adapté, cadrant les besoins spécifiques aux plateformes mobile. 
  • Un générateur de code disponible “sur étagère” et utilisable rapidement permet de booster le démarrage d’un projet. 
  • Réduction du support technique : le code ou les patterns complexes et qui sont enclins aux erreurs (typiquement liés à la persistance, mapping ORM) sont générés.
  • Un code de qualité suivant les bonnes pratiques assure une meilleure maîtrise et une réduction des coûts de maintenance. 
  • Un processus itératif : l’outillage MDA par amélioration continue va réduire les coûts des projets progressivement au fur et à mesure de son amélioration.
Un OS peut aujourd'hui être leader du marché et demain perdre certains marchés. Un exemple, avec les annonces de Samsung, premier fabricant mondial de smartphones, qui compte  sortir de nouveaux smartphones en 2013 en abandonnant Android pour Tizen. Ou encore à l’image du géant chinois Huawei qui propose son propre OS mobile ou encore plus récemment Firefox avec FirefoxOS.



En conclusion, au lieu d'investir sur la technologie qui abrite une application, mieux vaut investir dans une technique de développement qui permet de capitaliser la fonctionnalité d'une application indépendamment de sa technologie. Une méthode qui intègre l'évolutivité et la pérénité dans son processus de développement comme l'approche MDA.



dimanche 13 janvier 2013

Code trop commenté : signe de mauvaise qualité ?

Les commentaires de certains programmes m'ont toujours surpris : Soit il n'y en a pas, soit il y en a trop ... Je suis toujours surpris par la quantité de commentaire de certains programmes, surtout lorsque ceux ci n'apportent rien et qu'ils polluent la lecture du code. 

En réalité, et au risque d'en faire bondir certains, il est préférable d'avoir peu de commentaires dans du code bien écrit, plutôt que l'inverse.
D'ailleurs, une méthode trop commentée est même peut-être un signe que quelque chose est louche, comme le dit si bien Martin Fowler.
Ne vous inquiétez pas, je ne dis pas que les développeurs ne devraient pas écrire de commentaires. Dans notre analogie olfactive, les commentaires ne sentent pas mauvais ; en fait ils sentent plutôt bon. La raison pour laquelle nous mentionnons les commentaires ici est qu'ils sont souvent utilisés comme déodorant. C'est étonnant de remarquer que souvent, un code généreusement documenté est en fait vraiment mauvais.

Les commentaires nous guident vers du mauvais code qui a toutes les mauvaises odeurs dont nous avons discuté dans le reste de ce chapitre. Notre première action est de supprimer cette "mauvaise odeur" en refactorant. Et dès que nous avons fini, nous nous rendons compte que les commentaires sont superflus.

Si vous avez besoin d'un commentaire qui explique ce qu'un bloc de code fait, essayez d'extraire la méthode. Si la méthode est déjà extraite mais que vous avez toujours besoin d'un commentaire pour expliquer ce qu'elle fait, alors renommer la. Si vous avez besoin de définir quelques règles à propos de l'état du système, introduisez des assertions.

Quand vous sentez le besoin d'écrire un commentaire, essayez d'abord de refactorer le code pour que chaque commentaire devienne superflu. Un bon endroit pour utiliser un commentaire est quand vous ne savez pas quoi faire. En plus de décrire ce qu'il fait, les commentaires indiquent les points sur lesquels vous n'êtes pas sûr. Un commentaire est une bonne place pour dire pourquoi vous avez fait quelquechose. Ce type d'information aide les futurs développeurs qui reprendront votre code, et spécialement ceux qui oublient vite.
Martin Fowler

Avoir un outil de qualimétrie (type Sonar) qui oblige les développeurs de mettre des commentaires Javadoc peut donc être contraignant sur certains aspects car il peut pousser à mettre du commentaire superflu sans aucune valeur ajoutée, car cet outil ne fait qu'une analyse du code source sans intelligence, sans contexte.

Quelques contre-exemples assez problématiques (issus de vrais code source sur de vrais projets !!) sur les accesseurs :

/**
* Accesseur en écriture sur l'attribut Name
* @param newName Nouveau nom à assigner à l'attribut name **/
public String setName(String newName) {
    this.name = name;
}
/**
* Accesseur le lecture sur l'attribut Name
* @return l'attribut Name
*/
public String getName() {
    return this.name;
}

Ou dans certains cas, quand un développeur prend conscience du peu d'intérêt du commentaire mais DOIT respecter les règles imposées par l'outil de qualimétrie (Sonar en l'occurence dans l'exemple suivant) et sort l'astuce du point commenté pour le code soit sans violations !

/**
* .
**/
public int getName() {
    return this.name;
}

En réalité le code des accesseurs est beaucoup plus lisible sans aucun commentaire : 
public void setName(String name) {
    this.name = name;
}

public int getName() {
    return this.name;
} 



Ceci nous amène à plusieurs règles pour l'écriture de bons commentaires :
  1. Privilégiez le pourquoi et non pas le comment. Documentez les classes et les opérations pour décrire leurs effets et leurs objectifs sans référence aux moyens par lesquels ils le font. Le commentaire ne doit pas faire référence aux détails d'implémentation (Cette règle s'applique également en tant que règle de nommage des classes et opérations).
  2. Ne dupliquez pas les commentaires entre les interfaces et les classes d'implémentations. En cas de refactoring, il sera difficile de maintenir une documentation à jour aux différents endroits. Il est préférable de positionner le commentaire sur l'interface et de laisser la classe d'implémentation sans commentaire. 
  3. Privilégiez la concision des commentaires. N'oubliez pas qu'un commentaire est rarement lu, surtout s'il est long. Il est préférable de vérifier automatiquement la validité de paramètres dans le code avec des assertions plutôt que d'écrire dans le commentaire ce qui est attendu.
  4. Privilégiez les conventions de codage pour comprendre l'objectif d'une méthode. Par convention, on sait qu'une méthode commençant par get est un accesseur en lecture. Même chose avec les méthode set qui indique un accesseur en écriture. Il n'est pas nécessaire de ré-expliquer un comportement dont la lecture du code saute aux yeux !
  5. Privilégiez un vocabulaire commun à tous les développeurs pour que chacun puisse appréhender rapidement le sens d'une fonction juste en lisant son nom. En réalité, il est préférable de nommer correctement une méthode plutôt que d'écrire du commentaire pour expliquer ce qu'elle fait. Il peut être utile de définir une liste de mot-clés à utiliser pour que les développeurs s'appuient sur une même convention de codage.
  6. Prenez du recul sur le besoin d'un commentaire. Ne vous forcez pas à écrire un commentaire parce que l'outil de qualimétrie a remonté une violation, ou parce qu'un taux de commentaire minimal n'est pas respecté. Posez vous la question "Est ce que ce commentaire a une valeur ajoutée ?" si la réponse est non, alors supprimer le !  

L'info en plus : Personnaliser cette règle sous Sonar

  • La Javadoc n'est pas requise sur une méthode annoté @Override. Le commentaire sera automatiquement hérité. (Privilégiez cette approche à l'utilisation de inheritDoc qui nécessite un commentaire). N'hésitez donc pas à en tartiner les méthodes déjà commentées dans les interfaces et dans les classes parentes (notamment equals, hashCode, toString, etc.);
  • le paramètre allowMissingPropertyJavadoc de Sonar permet de ne pas remonter d'erreurs pour les getter et setter non commentés.

Pour aller plus loin, je vous conseille les lectures suivantes :

samedi 7 juillet 2012

Retour d'expérience : bonnes pratiques d'une équipe d'architecture logicielle

Je termine une mission d'architecture logicielle dans une cellule Méthodologie de Développement et MDA dans une grande DSI française. Au sein de cette équipe, nous définissons et mettons en place des architectures logicielles pour les projets.
Le travail s'axe autour de plusieurs aspects :
  • Formation et accompagnement des équipes projets sur les phases de conception (modélisation, Design Pattern), développement, déploiement.
  • Conception d'outillage pour la démarche MDA : langage de modélisation interne, outils de modélisation et générateur de code;
  • Réalisation et mise à disposition des outils du poste de développeur.
Le tout dans un contexte de méthodologie agile.
Je voulais vous remonter mon retour d'expérience pour partager les bonnes pratiques qui ont fait le succès de cette approche.

Faciliter le passage de connaissance pour consolider l'équipe

Afin de renforcer l'esprit d'équipe, les membres de l'équipe "tournent" sur le support au développement. Forcément, en pratique, certains auront certaines affinités sur des sujets selon leurs propres expériences (on avait le "specialiste performance", le "specialiste sécurité", etc), mais on essaie toujours de partager cette connaissance.
On consolide l'équipe avec cette approche. En cas d'indisponibilité, chaque membre de l'équipe peut reprendre le travail de l'autre rapidement. On est également plus réactif, car si un membre n'est pas disponible, on ne se retrouve pas bloqué à l'attendre. Mais surtout, chaque membre monte en compétence sur les différents sujet Même chose sur la méthodologie agile : A chaque sprint, le rôle de Scrum master tourne.
Pour faciliter les passages de connaissances entre les membres de l'équipe un blog permet de poster des solutions de certaines problématiques techniques qui pourront servir pour les autres membres plus tard. Lorsque le blog n'est pas suffisant, et que nous avons des besoins d’interaction, nous faisons un point technique "démo/tutoriel" avec le vidéoprojecteur.

Faciliter le passage de connaissance aux équipes projets

"Quand un homme à faim, mieux vaut lui apprendre à pêcher que de lui donner du poisson" disait Confucius.
C'est dans cet état d'esprit que nous faisons le support aux développeurs. Nous privilégions le passage de connaissance afin que les développeurs soient autonomes et montent en compétences, plutôt que de corriger leurs problèmes sans explications.
Ce passage de connaissance se fait de plusieurs manières : Un blog et une FAQ avec des articles expliquants les cas les plus récurrents (mise en place de la sécurité par exemple), du pair-programming avec les développeurs et même des screencasts.

Proximité de l'équipe

L'équipe au complet est localisée dans un même bureau. Quand le Product Owner, le Scrum master et les membres de l'équipe sont dans un même espace de travail, on favorise les échanges et on facilite la communication tous les membres de l'équipe. Les problèmes sont remontés au plus tôt et on sait plus facilement sur quoi travaille chacun de nous.
Pour aller encore plus loin dans l'échange et le suivi, nous avons - en tant que bons agilistes - notre stand-up meeting quotidien (limité à 15 minutes pour l'équipe, attention !), où chacun revient sur ces 3 questions "Qu'ai-je fait hier", "Sur quoi ai-je été bloqué" et "Que fais-je aujourd'hui". En essayant de ne pas s'égarer...
La proximité est également "virtuelle" Nous partageons des outils de travail : boite mail commune à l'équipe, outil de suivi commun à l'équipe.

Capitaliser sur les outils pour développer durablement

Lors de nouveaux besoins des équipes projets, certains outils spécifiques ont été développés. Il a rarement été question d'outillage "jetable". Chaque outil est développé selon les besoins actuels, puis remonté dans le référentiels des outils. Si un nouveau besoin se fait ressentir, alors on fait des évolutions sur l'outil.
Cette approche présente plusieurs intérêts :
- Lors d'un nouveau besoin : on se limite au cas d'utilisation actuel en ne développant que les fonctionnalités utiles au moment T.
- Lors de la réutilisation : on ne repart pas de zéro : on réutilise l'outil existant dans le référentiel
- Lorsque de nouveaux besoins se font ressentir : on fait les évolutions mais seulement sur le nouveau cas d'utilisation, en refactorant si besoin le code existant.
On garde une approche incrémentale, en se focalisant seulement sur les besoins en cours et en ne surdimensionnant pas les outils (on reste agiles).

Appliquer à soi-même les conseils que l'on prodigue aux autres

Nous poussons les équipes projets à avoir une approche TDD et d'intégration continue. Nous appliquons à nous-même ces préconisations. Notre outillage suit une approche TDD et il est placé dans une chaîne d'intégration continue afin de valider au plus tôt les problèmes.
Nous avons mis en place cette approche car nous nous sommes rendu compte que lors d'évolutions ou de corrections de bug sur notre outillage, nous pouvions amener des régressions. Même si nous sommes une équipe d'architectes logiciels, nous sommes avant tout des développeurs et à ce titre, nous devions également suivre les même processus de développement que les projets "métier" afin d'assurer un outillage de qualité.

Se remettre en question pour s'améliorer

Nous mettons un point d'honneur à l'amélioration continue grâce, entre autre, aux rétrospectives de Sprint.
Tout n'est pas parfait et nous l'acceptons. D'ailleurs, je pense que c'est ce qui fait que ça fonctionne bien : accepter que tout n'est pas parfait, permet de s'améliorer. Lors de la rétrospective de Sprint, nous remontons donc tout ce qui ne va pas au niveau organisationnel, humain ou technique et on tente de mettre en place des solutions pour améliorer ces points lors itérations suivantes.
L'autre point d'amélioration continue, ce sont les retours d'expérience auprès des équipes projets. Lorsque les projets sont terminées (ou en phase avancées de développement), nous faisons un point avec le lead developer, le responsable de l'équipe, l'architecte. et nous prenons en  compte les remarques et critiques sur notre outillage, nos formations, notre support. Nous prenons en compte également les idées qui permettraient d'améliorer le travail des développeurs.

En conclusion

Toutes ces bonnes pratiques nous ont permis de rester ouverts sur les développeurs et de nous améliorer en continu et surtout d'éviter le syndrome de la tour d'ivoire.
Peut-être utilisez vous d'autres bonnes pratiques de développement ("Eat your own dog food" par exemple) ou d'agilité (Kanban) ou d'apprentissage (Shu ha ri)
N'hésitez pas à nous remonter vos retours d'expériences en interne ou en mission pour que l'on puisse partager sur ces sujets.

lundi 23 avril 2012

Agilité : Améliorer son planning poker


A Devoxx France, Petra Cross nous a donné sont point de vue sur l'agilité telle qu'elle est utilisée chez Google dans son talk "Day to day software development at Google" pour être efficace et éviter de perdre trop de temps. Je trouve interessant de poster à ce sujet, car nous avons toujours du mal a estimer les user stories de manière abstraite et avons tendance à pendre trop de temps dans la négociation (et s'égarer dans les explications). Petra nous donne des astuces intéressantes pour mieux mettre en place son planning poker.

Comment s’abstraire du temps dans la macro-estimation des user stories ?
L’estimation des stories se fait normalement de manière abstraite. On parle de macro-estimation en point. Je m’explique. L’estimation des stories ne doit pas être faite avec la notion de temps (durée prévue pour la réalisation en jours/homme) mais avec une notion de points sans unité.

Pourquoi cette abstraction ? Car elle permet de mieux estimer une story et éviter les écarts de temps en fin d’itération. En voulant macro-estimer en j*h, on va faire en sorte que la somme des estimations de tâches corresponde avec l'estimation de la story. Or, le résultat est forcément biaisé, car la macro-estimation suit une suite de Fibonacci (1, 2, 3, 5, 8…) et ce qui va induire des décalages dans les estimations qui, elles, ne sont suivent pas cette suite. 

Alors comment bien macro-estimer ?
Il faut pouvoir juger de la complexité d’une story et non pas de son temps de réalisation prévu. L’idée est de définir, avant le début du premier sprint (et donc avant les premières estimations) 2 étalons sur des stories déjà réalisées par l’équipe et dont tous les membres maîtrisent la complexité. Tous les membres de l’équipe doivent se mettre d’accord pour définir ce qu’est :
  • un story A de 2 points
  • un story B de 5 points

par exemple
  • la story « implémentation de page d’information utilisateur » est estimée à 2 points;
  • la story « implémentation du tableau d’affichage des indicateurs » est estimée à 5 points

Avoir un seul étalon de 1 point n’est pas suffisant car il est difficile de savoir ce que représenteront des stories plus grandes. Avoir 2 stories étalons va permettre de mieux estimer car il est plus facile de faire des comparaisons entre plusieurs valeurs.

par exemple
  • Je considère que cette story X est plus simple à réaliser que la story étalon A => alors elle est estimée à 1 point
  • Je considère qu’elle est plus complexe que l'étalon A, mais plus simple que l'étalon B => alors elle est estimée à 3 points.
  • Je considère qu’elle est plus complexe que l'étalon B => Alors elle est estimée à 8 points.

Une fonctionnalité ne doit pas être estimée à plus de 8 points. Si les membres de l'équipe estiment la story comme ayant plus de 8 points alors il faut découper la story en plusieurs moins complexes.

Petra propose également un point de vue intéressant sur l'étape de négociation des valeurs estimées. La négociation entre les membres ne se fait que si les estimations ont un écart important (sur l'échelle de fibonacci). Si l'écart est minime, alors, c'est la majorité qui l'emporte.

Par exemple, sur une équipe avec 3 membres Paul, Bill, John : 
Si une story est estimée à 2 par Paul, 2 par Bill et 3 par John (je note 2-2-3) => l'écart entre l'estimation de John (3) et les estimations de Paul et Bill (2) étant minime, alors on considère l'estimation finale à 2 sans négociation des membres. l'estimation 2 étant majoritaire. 
idem, si on a le cas 3-3-2 => l'estimation sera alors de 3.
Si on a 3-3-8 (ou 1-1-3), alors on négocie car l'écart est important. Mais, pour éviter que la négociation soit trop longue, les membres de l'équipes vont d'abord poser des questions fermées permettant de mieux comprendre le périmètre la story avant de se mettre d'accord sur une estimation finale.

par exemple, "Est-ce que le bouton valider doit être implémenté dans cette story ?", "Doit on prendre en compte les calculs de taux dans cette story ?"

S'il n'y toujours pas consensus à la suite des questions fermées, alors, on pourra envisager des négociations ouvertes.

La prise en compte de points abstraits n'étant pas naturelle  (puisque sans unité) son utilisation ne sera pas forcément efficace dès les premiers sprints. Mais normalement, après 3-4 sprints, tous les membres devraient mieux appréhender son utilisation.

Il ne reste plus qu'à essayer de mettre en place cette solution. Je reste ouvert si vous avez d'autres solutions / façons de faire !


mardi 7 février 2012

Les limites du MDA en entreprise

Je souhaitais faire un retour d'expérience concret sur les cas "typiques" de limites de l'approche MDA en entreprise d'un point de vue "développeur". Ces limites peuvent pousser, dans certains cas, à abandonner l'approche MDA.
Ce retour d'expérience personnel est issu de plusieurs points de vue : de mon œil neuf que j'avais lorsque j'ai débuté et que j'étais "utilisateur du générateur", puis d'un œil plus expérimenté en tant que "concepteur de générateur" et en condensant les retours d'expériences des développeurs au sein de différents projets utilisant l'approche MDA.

Une idée du contexte : les DSL ne sont pas forcément Turing-complet mais, dans tous les cas, le générateur mixe code manuel et code généré (approche par balises comme défini dans l'article précédent). Les DSL sont dans tous les cas des modèles (je n'ai pas de retour d'expérience sur des DSL texuels). Ils sont indépendants ou basés sur une extension d'UML avec des profils.

Les cas limites du MDA

L'inexpérience du développeur
Le développeur débutant ne connait pas les enjeux liés à l'approche MDA.
Il développe en dehors des balises prévues à cet effet et remet en cause l'outillage MDA de lui avoir fait perdre tout son travail.
Il considère que le code généré est trop compliqué à lire et à modifier et préfère considérer sa propre approche.
La phase de conception peut également être problématique pour les développeurs qui veulent tout de suite "coder du technique". Le cas le plus typique étant les développeurs avec une vision bottom-up et qui souhaite modéliser la base de données sans vision fonctionnelle ( "Comment ça je ne peux pas modéliser une colonne de table du type CHAR(3) pour Oracle ?" ).
Finalement, il laisse tomber l'approche MDA.

Le temps  (ou la paresse du développeur...)
Le développeur connait les intérêts de l'approche MDA, mais considère le round-trip trop consommateur en temps et préfère modifier le code sans passer par le modèle.  En fin de projet, les délais sont serrés et le modèle devient moins prioritaire : seule la livraison compte !

La raison est simple : ajouter du code depuis l'IDE lui prend très peu de temps comparé au temps de round-trip : modélisation, export XMI, validation du modèle, génération, vérification de la validité du code. Sans compter le temps d'ouverture des outils, le temps de chargement (du modeleur et du générateur) qui s’avèrent non négligeable. La fréquence de round-trip s'avère donc incompatible avec des délais courts.
De plus, la plupart du temps, le modèle ne fait pas partie de la livraison. Refaire une étape de modélisation n'est donc pas jugée prioritaire.

En solution, le développeur ajoute un maximum de code manuel alors que ce code pourrait être intégré au modèle. Finalement, il se rend compte que le modèle n'est plus vraiment à jour, et que la resynchronisation modèle / code sera coûteux et ne sera donc fait qu'"après la livraison, quand on aura plus de temps". Traduisez par "Jamais".

La perte de code
Le développeur effectue des roundtrips réguliers, mais il s'aperçoit que certaines portions de code ne sont pas correctement regénérées et lui font perdre son code manuel.
Ce cas peut arriver pour plusieurs raisons :

  • Les balises de code manuel peuvent être supprimées lors d'une réorganisation automatique du code par l'IDE.
    Par exemple, les balises autour des zones d'import de fichier Java sont souvent effacées lors d'une "réorganisation des imports" sous Eclipse. Sous FlashBuilder 4, les zones d'imports des AS3 sont systématiquement supprimées.
  • Les balises peuvent être modifiées lors d'un reformatage.
    Par exemple, Eclipse formate les commentaires : les balises (qui sont des commentaires) sont modifiées et ne sont donc plus valides. 
  • Une maladresse du développeur, une balise est modifiée et le code manuel n'est pas ré-intégré.
  • Un refactoring qui n'est pas pris en compte par l'outillage : Comment gérer les refactoring de méthodes, de classes ?
    Par exemple, les balises de code manuel pour les méthodes sont constituées de la signature de la méthode. En cas de changement de celle-ci, la balise est changée et le code perdu.
    Autre exemple, pour les renommages de classes : Un classe Toto devient un fichier Toto.java. Lors d'un renommage de Toto en Titi, le code de la classe existante Toto.java n'est pas ré-intégré dans Titi.java. Titi.java est vierge de tout code manuel. Toto.java est toujours présent mais orphelin.
  • Certains fichiers entièrement générés ont besoin d'être customisés par le développeur. Le développeur modifie donc le code généré consciemment. Lors d'une regénération, le code sera perdu, mais le développeur récupérera les modifications dans le SCM et les ré-intégrera manuellement.  
Le temps passé sur le SCM à réintégrer le code perdu devient donc problématique. D'autant plus, lorsque nous préconisons une approche incrémentale, le développeur fera nécessairement plusieurs round-trip au cours du développement de son logiciel. Chaque round-trip nécessitant de la part du développeur qu'il vérifie que du code n'as pas été perdu. La fréquence de round-trip s'avère donc incompatible avec des délais courts (point précédent).
A ajouter également, le non déterminisme du générateur :  Lors de génération successive, pour un même modèle, le code généré n'est pas dans le même ordre. Ce principe s'explique car la spécification du méta-modèle (UML en l’occurrence) n'ordonne pas certaines relations entre objets.

Là encore, il pourra remettre en cause l'approche MDA (notamment sur la fin des projets) comme étant problématique.

La conformité du code
Le développeur perd du temps à corriger des erreurs dans le code généré : erreur de compilation, erreur à l’exécution ou encore pertes de performances.
Suite à un audit de code, ou une validation de qualité, il est démontré que le code généré est la cause de perte de qualité du projet. Le code généré entraine donc une dette technique qu'il faudra prendre en compte.
Plusieurs cas peuvent être remontés :
  • Le code généré ne compile pas ou contient des portions de code au comportement douteux provoquant des bugs;
  • Le code généré fait baisser la note qualitative du code source de l'application. Il n'est pas formaté correctement, n'est pas commenté, il est difficilement lisible et donc difficilement maintenable.
Le développeur perd du temps à remettre le code en conformité.

Ces points à eux seuls ne sont en général pas des causes d'abandon du MDA, mais peuvent faire baisser l'image de cette approche et peuvent avoir un effet cumulatifs avec d'autres points remontés précédemment.


Comment résoudre ces cas ?
Suite à ces différents cas d'abandon, j'ai défini 9 bonnes pratiques à suivre pour résoudre ces cas.
  1. Former les développeurs et les chefs de projets pour leur faire comprendre les intérêts qu'ils vont trouver à l'approche MDA : démarrage du projet plus rapide, suivi des préconisations d'architecture logicielle concernant la stack logicielle de l'entreprise, qualité de code, fiabilité du code technique qui a été éprouvée par les architectes logiciels et dont le développeur n'a plus à se préoccuper.
  2. Limiter le modeleur au DSL. Dans le cas où le DSL est une extension d'un langage existant (UML par exemple), il est nécessaire de customiser le modeleur pour limiter les possibilités de modélisation aux cas restreint par le DSL. Dans la mesure où on peut "ajouter" des concepts à UML, mais pas en "enlever", le modeleur ne pourra pas limiter toutes les possibilités offertes par le langage existant, ce qui nous amène au point suivant...  
  3. Le modèle doit être validé, au moins en partie, pendant la phase de modélisation. Au même titre qu'un code qui ne compile pas, apparait en erreur dans l'IDE, il faut qu'un modèle qui ne soit pas valide apparaisse en erreur dans le modeleur. Ceci implique que la validation de la cohérence d'un modèle doit être faite au plus tôt dans la chaine de génération.
  4. La qualité du modèle doit être remontée au plus tôt. Au même titre que le code peut avoir une note de qualité (par exemple dans Sonar), il doit être envisager d'avoir une note de qualité du modèle. L'approche MDA permet une meilleure qualité de code, mais n'empêche pas de modéliser n'importe quoi (tout en respectant les règles du DSL déjà validées par le point 4). Noter la qualité du modèle permet donc d'assurer une qualité de code accrue. Ce point nécessite également de mettre en place un document de convention de modélisation.
  5. La chaîne de génération doit être transparente : la plus rapide et la moins intrusive possible pour le développeur. Idéalement le développeur devrait modéliser et développer de manière fluide en passant de son modeleur à son IDE de manière instantanée : L'étape de génération devrait lui être cachée !
  6. Le code généré doit être correct (il ne comporte pas d'erreur de syntaxe), efficace (le code généré n'implique pas de pertes de performances et n'ajoute pas de bug supplémentaires à l'application), fonctionnel (Il a été validé par des architectes logiciels par un POC) et maintenable (il répond aux standards de qualité définis dans les conventions de codage).
  7. Le générateur doit être déterministe : il doit toujours générer le même code (et surtout dans le même ordre) pour un même modèle en entrée.
  8. Le générateur, par son action (lors d'une regénération) ou son inaction (modification du code par l'IDE ou erreur du développeur), ne doit pas faire perdre de code manuel.
  9. Lors de la création du générateur, une étude importante doit être faite pour bien définir les zones de codes manuelles et les zones de code entièrement générées. Il faut pouvoir laisser des portes de sorties au développeur pour customiser le code et qu'il ne se sente pas restreint et  considère l'approche MDA comme étant limitative au développement.
Aller plus loin
Ces bonnes pratiques sont bien évidemment spécifiques à ma propre expérience d'un point de vue développeur sur le cas concrets des générateurs mixtes généré/manuel. Dans la suite des articles, j'expliquerai comment on peut faire en sorte de respecter ces bonnes pratiques.


Le point de vue concepteur de générateur apporte également tout un lot de bonnes pratiques à mettre ne œuvre pour que l'approche MDA soit un succès.
L'utilisation d'autres types de générateurs ou de DSL (DSL textuels par exemple) apportent également leurs lot de bonnes pratiques.