Gestions des numéros de version avec SVN

Le but de cet article est d’expliquer comment gérer les versions successives d’une application avec SVN. Par « gérer les versions », j’entends gestion des différents tags, branches de maintenances, merge, … Je vais m’appuyer sur SVN tout au long de cette article, mais tout ceci est également valable pour Git (bien que Git facilite grandement certaines des opérations à effectuer !)

Principe de la numérotation des versions

Il y a beaucoup de manières de numéroter un projet. Mais la façon la plus habituelle est généralement d’utiliser trois chiffres séparés par des points X.Y.Z :
- Le premier chiffre représente un changement majeur dans l’application. Mais cette notion de « majeur » est déjà très subjective : une refonte technique du logiciel (migration de technologies, refonte du modèle de données, …) pourra être considérée comme majeure par les développeurs, mais comme mineure par un utilisateur, car elle n’apporte aucune modification sur les fonctionnalités. Une bonne pratique consiste à réserver ce numéro pour les évolutions fonctionnelles de l’application.
- Le second chiffre correspond à des évolutions mineures : ajout de fonctionnalités, modification de quelques aspects d’ergonomie, …
- Le troisième chiffre correspond généralement à des corrections d’anomalies, des patchs, ou des refactors techniques.

Voilà pour la théorie. Le cœur du sujet de cet article repose sur la gestion de ces numéros de version à travers SVN.

Gestions des versions dans le développement d’une application

A l’issue d’un développement (par exemple on termine la version 1.3.0), on pose souvent un tag sur la version stable du tronc afin de pouvoir figer les sources au moment d’une livraison, et de pouvoir y revenir par la suite. Le nom de ce tag contient généralement le numéro de la version : « application-1.3.0-DATE ».

Peu après, une anomalie est remontée. Il faut donc la corriger. Mais où ? Si aucune évolution n’est prévue, on peut continuer à utiliser le tronc de l’application pour la corriger. On va alors taguer une version « application-1.3.1-DATE » avec le correctif. Mais l’idéal est, comme nous le verrons par la suite, de créer une branche de maintenance.

On souhaite maintenant poursuivre les développements de l’application et ajouter de nouvelles fonctionnalités qui restent relativement mineures. Là se pose la question : je pars sur une version 1.3.2 car c’est mineur, ou alors sur une version 1.4.0 mais qui apportera seulement de faibles évolutions ?

Si ces fonctionnalités demandent du développement, il n’y a pas à hésiter : il faut créer une version 1.4.0 ! Pourquoi ? Parce que s’il survient une anomalie sur la version 1.3.1 qu’il faut corriger en urgence, où va-t-on la faire ?

Si on a réservé la version 1.3.2 pour nos évolutions mineures, il faudra nécessairement que le correctif soit ajouté dans cette version, et il faudra attendre que celle-ci soit terminée pour que l’utilisateur puisse profiter de la correction de son anomalie. Si en revanche les développeurs travaillent sur un tronc qui va vers une version 1.4.0, il est toujours possible de créer une branche à partir de la version 1.3.1 pour effectuer la correction demandée, la déployer pour l’utilisateur, puis la fusionner avec le tronc pour que ce correctif soit également intégré dans la version 1.4.0.

Il faut toujours penser que le troisième chiffre, dans cet exemple, représente un patch, et doit donc être réservé pour la correction d’anomalies.

Gestion des versions avec SVN

Voyons maintenant comment tout ceci se passe côté SVN, et comment gérer concrètement cette numérotation de versions.

Je développe ma nouvelle version seul (le rectangle blanc représente mon répertoire local) :

svn-1

Je suis rejoint par un autre développeur :

svn-2

Petit à petit, les versions et corrections avancent :

svn-3

Je dois travailler sur ma version 1.3.0. Je pourrais travailler sur le tronc et laisser les corrections de la version 1.2 se faire sur des branches, mais par précaution, je crée une branche de développement pour ma nouvelle version afin de garder un tronc toujours en phase avec la dernière version du logiciel.

svn-4

Je pars sur ma version 1.4.0 avec de nouvelles fonctionnalités. Je crée alors une nouvelle branche (branche de maintenance) pour corriger les anomalies qui vont remonter sur ma version 1.3.0.

svn-5

On a l’impression que les branches vont se multiplier, mais finalement, il n’y en a que deux :
- La branche de maintenance sur laquelle je gère mes corrections d’anomalies et qui va finalement s’occuper d’incrémenter le troisième chiffre de mon numéro de version
- La branche de développement sur laquelle je développe mes nouvelles fonctionnalités et donc qui gère le second chiffre de mon numéro de version.

Bonne pratique de gestion de versions SVN

Voici quelques bonnes pratiques de travail avec SVN (les principes généraux sont bien sûr transposables à Git).
- Updater régulièrement, et surtout toujours avant de commiter.
- Ne pas commiter sur un tag. Il peut être tentant de faire un correctif rapide sur un tag pour ne pas avoir à créer de nouvelles versions du logiciel, mais il sera généralement préférable d’éviter et d’inclure ces corrections dans une nouvelle version.
- Limiter le nombre de branches. Mais si les branches sont de bonnes pratiques, leur surnombre complexifie grandement la gestion des versions et des merge. Particulièrement sur SVN, les merge ne sont pas toujours faciles à réaliser, donc c’est une manipulation à faire avec précaution.
- A chaque tag posé sur le tronc, penser à mettre à jour toutes les branches actives avec ces modifications du tronc (merge du tronc vers la branche). Il faut cependant étudier au préalable que la branche peut recevoir l’évolution du tronc, ce n’est pas toujours le cas !
- Lorsque l’on pose un tag sur une branche de maintenant (1.3.1, 1.3.2, …) il est bon de reporter ce tag sur le tronc en indiquant qu’il s’agit d’un tag de merge : merged-1.3.1, merged-1.3.2.
- Lorsqu’on crée une branche de maintenant, on la nomme X.Y.x ou x correspond à la succession des évolutions de cette branche (voir image ci-dessous).

svn-6

Conclusion

La gestion des numéros de version d’une application est dans la théorie assez simple (X.Y.Z), mais dans la pratique, ce n’est pas si facile à mettre en œuvre. Lorsqu’on se retrouve à devoir travailler sur une nouvelle version d’une application, sur la correction d’anomalies et sur des tests pour une future évolution innovante, cela se traduit pas la gestion à la fois du tronc, d’une branche de maintenance, d’une branche évolutive, d’une branche de test d’innovations, et des répertoires locaux de chaque utilisateur. Il est alors nécessaire de mettre en place dès le début du projet de bonnes pratiques pour faire coexister l’ensemble de ces lignes de gestions de versions, et de bien décider comment on va incrémenter les différentes versions de l’application.

Sources :
Versions d’un logiciel : http://fr.wikipedia.org/wiki/Version_d%27un_logiciel
Gestion des versions avec SVN : http://www.geek-directeur-technique.com/2009/03/31/gestion-de-sources-versions-de-logiciels

VN:R_U [1.9.22_1171]
Rating: 0 (from 0 votes)
Share
Publié dans Non classé | Laisser un commentaire

Epicez vos appels réseau Android avec RoboSpice

Le besoin

Lorsque l’on développe une application Android, il peut arriver que l’on ait besoin de faire appel à des web services.

Ces appels réseau peuvent prendre beaucoup ANRde temps et vous risquez de voir une boîte de dialogue indésirable apparaître (oups !). Il faut donc réaliser ces appels de manière asynchrone. Il peut aussi être intéressant de limiter les échanges pour consommer moins de bande passante notamment grâce à un système de cache.

Il est courant d’utiliser une AsyncTask et de se débrouiller pour enregistrer les données quelque part si besoin. Mais utiliser une AsyncTask n’est pas une bonne solution pour réaliser des appels réseau, nous verrons pourquoi. Heureusement, RoboSpice est là et il s’occupe de tout.

Si vous avez envie d’un résumé de ce qu’apporte RoboSpice, il vous suffit de regarder cette infographie. J’explique plus en détail les différents problèmes de l’existant dans la suite.

L’existant

AsyncTask

L’AsyncTask est la méthode la plus utilisée pour exécuter une tâche asynchrone. C’est notamment ce qui est décrit dans les tutoriels officiels Android pour réaliser un appel réseau. Cependant, l’AsyncTask ignore le cycle de vie de l’Activity et cela pose quelques problèmes non négligeables.

Dans notre cas, le but de l’AsyncTask est d’exécuter une tâche asynchrone et de répercuter le résultat dans l’Activity qui l’a appellée. L’AsyncTask  a donc une référence vers l’Activity. Tournez simplement votre appareil, l’Activity est détruite et une nouvelle est créée. L’AsyncTask ne connait pas la nouvelle Activity et ne peut donc plus la mettre à jour. C’est dommage surtout que pendant ce temps, l’AsyncTask s’exécute, le Garbage Collector ne peut pas s’occuper de l’Activity détruite car elle est toujours référencée. Nous sommes en présence d’une jolie fuite mémoire.

Des solutions existent mais demandent un effort pour être mises en place et sont couteuses en temps de développement. En gros il est difficile d’utiliser proprement les AsyncTasks. Elles restent réservées aux tâches très courtes.

Loader

Depuis Android 3.0 il existe le Loader, aussi disponible dans support v4, qui peuvent être utilisés par les Activities ou les Fagments. Celui-ci permet d’éviter les problèmes de fuite mémoire et de mise à jour de la mauvaise Activity en suivant le cycle de vie de l’Activity.

Le Loader est particulièrement adapté à la gestion des Cursors. Il surveille les changements de la source de données pour en informer l’Activity et se reconnecte au dernier Cursor après un changement de configuration pour ne pas recharger les données.

Il ne convient cependant pas parfaitement aux appels réseau. En effet, lancez une requête et tournez votre appareil avant d’avoir eu le résultat, la requête est perdue et une nouvelle est lancée. De plus, bien que le résultat de la requête soit conservé entre chaque changement de configuration, celui-ci est perdu après un changement d’Activity. Quittez l’Activity et revenez dessus, le résultat est perdu et la requête est relancée.

La solution RoboSpice

La solution

Une équipe d’Octo Technologie s’est penchée sur le problème et a créé RoboSpice. Bien qu’historiquement RoboSpice ait été créé pour exécuter des appels réseau, il est tout à fait possible de l’utiliser pour d’autres types de tâches longues. Vous pouvez utiliser cette bibliothèque à partir d’Android 8 / Foyo / 2.2.

RoboSpice utilise un Service Android pour exécuter la tâche. Des listeners (tout type de Context) sont informés de la progression de la tâche et du résultat sur l’UI Thread. Ils sont attachés et détachés en fonction de leur cycle de vie, il n’y a donc plus de fuite mémoire et le listener reçoit bien les informations même après un changement de configuration.

Un système de cache configurable (délai d’expiration, format d’enregistrement) enregistre le résultat de chaque requête. Cela permet d’éviter les appels réseaux répétés et donc d’économiser de la bande passante.

Pour finir, RoboSpice est orienté objet. Le résultat des requêtes est un objet et il est possible d’en envoyer dans la requête. Plusieurs extensions de client HTTP sont disponibles pour se plier aux habitudes de chacun :

Comment l’utiliser

Pour le coté pratique, allez lire le Starter Guide de RoboSpice. Il explique très bien comment utiliser RoboSpice en prenant l’exemple d’une Activity affichant une liste de tweets récupérée à partir d’un web service REST/JSON.

Vous allez devoir utiliser 4 classes :

  • SpiceRequest
  • SpiceService
  • RequestListener
  • SpiceManager

SpiceRequest

// Attention !! Cette classe ne doit pas être une classe interne du Context
public class MySpiceRequest extends SpiceRequest< ReturnType > {

    public MySpiceRequest() {
        super( ReturnType.class );
    }

    @Override
    public ReturnType loadDataFromNetwork() throws Exception {
        // Code à exécuter de manière asynchrone
        // Retourner le résultat de la requête
    }
}

Votre travail consiste à compléter la méthode loadDataFromNetwork et à choisir de quelle spécialisation de SpiceRequest hériter. Les différentes spécialisations de SpiceRequest simplifient l’écriture de loadDataFromNetwork. Par exemple si vous voulez utiliser Spring for Android RestTemplate, SpringAndroidSpiceRequest est fait pour vous comme le montre le bout de code suivant.

public ReturnType loadDataFromNetwork() throws Exception {
    return getRestTemplate().getForObject( "http://myaddress.com/get_something", ReturnType.class );
}

Cherchez la SpiceRequest qui vous correspond dans la Javadoc.

RequestListener

// Classe interne de l'Activity
private class MyRequestListener implements RequestListener< ReturnType > { 

    @Override
    public void onRequestFailure( SpiceException spiceException ) { 
        // Mettre à jour l'interface quand une erreur s'est produite 
        // durant l'exécution de la requête
    } 

    @Override
    public void onRequestSuccess( ReturnType result ) { 
        // Mettre à jour l'interface avec le résultat de la requête
    } 
}

Créez votre RequestListener avec les méthodes onRequestFailure et onRequestSuccess pour traiter le résultat de votre requête.

SpiceService

Un SpiceService se charge de gérer le cache, d’exécuter les requêtes et de notifier les RequestListeners associés aux requêtes.

Vous avez la possibilité d’écrire votre propre SpiceService si vous voulez tout gérer vous même mais il existe des SpiceServices prédéfinis fournis par RoboSpice. Ces SpiceServices prédéfinis devraient répondre à  la plupart de vos problématiques. Vous avez le choix du client HTTP, du format des données à traiter (JSON, XML, …) et de comment les traiter.

Par exemple, JacksonSpringAndroidSpiceService utilise Spring Android pour exécuter les requêtes, Jackson pour traiter les données JSON et enregistre les résultats en cache. Pour l’utiliser, il faut déclarer le service dans votre AndroidManifest. (Associez un SpringAndroidSpiceService avec une SpringAndroidSpiceRequest)

<service
    android:name="com.octo.android.robospice.JacksonSpringAndroidSpiceService"
    android:exported="false" />

Si vous préférez Google HTTP Client et Gson, pas de problème, GsonGoogleHttpClientSpiceService devrait faire l’affaire. Il en existe d’autres que je vous laisse découvrir dans la Javadoc.

SpiceManager

Le SpiceManager fait le lien entre le Context voulant exécuter des requêtes (Activity, Fragments…) et le SpiceService. Il connait le cycle de vie du context et peut ainsi s’occuper d’attacher/détacher les listeners en fonction de leur cycle de vie.

Pour exécuter une requête, ajoutez ce code dans votre Activity (ou autre Context)

// Utiliser le SpiceService choisi
protected SpiceManager spiceManager = new SpiceManager( MySpiceService.class );

@Override
protected void onStart() {
    super.onStart();
    // Penser à démarrer le SpiceManager
    spiceManager.start( this );
}

@Override
protected void onStop() {
    // Penser à arrêter le SpiceManager
    spiceManager.shouldStop();
    super.onStop();
}

public void request() {
    // Exécute MySpiceRequest et notifie MyRequestListener du résultat
    // CACHE_KEY est la clé pour enregistrer et retrouver le résultat de la requête
    // Les données en cache expireront après une heure (temps en millisecondes)
    spiceManager.execute( new MySpiceRequest(), "CACHE_KEY", DurationInMillis.ONE_HOUR, new MyRequestListener() );
}

Conclusion

Plus besoin de se prendre la tête avec le cycle de vie de l’Activity, les AsyncTasks et le cache, RoboSpice fourni un moyen simple et robuste de réaliser des appels réseau et autres tâches asynchrones dans une application Android. N’hésitez pas à l’utiliser, ce n’est pas compliqué d’épicer un peu votre code Android. En plus c’est open source.

VN:R_U [1.9.22_1171]
Rating: 0 (from 0 votes)
Share
Publié dans Android, Outils | Marqué avec , , , | Laisser un commentaire

La dague et la baguette magique : Utilisation de Dagger dans une application Dropwizard

Il était une fois…

J’ai écrit il y a quelque temps un article pour présenter le framework Dropwizard, si vous ne l’avez pas lu commencez par là, car voici la suite.

Petit rappel, Dropwizard est un framework pour réaliser des API REST avec une approche fullstack. Cependant comme vous avez pu le remarquer il manque à celui-ci une fonctionnalité qui me semble réellement importante : l’injection de dépendances. La tuyauterie de l’application se fait de façon manuelle dans la méthode run du Service, et pour peu qu’on ait une application qui dépasse la simple création de Todos, cela peut rapidement devenir le bazar.

Je me suis donc mis en tête de mettre de l’ordre dans mon application en utilisant un framework de DI. Oui mais lequel choisir ?
Continuer la lecture

VN:R_U [1.9.22_1171]
Rating: 0 (from 0 votes)
Share
Publié dans Java | Marqué avec , , , | Laisser un commentaire

Pagination SQL : l’autre solution

Je vais parler dans ce court billet d’un retour d’expérience. Et plus particulièrement d’une autre façon que le classique LIMIT … OFFSET … pour paginer les résultats en SQL. Comme j’utilise MySQL dans ma mission actuelle, les exemples de code SQL suivront le dialecte de ce SGBD, mais je n’utilise aucune fonctionnalité propre à celui-ci.
Continuer la lecture

VN:R_U [1.9.22_1171]
Rating: 0 (from 0 votes)
Share
Publié dans JDBC, Trucs & astuces | Marqué avec , | Un commentaire

Stubber des webservices avec JMS

Stubbing de webservices avec JMS

Mon équipe est amenée à concevoir et réaliser un ensemble de webservices REST. Ces services sont regroupés dans une webapp (alias “l’API”) qui constitue le point central de la plate-forme de production, exposant un ensemble de ressources à destination d’applications clientes, développées par d’autres équipes.

Situation initiale

Cette API en elle-même ne sert pas seulement de référentiel à des applications mobiles, elle s’interface aussi avec d’autres services internes ou externes au SI du client.
Continuer la lecture

VN:R_U [1.9.22_1171]
Rating: 0 (from 0 votes)
Share
Publié dans Java | 3 commentaires

Tester des services REST avec REST Assured

REST Assured est un DSL Java open source de chez Jayway simplifiant les tests de services REST. Il permet de créer des requêtes de type POST, GET, PUT, DELETE et HEAD et peut être utilisé pour valider et vérifier la réponse de ces types de requêtes.

Ok, étant donné que la documentation est bien faite, je ne vais pas entrer dans les détails, mais voici un avant-goût, en reprenant quelques exemples présents dans la documentation, qui j’espère vous donnera envie d’approfondir.
Continuer la lecture

VN:R_U [1.9.22_1171]
Rating: 0 (from 0 votes)
Share
Publié dans Non classé | Laisser un commentaire

Et si on parlait un peu système…

Introduction

On parle souvent des frameworks, APIs, librairies JavaScript, etc… mais très peu souvent de la partie “back” d’une application. Par là, j’entends serveur, base de données sur lesquels va tourner une application… Et quelquefois (souvent même je dirai), il faut mettre la main à la pâte pour pouvoir faire fonctionner tout ça car ce n’est pas forcément à l’ “administrateur système” ou à l’ “équipe production” de gérer entièrement cela et/ou auquel il faut déléguer cette partie très importante, sur laquelle repose et vit une application ! J’ajouterai même que c’est une étape incontournable lorsqu’on “touche” sérieusement à une application (que ça soit la création ou la maintenance (T.M.A.) de celle-ci).

Par contre, le choix du système d’exploitation et/ou du système de gestion de base de données (plus communément appelé S.G.B.D.) sur lesquels va s’appuyer le serveur et la B.D.D. est assez souvent imposé. Pourquoi ? Tout simplement car d’autres applications du parc de l’entreprise (petite ou grosse) pour laquelle on travaille utilisent déjà un S.G.B.D et un O.S particuliers…

 

Allez c’est parti !

Dans cette partie, je vais donc aborder le sujet de l’export/import d’une B.D.D., tâche qui peut être amenée à se répéter régulièrement lorsqu’on veut mettre à jour son environnement de recette et/ou de développement par rapport aux données de l’environnement de production.

Pour ma part, c’est un S.G.B.D. Oracle et un Windows Server  sur lesquels je me suis appuyé ! Dans la suite de cet article, je vais donc vous montrer comment j’ai pu mettre en place un “script” complet et paramétrable (adaptable assez facilement).

Continuer la lecture

VN:R_U [1.9.22_1171]
Rating: +2 (from 2 votes)
Share
Publié dans Outils, Trucs & astuces | Marqué avec , , , | Laisser un commentaire

Android et les icônes, mdpi, hdpi, xhdpi, xxhdpi …

Tout développeur Android, même débutant, se retrouve très rapidement à manipuler des icônes, que ce soit pour agrémenter l’ActionBar, un texte, un bouton, … Et tout développeur Android est donc vite confronté à une documentation intraitable sur un point : chaque icône doit être fourni dans différentes tailles, pour être utilisé sur des appareils ayant différentes densités d’écran (dpi). C’est d’ailleurs valable pour toutes les images du dossier drawable. On se retrouve donc à fournir, au minimum, 4 versions de différentes tailles pour chaque icône : mdpi (48×48), hdpi (72×72), xhdpi (96×96), xxhdpi (144×144).

Comme moi vous comprenez qu’ils n’ont pas eu le choix et que c’est mieux ainsi, alors comme moi vous téléchargez leur icon pack, comme moi vous copiez ça à la main, comme moi il vous arrive de vous tromper de dossier destination, comme moi vous l’avez dans le c** quand vous voulez une autre couleur que du noir ou du blanc, et comme moi, vous ne voulez plus y toucher une fois en place.

Continuer la lecture

VN:R_U [1.9.22_1171]
Rating: +1 (from 1 vote)
Share
Publié dans Non classé | Laisser un commentaire

Liferay 6.1 : Kaleo Forms dans le Control Panel

Kaleo est le moteur de workflow intégré à Liferay.  Le portlet Kaleo Forms permet à un utilisateur la création d’un process complet comprenant :

  • le choix d’une liste de données dynamiques (formulaire personnalisé : DDL)
  • le choix d’un sous formulaire de la DDL sélectionnée associé à la première étape du workflow
  • le choix du workflow
  • le choix des masques (sous formulaire de la DDL sélectionnée) associé à chacune des étapes du workflow.

Continuer la lecture

VN:R_U [1.9.22_1171]
Rating: 0 (from 0 votes)
Share
Publié dans Non classé, Trucs & astuces | Marqué avec , | Laisser un commentaire

Instrumentation d’une requête HTTP

Dans le cadre d’un projet d’intégration d’une solution de web analytics (PIWIK), nous avons mis en place une idée originale afin de ne pas avoir à modifier le code de l’application sur laquelle nous souhaitions positionner des tags javascript.

Notre objectif : rendre la solution retenue complètement transparente pour le code des applications à monitorer. Continuer la lecture

VN:R_U [1.9.22_1171]
Rating: 0 (from 0 votes)
Share
Publié dans Non classé, Trucs & astuces | Marqué avec , , , , , | Laisser un commentaire