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 11 juin 2010
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.
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.
Libellés :
Agile
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.
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 :
- http://www.entreprise-agile.com/ScopeMeta.htm : comparatif Scrum XP et PUMA
- http://www.dotnetguru.org/articles/dossiers/devagile/DevelopperAgile.htm : comparatif Scrum, XP, RUP et FDD
Bonne lecture.
Libellés :
Agile
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.
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 :
Pour plus d'info : http://java.sun.com/docs/books/tutorial/uiswing/components/tree.html#display
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;
}
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";
", 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;
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";
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") ;
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 exceptionUne 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) {
.....
}
.....
} 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();
}
}
}
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
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
SynchronisationLa 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) {
…
}
}
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é.
mercredi 21 avril 2010
Design Pattern Composite
Le pattern Composite est constitué d’objets ayant le même comportement sur une profondeur variable. Cela permet d’interagir sans avoir à connaître si on parle à un objet métier ou à un groupe.
Description du problème
Lorsque l’on travaille avec des données sous forme d’arbre, il est souvent nécessaire de différencier les branches des feuilles pour savoir quel traitement effectuer.Pour illustrer le contexte, prenons un exemple :
Nous souhaitons faire une application de dessin qui manipule des objets « graphiques » de base (carré, cercle, triangle,...). L’utilisateur lui a besoin de formes plus complexes qui seront fait à partir de formes de base ou même d’assemblage d’autres formes complexes. Il est donc nécessaire que ces formes complexes se comportent de la même façon qu’une forme simple.
Si on utilise un arbre simple, la programmation devient compliquée car il faut parcourir entièrement cet arbre tout en différenciant les actions réalisées sur les branches et les actions réalisées sur les feuilles. Cela nécessite du code et généralement des méthodes récursives pour effectuer les opérations.
Ce pattern répond à ce type de problème.
Diagramme UML
Définition de la solution
Composant : C’est la classe abstraite pour tous les composants, y compris les Composés. Elle déclare les interfaces pour les « opérations » et définit les méthodes de manipulation des enfants.Feuille : Représente les « feuilles » dans la composition. Elle met en œuvre toutes les méthodes « opération ».
Composé : Elle représente un composant composite (Pouvant avoir des enfants), elle implémente les méthodes pour la manipulation des enfants (ajout, suppression,…) ainsi que les méthodes « opérations »
Le pattern Composite permet au client de ne pas avoir à se soucier s’il interagi avec une feuille ou une branche (Composé).
Le composé s’occupera lui même de transmettre les demandes aux feuilles. On pourra même rajouter de l’intelligence au niveau de la branche.
Dans notre exemple, on pourrait très bien imaginer un calcul de volume : chaque feuille calcule son volume et le composé additionne tous ces volumes.
Le client exécute une « opération » sur un composé. Ce composé exécute un prétraitement (si besoin), parcoure tous ces fils en demandant l’exécution de la même opération, puis fait un post-traitement (si nécessaire).
Variante
L’élément « composant » peut être une simple interface. Mais alors il faut implémenter dans chaque feuille les méthodes pour la manipulation des fils.Conséquences
L’arbre ainsi réalisé est fortement typé. Il ne peut donc pas être utilisé de façon générique mais facilite fortement le développement du « Client ».L’interaction entre les branches et les feuilles en est aussi simplifié; les branches ne s’occupant que de retransmettre les ordres aux feuilles sans avoir à connaître leur comportement interne.
Ce design-paterne ne doit être utilisé que si les feuilles et les branches ont des opérations communes (déclaré dans la classe composant).
Exemple
Inscription à :
Articles
(
Atom
)