<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Blog Xebia France &#187; développement</title>
	<atom:link href="http://blog.xebia.fr/tag/developpement/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.xebia.fr</link>
	<description>J2EE, Agilité et SOA</description>
	<lastBuildDate>Thu, 09 Sep 2010 07:48:35 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>NoThunes, naissance d&#8217;un projet Grails</title>
		<link>http://blog.xebia.fr/2010/09/09/nothunes-naissance-dun-projet-grails/</link>
		<comments>http://blog.xebia.fr/2010/09/09/nothunes-naissance-dun-projet-grails/#comments</comments>
		<pubDate>Thu, 09 Sep 2010 06:19:24 +0000</pubDate>
		<dc:creator>Aurélien Maury</dc:creator>
				<category><![CDATA[Divers]]></category>
		<category><![CDATA[développement]]></category>
		<category><![CDATA[Grails]]></category>
		<category><![CDATA[Groovy]]></category>

		<guid isPermaLink="false">http://blog.xebia.fr/?p=5333</guid>
		<description><![CDATA[
table.tablo { border-collapse:collapse; border: 1px solid #6C626C; width:80%; font: normal normal normal 1.1em/normal Arial, sans-serif; } table.tablo thead { background: #EFEFEF; border-bottom: 1px solid #6C626C; border-top: 1px solid #6C626C; color: #4F2F4F; } table.tablo thead th { padding: 5px; } table.tablo tbody tr { border: 1px solid #6C626C; } table.tablo tbody tr td { padding: 5px; [...]]]></description>
			<content:encoded><![CDATA[<style type="text/css">
table.tablo { border-collapse:collapse; border: 1px solid #6C626C; width:80%; font: normal normal normal 1.1em/normal Arial, sans-serif; } table.tablo thead { background: #EFEFEF; border-bottom: 1px solid #6C626C; border-top: 1px solid #6C626C; color: #4F2F4F; } table.tablo thead th { padding: 5px; } table.tablo tbody tr { border: 1px solid #6C626C; } table.tablo tbody tr td { padding: 5px; }</style>
<p><img style="margin: 1em 1em 1em 1em; float: right;" src="http://blog.xebia.fr/wp-content/uploads/2010/09/nothunes_mini_logo.png" alt="Projet NoThunes" /></p>
<p>Les exemples de prise en main du framework Grails ne manquent pas sur la toile. Nous allons tenter de dépasser les <em>Getting started</em> en déroulant la réalisation d'une application web de bout en bout :</p>
<ul>
<li>Conception</li>
<li>Réalisation</li>
<li>Mise en production</li>
<li>Evolutions et maintenance</li>
</ul>
<p>Parce qu'il est toujours plus agréable de travailler sur du concret, nous allons réaliser pas à pas une plateforme de musique libre en ligne, que nous baptisons : <strong>Projet NoThunes</strong>, en clin d'oeil à une autre célèbre plateforme de musique payante. Tout le code du projet est <a title="disponible sur GitHub" href="http://github.com/aurelienmaury/nothunes">disponible sur GitHub</a>.  Ce projet est donc Open Source mais aussi "Open méthode" puisque je vous ferai partager toutes les étapes de conception/réalisation au travers d'une série d'article. Chaque article sera associé à un tag du dépôt GitHub, pour que tout le monde puisse savoir à quelle version on se réfère.</p>
<p>Bien évidemment il y a plus d'une bonne façon de faire. Ce projet est mené dans une optique d'amélioration personnelle et de partage donc n'hésitez pas à discuter les choix techniques et à fournir des solutions alternatives en commentaire.</p>
<p>Dans ce premier billet, nous allons :</p>
<ul>
<li>définir le product backlog du projet</li>
<li>présenter les classes du modèle</li>
<li>démarrer notre projet</li>
<li>mettre en place la sécurité et les classes du modèle</li>
<li>créer un menu dynamique, différencié par rôle utilisateur</li>
</ul>
<h3><a name="NoteTechnique"></a>Note technique</h3>
<p>Le projet est réalisé avec <a title="Grails v133" href="http://grails.org/dist/grails-1.3.3.zip">Grails v1.3.3</a>.</p>
<h3><a name="ProductBacklog"></a>Product Backlog</h3>
<p>On distingue 3 rôles utilisateurs :</p>
<ul>
<li><strong>les administrateurs :</strong> par définition omnipotents sur le site pour gérer les comptes utilisateurs, les règles de sécurité, etc.</li>
<li><strong>les internautes :</strong> les visiteurs lambda de notre site.</li>
<li><strong>les membres :</strong> des internautes qui se seront enregistrés pour accéder à plus de fonctionnalités.</li>
</ul>
<p>En sachant qu'un membre, s'il est authentifié, doit conserver l'accès à toutes les fonctionnalités des internautes, et qu'un administrateur doit aussi avoir accès aux fonctionnalités des membres.</p>
<p>Le product backlog est trié par business value décroissante. Je vous épargne le chiffrage agile et les fioritures de Scrum. <img src='http://blog.xebia.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<div>
<table class="tablo" border="0">
<thead>
<th>En tant que ...</th>
<th>je dois pouvoir ...</th>
</thead>
<tbody>
<tr>
<td>administrateur</td>
<td>créer des comptes utilisateurs (administrateurs et membres)</td>
</tr>
<tr>
<td>internaute</td>
<td>m'enregistrer pour obtenir un compte membre</td>
</tr>
<tr>
<td>membre</td>
<td>voir et mettre à jour mon profil utilisateur</td>
</tr>
<tr>
<td>membre</td>
<td>créer des groupes de musique</td>
</tr>
<tr>
<td>membre</td>
<td>modifier/supprimer les groupes de musique que j'ai créé</td>
</tr>
<tr>
<td>membre</td>
<td>créer/modifier/supprimer des albums liés à mes groupes</td>
</tr>
<tr>
<td>membre</td>
<td>créer/modifier/supprimer des morceaux liés à mes albums, en uploadant un fichier mp3</td>
</tr>
<tr>
<td>internaute</td>
<td>naviguer dans la hiérarchie de groupes/albums/morceaux</td>
</tr>
<tr>
<td>internaute</td>
<td>télécharger un morceau</td>
</tr>
<tr>
<td>internaute</td>
<td>écouter un morceau</td>
</tr>
<tr>
<td>internaute</td>
<td>rechercher des morceaux par mots-clés</td>
</tr>
</tbody>
</table>
</div>
<h3><a name="Prsentationdumodlededonnes"></a>Présentation du modèle de données</h3>
<p>Il s'agit d'un cas d'école donc nous simplifions à l'extrême le modèle de données à gérer. Le but n'est pas (encore <img src='http://blog.xebia.fr/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  ) de concurrencer les plateformes en place. On considère donc les objets :</p>
<div>
<table class="tablo" border="0">
<thead>
<th>Entité</th>
<th>représente ...</th>
</thead>
<tbody>
<tr>
<td>Role</td>
<td>les rôles utilisateurs</td>
</tr>
<tr>
<td>User</td>
<td>les comptes utilisateurs administrateurs et membres</td>
</tr>
<tr>
<td>Band</td>
<td>un groupe de musique, créé par un membre</td>
</tr>
<tr>
<td>Album</td>
<td>un album enregistré par un groupe</td>
</tr>
<tr>
<td>Track</td>
<td>un morceau, une piste d'un Album</td>
</tr>
</tbody>
</table>
</div>
<p>Les attributs de chacun de ces objets sont volontairement simplistes. Cela nous donne le modèle suivant :</p>
<div><img title="NoThunes" src="http://blog.xebia.fr/wp-content/uploads/2010/09/NoThunes.png" alt="NoThunes" /></div>
<h3><a name="Dmarrageduprojet"></a>Démarrage du projet</h3>
<p>Comme tous ceux qui ont déjà survolé Grails le savent, un nouveau projet démarre toujours par le lancement de la commande :</p>
<div class="syntax_hilite">
<div id="java-7">
<div class="java">grails create-app nothunes</div>
</div>
</div>
<p></p>
<p>qui va générer l'arborescence initiale du projet. Comme c'est toujours plus confortable, l'étape suivante sera d'importer ce projet dans votre IDE favori. Pour travailler avec Grails le choix est limité et le support inégal : <a title="NetBeans" href="http://www.netbeans.org/">NetBeans</a>, <a title="SpringSource Tool Suite" href="http://www.springsource.com/products/sts">SpringSource Tool Suite</a> ou <a title="IntelliJ IDEA" href="http://www.jetbrains.com/idea/">IntelliJ IDEA</a>. Au pire un <a title="bon vieux vim" href="http://www.vim.org/scripts/script.php?script_id=3120">bon vieux vim</a> suffira.</p>
<h4><a name="Miseenplacedelascurit"></a>Mise en place de la sécurité</h4>
<p>Le plugin de sécurité officiel du projet Grails est depuis peu le <a title="Spring Security Core Plugin" href="http://grails.org/plugin/spring-security-core">Spring Security Core Plugin</a>, couplé au plugin <a title="Spring Security UI" href="http://grails.org/plugin/spring-security-ui">Spring Security UI</a> pour la génération des écrans de CRUD concernant les rôles et utilisateurs. Malgré cela, je lui préfère encore pour quelques temps son prédécesseur : <a title="Acegi Plugin" href="http://www.grails.org/plugin/acegi">Acegi Plugin</a>, dont le développement a été stoppé, mais qui est plus complet et plus simple à mettre en place. D'autre part, le côté stable du plugin Acegi, comparé au développement hyperactif des plugins Spring Security est assez confortable pour notre projet.</p>
<p>Je vous renvoie donc au <a title="prcdent article" href="http://blog.xebia.fr/2010/02/25/grails-spring-security-plugin-la-securite-facile/">précédent article</a> que j'ai écrit sur le sujet. Le package de base à utiliser est : <code>fr.xebia.nothunes</code>.</p>
<h4><a name="Crationdesclassesdumodle"></a>Création des classes du modèle</h4>
<p>Maintenant que nous avons les classes utiles pour la gestion des utilisateurs et de la sécurité, ajoutons un peu de métier dans tout ça. Pour cela on utilise la commande <a title="grails createdomainclass" href="http://www.grails.org/GORM+-+Creating+a+domain+class"><code>grails create-domain-class</code></a> pour chacune des entités qu'on souhaite obtenir, puis on passe en édition dessus pour ajouter les attributs. Je trouve dommage de n'avoir pas plus poussé la ressemblance avec Ruby on Rails en autorisant l'ajout des attributs directement en paramètre de la ligne de commande.</p>
<p>Parmi les attributs que l'on donne à chaque classe, il y en a 2 qui sont partout et bien utiles : <code>lastUpdated</code> et <code>dateCreated</code>. Ces 2 attributs indiquent à GORM qu'il faut gérer le <a title="timestamping automatique" href="http://www.grails.org/GORM+-+Events">timestamping automatique</a> des objets qui les possèdent.</p>
<h3><a name="Dynamisonslemenu"></a>Dynamisons le menu</h3>
<p>La documentation du plugin Acegi n'en parle pas mais si vous téléchargez les sources du plugin et que vous allez voir le fichier <code>grails-app/taglib/org/grails/plugins/springsecurity/taglib/AuthorizeTagLib.groovy</code> vous tombez alors sur une taglib tout à fait disponible dès que vous faites usage de ce plugin dans votre projet, et qui offre les tags suivants :</p>
<ul>
<li>ifAllGranted</li>
<li>ifNotGranted</li>
<li>ifAnyGranted</li>
<li>loggedInUserInfo</li>
<li>isLoggedIn</li>
<li>isNotLoggedIn</li>
<li>loggedInUsername</li>
</ul>
<p>Nous allons baser la différenciation des menus sur ces tags qui permettent de tester, directement dans les GSP si l'utilisateur courant possède un rôle donné ou non.</p>
<p>La première étape est de séparer le contenu du menu dans un fichier GSP à part. Pour l'instant notre application est telle que générée par grails. Dans le fichier <code>grails-app/views/index.gsp</code> se trouve la page d'accueil par défaut. Elle contient une balise <code>&lt;div id="nav"/&gt;</code> qui encapsule le menu de gauche de la page d'accueil de l'application.</p>
<p>Pour ajouter plus de flexibilité, on sort cette div dans un nouveau fichier qu'on va placer dans <strong><code>grails-app/views/menu/_nav.gsp</code></strong> (après avoir créé le répertoire menu bien sûr), puis on remplace dans index.gsp la présence de cette div par un tag</p>
<div class="syntax_hilite">
<div id="java-8">
<div class="java">&lt;g:render template=<span style="color: #ff0000;">"menu/nav"</span>/&gt;</div>
</div>
</div>
<p></p>
<p>Si vous lancez un <code>grails run-app</code> et que vous allez voir la page d'accueil vous remarquerez que rien n'a changé. Le paramètre passé au tag <code>render</code> indique d'inclure le code du fichier GSP situé dans le répertoire <strong>menu/</strong> et nommé <code>_nav.gsp</code> (le caractère est indispensable en début de nom).</p>
<p>Ce découpage, allié aux tags du plugin Acegi, nous conduit à un joli découpage propre :</p>
<p><code><strong>grails-app/views/menu/_nav.gsp</strong></code></p>
<div class="syntax_hilite">
<div id="java-9">
<div class="java">&lt;div id=<span style="color: #ff0000;">"nav"</span>&gt;<br />
&lt;ul&gt;<br />
&nbsp; &nbsp; &lt;li&gt;Welcome,&lt;/li&gt;<br />
&nbsp; &nbsp; &lt;li&gt;Logout&lt;/li&gt;<br />
&nbsp; &nbsp; &lt;li&gt;Login&lt;/li&gt;<br />
&nbsp; &nbsp; &lt;li&gt;No account ? : Register&lt;/li&gt;<br />
&lt;/ul&gt;<br />
&lt;div <span style="color: #000000; font-weight: bold;">class</span>=<span style="color: #ff0000;">"homePagePanel"</span>&gt;<br />
&lt;div <span style="color: #000000; font-weight: bold;">class</span>=<span style="color: #ff0000;">"panelBody"</span>&gt;&lt;/div&gt;<br />
&lt;/div&gt;<br />
&lt;/div&gt;</div>
</div>
</div>
<p></p>
<p><code><strong>grails-app/views/menu/_admin.gsp</strong></code></p>
<div class="syntax_hilite">
<div id="java-10">
<div class="java">&lt;h1&gt;Admin manages ...&lt;/h1&gt;<br />
&lt;ul&gt;<br />
&nbsp; &nbsp; &lt;li&gt;roles&lt;/li&gt;<br />
&nbsp; &nbsp; &lt;li&gt;users&lt;/li&gt;<br />
&nbsp; &nbsp; &lt;li&gt;requestMaps&lt;/li&gt;<br />
&lt;/ul&gt;</div>
</div>
</div>
<p></p>
<p><code><strong>grails-app/views/menu/_user.gsp</strong></code></p>
<div class="syntax_hilite">
<div id="java-11">
<div class="java">&lt;h1&gt;Member manages ...&lt;/h1&gt;<br />
&lt;ul&gt;<br />
&nbsp; &nbsp; &lt;li&gt;...&lt;/li&gt;<br />
&lt;/ul&gt;</div>
</div>
</div>
<p></p>
<p><code><strong>grails-app/views/menu/_all.gsp</strong></code></p>
<div class="syntax_hilite">
<div id="java-12">
<div class="java">&lt;h1&gt;Menu&lt;/h1&gt;<br />
&lt;ul&gt;<br />
&nbsp; &nbsp; &lt;li&gt;&lt;a href=<span style="color: #ff0000;">"${createLinkTo(dir:'')}"</span>&gt;Home&lt;/a&gt;&lt;/li&gt;<br />
&lt;/ul&gt;</div>
</div>
</div>
<p></p>
<p>Maintenant il suffira d'utiliser le tag <code>&lt;g:render template="menu/nav" /&gt;</code> directement dans le layout global pour appliquer le menu sur toute notre application, et on a maintenant un fichier GSP par section de menu avec juste ce qu'il faut de tag de sécurité pour gérer l'affichage contextuel.</p>
<p>Après ce découpage, j'ai travaillé un peu le layout et la css afin d'avoir toutes les pages aux couleurs du projet, c'est toujours plus agréable pour travailler. Pour éviter de surcharger cet article, si vous voulez voir le détail complet du travail de mise en forme, reportez vous au <a title="GitHub du projet" href="http://github.com/aurelienmaury/nothunes">GitHub du projet</a>.</p>
<h3><a name="Debriefing"></a>Debriefing</h3>
<p>Voilà un bon démarrage pour notre plateforme de musique. Le projet est lancé et nous pouvons travailler dans de bonnes conditions pour la suite. L'état du product backlog :</p>
<div>
<table class="tablo" border="0">
<thead>
<th>En tant que ...</th>
<th>je peux déjà ...</th>
</thead>
<tbody>
<tr>
<td>administrateur</td>
<td>créer des comptes utilisateurs (administrateurs et membres)</td>
</tr>
<tr>
<td>internaute</td>
<td>m'enregistrer pour obtenir un compte membre</td>
</tr>
</tbody>
</table>
</div>
<p>Notre projet est déjà livrable en production avec ces fonctionnalités.</p>
<div><img src="http://blog.xebia.fr/wp-content/uploads/2010/09/home_page.png" border="0" alt="" width="600px" /></div>
<p>A bientôt pour le prochain épisode :</p>
<div>
<table class="tablo" border="0">
<thead>
<th>En tant que ...</th>
<th>je pourrai ...</th>
</thead>
<tbody>
<tr>
<td>membre</td>
<td>voir et mettre à jour mon profil utilisateur</td>
</tr>
<tr>
<td>membre</td>
<td>créer des groupes de musique</td>
</tr>
<tr>
<td>membre</td>
<td>modifier/supprimer les groupes de musique que j'ai créé</td>
</tr>
<tr>
<td>membre</td>
<td>créer/modifier/supprimer des albums liés à mes groupes</td>
</tr>
</tbody>
</table>
</div>
<h3><a name="Ressources"></a>Ressources</h3>
<ul>
<li><a title="Site officiel de Grails" href="http://www.grails.org/">Site officiel de Grails</a></li>
<li><a title="Dpt GitHub du projet NoThunes" href="http://github.com/aurelienmaury/nothunes">Dépôt GitHub du projet NoThunes</a></li>
<li><a title="Tag de la version dcrite dans ce billet" href="http://github.com/aurelienmaury/nothunes/tree/v0.1">Tag de la version décrite dans ce billet</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.xebia.fr/2010/09/09/nothunes-naissance-dun-projet-grails/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Refactorisation de bases de données avec Liquibase</title>
		<link>http://blog.xebia.fr/2008/12/03/refactorisation-de-bases-de-donnees-avec-liquibase/</link>
		<comments>http://blog.xebia.fr/2008/12/03/refactorisation-de-bases-de-donnees-avec-liquibase/#comments</comments>
		<pubDate>Wed, 03 Dec 2008 15:55:59 +0000</pubDate>
		<dc:creator>Emmanuel Servent</dc:creator>
				<category><![CDATA[Divers]]></category>
		<category><![CDATA[Exploitation]]></category>
		<category><![CDATA[Méthodes agiles]]></category>
		<category><![CDATA[bases de données]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[développement]]></category>
		<category><![CDATA[liquibase]]></category>
		<category><![CDATA[refactoring]]></category>
		<category><![CDATA[refactorisation]]></category>

		<guid isPermaLink="false">http://blog.xebia.fr/?p=1102</guid>
		<description><![CDATA[Gérer les modifications d'une base de données est toujours une affaire délicate, que ce soit lors du développement d'une application, pendant le déroulement des tests unitaires et même lors du déploiement en production.
On observe un grand nombre de difficultés, en particulier dans les projets Agile, où les changements sur le modèle de données sont fréquents.
A [...]]]></description>
			<content:encoded><![CDATA[<p>Gérer les modifications d'une base de données est toujours une affaire délicate, que ce soit lors du développement d'une application, pendant le déroulement des tests unitaires et même lors du déploiement en production.<br />
On observe un grand nombre de difficultés, en particulier dans les projets Agile, où les changements sur le modèle de données sont fréquents.<br />
A l'heure actuelle, peu d'outils sont disponibles sur le marché et on pense rarement à les mettre en place sur nos projets. On passe par des solutions « maisons » avec toutes les difficultés que cela peut engendrer.</p>
<p>Tout d'abord, nous ferons un point sur <a href="http://blog.xebia.fr/2008/12/03/refactorisation-de-bases-de-donnees-avec-liquibase#Problmespossparlagestiondesbas" title="les problèmes posés par la gestion des bases de données" >les problèmes posés par la gestion des bases de données</a>, puis nous verrons comment <a href="http://blog.xebia.fr/2008/12/03/refactorisation-de-bases-de-donnees-avec-liquibase#Refactorisationdebasesdedonnes" title="Liquibase, outils de refactorisation" >Liquibase, outils de refactorisation</a>, peut nous aider à les surmonter.<br />
Nous continuerons par la description de <a href="http://blog.xebia.fr/2008/12/03/refactorisation-de-bases-de-donnees-avec-liquibase#Caractristiquesetfonctionnalit" title="ses caractéristiques et fonctionnalités principales" >ses caractéristiques et fonctionnalités principales</a> et par <a href="http://blog.xebia.fr/2008/12/03/refactorisation-de-bases-de-donnees-avec-liquibase#LancementdeLiquibase" title="les différents moyens de l'exécuter" >les différents moyens de l'exécuter</a>.<br />
<a href="http://blog.xebia.fr/2008/12/03/refactorisation-de-bases-de-donnees-avec-liquibase#Petitexercicepoursefamiliarise" title="Un petit exercice" >Un petit exercice</a> pour se familiariser avec cet outil viendra conclure ce billet.</p>
<h3><a name="Problmespossparlagestiondesbas"></a>Problèmes posés par la gestion des bases de données</h3>
<p>Lorsqu'un projet démarre, on se demande souvent si l'on doit installer <strong>une base de données par développeur ou une base commune pour tous</strong>.<br />
Sur des projets de taille réduite, une base peut suffire et une personne est désignée pour centraliser les changements et éviter ainsi des problèmes de redondance, d'incohérence, etc. Mais dans ce cas-là, dès qu'un changement est effectué, tout le monde doit impérativement mettre à jour le modèle objet sinon il court le risque de ne plus pouvoir lancer l'application. Par ailleurs, les jeux de tests de chaque développeur peuvent "se télescoper" ce qui peut faire perdre beaucoup de temps.<br />
Sur des projets plus importants, il est préférable d'avoir une base par développeur, ce qui cause d'autres difficultés, telles que les répercutions des changements d'un développeur à l'autre ou encore une intégration plus laborieuse.<br />
Se pose aussi la question suivante : <strong>comment va-t-on tracer les changements successifs ?</strong> Le plus courant reste d'écrire un fichier d'update SQL mais ce n'est pas fait systématiquement pendant les développements et ça manque de structure (au sens XML) et ça pas de signification propre. Par exemple, rien ne permet rapidement de différencier dans un script, le code qui applique les changements de celui qui les rollback (à part les commentaires !); ou les actions comme "Renommer" se traduisent par un DROP COLUMN / ADD COLUMN, ce qui fait perdre le sens de l'action.<br />
Cette dernière question amène à s'en poser d'autres :</p>
<ul>
<li>comment versionner les changements effectués sur une base de données ?</li>
<li>comment appliquer les changements ? Entre développeurs, mais aussi lorsqu'on passe en intégration, puis en recette, etc. Pour le moment, cette étape prend du temps, que ce soit en amont si on décide de packager correctement les changements, ou en aval lorsqu'il s'agit de dérouler les scripts.</li>
</ul>
<p>Voilà en quelques phrases les multiples difficultés rencontrées lorsqu'on souhaite refactoriser une base de données.<br />
Regardons à présent ce qu'un outil comme Liquibase peut faire pour nous accompagner dans ce travail délicat.</p>
<h3><a name="Refactorisationdebasesdedonnes"></a>Refactorisation de bases de données avec Liquibase</h3>
<p>Liquibase est un outil qui peut s'intégrer dans un projet (Ant, Maven, etc.) ou se lancer <em>en mode standalone</em> directement en ligne de commande (jar).<br />
Son objectif est de faciliter les modifications apportées à une base de données. Il est particulièrement pratique dans des projets ayant adoptés une méthodologie Agile, car les changements sont nombreux, fréquents et importants.<br />
Le développeur enregistre dans un fichier XML (changelogs.xml), les différentes refactorisations qu'il souhaite effectuer (création d'une nouvelle table, renommage d'un champ, insertion de données, etc.). Ensuite, il suffit de lancer Liquibase en lui donnant les paramètres de connexion à la base de données et le fichier changelogs.xml. Liquibase applique ces modifications et les trace dans une table.<br />
Les fichiers changelogs.xml sont versionnés dans le gestionnaire de sources, et sont considérés comme n'importe quelle autre ressource du projet. La base de données est alors complètement intégrée au cycle de développement.</p>
<p>Après cette brève présentation de Liquibase, intéressons-nous aux caractéristiques principales de cet outil.</p>
<h3><a name="Caractristiquesetfonctionnalit"></a>Caractéristiques et fonctionnalités principales</h3>
<p>Liquibase est Open Source diffusé sous licence LGPL. Ce projet Open Source est actif, la dernière version (1.8.1) est sortie en octobre 2008 et sa road map montre qu'il veut aller encore plus loin. Il supporte un grand nombre de bases de données (> 10) et propose plus de 30 refactorisations possibles. Et pour certaines, il sait même faire un roll back (Ex: renommer une colonne).<br />
Les changements peuvent être regroupés dans un changeset, ce qui permet de conserver un sens et une cohérence aux modifications.<br />
On peut également n'exécuter des changements que sous certaines conditions, ou selon un certain profil d'exécution (utile pour les jeux de tests par exemple).</p>
<p>On peut noter également que Liquibase n'est pas juste "braqué" vers la refactorisation de la base de données, il offre d'autres fonctionnalit</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.xebia.fr/2008/12/03/refactorisation-de-bases-de-donnees-avec-liquibase/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Ce que vous avez peut-être raté au troisième trimestre 2008</title>
		<link>http://blog.xebia.fr/2008/10/01/ce-que-vous-avez-peut-etre-rate-au-troisieme-trimestre-2008/</link>
		<comments>http://blog.xebia.fr/2008/10/01/ce-que-vous-avez-peut-etre-rate-au-troisieme-trimestre-2008/#comments</comments>
		<pubDate>Wed, 01 Oct 2008 06:51:57 +0000</pubDate>
		<dc:creator>Xebia France</dc:creator>
				<category><![CDATA[Divers]]></category>
		<category><![CDATA[annotation]]></category>
		<category><![CDATA[développement]]></category>
		<category><![CDATA[Exploitation]]></category>
		<category><![CDATA[Java / JEE]]></category>
		<category><![CDATA[log]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[Supervision]]></category>

		<guid isPermaLink="false">http://blog.xebia.fr/?p=773</guid>
		<description><![CDATA[Voici la liste des billets les plus lus sur ce blog en juillet, août et septembre :
Les 10 commandements des logs applicatives
Tout au long du cycle de vie d'une application J2EE, il est nécessaire de posséder des traces de qualité :

durant le développement, afin de suivre l'exécution pas à pas et de détecter d'éventuelles anomalies.
durant [...]]]></description>
			<content:encoded><![CDATA[<p>Voici la liste des billets les plus lus sur ce blog en juillet, août et septembre :</p>
<h4><a href="http://blog.xebia.fr/2008/07/11/les-10-commandements-des-logs-applicatives/">Les 10 commandements des logs applicatives</a></h4>
<p>Tout au long du cycle de vie d'une application J2EE, il est nécessaire de posséder des traces de qualité :</p>
<ul>
<li>durant le développement, afin de suivre l'exécution pas à pas et de détecter d'éventuelles anomalies.</li>
<li>durant la recette, afin de corréler anomalies fonctionnelles et exécution du programme.</li>
<li>durant l'exploitation, afin de surveiller la "bonne santé" de l'application.</li>
</ul>
<p>Mais obtenir des traces de qualité n'est pas un exercice trivial. C'est pourquoi nous vous proposons nos 10 commandements des logs.</p>
<p><a href="http://blog.xebia.fr/2008/07/11/les-10-commandements-des-logs-applicatives/">Lire cet article »</a></p>
<h4><a href="http://blog.xebia.fr/2008/08/08/simplifiez-votre-configuration-spring-25-avec-les-annotations/">Simplifiez votre configuration Spring 2.5 avec les annotations</a></h4>
<p>Spring 2.5 <a href="http://www.springframework.org/node/561" title="est sorti" >est sorti</a> depuis le 19 novembre 2007 comme nous l'annoncions, il y a quelques temps, dans notre <a href="http://blog.xebia.fr/2007/11/26/revue-de-presse-xebia-33/#Spring" title="revue de presse" >revue de presse</a>. Vous avez comme moi sagement mis à jour vos poms Maven2 vers la dernière release de Spring (normalement et la plupart du temps compatible avec les versions 2.0.x).</p>
<p>Mais avez-vous vraiment profité des nouveautés de cette version en terme de configuration ?</p>
<p><a href="http://blog.xebia.fr/2008/08/08/simplifiez-votre-configuration-spring-25-avec-les-annotations/">Lire cet article »</a></p>
<h4><a href="http://blog.xebia.fr/2008/08/13/programmation-concurrentielle-notions-fondamentales/">Programmation concurrente : notions fondamentales</a></h4>
<p>Jouer avec les Threads n'est pas trivial. En informatique de gestion, cette difficulté est heureusement masquée par les serveurs d'application et les API spécifiques. La plupart du temps, ils permettent aux développeurs de s'abstraire de ces contraintes et de se concentrer sur le code métier, moins technique. Il arrive pourtant qu'il faille se relever les manches. Certains besoins vous ont certainement déjà poussé à faire communiquer 2 Threads.<br />
Si le développement n'est pas facile, le debug peut devenir une calamité ! La programmation concurrente ne soulève pourtant que 3 types majeurs de problèmes. Faites le sondage autour de vous, les développeurs associent trop rapidement le mot clé <code>synchronize</code> au multithreading sans en comprendre véritablement le fonctionnement. Demandez-leur ensuite de vous décrire l'utilité du mot clé <code>volatile</code> ...</p>
<p>Cet article revient sur les grands principes de la programmation concurrente.</p>
<p><a href="http://blog.xebia.fr/2008/08/13/programmation-concurrentielle-notions-fondamentales/">Lire cet article »</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.xebia.fr/2008/10/01/ce-que-vous-avez-peut-etre-rate-au-troisieme-trimestre-2008/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Les 10 commandements des logs applicatives</title>
		<link>http://blog.xebia.fr/2008/07/11/les-10-commandements-des-logs-applicatives/</link>
		<comments>http://blog.xebia.fr/2008/07/11/les-10-commandements-des-logs-applicatives/#comments</comments>
		<pubDate>Fri, 11 Jul 2008 08:34:40 +0000</pubDate>
		<dc:creator>Pablo Lopez</dc:creator>
				<category><![CDATA[Java / JEE]]></category>
		<category><![CDATA[développement]]></category>
		<category><![CDATA[Exploitation]]></category>
		<category><![CDATA[log]]></category>
		<category><![CDATA[Supervision]]></category>

		<guid isPermaLink="false">http://blog.xebia.fr/2008/07/11/les-10-commandements-des-logs-applicatives/</guid>
		<description><![CDATA[Tout au long du cycle de vie d'une application J2EE, il est nécessaire de posséder des traces de qualité :

durant le développement, afin de suivre l'exécution pas à pas et de détecter d'éventuelles anomalies.
durant la recette, afin de corréler anomalies fonctionnelles et exécution du programme.
durant l'exploitation, afin de surveiller la "bonne santé" de l'application.

Mais obtenir [...]]]></description>
			<content:encoded><![CDATA[<p>Tout au long du cycle de vie d'une application J2EE, il est nécessaire de posséder des traces de qualité :</p>
<ul>
<li>durant le développement, afin de suivre l'exécution pas à pas et de détecter d'éventuelles anomalies.</li>
<li>durant la recette, afin de corréler anomalies fonctionnelles et exécution du programme.</li>
<li>durant l'exploitation, afin de surveiller la "bonne santé" de l'application.</li>
</ul>
<p>Mais obtenir des traces de qualité n'est pas un exercice trivial. C'est pourquoi nous vous proposons nos 10 commandements des logs.</p>
<p>Une application J2EE possède de nombreux types de logs :</p>
<ul>
<li>Des logs purement techniques, ponctuelles, générées automatiquement ou à la demande comme les dumps (ThreadDump, MemoryDump...).</li>
<li>Des logs provenant de l'environnement d'exécution : logs Système (journaux d'évènements serveur...), logs du serveur applicatif et logs générées par les librairies tierces utilisées par l'application.</li>
<li>Les logs générées par le code développé pour l'application, que nous désignerons comme logs applicatives, sur lesquelles l'équipe projet a la main.</li>
</ul>
<p>Nous traiterons quasi exclusivement de ces dernières dans cet article.</p>
<h3><a title="Lescommandements" name="Lescommandements"></a>Les 10 commandements</h3>
<ol>
<li>Les logs sont un <strong>outil collaboratif</strong> issu d'un processus <strong>itératif</strong>.</li>
<li>Les logs sont une <strong>brique applicative intégrée</strong> à l'<strong>environnement d'exécution</strong> de l'application.</li>
<li>Les logs sont <strong>paramétrées</strong> en fonction des <strong>besoins</strong>.</li>
<li>Les logs doivent avoir un <strong>impact minimal sur les performances</strong> globales de l'application.</li>
<li>Les logs ne doivent pas occasionner de <strong>perte d'information</strong>.</li>
<li>Une utilisation correcte du logger est la première source d'information.</li>
<li>L'<strong>utilisation</strong> du framework de logs doit être <strong>simplifiée</strong>.</li>
<li>Une log efficace doit <strong>remplacer le debugger</strong>.</li>
<li>Le framework mis en place doit servir <strong>exclusivement</strong> à produire des <strong>logs applicatives</strong>.</li>
<li>Les logs permettent de décrire le <strong>comportement aux frontières</strong> de l'application.</li>
</ol>
<h3><a title="Entronsdansledtail" name="Entronsdansledtail"></a>Entrons dans le détail</h3>
<h4>1 - Les logs sont un outil collaboratif issu d'un processus itératif</h4>
<p>Les messages de logs sont destinés à tous les acteurs du projet.<br />
Il est essentiel de garder à l'esprit, lors de de tout développement, qu'une application est vouée à être développée, puis testée, puis exploitée (et éventuellement corrigée). Les logs doivent prendre en compte ces 3 phases de la vie du projet, et permettre à tous les acteurs intervenant lors de ces différentes phases de pouvoir interagir efficacement.<br />
C'est pourquoi chaque méthode devrait au minimum contenir des traces de niveau INFO, WARN et ERROR, chaque niveau ciblant un des acteurs intervenant sur l'application.<br />
De plus, il est difficile de réaliser une 'bonne' log du premier coup. La pertinence de celle-ci sera renforcée par des échanges constants entre exploitation et développement (ciblage spécifique d'un problème de performance, anomalie non remontée initialement...).<br />
Chaque correction d'anomalie devrait entrainer l'ajout de traces de niveau DEBUG, qui permettront un diagnostic plus fin en cas de nouvelle occurrence.</p>
<h4>2 - Les logs sont une brique applicative intégrée à l'environnement d'exécution de l'application</h4>
<p>C'est pourquoi il est essentiel de choisir un framework de logs bien intégré dans le middleware utilisé en production.<br />
Ce framework doit pouvoir être utilisé et paramétré aisément pour obtenir des traces de l'ensemble des composants du système, que ce soit de la part de librairies embarquées tierces comme des systèmes 'contenants' (serveur d'application par exemple).<br />
Par exemple, Jakarta Commons Logging est délicat à utiliser avec Websphere.</p>
<h4>3 - Les logs sont paramétrées en fonction des besoins</h4>
<p>L'écriture d'une log a un coût qu'il ne faut pas négliger. Les performances d'une application en production ne doivent pas être plombées par la génération de lignes de log inutiles. Et il est inenvisageable de demander à chaque développeur d'effacer systématiquement les logs qu'il ajoute (si ces logs ont été utiles à un moment de la vie du projet, il y a de grandes chances qu'elles puissent resservir plus tard).<br />
Il est donc impératif de choisir un framework de logs <strong>facilement administrable</strong> autant en développement qu'en production :</p>
<p><strong>Pour le développement :</strong></p>
<ul>
<li>Une configuration de logs par défaut quand on fait un checkout du code (typiquement un fichier log4j.properties dans le classpath configuré au niveau WARN qui redirige vers System.out).</li>
<li>La possibilité de modifier à chaud la configuration des logs lors de l'éxécution de l'application dans l'IDE (typiquement un configureAndWatch sur classpath:log4j.properties).</li>
</ul>
<p><strong>Pour l'exploitation :</strong></p>
<ul>
<li>Une configuration par fichiers, séparée du WAR, ce qui permet de livrer / modifier l'application indépendamment de sa configuration (et vice et versa).</li>
<li>Des mécanismes de reconfiguration à chaud par modification de fichier et/ou par API (JMX).</li>
</ul>
<p>On se doit d'exploiter au maximum les <strong>différents Appenders</strong>.<br />
Le système d'Appender fourni avec les principaux framework de log permet de gérer finement la persistence de la trace : elle peut être éphémère, par exemple dans une sortie Console, ou bien être archivée périodiquement, en utilisant un système de DailyRollingFileAppender.<br />
Une bonne connaissance des Appenders est essentielle dans la gestion à long terme de la log, aussi bien en terme de performance (utilisation des Loggers asynchrones en utilisant JMS) qu'en terme d'espace disque (configurer correctement les FileAppenders afin que les fichiers restent exploitables).</p>
<h4>4 - Les logs doivent avoir un impact minimal sur les performances globales de l'application</h4>
<p>La majorité des frameworks de log disposent de méthodes conditionnelles de type log.is&lt;Priority&gt;Enabled(). Conditionner l'écriture de la log par ces méthodes permet d'économiser des ressources précieuses lors du runtime (construction d'une aggrégation de chaînes de caractères par exemple). La méthode log.&lt;Priority&gt;(String) effectue bien entendu le même test, mais après la résolution des paramètres.</p>
<p>Evitez :</p>
<div class="syntax_hilite">
<div id="java-20">
<div class="java">log.<span style="color: #006600;">debug</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"Entrée dans la méthode doIt(), avec param1["</span> + param1 + <span style="color: #ff0000;">"], param2 ["</span> + param2 + <span style="color: #ff0000;">"]"</span><span style="color: #66cc66;">&#41;</span>;</div>
</div>
</div>
<p></p>
<p>Préférez :</p>
<div class="syntax_hilite">
<div id="java-21">
<div class="java"><span style="color: #b1b100;">if</span><span style="color: #66cc66;">&#40;</span>log.<span style="color: #006600;">isDebugEnabled</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp;log.<span style="color: #006600;">debug</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"Entrée dans la méthode doIt(), avec param1["</span> + param1 + <span style="color: #ff0000;">"], param2 ["</span> + param2 + <span style="color: #ff0000;">"]"</span><span style="color: #66cc66;">&#41;</span>;<br />
<span style="color: #66cc66;">&#125;</span></div>
</div>
</div>
<p></p>
<h4>5 - Les logs ne doivent pas occasionner de perte d'information</h4>
<p>Ce commandement s'applique plus particulièrement aux logs des exceptions.<br />
Il est primordial de qualifier le plus finement possible les exceptions tracées.<br />
C'est pourquoi on privilégiera systématiquement les méthodes Logger#error(java.lang.Object message, java.lang.Throwable t) à Logger#error(java.lang.Object message) , afin de ne pas perdre les informations exposées par la stackTrace.<br />
De plus, on explicitera au maximum le contexte d'exécution dans le message.</p>
<p>Evitez :</p>
<div class="syntax_hilite">
<div id="java-22">
<div class="java">...<br />
<span style="color: #66cc66;">&#125;</span> <span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #66cc66;">&#40;</span><a href="http://www.google.com/search?q=allinurl%3AUnknownUserException+java.sun.com&amp;bntl=1"><span style="color: #aaaadd; font-weight: bold;">UnknownUserException</span></a> exception<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp;log.<span style="color: #006600;">error</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"Une exception s'est produite :"</span> + exception<span style="color: #66cc66;">&#41;</span>;<br />
&nbsp; &nbsp;...<br />
<span style="color: #66cc66;">&#125;</span><br />
...</div>
</div>
</div>
<p></p>
<p>Préférez :</p>
<div class="syntax_hilite">
<div id="java-23">
<div class="java">...<br />
<span style="color: #000000; font-weight: bold;">catch</span> <span style="color: #66cc66;">&#40;</span><a href="http://www.google.com/search?q=allinurl%3AUnknownUserException+java.sun.com&amp;bntl=1"><span style="color: #aaaadd; font-weight: bold;">UnknownUserException</span></a> exception<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp;log.<span style="color: #006600;">error</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"L'utilisateur ["</span> + user :<span style="color: #ff0000;">"] n'a pas été trouvé dans l'annuaire ["</span>+ myLdap + <span style="color: #ff0000;">"]"</span>, exception<span style="color: #66cc66;">&#41;</span>;<br />
...<br />
<span style="color: #66cc66;">&#125;</span><br />
...</div>
</div>
</div>
<p>
<em>NB : le traitement des exceptions fera l'objet d'un prochain article.</em></p>
<h4>6 - Une utilisation correcte du logger est la première source d'information</h4>
<p>Chaque niveau de log a ses spécificités. Bien définir l'utilisation de chacun de ces niveaux permet de s'affranchir du risque de logger trop, ou trop peu, aux différentes étapes du cycle de vie de l'application. Utiliser des <strong>niveaux de log cohérents et pertinents</strong> donne donc un premier niveau d'information essentiel.<br />
Voici les niveaux existants dans les différents frameworks, et leur utilisation communément admise (Log4J/Apache Commons Logging - java.util.logging) :</p>
<ul>
<li>TRACE / FINE : niveau d'information ultrafin.</li>
<li>DEBUG / CONFIG : information détaillée pour le suivi d'exécution du programme (identification et résolution d'éventuelles anomalies).</li>
<li>INFO : information essentielle sur le programme, suivi de l'exécution d'un point de vue global.</li>
<li>WARN / WARNING : situation d'exécution non idéale (utilisation d'API dépréciées, ressource non critique absente...).</li>
<li>ERROR / &lt;pas d'équivalent&gt; : situation d'erreur ou inattendue, qui n'entraine pas forcément une situation de blocage (accès à un service externe non critique et dont l'accès est re-testé périodiquement).</li>
<li>FATAL / SEVERE : situation d'erreur critique, qui entraîne un blocage voire un arrêt du système (problème de connexion à la DB par exemple).</li>
</ul>
<h4>7 - L'utilisation du framework de logs doit être simplifiée</h4>
<p>L'ajout de log doit être le moins contraignant possible pour les développeurs. De plus, dans le cadre d'une équipe de développement, il n'est pas toujours facile pour un développeur de savoir quelles sont les informations pertinentes à tracer, s'il n'est pas l'auteur de la classe suivie. Il faut donc faciliter la création de logs de qualité...</p>
<ul>
<li> 	... en rendant ses <strong>classes explicites</strong>.<br />
En surchargeant la méthode Object#toString(), afin qu'elle renvoie les informations principales d'une classe, on peut facilement tracer les informations en entrée ou sortie de méthode, et expliciter le contexte applicatif de l'exécution. Attention, les méthodes toString() ne doivent jamais lancer d'exception.</li>
</ul>
<p>Evitez :</p>
<div class="syntax_hilite">
<div id="java-24">
<div class="java"><span style="color: #000000; font-weight: bold;">public</span> <a href="http://www.google.com/search?q=allinurl%3AString+java.sun.com&amp;bntl=1"><span style="color: #aaaadd; font-weight: bold;">String</span></a> toString<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp;StringBuilder sb = <span style="color: #000000; font-weight: bold;">new</span> StringBuilder<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;<br />
&nbsp; &nbsp;sb.<span style="color: #006600;">append</span><span style="color: #66cc66;">&#40;</span>getClass<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">getName</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><br />
&nbsp; &nbsp;<span style="color: #808080; font-style: italic;">// Ici, on peut avoir une NullPointerException</span><br />
&nbsp; &nbsp;sb.<span style="color: #006600;">append</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">" myfield=["</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">append</span><span style="color: #66cc66;">&#40;</span><span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006600;">myfield</span>.<span style="color: #006600;">toString</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">append</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"]"</span><span style="color: #66cc66;">&#41;</span>;<br />
&nbsp; &nbsp;<span style="color: #000000; font-weight: bold;">return</span> sb.<span style="color: #006600;">toString</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;<br />
<span style="color: #66cc66;">&#125;</span></div>
</div>
</div>
<p></p>
<p>Préférez :</p>
<div class="syntax_hilite">
<div id="java-25">
<div class="java"><span style="color: #000000; font-weight: bold;">public</span> <a href="http://www.google.com/search?q=allinurl%3AString+java.sun.com&amp;bntl=1"><span style="color: #aaaadd; font-weight: bold;">String</span></a> toString<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#123;</span><br />
&nbsp; &nbsp;<span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> ToStringBuilder<span style="color: #66cc66;">&#40;</span><span style="color: #000000; font-weight: bold;">this</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">append</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">"myfield"</span>, <span style="color: #000000; font-weight: bold;">this</span>.<span style="color: #006600;">myfield</span><span style="color: #66cc66;">&#41;</span>.<span style="color: #006600;">toString</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;<br />
<span style="color: #66cc66;">&#125;</span></div>
</div>
</div>
<p></p>
<ul>
<li> 	... en définissant, documentant et partageant la <strong>hiérarchie de logger</strong><br />
L'utilisation la plus répandue de la hiérarchie de Logger consitste à déclarer un logger par classe.</li>
</ul>
<div class="syntax_hilite">
<div id="java-26">
<div class="java"><span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #993333;">static</span> Logger LOGGER = Logger.<span style="color: #006600;">getLogger</span><span style="color: #66cc66;">&#40;</span>MyClass.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #66cc66;">&#41;</span>;</div>
</div>
</div>
<p>
Cependant, il est souvent interessant de réfléchir à une hiérarchie plus poussée, par domaines technico-fonctionnels par exemple.<br />
Il est parfois même utile de déclarer plusieurs Loggers par classe (un logger pour le suivi de l'exécution générale, un logger particulier pour surveiller une fonction critique)<br />
Afin d'avoir des logs cohérentes, il est nécessaire de définir et de documenter la hiérarchie des Loggers au plus tôt de la vie du projet, et de la communiquer à l'ensemble des équipes, afin d'unifier les méthodes de logging.</p>
<h4>8 - Une log efficace doit remplacer le debugger</h4>
<p>Il existe un grand nombre de circonstances qui rendent impossible l'utilisation d'un debugger, dont la plus évidente, la nécessité de debugger un système en production. Mais on pourrait aussi citer les traitements <span class="diffaddedchars">multi-threadés, etc</span><br />
Dans ces cas particuliers, l'utilisation de la log doit se substituer au débuggeur, et répondre aux mêmes besoins : "exécution" pas à pas <span class="diffaddedchars">des algorithmes</span>, inspection des valeurs d'entrée et de <span class="diffaddedchars">sortie des points de passage clefs</span>, parcours des différentes couches de l'application, surveillance des entrées / sorties du système.<br />
La mise à disposition d'un tel outil est vitale pour les développeurs, car trop souvent, les équipes de développements sont dans l'obligation d'attendre plusieurs occurrences d'un même bug en production avant d'être aptes à déterminer ses conditions précises d'occurrence.</p>
<h4>9 - Le framework mis en place doit servir exclusivement à produire des logs applicatives</h4>
<p>Les logs sont et doivent être un outil technique. Utiliser le framework de log pour générer des traces 'fonctionnelles' (audit, génération de traces métier, constitution de fichiers métier) présente un risque majeur de perte de données. En effet, le risque d'effacement des logs est réel : la configuration des différents Appenders provoquent souvent un effacement périodique des logs, le comportement global des logs peut être totalement modifié dans le cadre d'une intervention de type 'troubleshooting' (limitation des traces à un sous-ensemble de classes très restreint)...<br />
En revanche, il est possible d'utiliser les fonctionnalités offertes par le framework de logs (RollingFileAppender, etc) mais il faut que cette utilisation soit dissociée du fonctionnement et de la configuration des logs applicatives.</p>
<h4>10 - Les logs permettent de décrire le comportement aux frontières de l'application</h4>
<p>L'un des enjeux majeurs des Systèmes d'Information actuels est l'intégration des différentes composantes de ce SI.<br />
Il est très souvent ardu de suivre intégralement la chorégraphie entre les différents composants, aboutissant à la réponse 'finale' du système.<br />
D'où la nécessité de tracer le plus finement chaque appel entrant ou sortant du système, en utilisant :</p>
<ul>
<li>l'heure de cet appel</li>
<li>le système appelant / appelé (par HTTP, JMS, SOAP...)</li>
<li>une description concise de l'interaction sollicitée</li>
<li>éventuellement, au niveau le plus fin (TRACE), le message émis / reçu</li>
</ul>
<p>Certaines librairies Open Source, comme commons-http-client (HTTP) et CXF (SOAP) offrent ces fonctionnalités de manière native.</p>
<h3><a title="Enconclusion" name="Enconclusion"></a>En conclusion</h3>
<p>L'application de ces 10 commandements nous pousse de manière assez naturelle à l'utilisation de Log4J, qui répond à l'ensemble des besoins listés ci dessus.<br />
Le choix de Commons Logging ou de java.util.logging, si il est loin d'être proscrit, demande une plus grande vigilance (voir les articles 'Critiques' cités en références).</p>
<p>Quoi qu'il en soit, il est primordial d'avoir en tête ces bonnes pratiques dès le démarrage d'un projet. En effet, au même titre que les tests unitaires ou que la documentation interne du code, les logs ne peuvent être repoussées à 'plus tard' : plus le temps passe, plus la complexité et le volume de code à 'tracer' augmentent.<br />
Ceux qui ont expérimenté "l'intervention pompier" sur une application peu ou mal loggée savent qu'il est quasiment impossible d'otenir des logs globales et/ou pertinentes a posteriori (d'autant qu'il est difficile de 'budgeter' une telle opération, dont la valeur métier est nulle).</p>
<h3><a title="Rfrences" name="Rfrences"></a>Références</h3>
<h4>Les frameworks de logs les plus connus</h4>
<ul>
<li><em><a href="http://www.slf4j.org/" title="Simple Logging Facade for Java (SLF4J)">Simple Logging Facade for Java (SLF4J)</a> : A simple facade for various logging APIs allowing to the end-user to plug in the desired implementation at deployment time.</em></li>
<li><em><a href="http://logging.apache.org/log4j/" title="Log4J ">Log4J</a> : Site officiel du framework Log4J </em></li>
<li><em><a href="http://commons.apache.org/logging/" title="Java Commons Logging ">Java Commons Logging </a> : Site officiel du framework Commons Logging</em></li>
<li><em><a href="http://java.sun.com/j2se/1.4.2/docs/api/index.html" title="java.util.logging ">java.util.logging </a> : API de java.util.logging</em></li>
</ul>
<h4>Critiques</h4>
<ul>
<li><em><a href="http://radio.weblogs.com/0122027/2003/08/15.html" title="Rod Waldhoff's Weblog - Commons Logging was my fault ">Rod Waldhoff's Weblog - Commons Logging was my fault </a> : une critique de Commons Logging par son auteur</em></li>
<li><em><a href="http://tomcat.apache.org/tomcat-6.0-doc/logging.html" title="Tomcat Docs - Logging">Tomcat Docs - Logging</a> : The default implemenatation of java.util.logging provided in the JDK is too limited to be useful. ...</em></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.xebia.fr/2008/07/11/les-10-commandements-des-logs-applicatives/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Ce que vous avez peut-être raté au second trimestre 2008</title>
		<link>http://blog.xebia.fr/2008/07/01/ce-que-vous-avez-peut-etre-rate-au-second-trimestre-2008/</link>
		<comments>http://blog.xebia.fr/2008/07/01/ce-que-vous-avez-peut-etre-rate-au-second-trimestre-2008/#comments</comments>
		<pubDate>Tue, 01 Jul 2008 15:31:55 +0000</pubDate>
		<dc:creator>Xebia France</dc:creator>
				<category><![CDATA[Divers]]></category>
		<category><![CDATA[développement]]></category>
		<category><![CDATA[J2EE]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[Tests unitaires]]></category>
		<category><![CDATA[urbanisation]]></category>

		<guid isPermaLink="false">http://blog.xebia.fr/2008/07/01/ce-que-vous-avez-peut-etre-rate-au-second-trimestre-2008/</guid>
		<description><![CDATA[Voici la liste des billets les plus lus sur ce blog en avril, mai et juin :
Urbanisation pour les nuls
Le XKE (Xebia Knowledge Exchange) de mars a été l'occasion de présenter la démarche d'urbanisation. L'exemple présenté ne suivait pas le déroulement type : une démarche d'urbanisation est adaptée suivant les projets et organisations auxquels elle [...]]]></description>
			<content:encoded><![CDATA[<p>Voici la liste des billets les plus lus sur ce blog en avril, mai et juin :</p>
<h4><a href="http://blog.xebia.fr/2008/04/10/urbanisation-pour-les-nuls/">Urbanisation pour les nuls</a></h4>
<p>Le XKE (<a href="http://blog.xebia.fr/2008/03/03/un-xke-chez-xebia/">Xebia Knowledge Exchange</a>) de mars a été l'occasion de présenter la démarche d'urbanisation. L'exemple présenté ne suivait pas le déroulement type : une démarche d'urbanisation est adaptée suivant les projets et organisations auxquels elle est appliquée.<br />
Le but de ce billet est de dérouler cette démarche de manière simplifiée. Cela nous donnera l'occasion de définir le vocabulaire employé, et de faire un constat sur cette démarche.<br />
Nous déroulerons l'exemple avec une approche TOP-DOWN, c'est-à-dire que l'analyse commence par la définition de la stratégie pour descendre ensuite au travers des différentes strates du SI. Pour l'exemple, nous prendrons le cas d'une agence de voyages qui achète et vend des voyages.</p>
<p><a href="http://blog.xebia.fr/2008/04/10/urbanisation-pour-les-nuls/">Lire cet article »</a></p>
<h4><a href="http://blog.xebia.fr/2008/04/11/les-10-commandements-des-tests-unitaires/">Les 10 commandements des tests unitaires</a></h4>
<p>Les tests unitaires ne sont pas qu'une bonne pratique des méthodes agiles, ils sont un véritable pré-requis à la mise en place d'un développement itératif.<br />
Le refactoring et la modification d'une base de code existante, bien que facilités par les environnements de développement actuels, comportent un évident risque de régression, en partie couvert par les tests unitaires.</p>
<p>Vous trouverez dans ce billet nos 10 commandements des tests unitaires.</p>
<p><a href="http://blog.xebia.fr/2008/04/11/les-10-commandements-des-tests-unitaires/">Lire cet article »</a></p>
<h4><a href="http://blog.xebia.fr/2008/05/01/springsource-application-platform-la-breche-dans-java-ee/">SpringSource Application Platform : la brèche dans Java EE</a></h4>
<p>L'<a href="http://www.springsource.com/web/guest/products/suite/applicationplatform">annonce de SpringSource</a> a des allures de schisme. Après des années à critiquer la complexité et le monolithisme de Java Enterprise Edition (Java EE), les équipes de Rod Johnson ont franchi le Rubicon et proposent un serveur d'applications Java qui ne reposera pas sur la monolithique spécification Java EE.<br />
SpringSource Application Platform se limite à quelques fragments de cette spécification (principalement Servlet et JPA) assemblés dans un conteneur OSGI augmenté de quelques particularités Spring. Les applications web ne seront plus assemblées sous forme de WAR avec un fichier web.xml mais sous forme de plusieurs bundles OSGI avec des fichiers de configuration Spring.</p>
<p><a href="http://blog.xebia.fr/2008/05/01/springsource-application-platform-la-breche-dans-java-ee/">Lire cet article »</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.xebia.fr/2008/07/01/ce-que-vous-avez-peut-etre-rate-au-second-trimestre-2008/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
