Tue, Jul 6, 2004
Je vous parlais récemment de la venue de Richard
Stallman à
Toulouse.
Un gentil journaliste vient de publier cet article dans l’équivalent
toulousain du 20 minutes parisien (un journal gratuit) :
Le papa de Linux en visite
Le Culte, club des utilisateurs du libre à Toulouse et environs, va
inaugurer le 10 juillet sa nouvelle salle des machines en présence de
Richard Stallman, considéré comme le père des logiciels libres. Ce
dernier a commencé à s’intéresser au sujet lorsqu’il travaillait au
laboratoire d’intelligence artificielle du MIT, avant de mettre au
point une alternative au système d’exploitation payant comme Windows,
et de créer un système gratuit : Linux. Une conférence publique aura
lieu à 15 heures à l’université Paul-Sabatier.
Avant de publier des articles lus par autant de monde, ne pouvait-il pas
se donner la peine de vérifier ou au moins de faire relire ces 4 (!)
lignes par des gens qui auraient pû immédiatement lui expliquer que RMS
n’avait nullement écrit Linux, mais que c’était Linus Torvalds ? Ça lui
aurait évité d’avoir l’air idiot devant un certain nombre de
personnes…
RMS a eu un rôle certes non négligeable, il a lancé le projet
gnu, écrit gdb, emacs, est bien le père des
logiciels libres, mais n’a pas écrit Linux.
Fri, Jul 2, 2004
Quand on a des gros plantages en C++ on cherche toujours du coté des
pointeurs mal initialisés ou des dépassements d’espaces mémoire. Or
voila une petite liste d’erreur qui saute moins au yeux (donc plus
difficiles à debugger) mais dont l’effet est tout aussi destructeur:
- Utiliser le constructeur par copie pour copier un objet de classe
Polymorphe:
Object* y=new ObjectDeriv;
...
Object* x=new Object(*y);
=> l’appel au constructeur par copie n’est pas le bon Pour éviter de
tomber dans ce piège ou que d’autres y tombent en utilisant votre code,
mettez le constructeur par copie privé.
- Faire un tableau d’objets d’une classe dérivée et l’utiliser comme
tableau d’objet de la classe de base:
void f(Object *tab,int size){
int i;
for(i=0;i<size;++i)
// manipulation de tab[i];
}
...
ObjectDeriv tab[10];
f(tab,10);
Dans ce cas, le décalage effectué lors de l’accès à tab[i] est eronné.
Plus classique : oublier de surcharger le constructeurs par copie,
l’opérateur operateur= et du destructeur dans une classe contenant des
pointeurs.
- Oublier de mettre virtuel le destructeur dans une classe qui peut
être dérivée.
- Dans les classes contenant des pointeurs : oublier de vérifier les
auto-affectations dans l’operateur=.
const Object& operator= ( const Object& o){
delete pt;
pt=new PtType;
pt=o.Pt;
}
Dans le cas d’une auto-affectation (o==*this), le pt=o.pt va échouer
car o.pt est déjà libéré. Dans ce cas 2 solutions :
- Vérifier l’auto affectation :
if( this==&o )
return o;
PtType* tmp=pt;
pt=new PtType;
pt=o.Pt;
delete tmp;
Si vous avez d’autres erreurs du style, que vous avez planché dessus
pendant des heures et que vous voulez faire par de votre expérience
n’hésitez pas…
Thu, Jul 1, 2004
Oui, oui, vous ne rêvez pas, Richard M. Stallman vient à Toulouse dans
10 jours. Il est invité par le Club des Utilisateurs du Libre de
Toulouse et des environs.
Le programme de sa venue est indiqué plus en détail sur le site en lien
ci-dessus. Je vais tout faire pour essayer d’y aller et je ferai des
photos :-).
Pour ceux qui ne savent pas qui est RMS, eh bien en gros c’est monsieur
GNU et FSF. Le concept même
de logiciel libre, c’est lui. Il fait des conférences dans le monde
entier sur le sujet. Et le samedi 10 juillet, il va en faire une à 5km
de chez moi…
Geek, moi ?
Mon, Jun 28, 2004
Aujourd’hui, on va parler de best practices (ou bonnes pratiques en bon
françois) de programmation en Java. On parlera entre autre des quelques
classes de l’API fonctionnellement dépréciées, on parlera aussi
d’évolutivité et d’héritages abusifs, le tout encadré de design
patterns.
Les classes interdites
Je rencontre encore sur le net certains projets qui utilisent encore les
2 classes suivantes (cette liste n’est certainement pas exhaustive, mais
ces deux là sont les plus courantes) :
Vous ne devez pas utiliser ces classes. Elles ne sont toujours présentes
que pour assurer une compatibilité ascendante : la jvm 1.4 doit pouvoir
faire tourner un programme écrit en 1.0 qui peut contenir des objets de
ce type puisque leur alternative n’est apparue que pour la version 1.2.
Depuis la 1.2 donc, il ne faut plus les utiliser. Mais alors pourquoi,
vous allez me dire, est-ce qu’ils n’ont pas déprécié ces classes à
partir de la 1.2 ? C’est très simple : hashtable est une table de
hâchage (une liste de clé-valeur) et Vector une classe qui gère une
liste d’objets… C’est à dire des objets extrêmement courants et
utilisés. Sun a donc décidé de ne pas les déprécier pour éviter
plusieurs centaines voire milliers de lignes de warning à la compilation
de projets développés à l’époque du jdk 1.2.
pourquoi ne pas les utiliser ?
Ces classes sont synchronisées, elles sont ce qu’on appelle
thread-safe. Cela signifie que dans un environnement contenant
plusieurs fils de processus, si vous utilisez ces objets, vous vous
garantissez une cohérence de leurs données, ce qui ne serait pas le cas
si elles n’étaient pas synchronisées.
Le problème c’est que cette fonctionnalité est loin d’être utilisée dans
tous les projets, on n’utilise pas forcément ses objets dans un contexte
concurrentiel partout (encore heureux). En terme de performances, cette
synchronisation n’est pas gratuite, on peut même dire qu’elle est plutôt
chère (on parle communément d’un rapport de 1 à 5). Vous vous rendez
alors bien compte qu’utiliser un Vector pour stocker vos listes est le
plus souvent une perte totalement inutile de performances.
Les alternatives
Mais alors donc quelles classes utiliser en remplacement ? Celles-ci,
leurs équivalents non thread-safe :
ArrayList pour Vector
HashMap pour Hashtable
Et si je veux un conteneur thread-safe ?
Si vous avez pensé à poser cette question, bravo. Dans un environnement
concurrentiel, il faut toujours synchroniser les objets d’une façon ou
d’une autre… Il y a deux solutions pour ce faire :
Synchronisation aux endroits où c’est nécessaire en utilisant un
conteneur non synchronisé
- Avantage : Gain possible en performances car vous maîtrisez
parfaitement la synchronisation de votre code ;
- Inconvénient : Plus difficile parce que vous devez faire très
attention de ne pas faire d’oubli dans cette synchro si vous ne
voulez pas obtenir des résultats au mieux bizarres, au pire
catastrophiques.
Utilisation de conteneur synchronisé :
- Avantage : Il suffit de se concentrer une bonne fois sur le codage
du conteneur et ensuite on peut l’utiliser sans crainte de créer des
inconsistences à l’exécution ;
- Inconvénient : Perte possible de performance parce qu’il va
peut-être y avoir des synchronisation à des endroits où ce n’est pas
nécessaire.
Heureusement, vous vous dites, il existe donc Vector pour les cas où
on veut utiliser un conteneur _thread-safe_. Et bien non, vous pouvez
jeter cette classe, vous-n’en-aurez-plus-besoin :-). À la place,
utilisez la méthode statique
Collections.synchronizedList.
Vous obtiendrez ainsi une liste synchronisée à partir d’une qui ne l’est
pas, en appliquant de plus l’important principe qui consiste à cacher
les implémentations dont je vais maintenant parler.
Améliorer l’évolutivité du code
Masquer l’implémentation
Ce qui fait que beaucoup (trop) d’utilisations de Vector subsistent
encore aujourd’hui, c’est que cette classe était utilisée partout sans
être masquée par une classe ou une interface.
Depuis la version 1.2, Vector implémente l’interface List comme le
font ArrayList et LinkedList. Lorsqu’on utilise une liste, il ne
faut donc plus indiquer à l’extérieur qu’on utilise telle ou telle
implémentation mais il faut simplement indiquer qu’on utilise une classe
qui implémente l’interface List. En faisant systématiquement comme ça,
vous vous laissez la possibilité de changer d’implémentation
ultérieurement. S’il vous prend par exemple l’envie de ne plus utiliser
une ArrayList mais une implémentation personnelle de List pour telle
ou telle raison, personne ne le saura et tout le reste du code restera
inchangé (et ça, c’est très important).
Les factory
Utilisez des factory pour créer vos objets. Vous pourrez ainsi
facilement cacher une implémentation.
Exemple : Pouet doit pouvoir dire bonjour
public interface Pouet
{
/**
* Affiche bonjour à l'écran
*/
public void sayBonjour();
}
Très bien, la première chose à faire est donc d’écrire une
implémentation de Pouet :
public class PouetImpl implements Pouet
{
public void sayBonjour()
{
System.out.println("Bonjour");
}
}
Si vous ne faites que ça, les utilisateurs de votre classe n’auront pas
d’autre choix que d’écrire
PouetImpl pouet = new PouetImpl();
Et s’ils sont un petit peu plus expérimentés
Pouet pouet = new PouetImpl();
Et ils utiliseront Pouet et non PouetImpl partout dans leur code, mais
ce n’est pas forcément bon parce que vous laissez d’autres que vous
faire des choix de méthode d’utilisation de votre code. Autant que faire
se peut, il doit toujours y avoir un minimum de possibilité pour faire
quelque chose, sinon vous vous exposez à de gros problèmes de
maintenance…
Et s’ils le sont encore plus, ils pourront avoir envie d’utiliser un
framework de découplage, communément appelé conteneur léger en
opposition avec les conteneurs d’EJB beaucoup plus intrusifs et lourds à
mettre en oeuvre, comme spring,
PicoContainer ou
Avalon qui permettent d’utiliser de simples
POJOs.
Ou alors, il écriront eux-mêmes la factory que vous auriez dû fournir :
public final class PouetFactory
{
public Pouet createPouet()
{
return new PouetImpl();
}
/**
* Singleton pour cette factory.
*/
public static PouetFactory getFactory()
{
if(pouetFactory==null)
{
pouetFactory = new PouetFactory();
}
return pouetFactory;
}
private static final pouetFactory;
private PouetFactory()
{
}
}
Ici, on aura pris soin de faire 3 choses :
- fournir une méthode statique
getFactory() ou getInstance() ;
- mettre un constructeur private pour interdire l’instanciation de la
factory par du code extérieur ;
- mettre la classe final pour empêcher sa dérivation.
Vous voyez bien ici que si j’ai envie d’utiliser autre chose que
PouetImpl, personne ne le saura si j’ai bien contraint à utiliser
correctement mon code (en mettant par exemple la classe PouetImpl
protected si c’est possible afin d’éviter qu’elle soit instanciable par
un autre objet que ceux du package). Je pourrai librement changer
d’implémentation en impactant le moins de code possible.
Héritage abusif
Dans la série du code anti-évolutif, mettons au top les dérivations
excessives. Qui n’a jamais dérivé une JFrame pour afficher une pauvre
fenêtre qui n’a rien de plus que la JFrame d’origine ? Et bien non, vous
devez déléguer dans la plupart des cas. C’est à dire encapsuler l’objet
que vous utilisez et fournir une méthode getComponent() renvoyant un
Component par exemple pour le fournir à l’extérieur.
On ne décide pas de faire une dérivation à la légère, ce choix de
conception doit être motivé par le fait que l’objet que vous voulez est
une variante de la classe dont vous souhaitez hériter. Si ce n’est pas
le cas, il y a de fortes chances pour que vous ne deviez pas hériter
mais plutôt déléguer.
Ça ira pour aujourd’hui
Voilà, ce sera tout pour aujourd’hui. J’ai encore d’autres trucs dont je
veux parler. Il faudra que j’en trouve le temps, ce qui n’est pas gagné.
J’ai envie de vous parler de DAO, de commons-logging, de JNI … Bref,
encore de quoi dire pleins de choses :-).
Si vous n’êtes pas d’accord avec certains points ou que vous souhaitez
des éclaircissements, les commentaires sont là pour ça :-).
Mon, Jun 21, 2004
Cette phrase, je l’ai tant entendu qu’elle me donne des nausées… J’ai
l’impression que c’est un peu l’excuse bidon qu’on donne quand on est un
peu jeune. C’est aussi celle que je m’attends à recevoir de ceux qui
osent poster des sentences du genre de celle qui va suivre.
Quand je parlais de
l’orthographe
et que je vous disais que rien ne va plus… Sans aller jusqu’à
l’extrême suffisance dont fit preuve notre étudiant modèle en
trackbackant cybercodeur (je vous laisse retrouver le fil, j’ai pas
envie de linker vers ce pauvre type, François pour vous aider),
suscitant ainsi un torrent de critiques bien méritées, je dois avouer
que j’ai véritablement eu mal aux yeux en voyant ça :
“que ce ne soit pas qu’un effet d’anonce destiné à faire un appel du
pier à une certaine sociétée américaine”
Je vous laisse trouver où cette phrase a été écrite …
Je trouve regrettable de faire aussi peu d’effort quant à l’utilisation
du français. Je veux bien admettre que ce n’est peut-être pas aussi
facile pour tout le monde. Toutefois, à moins d’être hautement
dyslexique, il n’aurait pas été si difficile d’écrire la phrase
ci-dessus sans fautes. Même Syl y parviendrait :-) !
J’ai un petit frère comme ça, il a toujours un surnom MSN à se tirer une
balle. Tout à l’heure, il s’appelait XXX qui ai crevé (non, il n’a
pas crevé un pneu de sa voiture, il n’en a pas, il est fatigué quoi
:-)). Pourtant dès que je lui signale, il dit “Ah oui ! Merci !”… Il
s’en fout, c’est tout, il s’en contrefout et c’est bien dommage parce
qu’il ne pourra jamais se débrouiller seul, comme beaucoup, pour écrire
des lettres officielles sans se faire relire par ses proches…
Alors pensez y, faites un petit effort tous les jours pour vous mêmes
mais aussi dans le respect de ceux qui vous lisent.
Wed, Jun 16, 2004
Malgré
l’effort
de mat de chez totalementcrétin pour m’aider dans ma tâche de
traduction, personne ne s’est proposé…
C’est pas grave, j’ai donc continué tout seul. Le blog me semblait
quelque peu inapproprié pour ce travail, j’ai donc choisi de mirrorer
complètement les pages concernant Ken Brown du site de
Tanenbaum et de les traduire
toutes…
Mais où donc les ai-je mises ? Ben sur mon site, ici
quoi.
Comme vous le verrez, ces pages ont donc la même charte graphique que la
version anglaise (normal, c’est la même CSS). La différence, c’est ce
que c’est maintenant du XHTML 1.0 (fallait au moins ça :-D).
Il y a 4 articles, les 3 premiers sont entièrement traduits :
- Le premier a déjà été publié sur ce
billet,
il a donc été relu quelques fois ;
- Les deux suivants sont bruts de décoffrage. Comme j’ai pas mal de
travail en dehors de ces traductions et que je n’ai pas trop le
courage de relire tout de suite, je vous laisse le soin de
m’indiquer les éventuelles fautes de
tout type qui peuvent subsister afin d’améliorer ensemble le
document ;
- Le quatrième le sera au fur et à mesure. J’en ai déjà fait environ
1/4, si quelqu’un veut m’aider à le finir, je serais heureux de
recevoir sa contribution et d’ajouter son nom au bas de la page :-).
Je suis bien entendu prêt à ajouter tout lien vers des traductions ou
toute page html que vous m’enverriez concernant l’affaire. J’aimerais
par exemple trouver le temps de traduire la réponse de Linus à Ken
Brown, mais je pense que je
n’y arriverai pas… :-( Allez ! Quelqu’un peut s’y coller, y a pas
grand chose :-).
Tue, Jun 15, 2004
Allez…un p’tit peu de physique, ça peut pas faire de mal.
Mamie et la relativité
restreinte
Moi j’trouve ça marrant la façon dont c’est expliqué… même si j’ai pas
tout compris. Alors si y en a pour qui c’est super clair… N’hésitez
pas à poster.
Sat, Jun 12, 2004
Demain, vous qui utilisez l’informatique ou vous qui travaillez dans le
domaine, votez !
Procuration
C’est très simple à faire, je l’ai fait récemment, il suffit de suivre
les quelques étapes suivantes :
- Trouver quelqu’un qui vote dans la même ville que vous.
- Vous allez à la gendarmerie ou au commissariat le plus proche avec
votre carte d’identité et votre carte d’électeur
- Vous dites que vous souhaitez remplir une demande de procuration
- Vous remplissez la paperasse
- Environ 15 minutes plus tard, vous êtes repartis et c’est fini…
Pourquoi et pour qui voter
Parce que votre vote aura d’autant plus de poids que le taux
d’abstention est annoncé fort ! Si 20% de la population seulement vote,
le vôtre en vaut 5 fois plus.
Personnellement, je pense voter à gauche indépendamment de mes opinions
politiques habituelles parce que c’est le seul parti à posséder une
section dédiée à l’informatique (TemPS réels) et à lutter contre les
brevets.
Rappel pour ceux qui ont oublié : Chirac était contre les brevets et le
gouvernement a voté pour…
DEMAIN, VOTEZ ET VOTEZ BIEN
Wed, Jun 9, 2004
Mise à jour 2009 : Aujourd’hui, préférez simplement l’utilisation de
la classe StringBuilder à la place de StringBuffer. Le reste de
l’article reste valable.
Voici donc le premier billet traitant de programmation, je pense que ce
n’est que le premier d’une longue série. J’espère aussi que ça sera le
petit coup de pouce qui manque à Syl pour savoir sur quoi blogguer plus
souvent :-).
Aujourd’hui on va faire du Java.
Exemple de code qu’il est MAL®
Vous le savez certainement ou vous l’avez au moins entendu dire : la
classe String est non mutable. Qu’est-ce que ça signifie ? Ça veut
dire qu’une fois instanciée vous ne pouvez plus la modifier… Vous
pouvez vérifier, il n’existe aucun mutateur (setter) pour cette
classe.
Exemple : écrivons une méthode qui ajoute à hello les chiffres 1 à 9.
public static String sayBadHello(){ String bonjour = "bonjour"; for(int i=1;i<10;++i) { bonjour += i; } return bonjour;}
Ici, qu’est-ce qui se passe ? On instancie un objet String et on y met
“bonjour”. Ensuite, on fait quoi ? Ben, à chaque boucle, on prend la
variable bonjour, on lui concatène le chiffre en cours et on affecte le
résultat à bonjour.
En faisant ça : on instancie une nouvelle String à chaque fois et
l’ancienne String est garbagée (comme l’utilisateur-développeur ne
possède alors plus aucune référence vers cette variable, la machine
virtuelle sait qu’elle peut supprimer cet ancien objet dès qu’elle le
voudra).
Vous voyez le problème maintenant ? Pour une boucle de n éléments, on va
instancier n objets ! Si vous passez votre temps à appeler cette
méthode, vous déclencherez autant de fois cette aberration.
StringBuffer
Pour éviter ces nombreuses instanciations inutiles, il existe la classe
StringBuffer qui, elle, est mutable. J’ose espérer que vous les
utilisez déjà et que pour les étudiants d’entre vous, vos profs ont
pensé à insister dessus. S’ils ne connaissent pas, ben je m’inquiéterai
pour votre formation. Si vous ne connaissiez pas, à partir de maintenant
vous n’aurez plus d’excuse :-).
Utilisation des méthodes append
Ces méthodes permettent d’ajouter un grand nombre de types différents à
la chaîne stockée sous forme de caractères.
Voici un exemple simple d’utilisation pour corriger l’exemple précédent
:
public static String sayGoodHello(){ StringBuffer bonjour = new StringBuffer(20); bonjour.append("bonjour"); for(int i=1;i<10;++i) { bonjour.append(i); } return bonjour.toString();}
Plus de finesse
Quelques petits compléments pour les plus affamés :-).
-
Les plus attentifs auront remarqué le ++i là où on rencontre le
plus souvent un i++. Ce n’est pas anodin, c’est juste un léger
gain en terme de performances mais tellement simple à obtenir que je
ne vois pas pourquoi je m’en priverais. À l’origine, je tiens ce
conseil d’Anubis qui m’a fait réaliser que
dans l’un des cas, on a besoin d’une variable temporaire
supplémentaire et non dans l’autre.
Grossièrement, c’est dû à ça (ces deux déclarations sont environ
celles du C++, d’après les quelques souvenirs qu’il m’en reste. Avec
ma chance, d’ailleurs, c’est sûrement l’inverse puisque je les
remets au pif. Pas grave, l’objectif n’est pas de faire du C++ mais
de faire saisir la différence entre la pré et la
post-incrémentation) :
Post-incrémentation : i++
int operator++() { int sauvegarde = i; this.i = this.i +1; return sauvegarde;}
Pré-incrémentation : ++i
int operator++(int) { this.i = this.i +1; return this.i;}
-
Si vous utilisez un StringBuffer avec plusieurs append statiques
qui se suivent (merci Linux Magazine) :
buffer.append("bonjour");buffer.append("au revoir");
Utilisez plutôt :
buffer.append("bonjour") .append("au revoir");
Vous éviterez ainsi d’empiler inutilement le retour de la méthode
append sans vous en servir.
Tue, Jun 8, 2004
On vient de célébrer l’anniversaire du débarquement, je reste donc dans
le sujet en vous donnant un lien sur site qui parle des canons les plus
effrayants qui existent comme le canon de
Paris ou la Grosse
Bertha.
Donc si ça vous intéresse, allez donc faire un tour sur le site des
canons de l’apocalypse.