Archive for the 'developpement' Category

Responsabilité et atomicité des fonctions

Le projet sur lequel je travaille comporte des problèmes d’architecture que j’ai déjà évoqué dans mon billet précédent. Aujourd’hui, je souhaite aborder un autre problème de conception, qui concerne la répartition des responsabilités dans une classe.

Craig Larman nous conseille de respecter le principe de forte cohésion lorsqu’on défini les responsabilités que doit implémenter une classe. A une échelle inférieure, une méthode doit également respecter une certaine cohésion.

Pour être concret prenons l’exemple d’une méthode qui s’appellerait isValide() et supposons que l’implémentation de cette méthode nécessite d’effectuer une itération sur une liste. La tentation est de profiter du parcours de cette liste pour effectuer des traitements annexes « à la volée », ce qui évite de parcourir la liste une deuxième fois. Dans notre cas, le contrat annoncé par la méthode isValide() consiste fournir la réponse à une question. Pour respecter la cohérence de la fonction, celle-ci doit se contenter strictement d’y répondre et rien d’autre. Tout traitement annexe vient polluer la méthode et rend son utilité moins évidente.

Le problème qu’on peut rencontrer est que cela peut aboutir à une duplication de code. Pour reprendre l’exemple d’une fonction qui implémente une itération sur une liste, on peut se retrouver à implémenter cette itération dans plusieurs méthodes pour respecter l’unitarité de chacune d’elle. Si cela pose des problèmes rédhibitoires de performance, la solution est de n’avoir qu’une seule itération et d’implémenter le pattern Observer pour effectuer plusieurs traitements sur les éléments de la liste.

La cohérence d’une fonction rend son utilité plus claire ce qui facilite la maintenance du code.

Publicités

Le développement Web en Java

La conception de sites Web est possible en Java, elle est basée fondamentalement sur la technologie des Servlets et requière l’installation d’un conteneur comme le serveur Tomcat. C’est ce conteneur qui reçoit et oriente les requêtes http vers les Servlets idoines. En retour, la Servlet doit construire la réponse à la requête, en général au format html ou xml.

Le principe des Servlets est très puissant car il permet de répondre à n’importe quel type de requête http qui est le protocole standard des applications Web. Mais l’inconvénient est que les développeurs partent d’un fichier en langage Java pour produire un document en langage html. Ainsi, la rédaction d’une page Web est malaisée. Le handicap se fait particulièrement ressentir lors de la mise à jour du document. Voyez par vous-même :

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class ExempleDeServlet extends HttpServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse res)
    throws  ServletException, IOException {
        OutputStream out = res.getOutputStream();
	out.println("<?xml version="1.0" encoding="UTF-8" ?>") ;
        out.println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitionnal//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitionnal.dtd\">"
        out.println("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" /><title>Exemple de Servlet</title></head>");
        out.println("<body>Vous ne vous en rendez peut-être pas compte, mais ce n'est vraiment pas pratique</body></html>");
    }
    protected void doPost(HttpServletRequest req, HttpServletResponse res)
    throws  ServletException, IOException {
        doGet(res, req);
    }
}

Les fondements de la technologie n’ont jamais été remis en cause et ils ont maintes prouvé leur pertinence. En revanche, le langage Java a été enrichie d’une nouvelle spécification avec l’arrivé des JSP (Java Server Page) il y a bientôt dix ans. L’inconvénient des Servlets a ainsi été surmonté en inversant les pôles : les JSP sont des documents qui suivent la structure du langage html avec la possibilité d’ajouter du code Java.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Exemple de JSP</title>
</head>
<body>
C'est beaucoup plus pratique à écrire et à mettre à jour
</body>
</html>

Comme on le voit ci-dessus, une JSP ressemble à s’y méprendre à un document html, c’est le conteneur qui se charge de compiler la JSP en Servlet. En fait, une JSP permet de faire bien plus de choses que d’écrire des balises html. Comme nous l’avons dis, il est également possible d’y insérer du code Java grâce aux Scriplets mais aussi de faire référence à une variable avec les Expressions Langage. Enfin, et c’est le plus important, les JSP reposent sur un langage de balises extensible, c’est-à-dire que contrairement au langage html qui définit l’ensemble des balises autorisées, le développeur de JSP peut créer ses propres balises. Ce mécanisme est extrêmement puissant et offre un gain de temps considérable en permettant de créer des composants complexes qui pourront être utilisés par la simple apposition d’une balise.

Malgré tous ces avantages, les JSP ne sont pas pour autant la panacée. Elles ont l’inconvénient de leur avantage, leur souplesse est telle que les JSP deviennent rapidement illisibles si le développeur ne s’astreint pas à une certaine rigueur. C’est à ce niveau qu’intervient le framework. Le rôle qui lui est dévolu est de définir un cadre de travail qui doit permettre de conserver l’avantage premier des JSP, à savoir leur facilité de mise à jour.

Nous reviendrons sur les frameworks dans un prochain billet.

L’encapsulation des attributs en programmation orientée objet

L’encapsulation est un des piliers de la Programmation Orientée Objet avec l’héritage et le polymorphisme. C’est aussi la technique la plus simple à mettre en oeuvre puisqu’elle constiste dans la plupart des langages, et c’est le cas en Java, à apposer le mot private afin de modifier la visibilité d’un membre de classe. C’est aussi la technique la plus importante et à cet égard les enjeux de l’encapsulation ne sont pas toujours bien compris.

Exemple :

public class PetiteCalculatrice {
	private double resultat = 0;

	public double additionner(double nb1, double nb2) {
		return resultat = nb1 + nb2 ;
	}

	public void effacer() {
		restultat = 0;
	}

	public double getResultat() {
		return resultat;
	}
}

Dans cet exemple, la variable d’état resultat a été encapsulée. C’est une bonne habitude d’encapsuler toutes les variables d’état par défaut. Mais voyons pourquoi le choix a été fait de ne pas rendre cette variable publique.

L’intérêt de la programmation orientée objet, ou paradigme classe/instance pour reprendre le terme de Craig Larman, est la possibilité d’écrire un code facilement réutilisable de sorte à ne pas réinventer la roue. Là je ne réinvente pas la roue, je vous montre juste comment remplir le coffre 😉 Seulement, lorsque vous écrivez du code avec l’intention de le réutiliser, l’idéal est que ce code soit sûr et qu’il ne soit pas à l’origine d’un bug qui obligerait à se replonger dans le code source. Le gain serait finalement nul.

L’idée du paradigme classe/instance est de modulariser le code en classes et de donner au développeur de chaque classe l’entière responsabilité de son bon fonctionnement. Bien sûr, il n’est pas toujours possible de prévoir toutes les situations et c’est pour ça qu’a été inventé le mécanisme des exceptions, mais ce n’est pas le sujet de ce post. Dans notre cas, nous proposons du code qui permet d’obtenir un résultat mathématique, il est de notre responsabilité de garantir la cohérence de ce résultat. Voilà pourquoi l’attribut de notre PetiteCalculatrice a été encapsulé : il est hors de question d’autoriser l’utilisateur de notre classe à injecter le résultat qu’il veut, ce résultat doit être uniquement celui obtenu par les opérations que nous avons implémenté, en l’occurence l’addition.

Ainsi, en encapsulant un attribut il est possible de choisir si celui-ci doit être accessible en lecture ou en écriture, et dans ce dernier cas de définir les conditions pour lesquelles les valeurs sont autorisées.

Pour terminer, et c’est sans doute l’aspect le plus important de l’encapsulation, le développeur est responsable du code qu’il fournit. Bien sûr il n’est pas responsable socialement, ou du moins cet aspect ne nous intéresse pas ici :p, mais, et cela revient d’une certaine manière à la même chose, il est responsable au regard des autres classes avec lesquelles celle qu’il a écrit collabore, ainsi que celles avec lequelles elle sera amené à collaborer. Cela en ne perdant jamais de vue que si on sait dans quel contexte on a écrit son code, on ne sait jamais celui dans lequel il sera appelé.