Imaginons une pizzeria qui commence à connaître un franc succès... 🍕 Appelons-la Pythonia !
Chez Pythonia, on est fier de l’expérience de qualité qu’on offre aux clients, avec des lumières tamisées, de la musique d’ambiance douce, et bien sûr de la délicieuse cuisine italienne ! 😋
Ce soir, on présentera pour la première fois une équipe de robots — programmés en Python — afin d’assurer un service efficace à tous les convives. 🤖
Malheureusement, la direction vient de se rendre compte que les robots ont été programmés uniquement pour servir des groupes de deux convives. 🤦 Aidons-les à réparer rapidement leurs robots en urgence avant l’ouverture du restaurant !
def serve_group_of_two():
"""Sert un groupe de deux clients affamés.
S'assure d'une expérience inoubliable !
"""
greet_guests()
table_number = prepare_table(2)
for guest in range(2):
lay_spoons_on_table(2)
lead_customers_to_table(table_number)
fill_water_carafe(800)
adjust_music_volume(2)
present_menus(2)
wait_minutes(2)
drinks_order = take_order(table_number)
process_order(drinks_order)
# ...
present_bill()
thank_guests()
Notre premier groupe de clients est là pour un anniversaire et compte 15 personnes. Comment modifieriez-vous le code pour répondre à leurs besoins (pour commencer, nous nous contenterons de remplacer 2 personnes par 15 personnes – nous pourrons toujours généraliser avec num_customers
plus tard) ?
Ça m’a l’air facile – est-ce qu’on peut simplement remplacer tous les « 2 » par des « 15 » ?
Pourquoi pas, mais passons d’abord sur chaque fonction contenue dans le code pour nous assurer que cette solution serait correcte…
greet_guests()
table_number = prepare_table(15)
lead_customers_to_table(table_number)
Ce code dit au robot de préparer une table pour 15 personnes, et de les amener à leur table. Jusqu’ici tout va bien.
fill_water_carafe(800)
Le code ne mentionne pas « 2 », mais il s’avère qu’il remplit une carafe avec 800 ml d’eau, à partager par les convives (soit 400 ml chacun). Ce ne sera pas suffisant pour notre groupe de 15 ! Il vaut mieux que nous remplacions le code précédent par ceci :
fill_water_carafe(15 * 400)
Et ensuite ?
for guest in range(15):
lay_spoons_on_table(15)
Bon, maintenant ça devient un peu ridicule – les robots vont donner 15 cuillères à chacun des clients. A-t-on vraiment besoin de 15 couverts pour manger ? ?
lay_spoons_on_table()
doit toujours donner 2 cuillères, une pour la soupe et une pour le dessert.
adjust_music_volume(15)
Évidemment, ce paramètre est indépendant du nombre de clients – si nous passons le volume de notre douce musique de fond du niveau 2 au niveau 15, nous allons assourdir tout le monde… 🔊
present_menus(15)
D’accord, les clients ont besoin d’un menu par personne, donc c’est logique !
wait_minutes(15)
drinks_order = take_order(table_number)
process_order(drinks_order)
Pourquoi attendons-nous si longtemps avant de commencer à prendre leur commande ? Gardons ce réglage fixé à 2 minutes, quelle que soit la taille du groupe.
Et voilà, tout est enfin réparé, juste à temps pour l’arrivée des convives pour l’anniversaire. 🥳 Si seulement le développeur qui a écrit cette fonction au départ avait utilisé le pattern Constant, cela aurait été beaucoup plus simple !
Comment utiliser le design pattern Constant
Le problème que nous avons rencontré, c’est que le code était plein de nombres non expliqués. Du coup, la façon dont un changement sur une valeur allait affecter les autres valeurs n’était pas claire.
Voici comment nous pourrions résoudre ce problème en utilisant le design pattern Constant :
Identifiez tout nombre (ou autre variable) qui est utilisé à plusieurs emplacements, ou dont la signification n’est pas claire.
Déclarez sa valeur en tant que variable globale (dans la portée du module), avec un nom clair – même si nous n’avons pas l’intention de la changer. Par exemple :
number_of_guests = 2
.Ces valeurs constantes seront souvent utilisées par plusieurs fonctions, classes et fichiers au sein d’un projet, donc d’après la PEP 8, elles devraient être définies vers le haut du fichier en majuscules, par exemple
NUMBER_OF_GUESTS = 2
.Reformulez toutes les déclarations qui reposent sur ce nombre en utilisant la nouvelle valeur constante.
Ensuite, si un développeur a un jour besoin de modifier ce comportement, il n’a plus qu’à changer la définition de la variable, tout simplement ! Par exemple :
NUMBER_OF_GUESTS = 15
.
Travaillons ensemble à l’amélioration de notre code de départ, pour qu’il soit beaucoup plus facile à maintenir à l’avenir !
Si vous êtes bloqué, vous pouvez consulter la solution.
Quand utiliser le design pattern Constant
Gardez en tête ce pattern quand vous écrivez un nombre ou une chaîne fixe dans votre code, car en cas de changement, un futur développeur rencontrerait des problèmes !
Et si je sais qu’une valeur ne changera pas ? Est-ce qu’il y a une raison d’utiliser le design pattern Constant dans ce cas ?
La fréquence à laquelle il vous faudra modifier des choses que vous pensiez gravées dans la roche éternellement vous surprendrait ! Mais il y a en réalité une autre raison d’utiliser le design pattern Constant.
Imaginez que mon équipe écrive un module Python qui fasse beaucoup de géométrie avec des cercles.
L’un d’entre nous utilise 3.14159265 comme valeur de π, un autre utilise 3,14, et j’utilise la fraction continue.
Nous allons commencer à voir des comportements étranges et incohérents à cause de ces différentes approximations.
Il serait préférable d’utiliser le design pattern Constant pour π, en écrivant par exemple :
MATH_PI = 3.1416
Puis, chaque fois que quelqu’un aura besoin d’utiliser π dans une formule, il pourra simplement utiliser MATH_PI
. Problème résolu !
def find_circumference(radius):
return 2 * MATH_PI * radius
Le design pattern Constant est aussi une forme de documentation du code : il met des mots sur des valeurs « brutes ». Ainsi, NUMBER_OF_MONTHS
sera toujours plus clair que 12
. On appelle les nombres mal documentés des « nombres magiques ».
En résumé
Le design pattern Constant est un modèle simple qui n’affecte qu’une seule valeur.
Les valeurs qui se répètent peuvent être définies une seule fois dans l’application.
Les futurs développeurs pourront facilement comprendre la signification de la valeur.
Les futurs développeurs pourront facilement modifier la valeur si les prérequis sont modifiés.
De nombreux bugs étonnants peuvent être évités en utilisant le design pattern Constant.
Au chapitre suivant, nous explorerons le design pattern Décorateur, qui affecte le design de fonctions entières.