Thématiques principales

Affichage des articles dont le libellé est processus de développement. Afficher tous les articles
Affichage des articles dont le libellé est processus de développement. Afficher tous les articles

samedi 24 février 2018

Agilité: Combinatoire d'activité

Dans un article précédent [1] nous avons vu un modèle de processus de développement dans lequel je faisais intervenir 5 acteurs clefs responsables des axes majeurs intervenant dans le développement logiciel:
  • axe fonctionnel : le PO
  • axe technique : l’architecte
  • axe process : le scrum master
  • axe IVQ : le responsable IVQ (Intégration Validation Qualification)
  • axe savoir faire : le développeur


Je suis bien sûr très intéressé par votre opinion concernant mon avis sur le sujet. Alors n’hésitez pas à mettre des commentaires.

Références:


[1] http://un-est-tout-et-tout-est-un.blogspot.fr/2018/02/integration-continue.html

mercredi 21 février 2018

Intégration continue

Petit aparté pour parler un peu de l'intégration continu. Nous avions évoqué un peu le sujet dans l’article précédent [1] sur Gradle qui en est tout comme Maven [2] un élément et outil central à la construction d’un composant logiciel. Cependant, si nous avions décrit son rôle dans le processus de développement, nous n'avons pas décrit qu’elles sont les autres outils qui peuvent nous aider a automatiser l’ensemble du processus, nous aider à mener à bien l’entreprise de production logiciel complet, de A a Z.

Contextualisation

Repartons d’un processus de développement de base. Nous en avions vu quelques un dans l’article [3]. En voici un, sûrement perfectible, dans lequel nous utilisons une approche agile au sein de laquelle vont intervenir nos outils d'intégration continue.




Sans forcément faire un long discours explicatif des différents éléments de ce schéma (qui n’est qu’un modèle parmi d’autres possibles), nous pouvons décrire ce processus comme suit:

A partir de l’idée du client, sont définies un certain nombre de spécifications fonctionnelles plus ou moins raffinées. Ces spécification sont injectées, une fois suffisamment mature et dont la valeur ajoutée est considérée comme suffisamment significative, dans un certain nombre de Sprint sous la forme de Stories fonctionnelles et ou techniques. Le but final de l’approche étant de produire un certain nombre d'artefacts évoluant au fil d’un certain nombre de versions

Différents acteurs cités ici ont des rôles spécialisés selon les différents axes majeurs du développement logiciels :

  • axe fonctionnel : le PO
  • axe technique : l’architecte
  • axe process : le scrum master
  • axe IVQ : le responsable IVQ (Intégration Validation Qualification)
  • axe savoir faire : le développeur
La collaboration de ces différents acteurs est primordiale (et a mon sens, l’absence de l’un d’eux ne peut que mener à un désastre mais nous y reviendrons lorsque nous traiterons de la combinatoire de leur activités).

Nous avons déjà parler de l’approche agile mais nous pouvons constater ici qu’une phase importante du processus concerne la sortie de la partie cyclique. Cette phase peut être appeler livraison car elle correspond à la finalisation du ou des développements, et correspond au final à la livraison d’un nouvel incrément fonctionnel par l’ajout de nouveaux morceaux de code. Il faut comprendre que cette phase n’est pas terminale mais itérative comme l’est le développement et consiste à soutenir le développement en permettant la validation/livraison a chaque itération.

L'integration Continue

Cette phase est en fait appeler la phase d’intégration continue. Elle provient du besoin de tester systématiquement le code source et les nouvelles fonctionnalités apportées tout en garantissant la non régression des fonctionnalités déjà développées précédemment.


Mot d'ordre : automatisation

Dans ce schéma, le processus d'intégration continu fait intervenir un ensemble de composants en interaction et répondant à différents besoins. En entrée de l'intégration continu nous avons l’outil de gestion des sources (tel que Git [4], SVN [5] ou Mercurial [6]) dans lequel les développeurs déposeront le code produit et tester localement unitairement.

Ceci n’est cependant clairement pas suffisant car si un ajout de code peut être correct sur le poste du développeur et même en considérant que ce poste est conforme à un standard commun à toute l'équipe, il persistera toujours des différences sans compter les différences évidentes entre le poste de dev et la configuration d’un serveur cible.


Feed-back

Pour résoudre ces problèmes, intervient alors la phase d'intégration continu. Elle va permettre de procéder à une construction complète, automatisé et régulière de l’ensemble du composant logiciel soit de façon journalière, soit a chaque modification du référentiel de code, voir les deux. En procédant ainsi, l'intégration continu permettra la validation dans des plateforme de référence, de l’ensemble de fonctionnalités en déroulant l’ensemble des tests prévus (à noter que ces tests sont définis selon des niveaux différents, N1: tests unitaires, N2 tests d'intégrations, N3 : tests fonctionnels; les niveaux N2 et N3 sont souvent fusionnés). Les tests une fois validés, les développement réalisés par les développeurs sont alors intégré ensemble au sein d’une même branche ou de nouvelles validations sont déroulées (voila le coté intégration en continu).

Dans les faits, les sources sont récupérées par un outil d'orchestration tel que Jenkins [7] ou Travis [8] qui par configuration va appliquer un certain nombre de processus via un outil de build comme maven ou gradle ou directement sur la branche contenant les sources.

Procéduralement l’outil d’orchestration va devoir:

  • construire le composant (via maven [9] ou gradle [10]) en s’appuyant sur un entrepôt de composant (artifactory [11] ou nexus [12])
  • utiliser les éléments produit pour effectuer des tests unitaires
  • utiliser les éléments produit pour effectuer des tests fonctionnels dans un plateforme cible (virtuelle VM/docker ou non) avec des outils tels que robotframework [13] , sikuli [14]
  • effectuer de l’analyse de code à l’aide d’un outil comme sonar [15]
  •  produire de la documentation à l’aide d’outils comme maven site [16] ou java doc [17]


Vers le continuous delivery et le DevOps

En parallèle de cette approche ou le but est de vérifier au plus tôt l’absence de défauts mais aussi de problème d'intégration, il est considéré aujourd’hui de nouvelles approches par l’utilisation de conteneur versionable et livrable directement au client.

Ces nouvelles approches permettent au développeur de disposer d’un environnement de test ( voir de développement) local beaucoup plus proche et conforme à ce que sera la cible chez le client. Ces approches portées par des logiciels comme Docker fournissent des moyens beaucoup plus simple et élémentaires de validation et d'intégration en rapprochant le développeur de la plateforme cible cependant, elle nécessite l’utilisation par le client d’architecture spécifique basé sur ce type de conteneur. 


Facilitant d’un coté la maintenance, ces solutions doivent malgré tout, “en solution de virtualisation”, fournir des moyens de sécurisation et d’optimisation des performances au moins équivalentes aux solutions conventionnelles.

Conclusion

Dans ce blog, nous avons déjà traité des sujets tels que Docker. Il ne fait aucun doute que ce type de technologies ont leur adepte, et à juste titre. Cependant, même si ces approches ont leur avantages, il me semble que les approches conventionnelles (parce que omniprésente) gardent elles aussi leur points forts et que les solutions de productions logicielles futurs devront surtout composer avec des approches mixtes.

Il n’en reste pas moins que l'intégration continu est un environnement fortement outillé. Certains de ces outils, comme Maven, Gradle ou même la production documentaire, ont été évoqué dans différents articles. Pour les prochains articles, afin d’affiner notre vision des possibilités de l'intégration continu et des architectures possible la guidant, nous tacherons de rentrer un peu plus dans le détails de ces autres outils

References

[1] http://un-est-tout-et-tout-est-un.blogspot.com/2018/01/gradle.html
[2] http://un-est-tout-et-tout-est-un.blogspot.com/2017/12/maven-introduction.html
[3] http://un-est-tout-et-tout-est-un.blogspot.com/2017/12/les-processus-de-developpement-ou.html
[4] https://git-scm.com/
[5] https://subversion.apache.org/
[6] https://www.mercurial-scm.org/
[7] https://jenkins.io/
[8] https://travis-ci.org/
[9] https://maven.apache.org/
[10] https://gradle.org/
[11] https://jfrog.com/artifactory/
[12] https://www.sonatype.com/nexus-repository-sonatype
[13] http://robotframework.org/
[14] http://www.sikuli.org/
[15] https://www.sonarqube.org/
[16] https://maven.apache.org/plugins/maven-site-plugin/
[17] https://maven.apache.org/plugins/maven-javadoc-plugin/

dimanche 28 janvier 2018

Gradle

Lors de la production de systèmes logiciels, il ne fait aucun doute que la phase la plus importante est la compilation qui nécessite l’utilisation d'outils tels que gcc ou javac. Aujourd’hui pourtant limiter la production d’un logiciel a la compilation n’est plus suffisant. De nombreuses phases périphériques à la compilation sont devenu indispensables, comme l'exécution des tests unitaires ou des tests fonctionnels, la production automatique de documentations ou de code, le packaging multi plateforme, ou même la mise en production. Ceci s'appelle l'intégration continu au sein duquel on va trouver divers outils à différents niveau d’abstraction (Jenkins[1] , artifactory [2]) ou differents roles (Sonar [3], RobotFramework [4]). Nous reviendrons sur ces outils, mais nous en avions déjà vu un nommé Maven dans un précédent article [5] dont le but est justement de couvrir l’ensemble des phases du build.

Aujourd’hui nous allons nous intéresser à ce que l’on pourrait appeler un peu abusivement son concurrent: Gradle [7].

A mon sens Gradle en est plutot le successeur et nous verrons pourquoi. En effet, même si personnellement j’utilise encore beaucoup Maven, les raisons sont surtout historique et que faire la migration de l’un vers l’autre, ne peut être qu’un bien [9] mais cela repose sur une bonne disponibilité en temps.

Voyons ce que propose Gradle par dela Maven. Pour faire simple et rapide sur l'intérêt de Gradle est qu’il permet de dépasser le côté monolithe de Maven. En effet, Maven repose sur un socle stable et très sain d’un process de build. Du moins lorsque ce processus est classique et standard. Gradle, tout en conservant ce socle permet d'être plus souple et dynamique car contrairement a Maven qui repose sur xml pour décrire le contenu du build (donc a une vision configuration du process), Gradle lui repose sur groovy qui est lui un langage de programmation.

En fait si l’on reprend le titre de la publication de Leon Osterweil:  “software processes are software too” [8], nous sommes face à un véritable changement de paradigme dans la façon de gérer la production de logiciel ou celle-ci est également vu comme une partie intégrante du logiciel lui même.

Par exemple, Google a adopté Gradle pour la production de ses applicatifs Android et l’on peut assister que cette adoption a été largement suivi par une très bonne intégration de ce nouvel outils dans les IDE standard de la communauté. Ainsi developper une application android sous Gradle n’est vraiment pas un probleme [11] (nous y reviendrons dans un futur article)

Initialisation

Avant de nous pencher sur android, regardons déjà comment faire le build d’une application java standard avec Gradle.

Il faut commencer par télécharger Gradle [12] et d’ajouter son GRADLE_HOME/bin au PATH du système. Ceci permettra de lancer gradle en ligne de commande :

gradle -v

Votre installation est bonne? Ok nous allons alors pouvoir initialiser notre premier projet Gradle en lancant la commande init:

gradle init

A la console normalement vous devriez obtenir les log suivant

Starting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details
Support for running Gradle using Java 7 has been deprecated and is scheduled to be removed in Gradle 5.0. Please see https://docs.gradle.org/4.3/userguide/java_plugin.html#sec:java_cross_compilation for more details.
BUILD SUCCESSFUL in 7s
2 actionable tasks: 2 executed

Cette commande va tout d’abord lancer un demon pour accélérer les build suivant du projet et va preinitialiser pour votre système un certain nombre de fichiers, un répertoire wrapper et un répertoire .gradle (invisible sous unix)

ls -a
.  ..  build.gradle  gradle  .gradle  gradlew  gradlew.bat  settings.gradle

Alors commençons par la partie wrapper. Celle ci n’est pas indispensable mais Gradle préconise son utilisation afin de garantir l'homogénéité des builds du projet [13]. Les repertoires et fichiers concernés sont gradle, gradlew et gradlew.bat. En fait le wrapper permet contrairement à Maven,  le rechargement lors du build de la version proposée de gradle qui doit être utilisée pour construire le projet. Ainsi, pour tous les développeurs utilisant le wrapper, le build sera forcément identique (ou du moins reposera sur un environnement identique). Les fichiers gradlew permettent de lancer le wrapper et dans le repertoire nous trouverons un jar (réalisant le maintien de la version) et un fichier de propriétés pour le wrapper (contenant des données d’environnement) [14].

Les fichiers et répertoires participant a proprement parler au build sont build.gradle, settings.gradle et .gradle. Le repertoire .gradle est un repertoire interne a gradle propre au projet permettant à gradle de tagger les fichiers nouvellements modifiés et devant être incorporé au build incremental (c’est lui qui va rendre le processus de build plus efficace et plus rapide également). Normalement il ne devrait pas y avoir de besoin d’aller mettre son nez dedans; par contre, nous arrivons enfin sur les deux fichiers qui nous interesse le plus settings.gradle et build.gradle.

Le fichier settings.gradle est optionnel mais, il est recommandé de systématiquement l’utiliser. En effet celui-ci n’est pas utile pour un projet isolé mais sera indispensable dans le cas des multi-projets (equivalent aux modules maven). De plus il permet de définir un nom aux projets qui par défaut s’il n’existe pas est pris sur la base du nom du repertoire contenant le projet (ce qui n’est pas tiptop…)

settings.gradle

De façon simple voici ce qu’il peut contenir:

/*
// To declare projects as part of a multi-project build use the 'include' method
include 'shared'
include 'api'
include 'services:webservice'
*/
rootProject.name = 'monProjetGradle'

On aura compris que rootProject.name est le nom de notre projet…. A noter la primitive include afin de déclarer des sous projets à construire.

build.gradle

Intéressons nous au fichier de build lui-même: build.gradle. Ce fichier a pour vocation de décrire le contenu du build lui-même en s’appuyant sur la syntaxe Groovy. On imagine alors ce que l’on va y decrire sera considéré avant tout comme du comportement plutôt que de la configuration (a l’inverse de Maven) et c’est effectivement le cas à quelques exception près.

Prenons l’exemple d’un projet Java, il va falloir commencer par indiquer à Gradle que le build s’effectuera en Java. Pour cela, on va lui specifier l’utilisation d’un plugin [15]:

apply plugin: 'java'

Ensuite, à l'instar de maven on pourra donner une description et une version à l’artifact que nous allons créer. A la suite de quoi on va lui donner la version java pour la compilation:

description ="Projet de test pour gradle"
version = '0.1.0-SNAPSHOT'
sourceCompatibility = 1.8

Pour identifier les sources, il est possible de spécifier leur emplacement, ainsi que l’emplacement des tests.

sourceSets {
    main {
         java {
              srcDir 'src/main/java'
              }
         }
    test {
         java {
              srcDir 'src/test/java'
              }
         }
}

Encore une fois comme pour maven, il faut définir quelles vont être les dépendances nécessaires à la compilation et aux tests: Plus simplement que pour maven il suffit de déclarer le bloc dependencies comme suit:

dependencies {
    compile 'org.tc.osgi.bundle.utils:tc-osgi-bundle-utils-interfaces:0.1.0-SNAPSHOT'
    testCompile 'junit:junit:4.12'
    testCompile 'org.mockito:mockito-all:1.9.5'
}

A noter que le nommage des artifacts peut suivre les règles d’ecriture prescrit par Maven et permettre d’utiliser des repository Maven.
C’est d’ailleur ce que l’on va ajouter à notre build, la possibilité d’aller rechercher des artifacts dans un artifactory maven. Ainsi, si vous utilisez un repository maven perso, il faudra le déclarer avec la primitive repositories comme suit:

repositories {
    //jcenter()
    maven {
        url "http://localhost:8081/artifactory/cots"
        credentials {
            username = "toto"
            password = "tata"
        }
   }
}

Voila, et enfin pour les plus aguerri, il est possible de modifier manuellement le Manifest du jar produit. Pour exemple, pour construire des Bundles OSGI (nous regarderons cela dans un autre article sur ce qu’est OSGI) il faudra non seulement rajouter le plugin osgi mais aussi triturer un peu le manifest:

apply plugin: 'osgi'
jar {
    manifest {
    attributes 'Bundle-SymbolicName' : project.name
attributes 'Bundle-Name' : project.name + '-' + version
attributes 'Bundle-Version' : version
attributes 'Bundle-Vendor' : 'TC'
        attributes 'Bundle-Activator': 'org.tc.osgi.bundle.utils.module.activator.UtilsActivator'
        attributes 'Bundle-Description': 'Un bundle pour contenir des services utilitaires'
    }
}

ou plus classiquement pour un jar java standard:

jar {
    manifest {
        attributes 'Main-Class': 'monProjet.Main'
    }
}

Voila, ceci termine la partie statique du build. Maintenant découvrons sa partie dynamique, les taches.

Les taches

Les tâches sont du code groovy permettant d’orchestrer le déroulement du build. Alors bien sur, il ne faudra pas écrire tout le code nécessaire à son exécution. En effet si il existe deux types de tâches, les premières et les plus employées sont celles par défauts déclarer dans les plugins [15] [16].

Ensuite bien sur, il est possible d’en créer soit même avec à terme la définition d’un plugin.. A noter que outre la simplicité évidente du langage, dans le monde maven, il ne serait pas possible d’ajouter du comportement au build sans faire obligatoirement un plugin-maven puisque l’on ne peut ajouter directement du comportement dans le pom (a moins d’utiliser un plugin de type script).

Par exemple voici une petite tache propre a notre build:

// définition d'une tache perso nommé hello
task matache {
    doLast {
        println 'Building ' + project.name
    }
}

Voila il suffira d’appeler la commande

gradle matache

Pour afficher dans la console de build, “Building monProjetGradle”

Voila on a fait le tour de Gradle sans forcement etre rentrer dans le détail mais probablement suffisamment pour pouvoir rapidement mettre en oeuvre un début de build. A mon sens gradle, au vue de sa flexibilité, ne peut que finir par remplacer Maven car il en détient tous les avantages et en complète les défauts (attention par contre a ce que flexibilité ne ressemble pas a chaos). Finalement, son seul tort est peut etre encore son manque de popularité et de visibilité auprès des grands groupes du fait de son “jeune” âge même si la communauté est très active et fournit du contenu riche et très varié.  Pour plus d’informations, n'hésitez pas à consulter [17] [18] qui m’ont été d’une grande aide pour découvrir gradle et écrire cet article.

References:

[1] https://jenkins.io/
[2] https://jfrog.com/artifactory/
[3] https://www.sonarqube.org/
[4] http://robotframework.org/
[5] https://maven.apache.org/
[6] http://un-est-tout-et-tout-est-un.blogspot.com/2017/12/maven-introduction.html
[7] https://gradle.org/releases/
[8] Leon Osterweil:  “software processes are software too”, Proceeding ICSE '87 Proceedings of the 9th international conference on Software Engineering, Pages 2-13
[9] https://dzone.com/articles/gradle-vs-maven?edition=306207&utm_source=Daily%20Digest&utm_medium=email&utm_campaign=dd%202017-07-02
[10] https://devops.com/puzzle-gradle-maven/
[11] http://www.tutos-android.com/maitriser-gradle-partie-1
[12] http://www.gradle.org/downloads
[13] https://docs.gradle.org/current/userguide/gradle_wrapper.html
[14] https://docs.gradle.org/2.4/userguide/build_environment.html#sec:gradle_configuration_properties
[15] https://docs.gradle.org/2.4/userguide/standard_plugins.html
[16] https://plugins.gradle.org/
[17] https://www.petrikainulainen.net/getting-started-with-gradle/
[18] http://www.vogella.com/tutorials/Gradle/article.html

dimanche 7 janvier 2018

Maven, préparons des parents

Dans un précédent article [1], nous avions vu les principes généraux de Maven et son utilisation. Nous avions egalement vu le pattern parent/module/projet qui permet d’organiser la structure des projets.

Dans cet article, nous allons nous concentrer sur la partie haute de ce pattern en présentant une proposition de pom parents génériques ainsi que quelques déclinaisons de sous parents pour des sous classes d’applications (dans notre cas pour des application OSGI, des projets de plugins mavens et dans un avenir proche pour des application JEE)



Pour illustrer et expliquer ce pattern, je me permettrai de m'inspirer de mes propres projets de mes pom parents du dépôt Git Hub [2]

Nomenclature 

De façon générale, tous pom doit définir 4 points pour lesquels j’applique la nomenclature suivantes:
  • groupid = org.tc.${FONCTION}
  • artifactid = tc-${FONCTION}[-module]
  • version = [maj].[min].[ft]
  • packaging = pom
ou

  • $[FONCTION] est le rôle du pom courant 
  • [-module] la gestion du cas particulier du pom module
  • [maj] modification majeur du composant ( généralement fonctionnelle)
  • [min] modification mineur du composant ( généralement technique)
  • [ft] modification suite à un correctif 

Le groupId permet a maven de classer le pom, ainsi si l’on transpose cela a un répertoire, cela représente un chemin de répertoires dans lequel on trouvera tous les projets de ce type.
L'artifactId représente l’identifiant unique du pom dans la famille de pom classer sous le groupId.
La version permet de gérer les évolutions dans le temps et les dépendances des composants entre eux selon ces évolutions.

Le packaging permet à maven de connaitre la nature du composant qu’il aura à construire ainsi, un packaging pom est typiquement un pom parent ou module alors que jar, implique que l'exécution du pom produise une application java packager. (On aura aussi par exemple des packaging de type war, ejb, bundle ou ear… [3]

Optionnellement, les poms (et dans mon cas ils seront systématiquement définis) il est possible de donner une description au pom permettant de rentrer un peu plus dans le détail de son rôle et egalement de definir le name qui n’est que le nom simple du pom (“human readable”) tel qu’il sera affiché dans le reator du processus Maven (le resultat d’execution du build) il est donc important d’en choisir un lisible, simple et évident.

On choisira un name comme ci-dessous:
name = ${project.artifactId}-${project.version}

Pom parent


<groupId>org.tc.parent</groupId>
<artifactId>tc-parent</artifactId>
<name>${project.artifactId}-${project.version}</name>
<version>0.7.0-SNAPSHOT</version>
<packaging>pom</packaging>
<description>Pom parent des projets</description>

Le plus important dans le pattern parent/module/projet est, comme pour une hiérarchie de classe, l'élément le plus abstrait, celui de plus haut niveau c’est a dire le pom parent. Le pom parent a pour role de factoriser l’ensemble des informations concernant les composants participant à la construction de toutes les familles d’applications de nos projets.

De plus il participe également  à la définition d’information d’ordre plus générale comme l’identité du mainteneur du pom, les url permettant d'accéder au dépôt git ou au site web du projet. Pour ce genre d’informations je vous invite à consulter le pom en question, nous nous intéresserons aux premières composantes.

Donc pour proposer aux futur projet un environnement de production cohérent, le pom parent va définir le type d’encodage des sources:


<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>


Il peut aussi déclarer ou sera déployée la production produite par maven en définissant le distributionManagement qui poussera les jar et les pom dans par exemple un artifactory ou un nexus:


<distributionManagement>
    <snapshotRepository>
     <id>artifactory</id>
     <name>artifactory-snapshots</name>
     <!-- ${arti-url} defined in conf/settings.xml url d'artifactory-->
     <url>${arti-url}/artifactory/libs-snapshot-local</url>
    </snapshotRepository>
    <repository>
     <id>artifactory</id>
     <name>artifactory-releases</name>
     <!-- ${arti-url} defined in conf/settings.xml  url d'artifactory-->
     <url>${arti-url}/artifactory/libs-release-local</url>
    </repository>
    <site>
     <id>siteweb</id>
     <!-- defined in conf/settings.xml correspond au repertoire local ou sera déposé le contenu du build de la phase site-->
     <url>${local-siteweb-url}</url>
    </site>
</distributionManagement>


Dans le cas présent, on en a profité également pour définir ou sera déployé le site maven si la phase site est exécutée (variable ${local-siteweb-url}). A noter, que l’on utilise des variables directement dans le pom qui doivent avoir été défini dans le settings. Cette approche rend certe le pom non utilisable directement mais il procure l’avantage de permettre la pré-configuration des builds pour l’environnement dans lequel il va s'exécuter. Dans le settings pour pouvoir exécuter le build, il faudra affecter a ces variables les urls de artifactory et du site web.

On passe ensuite à la définition des outils de reporting a utiliser pour la génération du site web maven du projet.

Dans notre cas, nous employons


<reporting>
    <plugins>
     <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-plugin-plugin</artifactId>
      <version>3.3</version>
     </plugin>
     <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-changelog-plugin</artifactId>
      <version>2.2</version>
     </plugin>
     <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-checkstyle-plugin</artifactId>
      <version>2.10</version>
     </plugin>
     <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-docck-plugin</artifactId>
      <version>1.0</version>
     </plugin>
     <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-jxr-plugin</artifactId>
      <version>2.3</version>
     </plugin>
     <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-pmd-plugin</artifactId>
      <version>3.0.1</version>
     </plugin>
     <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-project-info-reports-plugin</artifactId>
      <version>2.6</version>
     </plugin>
     <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-surefire-report-plugin</artifactId>
      <version>2.18.1</version>
     </plugin>
    </plugins>
</reporting>


Dont les rôles sont [4] :

  • maven-plugin-plugin : Permet de generer la description d’un plugin maven
  • maven-changelog-plugin : Permet de generer le rapport changelog
  • maven-checkstyle-plugin : Permet de generer le rapport d’analyse de checkstyle (bonne pratique d’ecriture du code)
  • maven-docck-plugin : Permet de vérifier la documentation
  • maven-jxr-plugin : fourni un rapport des references croisées des sources java
  • maven-pmd-plugin : fournir un rapport d’analyse de code du code java
  • maven-project-info-reports-plugin : Permet de consolider dans un rapport les informations complémentaire contenu dans les pom
  • maven-surefire-report-plugin : permet de fournir un rapport d'exécution des tests unitaires

Ensuite par défaut il est possible de déclarer que tous les projets utilisent les même outils de tests. Dans le cas de nos projets nous avons fait le choix d’utiliser JUnit et Mockito


<dependencies>
    <dependency>
     <groupId>junit</groupId>
     <artifactId>junit</artifactId>
     <version>4.10</version>
     <scope>test</scope>
    </dependency>
    <dependency>
     <groupId>org.mockito</groupId>
     <artifactId>mockito-all</artifactId>
     <version>1.9.5</version>
     <scope>test</scope>
    </dependency>
</dependencies>


Nous avons traité tous les éléments annexes au build lui même (c’est a dire la documentations et les informations complémentaires générées lors de la construction du site maven) . Maintenant, il convient de définir la configuration des builds eux même et donc la configuration des composants participants à ces builds. Ces éléments sont à déclarer entre les balises <build></build>.

Premier point a ajouter aux builds est la déclaration des répertoires de ressources et de les spécifier filtering. De cette façon, il est possible de déclarer des fichiers de configuration incluant des variables qui seront remplacées et affectées au moment du build par la valeur déclarée dans le pom. Ainsi, en déclarant des profils avec des valeurs différentes, il est possible de réaliser des productions incorporant des configurations differentes. (Nous reviendrons sur ce point plus tard, ce ne sont pas les exemples d’utilisations qui manquerons)


<resources>
 <resource>
  <directory>src/main/resources</directory>
  <filtering>true</filtering>
 </resource>
</resources>


Ensuite, il faut ajouter différents plugins:

Le plugin permettant de spécifier le JDK à employer ainsi que sa version:


<plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-compiler-plugin</artifactId>
 <version>3.1</version>
 <configuration>
  <verbose>true</verbose>
  <source>1.8</source>
  <target>1.8</target>
  <testSource>1.8</testSource>
  <testTarget>1.8</testTarget>
  <arg>-XprintRounds -XprintProcessorInfo -Xlint -J-verbose</arg>
  <encoding>UTF-8</encoding>
  <fork>true</fork>
  <!-- defined in conf/settings.xml -->
  <executable>${JAVA_1_8_HOME}\bin\javac</executable>
 </configuration>
</plugin>


Les options -XprintRounds -XprintProcessorInfo -Xlint -J-verbose ont pour but d’augmenter la verbosité pendant la compilation et de fournir plus d’informations sur l’utilisation du processeur d’annotation [5].

Comme pour les urls dont nous avons parlé, il faudra ajouter la variable ${JAVA_1_8_HOME} à votre settings permettant à maven de savoir ou se trouve votre installation de Java.

Pour produire la javadoc on ajoutera le plugin suivant avec le paramètre Xdoclint:none afin a rendre le parseur générant la documentation moins rigide [6], (sinon il se peut que vous ne puissiez plus générer votre java doc):


<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-javadoc-plugin</artifactId>
  <version>2.9</version>
  <executions>
    <execution>
      <id>attach-javadocs</id>
      <goals>
        <goal>jar</goal>
      </goals>
      <configuration>
        <additionalparam>-Xdoclint:none</additionalparam>
      </configuration>
    </execution>
  </executions>
</plugin>


Même combat avec le plugin maven site qui va aussi vous produire la javadoc en plus des reporting que nous avons vu précédemment:


<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-site-plugin</artifactId>
  <version>3.3</version>
  <configuration>
  <reportPlugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-javadoc-plugin</artifactId>
      <configuration>
        <additionalparam>-Xdoclint:none</additionalparam>
      </configuration>
    </plugin>
   </reportPlugins>
   </configuration>
</plugin>


Enfin si vous livrer vos sources sous la forme d’un jar séparé de vos binaires, il faudra ajouter le plugin maven-source-plugin:

Pom parents fils

Voila on a fait le tour des plugins du pom parent principal. De la même manière, on va pouvoir créer d’autres pom parent plus spécialisés héritant de ce pom [2]. Sans entrer dans le détail, le dépôt propose par exemple de façon plus ou moins abouti des pom parent pour la production de bundles OSGI ou des plugins maven ou des ébauches pour la production de projets JEE ou Android.

Pom Module

Une fois ces pom définit, il reste à orchestrer leur production. Pour cela on utilisera un pom module.


<groupId>org.tc.module</groupId>
<artifactId>tc-parent-module</artifactId>
<name>${project.artifactId}-${project.version}</name>
<version>0.1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<description>Pom module de tc-project</description>


De façon très simple, un pom module ne définit que la liste des projets à construire.  Dans le cas de notre dépôt ce pom se constitue donc du pom parent principal et des pom fils au sein du balisage xml module:


<modules>
  <module>tc-parent</module>
  <module>tc-osgi-parent</module>
  <module>tc-jee-parent</module>
  <module>tc-maven-plugin-parent</module>
  <module>tc-android-parent</module>
</modules>


A noter que l’on retrouve souvent les pom parents et les pom modules sous la forme d’un seul et même pom. Si cette configuration est souvent la plus simple lorsque l’on a qu’un seul projet java a réaliser (même constitué par plusieurs sous projet), il n’est pas préconisé de procéder ainsi. En effet comme pour le pattern MVC ou l’on retrouve souvent le contrôleur et la vue implémenter dans le même composant, il est important pour éviter des rework de respecter la règles de la séparation des préoccupations. Ainsi, il sera plus simple de modifier la liste des éléments à construire sans avoir a modifier la version du pom parent et par voie de conséquence tous les pom en héritant.

Enfin dernier point à considérer selon les convenances, pour que le build puisse aboutir dans le cas d’utilisation de la phase deploy de maven, il est nécessaire de permettre au pom module d'être uploader dans un repository distant. Il reste alors a votre choix de soit declarer dans le pom un bloc distributionManagement comme nous l’avons fait pour le pom parent mais cela revient à dupliquer du code ou plus simplement, de déclarer le pom module comme fils du pom parent afin de bénéficier du distributionManagement hérité de celui ci.

Pour plus d’information sur la construction des pom je vous invite a consulter la documentation officielle [7]

References:

[1] https://un-est-tout-et-tout-est-un.blogspot.fr/2017/12/maven-introduction.html
[2] https://github.com/collonville-tom/tc-parent
[3] https://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Packaging
[4] http://matthieu-lux.developpez.com/tutoriels/java/maven/?page=site
[5] http://www.javatronic.fr/articles/2014/08/31/how_to_make_sure_javac_is_using_a_specific_annotation_processor.html
[6] http://blog.joda.org/2014/02/turning-off-doclint-in-jdk-8-javadoc.html
[7] https://maven.apache.org/guides/introduction/introduction-to-the-pom.html

samedi 23 décembre 2017

Les processus de développement ou cycles de vie du logiciel

Dans cet article faisons un état des lieux plus détaillé des cycles de vie les plus importants et les plus couramment utilisés. Après une présentation des cycles classiques comme ceux en Cascade ou en V, seront présentées des méthodes plus récentes basées sur l’agilité.

Les Classiques

Cycle en Cascade

Le cycle en cascade est typiquement un cycle de développement prédictif. Provenant du bâtiment, il part du principe que la construction nécessite, en général, un enchaînement logique ; la couverture d’une maison ne peut pas être effectuée sans avoir préalablement fait les fondations. Il définit une démarche de développement séquentiel (figure 2.9) où chaque phase conduit à la production d’un ou plusieurs livrable(s) qui doivent être validés avant d’être utilisés lors de la phase suivante.

Le modèle en cascade nécessite la définition d’un planning détaillé qui énonce toutes les étapes et réalisations attendues. Différentes activités d’analyse, de conception, d’implantation, de tests et d’intégration sont effectuées afin de converger vers l’obtention du système logiciel final.



Initialement, le modèle en cascade est un cycle de développement purement séquentiel, cependant, diverses possibilités d’itération ou de retour vers les phases amont ont ensuite été intégrées au modèle. Ces itérations permettent de vérifier les produits obtenus au fil du développement et ainsi fournir plus de souplesse à la conception.

Cycle en V

Le cycle en V est l’un des cycles les plus connus et utilisés (figure 2.10). C’est un cycle de type prédictif qui a été défini pour remédier aux lacunes du cycle en cascade qui manque de réactivité face aux erreurs découvertes lors de la conception, du développement ou encore de l’analyse. La structure en V du cycle a l’avantage de mettre en vis à vis les activités de développement et de tests permettant de mieux préciser les documents à
partager entre ces phases, notamment les rapports de tests et les modifications qu’il est nécessaire d’apporter pour corriger les erreurs. Ainsi, lors de la phase montante du cycle, toutes les réalisations doivent être testées et validées.


Depuis les années 80, le cycle en V est considéré comme un standard du développement logiciel et de la gestion de projet dans les industries. A la suite du cycle en V sont apparues diverses variantes telles que, par exemple, le cycle en W qui propose d’effectuer deux cycles en V successivement, le premier servant à la conception d’un prototype de l’application, le second à construire l’application finale.

Cycle en Y


Dans son principe, le cycle de développement en Y, est proche du cycle en cascade dont il reprend l’aspect descendant. Son intérêt est de séparer les préoccupations concernant les aspects fonctionnels liés au domaine métier et les aspects techniques liés aux solutions technologiques à employer pour la mise en oeuvre.

Avec le MDA, un cycle en Y orienté modèle a été proposé afin de séparer les spécifications fonctionnelles (PIM) et les spécifications techniques (PSM). Cette approche a pour avantage de fournir un modèle plus rationnel de la gestion des modèles et de l’utilisation des transformations de modèles employées lors de la phase de conception pour faire coïncider les modèles techniques et fonctionnels (employés également lors de la phase d’implantation sous la forme de génération de code).

Cycle en Spirale

Défini par Barry Boehm, le cycle en spirale est une approche itérative du cycle de développement en V. Ainsi, il en reprend l’essentiel des concepts en s’articulant autour de quatre phases importantes (figure 2.12) : la détermination des objectifs, la détermination des risques, le développement et les tests et enfin la planification de l’itération suivante.




Par contre, à l’inverse du cycle en V, le modèle en spirale met un focus plus important sur l’analyse et la résolution des risques. Ceci est nécessaire car au fur et à mesure des itérations, la réalisation devient de plus en plus conséquente. Il est donc important d’évaluer correctement le risque à chaque itération sachant que toute erreur sera d’autant plus difficile à corriger que le développement sera avancé.

Pre-agilité

Cycle avec Prototypage Rapide (RAD)



Proposé dés la fin des années 1980, le cycle de développement avec Prototypage Rapide (Rapid Application Development aussi appelé semi-itératif) se situe entre une approche prédictive et une méthode agile dans le sens où il s’agit de l’une des premières approches à introduire la notion d’itération au sein du processus de développement. La méthode RAD se structure ainsi autour de cinq phases :
1. L’initialisation pendant laquelle le périmètre du projet et les ressources nécessaires à celui-ci sont définis. Le travail à effectuer est alors organisé par thèmes.
2. Le cadrage qui va définir les besoins et les fonctionnalités du produit. Cette phase est effectuée lors de réunions se basant sur des techniques d’animation spécifiques.
3. La conception des modèles nécessaires à l’élaboration du système logiciel proprement dit. Le client est fortement impliqué dans cette phase puisqu’il a pour rôle de valider les modèles proposés.
4. La construction du système logiciel par l’équipe de développement par une approche itérative selon les fonctionnalités demandées. Le client est toujours présent afin de valider les différentes réalisations.
5. La finalisation est une phase de validation globale du livrable final par le client.

Ainsi, les deux premières phases se placent dans une approche descendante comme celle en V ou en Cascade. Par contre, à partir de la troisième phase, le cycle de développement devient itératif en permettant d’alterner conception et validation. De plus, avec l’intégration du client dans le développement, cette démarche fournit plus de réactivité.

La méthode RAD est pionnière dans l’utilisation de l’itération et d’une intégration plus importante du client dans le processus de développement. A ce titre, elle peut être considérée comme initiatrice des méthodes agiles qui sont fondamentalement tournées vers ces concepts. Les paragraphes suivants présentent les démarches et cycles proposant une approche agile du développement.

Unified Process UP

Tout comme RAD, UP est un cycle de développement qui se positionne entre les approches prédictives et les approches agiles. Ce cycle de vie est né de l’approche orientée objet issue de la collaboration de Ivar Jacobson, Grady Booch et James Rumbaugh. L’approche UP tente de rationaliser les processus de développement logiciel en fournissant un guide de bonne pratique fondé sur six points :

1. Avoir une démarche incrémentale et itérative pilotée par les risques et les cas d’utilisation.
2. Avoir une gestion rigoureuse des exigences.
3. Centrer le développement sur l’architecture.
4. Faire une modélisation graphique des exigences.
5. Contrôler en permanence la qualité.
6. Contrôler les changements éventuels à effectuer.
Ces six bonnes pratiques prônées par UP sont en l’occurrence ce qui permet de rattacher ce cycle de développement aux méthodes agiles. En effet, contrairement aux démarches de développement classiques, UP oriente naturellement le développement pour que celui-ci soit à même de répondre aux changements.
UP définit une démarche de développement intégrant les neuf disciplines majeures nécessaires au développement : la modélisation métier, la définition des exigences, l’analyse et la conception, l’implantation, les tests, le déploiement, la gestion des changements, la gestion du projet et enfin la prise en compte de l’environnement. Basé sur ces disciplines qui seront employées à chaque itération, le processus de développement va alors pouvoir suivre les quatre phases du processus qui consistent en :
1. Le début dont l’objectif est d’unifier les points de vue de chacune des disciplines sur l’ensemble du projet.
2. L’élaboration qui a pour objectif de définir et de valider l’ensemble des modèles permettant la conception du système logiciel.
3. La construction qui doit fournir une version documentée et fonctionnelle du logiciel.
4. La transition dont le but est de finaliser le système.

Avec Unified Software Process Metamodel (USPM), les démarches de développement se sont orientées vers la modélisation des processus en suivant le credo issu de la publication de Lee Osterweil : Software processes are software too. Traduit littéralement que les processus de développement de logiciel sont aussi une forme de logiciel. Cette publication montre la nécessité de maîtriser le processus de développement en modélisant sa structure et son évolution.

L'agilité

L’extreme programming

L’extreme programming est à proprement parler une approche agile qui propose des itérations courtes impliquant au maximum le client et cherche à recentrer le développement sur la composante humaine en revalorisant les bonnes pratiques de développement telles que le binomage, la définition au plus court de tests fonctionnels permettant de valider l'application, la promotion de styles ou de pattern d'écriture de code.
XP fonctionne autour de 5 valeurs fondamentales souvents reprise dans les approches agiles plus récentes:

  • Communication
  • Feedback
  • Simplicite
  • Courage
  • Respect

Scrum

Développée en 1993, Scrum est une approche agile qui met en avant l’intérêt des petites équipes de développement. Dans ces petites équipes, sont avant tout recherchées les compétences multidisciplinaires et la capacité d’intégration sociale des acteurs. Dans Scrum, les itérations appelées Sprint sont planifiées sur quatre semaines maximum. Ces itérations sont axées sur les besoins définis par le client qui constituent alors le référentiel de travail.
Les besoins sont hiérarchisés par degré d’importance et développés selon les priorités définies par le client. Chaque jour constitue une itération pendant laquelle une réunion est organisée pour établir l’état d’avancement du projet et de vérifier que les fonctionnalités et les délais sont bien respectés.



A la fin de chaque Sprint, une réunion établissant le bilan des réalisations est menée afin d’établir l’efficacité de l’équipe et les éventuelles améliorations qui doivent être apportées. La finalité d’un Sprint est de présenter un démonstrateur au client afin que celui-ci puisse valider les réalisations. Scrum définit un certain nombre d’acteurs qui vont intervenir lors de la mise en oeuvre du processus :
1. Le ScrumMaster a pour rôle d’aider les acteurs du développement à communiquer au sein de l’équipe ainsi qu’avec le client. Il doit s’assurer que la philosophie et les pratiques de Scrum sont correctement suivies. Par contre son rôle n’est pas à confondre avec celui du chef de projet dont il est plutôt un conseillé.
2. Le Client ou Product Owner est lui aussi acteur du développement, il a pour rôle de définir les besoins. Il doit également définir les priorités dans les fonctionnalités à réaliser. Ainsi, il participe activement à l’élaboration du produit en suivant les étapes de sa réalisation afin de pouvoir en valider la finalité.
3. Enfin, l’Équipe qui est constituée de l’ensemble des corps de métiers nécessaires à l’élaboration du produit. Ces métiers sont classiquement ceux rencontrés lors des développements logiciels classiques (Développeur, Analyste, Testeur, etc.)

Pour finir, la méthode Scrum s’appuie sur la notion de Visibilité pour qualifier et quantifier les résultats de l’équipe. Des critères de validation doivent exister afin de définir si une fonctionnalité a été complètement réalisée ou non. Des critères d’Inspection doivent être définis afin de déterminer l’existence d’écarts entre la réalisation concrète et l’objectif final. Enfin, la notion d’Adaptation permet, lors d’écarts trop importants détectés pendant des Inspections, de modifier la gestion interne de l’équipe afin d’éviter que ces écarts ne s’amplifient. Ces critères permettront alors de gérer de la dette techniques ou encore d'évaluer la vélocité de l'équipe de développement afin de planifier au mieux les contenus des livraisons futurs

On peut noter que Scrum et XP sont deux approches très proches (on note d’ailleur une forte proximité des valeurs vehiculés) qui cherchent l’une comme l’autre a remettre la vie du développeur au centre du processus. Cependant Scrum a une volonté plus marqué de fournir un processus formellement établi pour gérer le cycle de vie du logiciel alors que XP s'intéresse plus sur les bonnes pratiques. Généralement les equipes de développement pratiquant l’une pratique préférablement la seconde.

Lean

Le lean est une approche de gestion de production développé par Toyota dans les années 90. Avec un héritage assumé issu du Taylorisme, le lean se définit dans une recherche d'accroissement de la productivité, de la qualité et d'une réduction systématique du gaspillage.

Dans les approches agiles, si XP a pour propos de mettre en avant des valeurs humaines et si Scrum a pour objet de recentrer le processus autour de la production des éléments a plus haute valeur, le Lean complète ces approches en visant l’optimisation des processus eux même.

Pour cela, le lean va se focaliser sur 7 règles qui servent d’axes de progressions (qui sont probablement des questions systématiques aux rétrospectives de sprints):

  1. comment reduire les dechets? (temps perdus, réduction de dette technique, etc…)
  2. comment améliorer la monté en compétences?
  3. decider au plus tard
  4. livrer au plus tot
  5. valoriser l’equipe
  6. la qualité commence des la conception
  7. avoir toujours une vision du logiciel dans sa globalité (maintenir le recul)

Conclusion

Les processus de développement sont nombreux et si historiquement l'approche en V a été adoptée majoritairement, les nouvelles approches comme les approches agiles tendent a s'imposer comme étant des solutions plus dynamique et adaptées aux changements actuel. Je reviendrais plus dans le détail des approches telles que Scrum et Lean qui mérite au vue de leur présence actuel d'être approfondie. De la même manière, ces dernières années, au delà des processus de développement, on a pu voir émerger le DevOps dont le but est de regarder au delà des équipes de développement en prenant en considération l'ensemble des besoins des acteurs agissant de près ou de loin dans la livraison du produit au client. Il me semble que même si cela déborde du cadre des processus de développement de l'équipe logicielle, celle ci doit prendre en compte ces nouvelles préoccupations et cela a forcément un impact sur leur activité

dimanche 10 décembre 2017

Maven : Introduction

Qu'est ce que Maven ? Je vais vous en faire un résumé rapide mais pour ceux qui veulent une bible et de details, consulter ce livre.

Généralités

Maven est un gestionnaire de build ou constructeur de projet. Il est open source et soutenu par la fondation Apache. Maven a pour but de simplifier, rationaliser et automatiser la construction d'un projet sur l’ensemble de ses phases et activités de façon a garantir la qualité de no build.

Initialement orienté pour les projet Java, Maven est maintenant capable de construire des projets de tout type de nature, c++, Python, etc....

Ainsi, et c'est sa fonction première, Maven va permettre de compiler le code de notre application, ceci en fournissant des moyens de gestion simple pour les dépendances du projet. Cependant, s’arrêter a cela, serait hyper réducteur car Maven a plus la vocation de couvrir tout le périmètre de build.

En fait avec Maven, il est possible de:
  • préparer la compilation (en générant du code par exemple) 
  • effectuer la compilation
  • exécuter des tests unitaire, 
  • faire de l'analyse de code,
  • faire du packaging (construction de jar, war, tar.gz ou même des deb) 
  • exécuter des procédures d'installation sur des plateformes spécifiques de tests, exécuter des tests fonctionnels (avec roboframework par exemple)
  • préparer un livrable
  • générer differentes doc (technique ou utilisateur)
  • etc... car il est possible d'adjoindre des plugins supplémentaires pour compléter son fonctionnement.
Tout ceci concerne les activités directement lié au build de notre projet mais avec maven, il sera aussi possible d'aller plus loin en permettant la constitution de processus plus générique autour de la gestion du projet comme :
  • la construction automatique de template de projet
  • la gestion de multi-projet, de leurs dépendances et de leur orchestration dans un même process
  • la gestion d'un cache local de vos dépendances
  • la gestion des builds passés sous la forme de SNAPSHOT et de RELEASE
  • du deployement de documentation web en ligne

Configuration

Maven s'articule autour d'un runner que l'on telecharge ici. Je ne vais pas rentrer dans le details de l'installation de Mave, mais celle-ci se résume globalement a spécifier convenablement JAVA_HOME qui exécutera Maven. (Attention, ce dernier n'est pas forcement celui employé pour la compilation). On pourra specifier ce JAVA_HOME directement lors de l'appele de Maven en faisant un alias par exemple sous unix/cygwin.

Il est ensuite nécessaire de configurer ce que l'on appelle les Settings. Ce setting est constitué de deux fichiers, le fichier système présent dans le répertoire conf de Maven et un fichier utilisateur présent dans le répertoire .m2 de l'utilisateur courant.

Comme on peut se le douter, le setting système permet de configurer Maven pour toutes ses utilisations alors que celui de l'utilisateur sera spécifique au compte utilisateur lançant le processus Maven. (la commande mvn, que nous verrons plus loin)

L'ordre de chargement de ces settings se réalisera toujours dans le sens Systeme puis Utilisateur, le dernier chargé faisant fois de sa configuration en cas de conflits. A noter qu'il est possible de spécifier un setting lors du build afin de personnaliser celui-ci avec l'option -s

Le settings est le fichier de configuration dans lequel seront définis les variables d’environnement locales (comme les differentes versions Java installées sur la machine),  les repositories de dépendances (artifactory ou nexus, SNAPSHOT ou RELEASE), les serveur web, des serveurs de base de données, des server de vérification de code (Sonar par exemple) , des secrets éventuels pour s'y connecter, etc.... en fait toute configuration et ressource spécifique a l'environnement de build, utilisable non directement par les projets.

Par convention (unix) on build dans un compte spécifique (maven par exemple) et on initialise ces données dans le settings utilisateur, le settings système étant réservé aux configurations partagées.

Par exemple un settings spécifiant les variables pour la compilation en java 6, 7 ou 8, les variables pourront alors être utiliser dans les pom.xml des projets (nous verrons par la suite ce que sont les pom):


<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" 
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
  <localRepository>/home/m2Repo</localRepository>
  <profiles>
    <profile>
      <id>compiler</id>
        <properties>
          <JAVA_1_6_HOME>jdk1.6.0_33_win_x64</JAVA_1_6_HOME>
          <JAVA_1_7_HOME>jdk1.7.0_80_win_x64</JAVA_1_7_HOME>
          <JAVA_1_8_HOME>jdk1.8.0_66_win_x64</JAVA_1_8_HOME>
        </properties>
    </profile>
  </profiles>  
  <activeProfiles>
    <activeProfile>compiler</activeProfile>
  </activeProfiles>
</settings>


Ici nous avons spécifique un répertoire différents du répertoire par défaut du repository maven locale qui permet a Maven de stoker toutes les dépendances dont il aura besoin lors des builds (nous verrons également ce point par la suite)

Dans ce cas ci, nous n'utilisons pas de repository distant permettant a Maven de resoudre les dépendances manquantes de son repository locale. Nous sommes donc dans une configuration hors-ligne. Donc si lors du build Maven, il manque une dépendance dans le repository locale, Maven finira en echec.

Pour permettre a Maven de résoudre des dépendances manquantes et de les mettre dans son repository locale, on ajoutera le serveur central Maven :


<profile>
  <id>securecentral</id>
  <!--Override the repository (and pluginRepository) "central" from the
     Maven Super POM -->
  <repositories>
    <repository>
      <id>central</id>
      <url>https://repo1.maven.org/maven2</url>
      <releases>
        <enabled>true</enabled>
      </releases>
    </repository>
  </repositories>
  <pluginRepositories>
    <pluginRepository>
      <id>central</id>
      <url>https://repo1.maven.org/maven2</url>
      <releases>
        <enabled>true</enabled>
      </releases>
    </pluginRepository>
  </pluginRepositories>
</profile>


Processus Maven

Maintenant que Maven est configuré (sommairement) intéressons nous aux processus de build en lui-même.

Nous l'avons vu précédemment, Maven répond a un grand nombre de besoin, son processus va s'appuyer sur de nombreux plugin décrits sur cette page qui vont interagir afin de procéder a l’exécution de tout ou partie du cycle de vie.

Le cycle de vie Maven est ce que l'on pourra appelé complet. Il se compose d'un cycle par défaut contenant les processus de compilation, test, packaging et déploiement précédé optionnellement d'un cycle de nettoyage des projets et suivi optionnellement d'un cycle de génération de site documentant les projets.




Ainsi via l'appel de la commande mvn (répertoire bin de Maven) et en se plaçant dans notre projet, il sera alors possible de faire appel a un processus déroulant les phases décrites par le schéma ci dessus. A noter que les deux cycles de vie optionnels clean et site ne seront déroulés que si appeler explicitement via la commande Maven alors que le cycle de vie Default sera de toutes façon exécuter jusqu’à l’étape (ou phase dans le jargon Maven) explicitement appelée

Ainsi, la commande


$ mvn compile 


exécute les phases validate a compile du cycle default, tandis que


$ mvn clean test


exécute toutes les phases du cycle clean et les phases validate a test du cycle default.

Ainsi, la commande


$ mvn clean deploy site-deploy


exécute toutes les phases, mais ce ne sera pas forcement une bonne idée....

Mais on a parler de plugins ? qu'est ce que c'est?

Et bien tout le processus présenté ci dessus est la modélisation des activités classiques auxquelles les builds vont répondre. Cependant, on peut facilement imaginer que d'un projet a l'autre les builds ne vont pas s'appuyer sur les même concepts selon les phases. Ainsi tout bêtement la compilation d'un projet Java ne sera pas la même chose qu'une compilation d'un projet C++. De même, certains projets vont s'appuyer sur des configurations differentes de packaging, de compilations, de test. Et même sur des projets relativement semblables, des choix technologiques peuvent amener des outils différents.

Face a cette richesse de besoin et de possibilité, Maven a adopté le principe du : voici un plugin implémentant le comportement par défaut pour le cas le plus général et si le plugin ne correspond pas, est bien il existe des moyens de créer les siens (nous reviendrons sur ce point dans un autre article).

Ainsi pour que pour chaque phase soit proposée  les outils et les moyens de configuration adaptés, Maven va s'appuyer sur ces fameux plugins pour donner une implémentation et une opérationnabilité liés aux spécificités de chaque projet. Le plugin selon le cas sera configuré difficilement ou simplement substitué par un autre, voir même parfois ajouter et exécuté parallèlement.

Pour une liste exhaustive de l'ensemble des plugins "standard" utilisable je vous invite a consulté cette page. Cela donnera une idée des possibilités par défaut, et les plugins utilisables selon les phases des cycles de vie Maven.

Il manque maintenant un dernier élément a tout cela. Comment donner a Maven la carte des plugins a utiliser pour son cycle de vie et leur configuration? Le POM!

Project Object Model

Le POM ou fichier pom.xml est ce qui permet à Maven de connaitre le comment builder le projet courant.

Il va en exister de différents types, si l'on veut suivre de bonnes pratiques Maven, on va s'appuyer sur le pattern parent/module/projet (décrit aussi dans cet article):

  • Des pom projet supportant la production d'un composant logiciel spécifique de type jar, deb, ear, etc... Il s'agit de ce que l'on peut considérer comme étant la composante Maven qui nous vient en premier a l'esprit. Ce pom va donc définir les variables locales au projet, les processus spécifiques nécessaire à la compilation du composant, les dépendances et ou encore de quel pom parent le projet va hériter.
  • Des pom parent qui ont pour but de factoriser des comportements standard de build dont vont heriter des pom projets . Dans ces pom on trouvera alors l'ensemble des spécificités propre à des familles de projets partageant des processus ou des propriétés de compilation commune.
  • Des pom module permettant d'orchestrer la construction d'un ensemble de projets techniquement interdépendant en les agrégeant.

Attention un POM se définit en XML, de ce fait, ce dernier est conforme a ce que l'on appelle un schéma (XSD) pour en structurer les informations a la manière d'une grammaire. Ainsi, tous les types de pom se base sur le même XSD amenant souvent a des utilisations fusionnées des précédents concepts présentés. Alors bien sur, Maven aurait pu simplement définir des XSD différent pour répondre aux différents types. Le choix a été fait de ne pas brider leur utilisation et de permettre malgré tout quelques digressions. Quelques digressions ne signifie pas que cela doit être une généralité car suivre le pattern parent/module/projet permet largement de couvrir 90% des cas d'utilisation. Et comme dans tous les cas d'utilisation des patterns, si vous faites autrement, c'est que vous avez une vraie bonne raison technique (et pas une raison du type : on livre demain...)

Pour avoir une illustration plus précise de cette décomposition, je vous invite a consulter cette question sur stackoverflow. Elle traite bien de la question et nous ramène comme souvent au problème de la division des préoccupations et des besoins comme en POO et ce selon la complexité du problème. En effet, dans un cas simple, on préférera avoir un POM projet classique.... ensuite lorsque les projets commenceront a se multiplier un peu on décidera de construire un POM parent pour factoriser les propriétés et donc on y déposera également une définition des modules à construire (la liste des POM projets). Finalement, lorsque l'on aura des projets dont les POM parent n'auront plus de points communs et qu'il faudra les diviser, alors on placera des POM modules afin d'orchestrer le ou les builds possibles pour les lots de projets a gérer...

Ainsi rien que par cet exemple, certes, on se rend compte que progressivement on en arrivera de toute façon a tendre vers l'application du pattern parent/module/projet... cependant, afin d’éviter des modifications douloureuses dans les dépendances des builds, il est vraiment préférable de définir de suite un structure de POM parent, factorisant des processus standard de build, et des modules définissant séparément les lots de builds.

Je ne vous ferais pas l'affront de vous donner un exemple, avec les differentes références que je vous ai donné ci dessus, vous avez largement les moyens de soit débuter, soit enrichir l'architecture des builds de vos projets.

Voila, un grand tour d'horizon de Maven, ce que l'on en fait et ce qui est important de faire des le départ au niveau structure des projets. Ceci n’était cependant qu'une introduction donc dans les prochains articles sur Maven sous essayeront de voir les points suivant:

  • un POM et une architecture parent/module/projet en vrai
  • comment faire son propre plugin
  • c'est quoi les archétypes

vendredi 8 décembre 2017

La modélisation

La réalisation d'un logiciel informatique nécessite de nombreuses taches de nature multiples. Généralement on définit les activités de production d'un logiciel au travers d'un processus de développement. Il en exige de plusieurs comme par exemple en  V, en cascade, en cycle, etc... Leur point commun est de poser un certain nombre de phases indispensable a la bonne marche du développement.

Ces phases sont généralement : Analyse, Modélisation, Conception, Développement, Test. Il peut en existe plus, on peut en considérer moins en allant parfois dans le pire des cas a se restreindre à la seule phase de développement.

Je traiterai des phases de développement dans un autre article mais j'aimerai me focaliser sur une phase que j'estime fondamentale et pourtant très souvent mise de coté : la modélisation.

Comprise entre la phase d'analyse et la phase de conception, la modélisation est très souvent négligée car assimilée soit à l'analyse soit à la conception, quand elle n'est pas complètement ignorée.

Revenons sur ce qu'est la modélisation et ses concepts:
La modélisation est l'activité consistant a produire des modèles. 
Nous avons deux termes a définir:
  • Produire: la production est la mise en œuvre de quelque chose au moyen d'outils sur la base de plans et schémas de construction ainsi que de méthodes. Produire est donc une activité intentionnelle permettant l'apparition par différents moyens de l'artefact voulu
  • Modèle: élément de représentation, de simplification ou d'abstraction réalisée dans une intention et un contexte particulier.
Ainsi produire des modèles c'est faire usage de moyens pour abstraire, simplifier, mettre en évidence quelque chose pour faire la mise en perspective de notre compréhension d'un problème et ce avec les outils dont nous disposons, c'est a dire langage de modélisation, schéma ou encore langage naturel, etc.

Cette description pourrait être assimiler à de l'analyse , sauf que l'analyse ne se réduit qu'a la compréhension du problème sans l’établissement de solution, de même on pourrait l'associer à de la conception sauf que la conception  nécessite une décomposition fonctionnelle cohérente pour être menée.

En fait on le voit ici la modélisation se superpose clairement sur l'analyse et la conception sans les remplacer complètement non plus. Mais alors qu'apporte la modélisation ? Et bien elle rempli le gap existant entre les deux. Voyons comment :

La modélisation apporte la possibilité de traduire le résultat de l'analyse pas forcement formel en des modèles compréhensibles pour la phase de conception et ce par le biais de langage de modélisation (UML, AADL, SysML, etc... tout langage permettant la mise en perspective des points de vue à aborder)

Et c'est la que c'est important, car concevoir une application c'est souvent s'appuyer sur des architecture connues et maîtrisées (en couche, décentralisées, agents, etc...) mais l’intégration du besoin dans ces architecture nécessite forcement la conceptualisation de ces modèles sans lesquels les concepts seraient dilués (comme on le voit souvent) dans la solution;  les mécanismes techniques associés mis en œuvre se retrouvent alors mal définis et mal identifiable.

En conclusion, on dit que le langage forme les idées, qu'il est impossible de conceptualiser sa penser sans le support de notre langue, il est important a ce titre que nous utilisions les langages de modélisation pour former correctement les programmes. Ces langages nous donne des outils et des méthodes adapter pour combler le vide entre spécification et conception par cette phase qui s’appelle la modélisation.