jeudi 15 juillet 2010

Java - Ivy : création d'un repository local

Voila une façon simple de créer un repository local :
  • Créer un repertoire partagé sur une machine en réseau. Exemple :  \\ma-machine\repository
  • Créer un fichier de configuration Ivy :
    <ivysettings>
        <properties file="${ivy.settings.dir}/ivysettings.properties">
        <property name="myrepository" overrite="true" value="//ma-machine/repository">
        <settings defaultresolver="chain-local">
        <resolvers>
            <chain name="chain-local">
                <filesystem checkmodified="true" name="local">
                    <ivy pattern="${myrepository}/[module]/[revision]/ivy-[revision].xml">
                    <artifact pattern="${myrepository}/[module]/[revision]/[artifact]-[revision].[ext]">
                </filesystem>
                <ibiblio m2compatible="true" name="maven2">
                <ibiblio m2compatible="true" name="jboss" root="http://repository.jboss.org/nexus/content/groups/public/">
            </ibiblio>
        </resolvers>
    </ivysettings>
  • Il suffit ensuite d'importer le fichier de configuration dans ant :
    <ivy:settings file="${basedir}/ivysettings.xml" />
Bien sur il reste à remplir se repository...

vendredi 11 juin 2010

Java - Ivy : découverte

Depuis longtemps, je gérais mes dépendances en utilisant SVN. En gros j'importais toutes mes librairies et leurs dépendances dans SVN en les taggants avec leur version. L'export se faisait via un script batch mais cela demandait la gestion des dépendances des dépendances... (Pas très pratique quand on changeait de version de lib). Le pire était pour la gestion des modules car il fallait les importer dans SVN dès qu'une modification était réalisée. De plus, SVN n'étant pas vraiment fait pour l'import de binaire, la base avait tendance à grossir.

Dernièrement, je me suis mis à l'intégration continue (Hudson pour tout vous dire). Tout fonctionne bien avec l'utilisation de mes lib chargées dans SVN. Mais en voulant utiliser des plugins de type "tag automatique" j'ai rencontré un problème vu qu'Hudson essaye de tagger tout ce qui a été extrait de SVN donc mes Jar, ce qui pour le coup pose vraiment problème.

En fouillant un peu, je suis tombé sur 2 solutions pour gérer mes dépendances : Maven et Ivy. Etant sous Ant, mon choix c'est porté sur Ivy.

Les premier pas ne sont pas forcément évident. Les tutoriaux proposés se limitent aux premiers pas et la documentation, bien que complète, est plutôt faite pour des connaisseurs. Mais en persévèrent un peu et en posant quelques questions sur mon forum favori (developpez.com). On passe cette étape et là, on se rend vraiment compte de la puissance de cette outil.

Plus besoin de se soucier des dependances, Ivy s'en occupe. Il suffit juste de lui donner quelle librairie on veut utiliser et il va chercher toutes les dépendances utiles. Par défaut, Ivy va chercher dans le repository de Maven qui est bien complet. Et pour les modules que l'on développe et que l'on partage, il suffit de se créer un repository local (dans mon cas un simple répertoire partagé, mais on peut faire beaucoup plus complet si on le souhaite) où l'on publirea nos modules. Et là encore Ivy s'occupe de ses dépendances.

vendredi 7 mai 2010

Agilité - Le rythme soutenable

L'un des principes du manifeste agile est "le rythme soutenable". Mais dans nos entreprises il n'est pas toujours facile de le déterminer ni même de le garder sous la pression des managers.
Emmanuel Chenu vient de publier un post fort intéressant à ce sujet sur son blog. Il parle du rythme de travail mais aussi du stresse apporté pour la pratique des méthodes agiles.

C'est par ici.

mardi 27 avril 2010

Agilité - La chasse à la bonne méthode

Comme beaucoup, je suis attiré par la mise en pratique des méthodes agile dans mon travail pour palier aux inconvénients rencontrés par la pratique de méthodes dites standard. Connaissant de nom Scrum et XP je me suis déjà penché dessus pour voir leur bénéfices et comment les appliquer. Mais très rapidement on découvre qu'il existe d'autres méthodes : Kanban, Lean, RUP, PUMA, FDD...
Et la ça commence à être le bazar, les questions s'accumulent : quelle méthode choisir? Faut il en prendre qu'une ou plusieurs? Faut il faire un mixte? Prendre que ce qui nous intéresse? Prendre un coach? Suivre des formations?...

Dans cette quête de réponses, quelques sites proposent des comparatifs qui, même s'ils ne peuvent pas tout comparer, peuvent aider :
 
Bonne lecture.

lundi 26 avril 2010

Java - Swing : Exemple de base

Tout ceux qui on un jour fait du client lourd en Java se sont pris la tête pour avoir un composant qui répond exactement à leur besoin. Les bibliothèques Java Swing et AWT propose déjà un bon nombre de composant prêt à l'emploi. Sans parler des « nouvelles » librairies tel que SwingX qui permettent d'étendre le nombre de composant prêt à l’emploi. Mais même ainsi, il n'est pas rare de vouloir un comportement diffèrent de celui qui est implémenté de base. Heureusement ces librairies ont été conçues pour être entièrement paramétrable. Mais ces modifications ne sont pas toujours évidantes à réaliser, surtout si l'on n'est pas un spécialiste dans ce domaine.

Ce site référencie les modifications fréquemment faites avec le code java correspondant : SwingExamples.

vendredi 23 avril 2010

Java - JTree avec des icones spécifiques

J'ai voulu faire un JTree affichant des icones spécifiques à chaque noeud.
Dans mon cas, l'objet du noeud est capable de fournir sa propre icone, ce qui simplifie le code. Du coup la solution est simple : il suffit de faire un Renderer héritant de DefaultTreeCellRenderer et de redéfinir la méthode getTreeCellRendererComponent.

Ce qui donne :
  @Override
  public Component getTreeCellRendererComponent(JTree tree,
            Object value,
            boolean sel,
            boolean expanded,
            boolean leaf, int row,
            boolean hasFocus) {
    Component component = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
    if (Filiale.class.isInstance(value)) {
      setIcon(((Filiale) value).getIcon());
    }
    return component;
  }

Pour plus d'info : http://java.sun.com/docs/books/tutorial/uiswing/components/tree.html#display

jeudi 22 avril 2010

Java - Bonnes pratiques


Je rassemble ici en ensemble de bonnes pratiques trouvées dans mes périgrinations.

Les classes interdites

Lors d’utilisation de classe provenant d’un SDK, il faut s’assurer qu’elles correspondent bien a nos besoins et qu’il n’y a pas plus « léger » à utiliser. Certaines classes ne sont la que pour assurer la compatibilité ascendante. On en exclura donc leur usage sauf si leur remplacent ne satisfont pas au besoin.

Exemple de classes "interdites" :
  • Hashtable : classe synchronisée => Thread-safe mais lourde (rapport 1 à 5)
    Utiliser plutôt dans une utilisation standard : HashMap
    Si besoin d’un conteneur thread-Safe utiliser : Collections.synchronizedMap
  • Vector : classe synchronisée => Thread-safe mais lourde (rapport 1 à 5)
    Utiliser plutôt dans une utilisation standard : ArrayList
    Si besoin d’un conteneur thread-Safe utiliser : Collections.synchronizedList

Concaténation de chaînes de caractères

Malgré ce que l’on pense, le code suivant n’est pas mauvais ; il est même optimum :
String s = "In memory-constrained situations" +
           ", you should pay close attention" +
           " to the" +
           " proliferation " +
           " of"+
           " strings";

En effet, le compilateur va optimiser l’expression en la transformant en une seule chaîne. De même que ce code :
String myValue = “Ma valeur à afficher”;
String s = “You should pay close attention" +
         " to the" +
         " proliferation " +
         "of"+ myValue;

Par contre celui-ci est plus coûteux car le compilateur ne sait pas l’optimiser. Et, il sera à éviter.
String s = "In memory-constrained situations";
s+= ", you should pay close attention";
s+= " to the";
s+= " proliferation ";
s+= "of";
s+= " strings";

Il est possible d’utiliser un StringBuilder qui sera moins couteux et plus flexible lorsque le 1er cas ne peut être suivi :
StringBuilder sb = new StringBuilder() ;
Sb.add("In memory-constrained situations") ;
Sb.add(", you should pay close attention") ;
Sb.add(" to the") ;
Sb.add(" proliferation ") ;
Sb.add("of") ;
Sb.add(" strings") ;

Classes retournant des collections.

Beaucoup de classe retournent des collections (List, Map,...). Ces collections doivent toujours être initialisées. S’il n’y a pas d’objet dans la collection celle-ci doit être vide mais non null.

Les tableaux fourretouts

Il faut éviter les tableaux fourretouts de type Object[]. Cela rend le code illisible et compliqué à utiliser (quel objet vais-je trouver dans le tableau ? Comment dois-je construire ce tableau ?) et source d’erreur vu qu’il n’y a pas de typage. Il est préférable de créer une classe « Bean » rassemblant les objets composant ce tableau.

Exceptions

Ne jamais ignorer une exception
Une erreur fréquente est de mettre un bloc catch vide sans aucune instruction afin de pouvoir compiler le programme. Ceci est très dangereux. En effet, si une exception survient, elle sera passée sous silence et le programme continuera de fonctionner ce qui peut déboucher sur des bugs incompréhensibles. Le bon réflexe est de bien traiter les exceptions dans les blocs catch. Mettre un commentaire clair si c’est normal de ne rien faire.

Reflet de l’erreur
Les exceptions doivent refléter l’erreur levée. Trouvez la bonne granularité : une interface graphique se moque de savoir que c’est la base de données qui ne répond pas. Elle a juste besoin de savoir que le service est momentanément interrompu. Le niveau de précision (la granularité) de l’exception doit être adapté à la position du module dans une architecture en couche.

Les exceptions génériques
Eviter de catcher les exceptions génériques du style :
Try {
     .....
} catch (Exception e) {
     .....
}

Il est préférable de catcher exception par exception et de faire le traitement spécifique. Cela permet un débogage plus facile en cas de problème.

De même, il est déconseillé de renvoyer une exception générique. Il est préférable de créer des exceptions par package ou d’utiliser les exceptions fournis dans le SDK, cela permet, sur une trace, de retrouver plus facilement les causes de l’exception levée.

Les exceptions et les entrées/sorties
En cas d’exceptions, il faut s’assurer que l’état après le catch est stable et qu’il ne reste rien d’ouvert (fichier, flux, connexion,...).
Il faut donc utiliser le « Finally » pour libérer les ressources.

Exemple java :
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class FluxMajuscule {

/** Crée une nouvelle instance de FluxMajuscule */
  public FluxMajuscule() {
  }

  public void readMaj(){
    try{
      BufferedReader br=new BufferedReader(new FileReader("monFichier.txt"));
        try{
          String ligne;
          String ligneMajuscule;
          while((ligne=br.readLine())!=null){
            ligneMajuscule=ligne.toUpperCase();
            System.out.println(ligneMajuscule);
          }
        }finally{
          br.close();
        }
      }catch(IOException ex){
        ex.printStackTrace();
      }
    }
}

Manifest

En Java, il est conseillé de remplir le manifeste de façon standard. Le SDK fournit des méthodes pour aller lire ce manifeste dans des packages.

Exemple de manifest java :
Manifest-version: 1.0
Implementation-Version: 1.2

Specification-Title: MaLibrary
Specification-Version: 1.2
Specification-Vendor: MaSociété
Implementation-Vendor: MaSociété
Implementation-Title: MaLibrary
Implementation-Version: 1.2
Build-date: 2009-09-07 19:01:52

Thread

Synchronisation
La mise en place d’un processus de synchronisation est tres gourmant en ressource. Du coup avant de se lancer dans la synchronisation, on doit se poser quelques questions :
  • A-t-on vraiment besoin d’avoir une méthode synchronisée ? (Utilisation de ressource synchrone ? Ordre d’exécution important ?...)
  • Cette méthode peut-elle être utilisée en multi-thread ?

Le mot clé « synchronized » en java permet de définir des sections critiques thread safe. Il est souvent utilisé avec la déclaration de la méthode d’une classe.

public synchronized void theMethod() {}

Cette écriture est équivalente à
public void theMethod() {
  synchronized (this) {
    …
  }
}

Plutôt que d’utiliser la synchronisation au niveau de la méthode, il est préférable de l’utiliser uniquement sur la section de la méthode qui nécessite un accès thread safe. D’ailleurs, rien n’oblige le développeur à utiliser « this » comme objet de synchronisation. On peut par exemple utiliser un singleton si l’on souhaite synchroniser plusieurs méthodes disséminées dans plusieurs objets.
Le principal reproche que l’on puisse faire à la technique du synchronized, c’est le manque de granularité. En effet, si un système multi thread tente de lire et de modifier une variable en même temps, le verrou sera le même pour la lecture ainsi que pour l’écriture, provoquant un goulot d’étranglement.

Pour palier a cela, il est possible d’utiliser des verrous d’écriture et de lecture, mais le code s’en retrouve complexifié.
Un verrou de lecture est différent d’un verrou d’écriture. Le verrou d’écriture doit attendre que les verrous de lecture soient tous levés pour être posé. Plusieurs verrous de lecture peuvent être posés en même temps alors qu’un seul verrou d’écriture ne peut être posé à un instant donné.