Talents en applications - Blogue | Nexapp

Augmenter l'encapsulation en déplaçant le code hors des classes

Rédigé par Martin Boucher | May 21, 2024 7:18:59 PM

Dans cet article, je propose une astuce pour augmenter l'encapsulation de votre code. Je l'utilise systématiquement. Elle a l'avantage de s'appliquer sans réfléchir (ou presque 😊). La prise de décision est simple.

Définition de l'encapsulation

L'encapsulation fait référence au regroupement des données avec les mécanismes qui opèrent sur elles. L'encapsulation présente deux avantages principaux :

  • Contrôle d'accès aux données : Les données d'un objet sont cachées à l’intérieur de la classe et ne peuvent être modifiées que par des méthodes spécifiques de cette classe (généralement appelées méthodes d'accès ou accesseurs). Cela permet de maintenir l'intégrité des données en évitant les modifications incontrôlées.

  • Modularité : L'encapsulation sépare les détails de l'implémentation d'une classe de son utilisation. Cela signifie que le code qui utilise une classe n'a pas besoin de comprendre comment cette classe est implémentée. Cela facilite la maintenance et l'évolution du code.

Un exemple d'encapsulation

Je joue au jeu Arkham Horror: The Card Game. Ce jeu de cartes nécessite l'achat de paquets de cartes à jouer pour constituer une collection. J'aimerais avoir une application pour gérer ma collection de cartes (évidemment, je préfère la programmer plutôt que d'utiliser Excel 😉).

Heureusement, il y a ce site, mais surtout leur API. Dans l'exemple suivant, j'ai un dépôt pour obtenir une carte depuis cet API :

J'ai ce dépôt, qui récupère les données de l'API sur les lignes 14 à 16, puis délègue à un mappeur de données toCard sur la ligne 17 pour transformer les données reçues du serveur en un objet dont j'ai besoin pour mon application.

Avez-vous remarqué que ce mappeur de données toCard n'utilise pas this?

Bien que ce mappeur de données ait une forte cohésion avec les données reçues du serveur, il a très peu de couplage avec la classe. Il peut être extrait vers une fonction. Essayons ça!

En termes de comportement pendant l'exécution, c'est la même chose : nous récupérons les données du serveur, nous les transformons.

Pour l'interface publique de ce module, le mappeur de données est tout aussi caché qu'auparavant. Il n'est pas exposé aux utilisateurs du dépôt.

Qu'est-ce qu'on y gagne? L'encapsulation.

Comment l'extraction du mappeur de données toCard en dehors de la classe peut-elle améliorer l'encapsulation?

Examinons tout d'abord le contrôle d'accès aux données. Restreindre l'accès aux données améliore l'encapsulation. C'est le cas ici, et c'était facile parce que les données n'étaient pas utilisées. Pourquoi laisser le mappeur de données toCard accéder à des données dont il n'a pas besoin?

C'est comme si vous aviez des clés inutiles sur votre trousseau.

Qu'en est-il de la modularité? Le dépôt utilise le mappeur de données. Il n'a pas besoin de l'implémenter, et le mappeur de données n'utilise pas le client HTTP. Avec ce refactoring, nous avons obtenu deux morceaux de code liés mais indépendants. Chacun d'entre eux peut évoluer sans nécessairement impacter l'autre.

L'encapsulation est encore plus utile

En tant que développeurs, on lit beaucoup plus de code qu’on en écrit (90% de lecture et 10% d'écriture me rappelle mon collègue Alexandre Rivest dans cet article). Il est de la plus haute importance que l'interprétation qu’on en fait soit correcte.

Après tout, il s'agit de communication.

Représentons les deux situations à l'aide de diagrammes :

À gauche, nous avons le mappeur de données dans la classe ; à droite, le mappeur de données est extrait.

Pourquoi y a-t-il une intersection entre le client HTTP et le mappeur de données dans la classe?

Ce que je veux illustrer avec cette intersection, c'est le flou, cette possibilité qu'il y ait un lien tant que nous n'avons pas pris le temps de creuser les détails.

On navigue dans le code comme on le fait sur une carte interactive (ex. : Google Map) : plus on survole le code de haut, moins on voit les détails. De toute façon, on ne veut pas les voir. On veut pouvoir trouver notre chemin sans avoir à explorer tous les recoins.

Sur le côté gauche, on survole une classe. On voit deux méthodes : la classe a un membre. Quelles méthodes utilisent ce membre? Que font-elles avec ce membre? Comment ces méthodes fonctionnent-elles ensemble?

Ce sont autant de questions qu'on se pose inconsciemment lorsqu'on analyse du code.

Sur la droite, on survole une classe et sa méthode. Une fonction privée est disponible dans le module. On sait déjà que la classe n'a pas accès à l'implémentation de la fonction, et que la fonction n'a pas accès à l'implémentation de la classe.

L'isolement est explicite.

Conclusion

Lorsque vous constatez que cette méthode n’utilise pas this, vous devez l'extraire de la classe. Ce faisant, vous augmentez l'encapsulation puisque vous obtiendrez deux capsules plus petites et plus cohésives.

Les capsules obtenues peuvent évoluer indépendamment les unes des autres sans s'influencer mutuellement. Elles peuvent être déplacées vers d'autres modules ou packagées plus facilement.

Cette isolation sera exposée explicitement. Le code sera plus compréhensible sans avoir à l'examiner de près.