vendredi 12 décembre 2008

Et le blog ?

Le lecteur attentif aura remarqué que ce blog n'avance plus beaucoup.

En effet, il m'est assez compliqué d'appréhender une nouvelle technologie et d'écrire dessus. Au fur et à mesure que j'en découvre, je suis obligé de revenir sur ce que j'ai déjà fait.

Si j'avais écrit tout ce que j'ai fait, le résultat aurait été proprement imbitable

J'ai donc décidé de faire une pause dans Castle / Monorail pour publier de temps en temps des articles plus généraux sur le développement.

Je reviendrais sur Castle quand j'aurai maîtrisé la techno

vendredi 5 décembre 2008

Factorisation en base de donnée

Factorisation

La factorisation, qu'est ce que c'est ?

On parle factorisation de code quand on essaye d'extraire les points communs entre plusieurs problèmes, afin de ne les traiter qu'une seule fois.

Basiquement, l'utilisation d'une fonction (ou d'une procédure) appelée plusieurs fois dans un programme est la première forme de factorisation.
L'héritage en programmation orientée objet est un puissant outil de factorisation : le même code étant propagé à tout une famille d'objets présentant des caractéristiques communes.
La notion de service dans les architectures orientées service est une autre forme de factorisation.
etc.

Je pourrais ainsi faire une longue liste, mais ceci n'aurait pas d'intérêt et il y aura toujours un emmerdeur puriste pour débattre, vendre sa vision de la chose ou insister pour rajouter ou mettre en avant sa méthode favorite. L'objectif ici est simplement de justifier la suite de cet article.

L'idée ici est de montrer comment, grâce à ActiveRecord, on va pouvoir factoriser une partie du travail sur la base de donnée.

Factoriser le code, pourquoi faire ?

Pour éviter de refaire le même travail plusieurs fois.
Pour simplifier la maintenance d'une application
Pour généraliser une best-practice dans un framework
etc.

En l'occurence, ce qui m'intéresse ici c'est de factoriser la mise en place de certains champs quasi-obligatoires dans ma base de donnée.


Factoriser ma base de donnée

Points communs

Quels sont les points communs entre toutes les données nécessaires pour coder mon blog ?

  • Je souhaite tout d'abord qu'elles soient toutes identifiées de façon unique
  • Je veux que cette identification se fasse par un entier (principalement pour des questions de performance)
  • Parfois je pourrais aussi être amené à utiliser d'autre identifiant, notamment les GUID
  • J'aimerai stocker la date de création de la plupart des données
  • Il me semble sensé de noter également la date de dernière modification
  • Idéalement, il faudrait également connaitre l'identité de l'utilisateur ayant créé cette donnée
  • Et tant qu'à fait, si on pouvait également noter l'identité de l'utilisateur ayant fait la dernière modification

Mes champs communs

Grâce à la liste ci dessus, j'ai la liste des champs que veux dans chacune des données de ma base :

  • ID - un identifiant, soit entier, soit GUID
  • DateCreation - la date de création de mon entrée en base
  • DateModification - la date de dernière modification
  • IdCreator - l'identité du créateur
  • IdUpdator - l'identité du dernier utilisateur ayant modifié cette donnée

Quelques explications

Pourquoi ne pas stocker un historique global des modification ?
Ca serait très pratique en effet
Disons que d'expérience c'est beaucoup plus compliqué à mettre en place. On verra pour la v2.

Pourquoi utiliser des GUID pour identifier des données ? Il peut y avoir deux raisons :

  • Lorsque plusieurs bases de données peuvent créer des entrées dans une même table. La gestion d'un identifiant entier auto-incrémenté pose alors des problèmes de synchronisation.
  • Lorsqu'on veut pouvoir exposer un identifiant de façon sécurisée. Il est plus difficile pour un hacker de deviner un GUID que d'essayer différents entiers pour récupérer les informations d'un autre utilisateur ou d'un élément auquel il n'a pas accès. Dans une URL typiquement.

Pourquoi 'DateCreation' et pas 'CreateDate' ?
Parce que j'essaye de toujours mettre le type de la donnée en premier.
Ma règle implicite de nommage c'est 'quoi' en premier. D'où les "IdSchtroumpf" et pas "SchtroumpfId".
C'est une convention de nommage personnelle qui m'apporte beaucoup en terme de lisibilité.

jeudi 4 décembre 2008

Conventions de nommage

Une convention de nommage, qu'est-ce-que c'est ?

L'article de Wikipedia étant un peu réducteur, en voici une définition plus personnelle.

C'est un ensemble de règles de nommage des différents éléments du code.
Ces règles sont définies par le chef de projet ou l'architecte du projet, afin d'homogénéiser le code.
Un développeur travaillant seul défini et applique généralement ses propres conventions de nommage.

Fondamentalement, une convention de nommage est une discipline très stricte que cultivent tous les bons développeurs.

Une convention de nommage, pourquoi faire ?

Les projets informatiques sont de plus en plus vastes.
Il est quasiment impossible d'avoir en tête d'intégralité d'une application en détail.
Par conséquent, lorsqu'un développeur intervient sur un projet, il faut qu'il puisse lire le code sur lequel il travail.

Sans convention de nommage, la lecture du code n'est pas fluide, le développeur est toujours obligé d'aller voir à droite ou à gauche ce que représente telle ou telle variable, d'aller analyser un autre morceau de code pour savoir quelle est la fonction à utiliser pour faire telle chose.
Bref, c'est l'anarchie.

Sans même parler du bénéfice dans une équipe, un développeur qui travaille seul et qui revient sur son code passé quelques mois aura besoin de retrouver ses petits si son projet est conséquent.

Concentration

Une convention de nommage permet également au développeur de concentrer son attention sur ce qui est vraiment important : la résolution du problème.

Pour faire un rapprochement, imaginons un athlète avec des baskets pourries.
Lorsqu'il courre, il doit faire attention aux petits cailloux car ses semelles sont trop fines et il peut se piquer la plante des pieds ce qui est désagréable.
En plus, il doit faire attention à bien poser son pied par terre et surtout à ne pas taper le sol sous peine d'avoir des problèmes aux genoux.

Est-ce que cet athlète à une chance de devenir athlète de haut niveau ?
Non.
Il va se concentrer sur des détails qui vont l'empêcher de se focaliser sur son but : devenir le meilleur, et il ne va pas pouvoir exploiter tout son talent.

Utiliser des conventions de nommage, c'est donner des bonnes baskets à votre développeur qui vont lui permettre de pulvériser vos records problèmes.

mercredi 15 octobre 2008

HTML et exemples de code

Blogguer du code c'est lourd

Je code en HTML direct. Je n'aime pas trop les éditeurs déjà tout fait, sans doute parce que j'ai trop bossé sur l'optimisation pour le référencement naturel.

Jusqu'ici tout allait bien et j'écrivais joyeusement ces articles dans une boite de texte directement sur blogger.net. Mais après avoir passé un temps fou à mettre en page les exemples de code de l'article précédent, je me suis rendu compte que si je ne simplifiais pas le processus, je perdrais toute motivation à blogguer.

J'ai donc décidé de travailler depuis un outil assez pratique : Visual Studio.


Optimiser le HTML

Le problème c'est que le HTML derrière doit être retravaillé pour enlever les sauts de ligne... Pas de soucis, il existe beaucoup d'optimisateur de HTML en ligne pour minifier (terme officiel ?) mon code.

Mais pas de chance : aucun de ceux-ci ne gère la balise 'pre' (texte préformaté).
Or celle-ci est fondamentale pour mettre en ligne du code, sauf à faire des listes (balises ul / li), ce qui est encore plus laborieux !

J'ai donc pris quelques heures de la journée pour coder mon propre minifieur et optimisateur de HTML, basé sur de la solution de parsing de XML fournie dans le .Net framework : XmlDocument.LoadXml

Ce web tool est maintenant en ligne va me permettre de vous blogguer du code
http://www.chezmose.com/webtools

vendredi 10 octobre 2008

ActiveRecord : Premières lignes de code

La théorie

ActiveRecord

ActiveRecord est une design patternqui permet de masquer la complexité des interactions avec la base de donnée en évitant d'écrire du code SQL.

ActiveRecord dans le projet Castle

L'implémentation d'ActiveRecord dans le projet Castle est basée sur la technologie Microsoft.Net et le framework d'ORM (Object Relationnal Mapping) NHibernate.

La subtilité et la simplicité de cette technologie est qu'elle est basée sur la décoration du code par des attributs.

Entités, modèles

Officiellement, dixit la documentation du projet Castle, une classe décorée par des attributs ActiveRecord est appelée un Model, mais cette appellation est trop ambigüe à mon goût et peut prêter à confusion. On préfèrera parler d'Entité.

Toutes nos petites entités doivent donc être rassemblées dans une même couche.

Cette couche est à présent tout en bas de mon modèle multi-couche.

Mais si, souvenez-vous de mon post précédentHé bien avec ActiveRecord, c'est une nouvelle architecture qui se met en place où la couche basse d'accès au donnée n'existe pas, remplacée par une couche d'entités décrivant la structure de la base et les opérations CRUD de base qu'on pourra faire dessus.

CRUDdésignant les 4 opérations standard, en base de donnée relationnelle, sur les entrées d'une table :

  • C - (Create) Création d'une entrée
  • R - (Read) Lecture / sélection d'une entrée
  • U - (Update) Mise à jour
  • D - (Delete) Suppression d'une entrée

Exemple d'entité

Extrait des samples du projet Castle :

using Castle.ActiveRecord;

[ActiveRecord]
public class Entity : ActiveRecordBase
{
private int id;
private string name;

[PrimaryKey]
public int Id
{
get { return id; }
set { id = value; }
}
[Property]
public String Name
{
get { return name; }
set { name = value; }
}
}

L'attribut PrimaryKeyde la table. De très nombreuses options permettent de gérer les différentes spécificités dont on pourrait avoir besoin.

L'attribut PropertySon type sera automatiquement déterminé en fonction du type de donnée côté C#. De très nombreuses options sont disponibles pour personnaliser cette colonne.

Deux méthodes de codage

Explication

Lorsque l'on souhaite développer avec ActiveRecord, deux options s'offrent à vous :

  • Faire hériter chacune de vos entité de ActiveRecordBase
  • Ne pas faire cet héritage, mais utiliser ActiveRecordMediator

de base sont disponibles d'emblée mais peut potentiellement exposer des mécanismes délicats aux développeurs

mais permet d'éviter que des fonctionnalités délicates ne soient exposées par vos API

ouverts. Masquer les fonctionnalités CRUD me permettra de choisir ce que j'expose ou pas dans l'API.

ActiveRecordBase

Ou "je veux que mes développeurs puissent tout faire". Le code de l'entité

using Castle.ActiveRecord;

[ActiveRecord]
public class Entity : ActiveRecordBase
{
private int id;
private string name;

[PrimaryKey]
public int Id
{
get { return id; }
set { id = value; }
}
[Property]
public String Name
{
get { return name; }
set { name = value; }
}
}

Utilisation de cette entité :

// création en base
Entity monEntite = new Entity();
monEntite.Name = "joe";
monEntite.Save();
int id = monEntite.ID;

// chargement depuis la base
Entity monEntite = Entity.Find(id);
string nom = monEntite.Name;

ActiveRecordMediator

Ou "je veux choisir ce que j'expose dans mes entités". Le code de l'entité (c'est le même à l'exception de l'héritage)

using Castle.ActiveRecord;

[ActiveRecord]
public class Entity
{
private int id;
private string name;

[PrimaryKey]
public int Id
{
get { return id; }
set { id = value; }
}
[Property]
public String Name
{
get { return name; }
set { name = value; }
}
}

Utilisation de cette entité :

// création en base
Entity monEntite = new Entity();
monEntite.Name = "joe";
ActiveRecordMediator.Save(monEntite);
int id = monEntite.ID;

// chargement depuis la base
Entity monEntite = ActiveRecordMediator.FindByPrimaryKey(3);
string nom = monEntite.Name;

et notamment à la généralisation de certains développements grâce à la programmation orientée objet...

jeudi 9 octobre 2008

Architecture 3 tiers

Introduction

Première chose avant de commencer le travail technique proprement dit : un peu d'architecture logicielle.

Une bonne architecture logicielle aujourd'hui passe par un modèle multicouche.

L'accès, l'enregistrement et la gestion des données dans la base de donnée est une première de ces couches, qu'on appellera la couche donnée.

L'exploitation de ces données, l'intelligence des applications qui se reposeront dessus sont dans la couche métier. On parlera aussi d'API ou de framework.

Enfin tout ce qui concerne l'affichage graphique et les interactions avec les utilisateurs sont dans la couche interface.

Les explications qui suivent ont pour objectif de détailler et d'expliquer le pourquoi de cette architecture.

Vous noterez que le schéma est inversé par rapport à l'ordre dans lequel j'ai présenté les couches. Traditionnellement, les données sont dans la couche basse et l'interface dans la couche haute, mais il est plus facile d'expliquer ces concepts en commençant par la couche basse...

3 tiers

3 tier par N

Pour bien appréhender le concept et l'utilité de ce modèle en couche, voici un exemple d'architecture avec plusieurs sources de donnée et plusieurs interfaces, autour d'un unique framework.

Les sources de données peuvent être par exemple deux bases de données distinctes.

Pour les interfaces on peut imaginer un site web et un service windows (inspiré d'un cas réel).


La couche donnée

Une couche donnée, pourquoi faire ?

Cette couche contient l'ensemble des I/O (Input/Output : les entrées et sorties de donnée) des applications qui vont s'appuyer sur le framework. Il peut s'agir d'accès à une base de donnée, dans un fichier XML, de lecture/écriture sur un périphérique spécifique, etc.

Cette partie est séparée de la couche supérieur, la couche métier, car cette dernière se doit d'être indépendante des choix techniques mis en oeuvre.

Imaginez que vous travaillez sous SQL Server, et que du jour au lendemain la licence triple de prix ou que le produit s'arrête. Si l'architecte à bien séparé les couches, l'impact est minime : il suffit de recoder la partie d'accès aux données. Dans le cas contraire, l'équipe technique va souffrir.

Imaginez que votre application utilise un scanner de code-barre pour identifier des produits. Si votre commercial se fâche avec son fournisseur et décide de changer de matériel, une couche donnée vous évitera de remettre en question toute vos applications.

Une couche donnée : ça contient quoi ?

Cette couche est généralement divisée en deux sous-couches distinctes : une couche procédure stockée et une couche d'accès aux donnée.

couche donnee

La couche procédure stockée permet de requêter les tables composant l'application et de les remonter de façon très performante en utilisant la variante du langage SQL intégrée au SGBD. Si votre application fonctionne à partir de SQL généré par votre serveur, alors cette couche n'existe pas. Dans ce cas, la plupart du temps, cette logique de requétage sera mélangée à la couche d'accès aux données, ce que je déconseille.

L'autre sous-couche est donc la couche d'accès aux données. Celle-ci contient la logique d'accès au SGBD et le code permettant d'envoyer les requêtes, de remonter les données, de les convertir dans le langage de travail et de les mettre en forme pour une exploitation par la couche du dessus.


La couche métier

Une couche métier, pourquoi faire ?

Le concept de couche métier est le plus compliqué à appréhender. En effet, si on a les données dans la base, et qu'on veut les afficher, pourquoi s'encombrer d'une couche intérmediaire ?

Parmi les bonnes réponses, je citerai "parce que c'est propre", "pour s'abstraire de la manière d'accéder au données", "pour l'évolutivité", "pour la maintenabilité", etc.

La couche métier et la sécurité

Lorsque votre framework doit être utilisé par plusieurs développeurs, l'utilisation d'une couche intermédiaire permet d'ajouter des sécurités pour éviter qu'une ligne de code malencontreuse fasse planter votre application ou détruise des données par inadvertance.

Exemple : avant de créer une entrée dans une table, je vérifie la validité des paramètres.

La couche métier et l'évolutivité

L'abstraction fournie par la couche métier vous permet d'enrichir vos tables sans modifier négativement les objets existants, elle vous permet de séparer fonctionnellement les erreurs de calculs avec les erreurs d'accès à la base. Elle permet de rassembler des informations contenues dans plusieurs tables en un seul objet lorsque cela a du sens.

Exemple : la table utilisateur et la table adresse sont remontées ensemble dans le seul objet 'Utilisateur'.

La couche métier et l'interopérabilité

Une fois votre couche métier codée et fonctionnelle, qu'est ce qui vous empêche de l'utiliser dans une application web ? une application client lourd ? Une application embarquée ? Un service Windows ? Rien, et c'est l'avantage principal, à mon sens, de l'architecture 3-Tiers : faire une API interopérable sans même s'en rendre compte.

Une couche métier : ça contient quoi ?

Des classes, tout simplement.

Dans de nombreux projets, ces classes étaient construites à partir d'objets intermédiaires (DataSet, ...) remontés de la base de donnée.

Récemment, dans un gros projet, j'ai mis en place des objets intermédiaires très légers (conteneurs de donnée), et ces conteneurs étaient encapsulés dans les objets de la couche métier dans leur unique constructeur. Cette approche était très performante, même si elle oblige à coder un objet intermédiaire.


La couche interface

Une couche interface : pourquoi faire ?

Saisir et exploiter les informations du système, bénéficier d'un service ou exposer des fonctionnalités du framework à une exécution automatique.

Quelques types d'interfaces possibles :

Une couche interface : ça contient quoi ?

Il y a trop de réponses possibles ici pour entrer dans le détail dans un simple post sur un blog. Pour simplifier : ça dépend de l'interface choisie. Chaque type d'interface que j'ai cité plus haut fonctionne avec des mécanismes très différents. Il y a matière à écrire un livre sur chacun.

Inutile de perdre ici de l'énergie : je détaillerai en temps et en heure la manière très spécifique d'architecture une interface web en utilisant le framework Castle.

samedi 13 septembre 2008

ActiveRecord : installation

Etape 1 : téléchargement de Castle

J'ai dégagé une après-midi entière pour me consacrer (seul) à quelques expériences avec l'ami ActiveRecord.

Tout commmence par le téléchargement de Castle, via une URL accessible pour Tortoise SVN que m'a refilé l'ami Gildas.

Tortoise SVN ? C'est un client SVN pour Windows.

SVN ? Un des outils de contrôle de source les plus utilisés.

Le contrôle de source ? Ca consiste principalement à archiver les modifications sur une ensemble de fichiers source au fur et à mesure, pour garder les anciennes versions sous le coude, identifier qui à modifié tel module quand on travaille à plusieurs, verrouiller un fichier pour éviter des modifications concurrentes, etc.
Indispensable en développement, au moins autant que la cafetière, c'est dire !

L'URL des sources du projet 'trunk' (tronc commun) de Castle est la suivante :
http://svn.castleproject.org:8080/svn/castle/trunk
10mn et 27Mo plus tard, c'est terminé. Efficace !

J'en profite pour ajouter une autre URL qui contient les projets de contribution, qui me serviront plus tard :
http://svn.castleproject.org:8080/svn/castlecontrib/


Etape 2 : première compilation de Castle

Une fois les fichiers récupérés, un petit 'VSNET.Readme.txt' m'apprend qu'il faut d'abord faire une première compilation pour insérer le projet dans une solution Visual Studio. Et pour ça il faut NAnt.
Damned ! C'était trop facile... bon, c'est parti pour télécharger la dernière version stable de NAnt (0.85).

NAnt est un outil qui permet d'automatiser la compilation de fichier. Originalement appelé Ant et visant le Java, une version est sortie spécifique à la plateforme .Net appelée NAnt. Pour ceux qui connaissent, c'est un genre de make ou makefile, avec des outils en plus.

Après une courte lecture du readme.txt, je vois qu'il se lance en ligne de commande et qu'il va chercher un fichier .build dans le répertoire. Je rajoute donc le répertoire contenant l'exécutable nant.exe dans la variable d'environnement PATH, histoire que ça fonctionne en ligne de commande depuis n'importe quel répertoire.

Retour au répertoire de Castle, exécution de la ligne de commande 'nant' (ca me semble trop facile...) et là "ERROR : NUnit not found". Je le savais bien que c'était trop facile. Je maudis intérieurement l'open-source et son incapacité à délivrer des produits finis et packagés pour les utilisateurs lambda... comme si tout le monde utilisait NUnit !

NUnit est un framework permettant de créer facilement des tests unitaires, afin de valider que les différentes évolutions sur le développement d'un produit n'ont pas causé d'effets de bord sur une autre partie.

Aucune envie d'installer NUnit pour l'instant. Je viens de me souvenir que Gildas me suggérait d'outrepasser les tests unitaires à la compilation. Recherche dans le 'How to build.txt' de Castle : il faut utiliser la commande 'nant quick rebuild'. Et c'est reparti pour une exécution en ligne de commande, mais là nouvelle erreur !

NAnt ne trouve pas l'utilitaire AL.EXE, et il en a besoin. Avez-vous correctement installé le framework.Net 2.0 SDK ? (traduction personnelle). Je retient une envie furieuse de frapper l'écran.

Après une courte pause méditation, je décide très calmement d'installer le framework 2.0 SDK, qui fait... 377Mo ! Bon... bein c'est parti pour une seconde pause.

Le téléchargement s'achève, l'installation fonctionne parfaitement, merci Microsoft (je ne le dirai pas tous les jours). Je relance pour la troisième fois ma commande de compilation, et là... ça tourne...

La compilation s'achève enfin
! Et le plus drôle c'est le message qui s'affiche à la fin : BUILD SUCEEDED, Total time 11,3 seconds. La blague ! Je dirais plutôt dans les 1h40...


Etape 3 : compilation d'ActiveRecord dans VisualStudio

Après la compilation, il reste à créer ma solution de test sous Visual Studio, y intégrer ActiveRecord et commencer à coder...

Pas de surprise à la création de la solution. C'est parfaitement conforme à ce qui est requis dans la documentation d'ActiveRecord. J'ajoute le projet 'ActiveRecord', puis 'Castle.Core'. Et je termine en ajoutant au projet 'ActiveRecord' les références aux dll qui sont fournies :

  • nhibernate.dll
  • log4net.dll
  • Iesi.Collections.dll

Ca compile très bien. Je vais pouvoir coder. Mais coder quoi........ ?