Retour

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# ?

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é. 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.   

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.     Quand on lit le code de l’Olymppien, on s’aperçoit que :
  • 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 :      Avec ce modèle c’est un peu mieux :
  • 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é.
On peut aussi noter que la sémantique d’une exception indique un cas exceptionnel. Alors que l’absence de capsule dans une machine à café semble un simple sous-cas du cas nominal.

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” ? 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 :
  • 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.
  Héphaïstos est content de cette solution. Il allait choisir cette solution quand Hermès, de retour à Olympp lui dit : “Tu pourrais utiliser les Options !”. Interloqué Héphaïstos répond : “Qu’est-ce que les options ? Et depuis quand t’y connais tu en informatique ?” Hermès, mécontant de l’acceuil : “Tu n’a qu’a aller voir à cet endroit : http://codinghelmet.com/articles/custom-implementation-of-the-option-maybe-type-in-cs . Sur ce j’y vais. ”   

E - Les options

  Avec la solution dont lui à parlé Hermès, Héphaïstos obtient cette machine à café suivante :    Et il l’utilise comme ceci : Cette solution est très bonne :
  • 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>.
C’est décidé, Héphaïstos créera ce modèle de machine à café.

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.     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.  

4 - Conclusion

Avec ces techniques il est possible de se passer de la valeur null en toute occasion. Sans cette valeur le code est plus sûr, plus expressif, plus concis, plus modulaire et plus facilement modifiable. Bref, il fait le café :) !  

5 - Source

https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/ https://www.lucidchart.com/techblog/2015/08/31/the-worst-mistake-of-computer-science/ https://www.yegor256.com/2014/05/13/why-null-is-bad.html http://codinghelmet.com/articles/custom-implementation-of-the-option-maybe-type-in-cs https://dev.to/integerman/safer-code-with-c-8-non-null-reference-types-4f2c