Bonnes pratiques pour la création d'applications base de données

Rémi Gouyon

Cet article donne quelques conseils et bonnes pratiques pour créer sa première application utilisant une base de données. Il est surtout basé sur Lazarus et Delphi mais les principes énoncés sont universels.

Commentez

- Titre : Bonnes pratiques pour la création d'applications base de données

- Auteur : Rémi Gouyon

- Parution : 10 avril 2016

- Public visé :

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2016 Rémi Gouyon. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. Première étape : les outils

- II-A. Holà ça va servir à quoi tout ça ?

- II-B. Quelques outils

- III. Seconde étape : l'organisation

- IV. Troisième étape : les premières briques logicielles

- IV-A. La connexion application base

- IV-B. La visualisation des données

- IV-C. Dialogue avancé

- V. Lancez-vous

- VI. Quelques règles pratiques

- VI-A. Atomisez vos données

- VI-B. Utilisez les clefs primaires et étrangères (primary & Foreign keys)

- VI-C. Testez d'abord vos requêtes

- VI-D. Séparation dans le code

- VI-E. Pensez local

- VI-F. Évitez le code SQL dans l'interface

- VII. Conclusion

- VII-A. Remerciements

I - Introduction

Ça y est vous vous êtes décidé à vous lancer dans la création de votre superbe application base de données. Mais voilà c'est votre première du genre même si vous avez une certaine expérience dans la programmation, alors voici quelques conseils pour que ça ne tourne pas au cauchemar.

Dans cet article je vais surtout m'appuyer sur des EDI comme Lazarus et Delphi (CBuilder par extension) et d'exemples tirés d'applications que j'ai développées. Mais les principes que je vais énoncer sont aussi applicables à d'autres langages (Java, Python…) et EDI.

II - Première étape : les outils

Vous disposez bien entendu comme tout bon développeur d'un environnement de développement intégré (EDI), mais pour réaliser votre application, il vous faudra quelques outils supplémentaires.

Tout d'abord il faut un système de base de données. Il est à choisir en fonction de la destination de l'application et de la taille de la base. Si vous devez gérer des centaines d'enregistrements et que votre application est destinée à être distribuée, je vous conseille un système robuste.

Par contre s'il s'agit d'une application pour vous ne contenant que peu d'enregistrements, on peut utiliser des moteurs plus simples.

Une autre caractéristique du moteur est sa capacité à gérer le SQL (langage des bases de données). En effet vous allez utiliser le moteur en lui envoyant des requêtes et en fonction de la façon dont il gère SQL, vous pourrez exécuter des requêtes plus ou moins sophistiquées. Il faut aussi tenir compte des clients graphiques disponibles pour ce système. Dans certains cas ils sont intégrés au système (MSAccess par exemple) dans le cas contraire il faut aller en chercher sur Internet.

Ensuite, il faut des outils de connexion à la base. Là encore certains sont fournis dans l'EDI et d'autres sont disponibles sur Internet (gratuits ou payants).

II-A - Holà ça va servir à quoi tout ça ?

Le système de base de données va gérer votre base c'est lui qui va faire tout le travail que vous allez lui demander via vos requêtes. Il se charge aussi du stockage des données sur le disque.

Le client graphique est une application base de données qui permet d'avoir une interface graphique ergonomique pour interagir avec le système de base de données. On va l'utiliser pour créer la base, la modifier et tester les requêtes qui seront utilisées dans l'application.

Les outils de connexion sont des composants logiciels qui vont permettre de faire communiquer votre application et la base.

II-B - Quelques outils

Personnellement j'utilise MySQL (http://dev.mysql.com/downloads/) qui permet de gérer des bases importantes. Elle est bien documentée et a des versions sur tous les OS. Son installation n'est pas très complexe. Il existe plusieurs clients graphiques pour ce système :

- PhpMyAdmin [https://www.phpmyadmin.net/], gratuit ;

- Navicat [https://www.navicat.com/fr] payant. Il a existé une version light gratuite, mais difficile à trouver maintenant.

Pour les outils de connexion, j'utilise Zeoslib (http://zeoslib.sourceforge.net/) qui est gratuit et bien supporté.

III - Seconde étape : l'organisation

On lève les mains de son clavier, on pose la souris ! Mieux même on éteint tout, on prend une bonne vieille feuille de papier et un crayon et c'est là que commence le travail.

En effet avant de vous lancer dans la production de lignes de code, il est très important de vous poser des questions sur ce que vous voulez faire et comment vous allez le faire. Testez vos idées sur le papier, dessinez vos interfaces, organisez vos données. Si vous développez une application pour d'autres que vous, n'hésitez pas à les impliquer dans la conception en leur demandant d'exprimer ce qu'ils attendent de votre application.

IV - Troisième étape : les premières briques logicielles

Vous avez vos outils, vous avez fait une étude papier de votre application, il n'y a plus qu'à coder. Modérez votre enthousiasme, il vous faudra tout d'abord construire et tester les briques suivantes.

IV-A - La connexion application base

C'est le premier élément à mettre en place. Vérifiez que votre application est capable de se connecter à votre base. Surtout si vous souhaitez travailler avec une base sur une machine distante. Pour cela rien de plus simple : créer un projet et une base de données avec une table et quelques enregistrements. Dans votre projet, ajoutez le composant de connexion, configurez-le et testez si cela fonctionne. Les figures suivantes illustrent un exemple d'application de test de connexion avec des composants Zeos.

Donc on réalise une base de données avec une table.

Exemple de base simple créée avec NavicatLight

Ensuite on crée un projet dans lequel on met en œuvre un composant de connexion (repère F).

Exemple d'application de test développée avec Lazarus

Dans la partie gauche, on configure le composant en renseignant les propriétés (repère A à E) HostName, Password,Port, Protocol et Catalog. Puis on tente une connexion en mettant la propriété Connected (repère G) à true. En effet l'EDI Lazarus (Delphi et Cbuilder aussi) a le bon goût de faire fonctionner les composants sur l'interface ce qui permet de vérifier très rapidement le bon fonctionnement de la configuration d'un composant. Cela peut cependant présenter des inconvénients que l'on verra plus tard. Donc si tout est correctement paramétré, vous ne devez pas avoir d'erreur.

Par la suite je vous conseille de configurer votre connexion dans le code et non sur l'interface.

LaBase.Catalog:='test';
LaBase.HostName:='localhost';
LaBase.Password:='Pass3306';
LaBase.Port:=3306;
LaBase.User:='root';
LaBase.Connected := True;

Essentiellement pour deux raisons. La première est que cela permettra de la configurer votre connexion via un fichier d'initialisation. En effet, supposons que vous distribuiez votre logiciel et que la base soit sur un serveur. Vous ne pouvez pas imposer à vos utilisateurs que le nom de leur serveur soit « ServeurBase » et vous ne pouvez pas faire une compilation par utilisateur. D'où le fichier de configuration qui permet à chaque utilisateur d'adapter la connexion à son environnement. La seconde est que vous pouvez connecter l'application au moment de votre choix et non au moment du lancement du programme.

IV-B - La visualisation des données

Vous vous êtes connecté à la base. Maintenant vous allez avoir besoin de visualiser les données sur l'interface. En fonction des EDI et des langages, vous aurez accès à un certain nombre de composants vous permettant de visualiser les données et de naviguer dans les tables. Créez une table simple dans votre base qui contient des nombres, des chaînes de caractères et tous les autres types de données que vous serez amené à utiliser. Puis essayer de lire ces données à l'aide des composants logiciels. Préparez des interfaces simples pour tester et comprendre comment fonctionnent ces composants de visualisation avant de les utiliser dans votre application.

Exemple d'interface simple pour tester le fonctionnement de la barre de navigation

Dans l'exemple ci-dessus, on a affiché le contenu d'une table sous deux formes différentes. En haut à droite de la fenêtre figurent les composants de dialogue avec la base. À savoir le composant de connexion, un composant TDataSource (DSTable) et un composant TZTable (Table).

Schéma de principe d'une chaîne de composants pour l'affichage d'une table

Le composant Table est connecté au composant connexion et la propriété TableName est renseignée avec le nom de la table dans la base. Le composant DSTable permet de faire la liaison entre la Table et les composants d'affichage et de navigation.

Propriétés des composants Table et DSTable

IV-C - Dialogue avancé

Vous n'allez sans doute pas vous limiter à l'affichage de vos tables. Vous allez très certainement vouloir utiliser des requêtes pour manipuler vos données. Il existe des composants qui permettent de gérer et d'exécuter des requêtes avec ou sans paramètres. Je présente ici un petit exemple réalisé avec des composants Zeos. On dispose d'une table contenant des caractéristiques de navires du XVIIIe siècle. Il s'agit d'afficher les noms des navires de la classe trois ponts.

Exemple de requête simple avec des composants Zeos

Sur l'interface, on a le composant de connexion - un composant TdataSource (DSQuery) - et un composant TZQuery (Query) qui aura le même rôle que le composant TZtable du chapitre précédent, sauf qu'il ne se connectera pas à une table, mais on lui donnera un code SQL qui sera exécuté par le moteur de la base de données. C'est dans la propriété SQL qu'on mettra le code SQL qui sera exécuté. On a mis un composant d'affichage de type tableau sur l'interface pour visualiser le résultat de la requête. Il suffit de mettre à true le paramètre Active du composant TZQuery (Query) pour que la requête s'exécute et visualiser le résultat.

V - Lancez-vous

Maintenant que vous avez bien préparé votre travail, que vous maîtrisez les briques logicielles indispensables, vous pouvez vous lancer dans le développement de votre application. Cependant je vous conseille de suivre les quelques règles pratiques ci-dessous.

VI - Quelques règles pratiques

VI-A - Atomisez vos données

En plus clair, une table de votre base ne doit contenir que le strict minimum. Voici quelques exemples pour illustrer mon propos.

Si on réalise un carnet d'adresses, il sera bon de mettre dans une table à part le code postal ainsi que la ville correspondante.

Voici la table carnet d'adresses qu'il ne faut pas faire :

Nom

Prénom

Adresse

Code

Ville

Xxxx

Yyy

Zzz

12345

Oulanbator

Cette table contient toutes les informations.

Voici ce qu'il vaut mieux faire :

La table Carnet

Nom

Prénom

Adresse

RefCode

Xxxx

Yyy

Zzz

1

Dans cette table, il y a une référence vers une autre table qui contient les informations Code et Ville.

La table CodePostal

RefCode

Code

Ville

1

12345

Oulanbator

Chaque information code et ville est référencée par un identifiant unique.

Pourquoi cette organisation ?

Tout d'abord, un gain de place. Dans l'exemple ci-dessus, la seconde solution permet de gagner une chaîne de caractères par enregistrement. Le gain peut sembler dérisoire, mais si on a une base de quelques millions d'enregistrements, ça commence à compter. De plus la longueur des enregistrements peut avoir une influence sur les fonctions de recherche.

Ensuite cela facilite et accélère la saisie. Dans le premier cas, il faut rentrer au clavier le code postal et la ville tandis que dans le second cas ces informations sont saisies une fois puis lors de la saisie d'une autre adresse, il suffit de choisir le code et la ville dans une liste de choix.

Et enfin le plus important cela prévient un grand nombre d'erreurs et facilite corrections et mises à jour. Si pour une raison ou pour une autre les informations code postal et ville changent, il suffit de les modifier dans la table Code et toutes les adresses seront mises à jour automatiquement. Dans le cas contraire, il aurait fallu corriger chaque adresse ayant ce code postal.

VI-B - Utilisez les clefs primaires et étrangères (primary & Foreign keys)

Les clefs ont une grande importance dans les bases de données. Elles permettent de garantir l'unicité des informations et l'intégrité référentielle de vos tables. Dans l'exemple précédent, il serait bien d'établir une clé étrangère entre la table des codes postaux et le carnet. En effet si jamais on décide de supprimer la référence n° 1 ou si le numéro de code est changé, que va-t-il se passer avec tous les enregistrements du carnet qui contiennent cette référence. Sans clef étrangère il n'est pas possible de gérer ce type d'action.

VI-C - Testez d'abord vos requêtes

Au cours du développement, vous serez sans doute amené à écrire des requêtes plus ou moins complexes. Pour cela, je vous conseille de les tester d'abord dans un client graphique. En effet cela simplifiera la mise au point. Si vous mettez directement votre requête dans le code, vous devrez lancer le code à chaque fois que vous voudrez vérifier si elle répond bien à vos attentes. En outre, s'il y a une erreur de syntaxe dans le SQL, cette dernière ne sera pas forcément bien signalée selon le composant que vous aurez utilisé.

VI-D - Séparation dans le code

Séparer dans une unité particulière tout ce qui concerne les interactions avec la base. Cela a deux avantages : le premier c'est que tout ce qui concerne la base sera regroupé au même endroit et non dispersé dans tout votre code, le second c'est que cette unité pourra être utilisée par différentes applications. Par exemple vous pouvez envisager d'accompagner votre application d'une application de maintenance qui vous permettra de travailler sur la base ou encore une application de test qui va permettre de valider des portions de logiciel.

Sous Delphi, Lazarus et CBuilder, il existe le DataModule. C'est un composant particulier qui permet de regrouper tous les composants relatifs à la base de données.

Exemple de DataModule sous Lazarus

De même je vous conseille de stocker vos requêtes dans des fichiers texte dans la mesure où les composants permettent de charger la requête à partir d'un fichier. La raison est simple : vous avez mis au point votre requête dans le client graphique donc il est facile de la copier et de la sauvegarder dans un fichier texte plutôt que d'aller la programmer dans votre code.

Écrire :

QCaracSec.SQL.LoadFromFile(RepReq + 'QselectionCaracSec.sql');

est plus simple que d'écrire :

QCaracSec.SQL.Add('SELECT ST.Abreviation as st, CL.Abreviation as ct,  ');
QCaracSec.SQL.Add('MA.Acceleration as Acc, MA.Deceleration as Decc,  ');
QCaracSec.SQL.Add('CQ.SK, CQ.GunMod as gm ');
QCaracSec.SQL.Add('FROM t_speedtype as ST ');
QCaracSec.SQL.Add('JOIN t_classes as CL ');
QCaracSec.SQL.Add('on CL.RefClasse=:RefClNav ');
QCaracSec.SQL.Add('JOIN t_manoeuvrabilite as MA ');
QCaracSec.SQL.Add('on MA.RefMan=:RefManNav ');
QCaracSec.SQL.Add('JOIN t_qualequipage as CQ ');
QCaracSec.SQL.Add('on CQ.RefQualite=:RefQualNav ');
QCaracSec.SQL.Add('WHERE ST.RefSpeedType=:RefSpeedNav');

Dans le fichier QselectionCaracSec,sql figure votre requête :

SELECT ST.Abreviation as st, CL.Abreviation as ct,
MA.Acceleration as Acc, MA.Deceleration as Decc,
CQ.SK, CQ.GunMod as gm
FROM t_speedtype as ST
JOIN t_classes as CL
ON CL.RefClasse=:RefClNav
JOIN t_manoeuvrabilite as MA
ON MA.RefMan=:RefManNav
JOIN t_qualequipage as CQ
ON CQ.RefQualite=:RefQualNav
WHERE ST.RefSpeedType=:RefSpeedNav

Par ailleurs si jamais vous modifiez votre requête dans le cas où elle est inscrite en dur dans le code, vous êtes obligé de faire une compilation.

VI-E - Pensez local

Vous avez votre DataModule et il est très facile lorsqu'on en a besoin de mettre un composant requête dessus et hop le tour est joué. Sauf qu'au bout du vingtième, vous n'y voyez plus rien et vous ne savez plus qui fait quoi (cf. figure ci-dessus). Si un composant n'est utilisé que dans une procédure (ou fonction) n'hésitez pas à le créer et à le détruire à la fin de votre procédure.

procedure TCADM.PrepareMonJournal(Ref, Tour, CodeID: integer);
var
Query: TZquery;
begin
Query := TZquery.Create(nil);
Query.Connection := LaBase;
Query.SQL.Clear;
Query.SQL.Add('DELETE FROM t_journal');
Query.SQL.Add(Format('WHERE NOT(RefScenario=%d AND Tour=%d AND CodeID=%d)',
[Ref, Tour, CodeID]));
Query.ExecSQL;
Query.Free;
end;

Cela vous évitera en plus d'avoir des problèmes de mémoire et des lenteurs à l'initialisation.

VI-F - Évitez le code SQL dans l'interface

On a vu dans le chapitre IV.C qu'il était possible de placer du code SQL directement dans l'interface lors de sa conception. C'est très pratique dans un premier temps, car cela permet de visualiser rapidement le résultat. Cependant ça peut se révéler dangereux à plus long terme. En effet, pour peu que votre projet évolue vous risquez de faire des modifications qui entraînent une erreur d'exécution d'une de vos requêtes. Dans ce cas vous risquez d'avoir des messages d'erreur assez incompréhensibles quand vous ouvrirez votre projet. Mon conseil est une fois que vous avez testé votre requête enlevez-la du paramètre SQL et mettez-la dans un fichier.

VII - Conclusion

Il est évident qu'après la lecture de cet article vous n'allez pas devenir un pro du développement d'applications base de données. Cependant si vous venez de vous lancer dans un tel projet ces quelques conseils devraient vous aider à bien démarrer.

VII-A - Remerciements

Merci à Roland Chastain pour sa relecture technique et à Claude Leloup pour ses corrections.