Mercredi 13 janvier 2021
La Programmation Orientée Objet (POO), ce n’est pas null….
By Boris
********************************************
Null est très critiqué dans le monde de la programmation. La dernière version de C# (C# 8.0) permet de rendre les références non-nullable . Selon Tony Hoare l’ajout de référence null pour le langage Algol 60 aurait coûté plusieurs milliards de dollars en gestion d’erreur et en temps perdu ! Pourquoi se passer de null et par quoi le remplacer en programmation orienté objet, ici en C# ?
Un café se boit :
Lui utilise la machine à café, puis boit le café.
Pour la machine à café simple de son rêve :
Après ce rêve, d’une merveilleuse simplicité, Héphaïstos se réveille et entreprend de créer une machine à café, dans le monde réel.
Quand on lit le code de l’Olymppien, on s’aperçoit que :
Avec ce modèle c’est un peu mieux :
Comme ce café ne fait rien (comme la plupart des null object), on peut réutiliser la même instance à chaque fois.
Cette solution est mieux que la précédente :
Et il l’utilise comme ceci :
Cette solution est très bonne :
Ici, on voit que la variable privée “_title” est null tant qu’on n’a pas appelé une première fois la propriété “Title”.
Pour éviter d’avoir cette variable à null, on peut utiliser le design pattern state.
Pour ce faire nous définissons 2 états, 1 états non-initialisé et un état initialisé.
Ces états mettent tous les 2 à dispositions un Titre.
Lors de l’appel au titre de l’état non-initialisé, la configuration passe à l’état initialisé.
A l’initialisation de la configuration, son état est “à initialiser”.
Lors du premier appel à l’état, on transitionnera vers l’état “initialisé”.
Nul part la valeur null n’est présente dans cette implémentation.
On voit ici que la solution sans null est plus longue à mettre en place. Il existe des cas ou utiliser null reste une solution acceptable.
1- Pourquoi c’est null
Le premier reproche que l’on peut faire à la valeur “null”, c’est son absence de typage. Cette absence de typage rend impossible la détection d’erreur à la compilation. Et ainsi retarde la détection de certaines erreurs de programmation. Ensuite, cette valeur n’a pas de sémantique claire. Selon les cas, elle peut signifier : une valeur par défaut, une valeur non initialisée, une erreur, un résultat vide ou encore une absence de résultat. Son utilisation complexifie ainsi la compréhension du code et nécessite une analyse complémentaire pour lever toute ambiguïté. Enfin “null” n’est pas un objet et de ce fait ne peut être manipulé comme un objet, ni ne remplit le contrat défini par le type de l’objet. Cela nous oblige à vérifier dans l’ensemble du code si l’objet reçu n’est pas null avant d’y avoir recours. Cela va à l’encontre du motto “Tell don't ask” de la POO.2- Les alternatives
A - Un joli rêve
Afin d’illustrer mon propos, je vous propose l’histoire d’Héphaïstos, Dieux des développeurs et olympien de renom : celui-ci, paisiblement endormi (dans les bras de Morphée), rêve qu’il se prépare un café pour le petit déjeuner, à l’aide de sa machine à café DIY. Tout est beau et simple dans son rêve : Une machine à café sait faire du café.



B - La dure réalité
Et là, c’est le drame, la machine à café à un stock limité de capsule. Pour régler ce problème, Héphaïstos choisit de retourner la valeur null quand il n’y a plus de capsule.

- Il va a chaque appel falloir tester la présence d’un retour null, sinon on risque de lancer une NullReferenceException au moment de l’appel et pas au moment où l’erreur a été constaté.
- On ne peut plus aveuglément donner des ordre à l’objet qui nous ai retourné. Ce qui nous pousse vers un mode de programmation impératif.
- Le code est pollué par le traitement de null devenant ainsi moin lisible.
- Recevoir valeur null ne nous indique pas la cause du problème.
- On a violé le principe de responsabilité unique : on a du modifier le code de l’olymppien en plus de celui de la machine à café.
C - Une alternative exceptionnelle
Ni une, ni deux, Héphaïstos change ses plans. Il se dit qu’il pourrait créer une MachineEmptyException et une machine à café l’utilisant :

- L’olymppien reçoit une information plus précise quant à la cause du problème.
- Le problème est révélé au moment de sa découverte.
- S’il ne s’attend pas à recevoir d’exceptions notre olymppien risque de ne pas la réceptionner et causer l'arrêt du programme.
- C’est toujours à l’olymppien de savoir quoi faire en cas de non réception du café.
D - Un objet null
Avant de choisir cette solution, Héphaïstos aimerait expérimenter une autre solution. Pourrait-on retourner un objet “café vide” ?


- L’olymppien n’a plus à se soucier du résultat retourné par la machine à café. Seul les potentiels effets du café ne seront pas appliqués, si c’est un NullCafe qui est retourné.
- Cette solution est totalement transparente pour l’olymppien. Elle peut le surprendre.
- Elle necessite la définition d’un objet pour gérer ce cas spécial.
E - Les options
Avec la solution dont lui à parlé Hermès, Héphaïstos obtient cette machine à café suivante :

- Elle indique que la présence de café n’est pas garantie au retour de la machine à café grâce à son type de retour.
- Elle à l’avantage de ne pas nécessiter la définition d’un objet supplémentaire pour chaque cas où l’on a à traiter une valeur vide.
- Par contre, elle nécessite un peu plus de travaille initial pour créer le type Option<T>.
3 - Un nombre de null nul
Laissons Héphaïstos à ses machines à café et intéressons nous à un autre cas où l’on peut rencontrer la valeur null : Lorsqu’un objet n’est pas totalement fini d’initialiser lors de sa construction Prenons l’exemple de la gestion d’un cache. Voici une configuration qui met en cache une chaîne de caractères, après la première demande de la chaîne.




