mageekblog - Mot-clé - encapsulationLe blog personnel de Frédéric Hardy. Au menu, PHP, agilité, FreeBSD, cuisine et photographies.2021-12-02T08:20:54+01:00Frédéric Hardyurn:md5:26874ca5b8cd4cac8d08b0e68e64f63aDotclearprivate, protected et public sont dans un bâteau...urn:md5:7a7adc117ebc283dd1dfd487da290b912010-12-29T09:00:00+01:002010-12-29T10:13:03+01:00mageekguyPHPencapsulationformat ouvertPOOprivateprotectedpublic<p>Suite à <a href="http://blog.mageekbox.net/?post/2010/11/17/La-guerre-des-tests">mon billet sur l'intérêt des tests unitaires</a> sur les méthodes
privées ou protégées, j'ai eu beaucoup de <a href="http://blog.mageekbox.net/?post/2010/11/17/La-guerre-des-tests#c2232">commentaires</a> au sujet de <a href="http://fr.wikipedia.org/wiki/Encapsulation_%28programmation%29">l'encapsulation</a> et sur sa mise en œuvre.</p>
<p>Récemment, <a href="http://twitter.com/#%21/ubermuda">cousin @ub sans bermuda</a>, l'un de mes collègues chez <a href="http://pmsipilot.com/">PMSIpilot</a>, a relancé le débat via <a href="http://twtpoll.com/ehtgb8">un sondage</a>, même si son objectif était plutôt de lancer un débat sur le thème <q>la composition contre l'héritage</q>.</p>
<p>J'ai donc décidé de prendre mon clavier pour à la fois essayer de répondre à ces interrogations et mettre à plat ma propre réflexion sur le sujet.</p>
<p><a href="http://fr.wikipedia.org/wiki/Encapsulation_%28programmation%29">L'encapsulation</a>, dans le cadre de la <a href="http://fr.wikipedia.org/wiki/POO"><abbr title="Programmation Orientée Objet">POO</abbr></a>, consiste dans le fait de masquer à l'utilisateur d'une classe les détails de son implémentation.
</p>
<p>En <a href="http://www.php.net/">PHP</a>, elle est mise en œuvre à l'aide des mots-clefs <code>private</code>, <code>protected</code> et <code>public</code>, qui sont applicables au choix sur les propriétés d'une classe ou ses méthodes.</p>
<p>Le mot-clef <code>private</code> permet donc très logiquement de
masquer à l'utilisateur final les propriétés et les méthodes sur
lesquelles il est appliqué, alors que <code>public</code>, à contrario, permet de rendre les éléments sur lesquels il est appliqué totalement accessibles.</p>
<p>Enfin, tout ce qui est <code>protected</code> a un statut particulier, dans le sens ou tout ce sur quoi il est appliqué se comporte comme étant privé pour l'utilisateur de la classe, et comme étant publique dans les classes dérivées.</p>
<p>Lors de la conception d'une classe, le développeur doit donc choisir
entre ces différents niveaux de visibilité, et cela à bon escient, car
un mauvais choix à ce niveau peut avoir des répercussions <a href="http://blog.mageekbox.net/?post/2008/11/07/La-SPL%2C-c-est-bien...-ou-pas-%21">parfois très
gênantes</a> pour les utilisateurs.</p>
<p>Or, il n'y a aucune règle explicite gouvernant l'utilisation de ces
mots-clefs, car elle dépend très étroitement du contexte.</p> <p>La solution consiste donc à être pragmatique, et pour ce faire, rien ne vaut le développement piloté par les tests, <abbr title="Also Known As">aka</abbr> <a href="http://fr.wikipedia.org/wiki/TDD"><abbr title="Test Driven Development">TDD</abbr></a>, puisqu'il permet de mettre en situation le code de la classe et ainsi choisir le niveau d'encapsulation ad hoc pour chacun des composants de la classe en cours de conception.</p>
<p>Cependant, l'expérience m'a appris que cela n'est pas toujours suffisant, et en conséquence, j'applique lors de mes développement une philosophie complémentaire, basée sur le succès, ou plus précisément sur ce qui fait le succès des <a href="http://fr.wikipedia.org/wiki/Format_ouvert">formats ouverts</a>.</p>
<p>En effet, un <a href="http://fr.wikipedia.org/wiki/Format_ouvert">format ouvert</a>, du fait même qu'il soit ouvert et donc manipulable, échangeable ou manipulable facilement, a une espérance de vie beaucoup plus longue qu'un format fermé.</p>
<p>Il favorise de plus l'interopérabilité entre les systèmes et il est également beaucoup plus évolutif, puisque ces spécifications sont connus de tous et que tout à chacun peut donc le modifier pour l'adapter à ses besoins sans la moindre restriction.</p>
<p>Le principe des <a href="http://fr.wikipedia.org/wiki/Format_ouvert">formats ouverts</a> est d'ailleurs tellement puissant que des sociétés telle que la fondation Mozilla ont pour but, entre autre, de les promouvoir afin d'assurer l'interopérabilité au sein d'Internet.</p>
<p>Or, une classe, en <a href="http://fr.wikipedia.org/wiki/POO"><abbr title="Programmation Orientée Objet">POO</abbr></a>, a pour but d'interagir avec d'autres classes, et se doit d'être évolutive afin de pouvoir être adapté aux besoins des utilisateurs, via, entre autre, le mécanisme d'héritage.</p>
<p>Il est donc possible de faire un parallèle entre un format ouvert et une classe, et logiquement, il n'y a aucune raison que ce qui fait le succès de l'un ne fasse pas le succès de l'autre.</p>
<p>Le secret d'une classe réussie est donc dans l'ouverture maximale vers l'extérieur, et donc le recours le plus systématique possible au mot-clef <code>public</code>, et cela aussi bien pour les propriétés que pour les méthodes.</p>
<p>En conséquence, lorsque je développe, tous les composants de ma classe sont publiques par défaut.</p>
<p>Ce n'est qu'une fois que le <a href="http://fr.wikipedia.org/wiki/TDD"><abbr title="Test Driven Development">TDD</abbr></a> m'a permis de définir l'intégralité de l'interface de ma classe, aussi bien au niveau des propriétés que des méthodes, ainsi que son implémentation, que je réduis au besoin le niveau de visibilité des éléments de ma classe.</p>
<p>Arrivé à ce point, vous allez me dire que le développeur se retrouve dans la même situation qu'au départ.</p>
<p>En effet, à première vue, il ne dispose d'aucune règle qui lui permette de choisir son niveau d'encapsulation, mais en y regardant de plus prés, ce n'est pas exact.</p>
<p>Du fait de l'utilisation du <a href="http://fr.wikipedia.org/wiki/TDD"><abbr title="Test Driven Development">TDD</abbr></a>, le développeur dispose d'une implémentation, d'un code concret, qu'il peut analyser à loisir afin de définir les éléments critiques, c'est à dire ceux qui ne doivent absolument pas être altéré par l'extérieur sous peine de briser l'intégrité de l'objet ou de corrompre son fonctionnement.</p>
<p>Mais là encore, suivant le principe des <a href="http://fr.wikipedia.org/wiki/Format_ouvert">formats ouverts</a>, il est nécessaire de limiter au maximum le niveau d'encapsulation, en privilégiant l'utilisation de <code>protected</code> et en n'appliquant le mot-clef <code>private</code> que sur les éléments les plus spécifiques, et qui sont donc à ce titre intégralement extrêmement dépendant de l'implémentation de la classe.</p>
<p>De plus, toujours suivant le <ins>même principe</ins>, il ne faut pas perdre de vue qu'il est toujours possible de définir des accesseurs et des modificateurs pour les propriétés protégées ou privées afin de permettre leur modification sans corrompre l'objet.</p>
<p>C'est ainsi que par exemple, en <a href="http://www.php.net">PHP</a>, il est de bon ton de définir comme étant protégée une propriété qui doit être d'un certain type, et de définir la méthode permettant de l'initialiser comme étant publique, cette dernière étant chargée de s'assurer que la propriété sera toujours du bon type, de la manière suivante :</p>
<blockquote><pre><code><?php<br /><br />class foo {<br /> protected $adapter = null; // doit être une instance de \adapter.<br /><br /> public function setAdapter(\adapter $adapter)<br /> {<br /> $this->adapter = $adapter;<br /> return $this;<br /> }<br />}<br /><br />?></code></pre></blockquote>
<p>Cependant, l'utilisation du <a href="http://fr.wikipedia.org/wiki/TDD"><abbr title="Test Driven Development">TDD</abbr></a> permet de faire apparaître ces méthodes spécifiques au cours du processus de développement si elles sont nécessaires, et en conséquence, il n'y a pas besoin de s'en soucier outre mesure dans ce contexte.</p>
<p>Et il y a un autre point capital à ne pas oublier.</p>
<p>Le succès des <a href="http://fr.wikipedia.org/wiki/Format_ouvert">formats ouverts</a> vient du fait que leurs spécifications sont connues, et dans la grande majorité des cas, elles sont connues car rédigées sous la forme d'une documentation.</p>
<p>En conséquence, il est nécessaire de documenter les classes et surtout leur implémentation précisément, soit à l'aide des tests unitaires, soit à l'aide d'une documentation plus explicite.</p>
<p>Ce dernier point est notamment primordial pour tout ce qui a le niveau de visibilité <code>protected</code>, pour deux raisons.</p>
<p>Tout d'abord, ce n'est pas forcément <a href="http://blog.mageekbox.net/?post/2010/11/17/La-guerre-des-tests">testables</a>, et ensuite, une mauvaise utilisation d'un élément protégé par une classe fille peut potentiellement très facilement corrompre l'intégrité de l'objet, puisqu'un élément protégé est nécessaire à son bon fonctionnement, sans pour autant être spécifique à l'implémentation.</p>
<p>Et comme la bonne utilisation de ces éléments est de la responsabilité du programmeur et que le plus gros problème en informatique est situé entre la chaise et le clavier, il est absolument nécessaire de borner les choses au maximum afin de limiter au maximum le risque d'erreur.</p>
<p>Évidemment, tout cela tient plus de la recette de cuisine que d'autre chose, puisque c'est le fruit de mon expérience, que ce soit en tant que développeur <a href="http://fr.wikipedia.org/wiki/C%2B%2B">C++</a> ou en tant que développeur <a href="http://www.php.net">PHP</a>.</p>
<p>Dans l'ensemble, cela donne de bons résultats, mais je n'ai absolument aucun argument scientifique pouvant étayer mon propos.</p>
<p>Mais, après tout, le bon sens a-t-il besoin d'être validé par la Science ?</p>http://blog.mageekbox.net/?post/2010/12/28/private%2C-protected-et-public-sont-dans-un-b%C3%A2teau...#comment-formhttp://blog.mageekbox.net/?feed/atom/comments/224La guerre des testsurn:md5:8801b9a68eef784e394d89f13679e5432010-11-18T09:00:00+01:002010-11-18T14:32:17+01:00mageekguyRéfléxionsAtoumencapsulationHoaIvan Enderlinprivateprotectedrefactorisationtest unitaire<p>Dans le petit monde des tests unitaires, et comme dans beaucoup d'autres, qu'ils soient réels ou virtuels, il y a différents courants de pensées, différentes philosophies, qui s'affrontent dans des débats enfiévrés qui ont lieu sur Internet ou dans le monde réel, la plupart du temps autour d'une ou plusieurs bières.</p>
<p>Et depuis quelques temps, via le développement d'<a href="http://blog.mageekbox.net/?post/2010/11/17/../?post/2010/10/11/Teasing-4">Atoum</a>, mon framework de tests unitaires qui tire pleinement parti des possibilités offertes par <a href="http://www.php.net">PHP</a> 5.3, je suis partie prenante de l'un de ces débats.</p>
<p>En effet, certaines personnes travaillant avec moi sur le projet n'ont pas la même définition que moi d'un test unitaire.</p>
<p>En conséquence, elles n'ont pas forcément la même vision que moi de ce que doit permettre ou non un framework de tests unitaires tel qu'<a href="http://blog.mageekbox.net/?post/2010/11/17/?post/2010/06/16/Teasing-2">Atoum</a>.</p>
<p>Nous avons donc régulièrement des discussions sur différentes sujets, et c'est la synthèse de mes réflexions sur l'un de ces débats que je vous livre dans les lignes qui suivent.</p> <p>Tout a commencé il y a maintenant quelques mois, lorsque l'un des membres actuels de l'équipe de développement d'<a href="http://blog.mageekbox.net/?post/2010/11/17/../?post/2010/10/11/Teasing-4">Atoum</a> m'a contacté pour me poser une question sur la façon d'écrire des tests unitaires.</p>
<p>À l'époque, il ne participait pas encore au développement du projet, et s'il connaissait parfaitement l'aspect théorique des tests unitaires et qu'il prônait leur utilisation, c'était la première fois qu'il devait effectivement les mettre en pratique.</p>
<p>Et comme la plupart des débutants dans les tests unitaires, il s'est demandé comment il était possible de tester une méthode de classe privée ou protégée.</p>
<p>J'avoue avoir répondu sans réfléchir, tellement la réponse me semblait évidente.</p>
<p>À mon sens, il n'est pas nécessaire de tester ces méthodes.</p>
<p>Et pourquoi donc me direz-vous ?</p>
<p>Tout d'abord, pour en finir immédiatement avec mon argument le plus subjectif, je pense que les solutions permettant de tester ces méthodes ne sont pas propres ou bien relativement lourdes à mettre en œuvre.</p>
<p>Ensuite, l'encapsulation, qui se traduit en <a href="http://www.php.net/">PHP</a> par l'utilisation des mots clefs <code>protected</code> et <code>private</code> affectés à une propriété ou une méthode de classe, a pour but de masquer l'implémentation technique de la classe à son utilisateur.</p>
<p>Or, de mon point de vue, un test unitaire valide l'implémentation de la classe du point de vue de son utilisateur, et non du point de vue de son développeur.</p>
<p>C'est pour moi avant tout un contrat passé entre le développeur et l'utilisateur, qui garanti à ce dernier que l'interface publique de la classe se comportera comme elle le doit, ni plus ni moins.</p>
<p>Il est donc logique que je ne me soucis pas de tester les méthodes protégées ou privées de mes classes, puisque seul compte à mes yeux le fait que les méthodes publiques de ma classe se comportent correctement.</p>
<p>De plus, lorsque l'on fait du développement piloté par les tests, ce qui est mon cas, le processus à suivre pour créer une classe est le suivant :</p>
<ol><li>le développeur écrit un test pour une méthode <em>publique</em> de la classe.</li>
<li>Le développeur écrit le code <em>le plus simple possible</em> qui permet à la classe de réussir le test écrit précédemment.</li>
<li>Le développement se poursuit de cette manière tant que le comportement des fonctionnalités devant être assurées par la classe n'est pas intégralement défini par les tests.</li>
</ol>
<p>Et le mot le plus important dans ce qui précède, outre le mot <em>publique</em>, est <em>simple.</em></p>
<p>Par <em>simple</em>, j’entends même naïf, dans le sens ou il est par exemple permis de faire de la duplication de code, d'utiliser des algorithmes peu efficaces, et surtout de ne pas se soucier de l'encapsulation.</p>
<p>L'encapsulation n’apparaît que lors de l'étape de <a href="http://fr.wikipedia.org/wiki/Refactorisation">refactorisation</a>, qui intervient à l'issue du processus décrit ci-dessous, et qui a pour but de passer d'une implémentation naïve à une implémentation faite dans les règles de l'art, avec la garantie que la classe continuera à se comporter comme elle le doit grâce aux tests écrits précédemment.</p>
<p>Comme vous pouvez le constater, il n'y a pas de place pour des tests relatifs aux méthodes protégées ou privées dans ce processus, puisqu'elles sont une conséquence de la <a href="http://fr.wikipedia.org/wiki/Refactorisation">refactorisation</a> et n'apparaissent aucunement lors de l'écriture des tests.</p>
<p>Enfin, J'ai un autre argument pour justifier le fait qu'il est inutile de tester les méthodes protégées ou privées d'une classe.</p>
<p>L'encapsulation ayant pour but de masquer l'implémentation d'une classe, elle permet de faire de la <a href="http://fr.wikipedia.org/wiki/Refactorisation">refactorisation</a> à tout moment au cours de la vie de la classe sans impacter l'utilisateur de la classe.</p>
<p>Il est donc tout à fait possible de modifier de manière très radicale le fonctionnement interne de la classe sans que l'utilisateur final en ait conscience.</p>
<p>Or, si les méthodes privées et protégées sont testées, il faut que le développeur, lorsqu'il effectue la <a href="http://fr.wikipedia.org/wiki/Refactorisation">refactorisation</a>, modifie également les tests, ce qui représente un travail supplémentaire non négligeable.</p>
<p>De plus, lors de ce processus, les tests ne sont pas censés être modifiés puisqu'ils sont là pour garantir que le comportement de la classe ne change pas malgré les modifications effectuées sur l'implémentation.</p>
<p>Évidement, le camp adverse a également des arguments lui permettant de justifier la définition de tests pour les méthodes privées et protégées, et celui qui revient le plus souvent est qu'il est difficile de localiser précisément un bug ou une régression si ces méthodes ne sont pas testées.</p>
<p>Je répond à cela qu'un test unitaire n'est pas un débugger et qu'il ne remplace pas un cerveau, mais vous vous doutez bien qu'il est assez mal reçu.</p>
<p>L'autre argument récurrent est que, selon eux, je pense que l'unité dans mes tests est la classe, alors qu'ils considèrent que l'unité est la méthode.</p>
<p>J'avoue que ce n'est pas entièrement faux, même si je me plaît à préciser que pour moi, l'unité est la méthode <em>publique</em> et non la classe.</p>
<p>Évidemment, ce débat est une bataille de chapelles, et en tant que tel, il n'aura jamais de réponse absolu, d'autant que le monde des tests unitaires évolue.</p>
<p>Il y a en effet des gens comme <a href="http://hoa-project.net/Contact.html">Ivan Enderlin</a>, le créateur du framework <a href="http://www.php.net/">PHP</a> <a href="http://hoa-project.net">Hoa</a>, dont c'est le métier de réfléchir à ces problématiques.</p>
<p>Et à force de réfléchir, il a trouvé un moyen novateur de réaliser des tests, qui n'est pas une autre façon de faire des tests unitaires, mais plutôt une technique complémentaire qui permet entre autre de ne pas se préoccuper de l'encapsulation.</p>
<p>Je ne vous donnerais aucun détail sur ce qu'il propose, car je considère que c'est à lui de le présenter, et de plus, je pense que cela mériterait bien plus qu'un simple billet.</p>
<p>J'ajouterais de plus que je ne suis pas entièrement convaincu par ce qu'il propose, et je suis donc assez mal placé pour parler de son travail.</p>
<p>Je considère cependant qu'il a trouvé une nouvelle voie qu'il est intéressant de suivre un minimum, ne serait-ce que pour voir ou elle peut mener.</p>
<p>Vous l'aurez compris, le débat sur l'intérêt de tester les méthodes privées et protégées n'est pas prêt de se terminer, la preuve en étant que ce débat a, depuis la question d'origine, débordé du cadre d'<a href="http://blog.mageekbox.net/?post/2010/11/17/../?post/2010/10/11/Teasing-4">Atoum</a>, puisque j'ai eu l'occasion de discuter de ce sujet sur <a href="http://www.twitter.com/mageekguy">twitter</a> ainsi qu'au <a href="http://blog.mageekbox.net/?post/2010/11/15/Compte-rendu-du-forum-PHP-2010-1">forum PHP 2010</a> avec des gens totalement externes au projet.</p>
<p>Et pour ceux qui se poseraient éventuellement la question, <a href="http://blog.mageekbox.net/?post/2010/10/11/Teasing-4">Atoum</a> est potentiellement capable de gérer les deux philosophies, et je n'ai aucun problème pour travailler avec quelqu'un qui défend un point de vue opposé au mien de manière constructive, bien au contraire.</p>
<p>Je considère en effet que c'est de la différence, du débat, qu'émerge les idées novatrices, car cela nous force à voir les choses sous un autre angle.</p>
<p>Je suis donc extrêmement heureux d'avoir une force contradictoire au sein de l'équipe de développement !</p>http://blog.mageekbox.net/?post/2010/11/17/La-guerre-des-tests#comment-formhttp://blog.mageekbox.net/?feed/atom/comments/210