The fanciest pizzeria in town - Pythonia - prides itself in the fine dining experience it offers its guests, with soft mood lighting, gentle background music, and of course, delicious Italian food! 🍕
This evening they’ll be introducing a team of robot staff - programmed in Python - to ensure efficient customer service.
Unfortunately, the management has just realized that the robots have only been programmed to serve groups of two guests. 🤦 Let’s help them quickly fix their robots before the restaurant opens!
def serve_group_of_two():"""Serves a party of two hungry customers.Ensures an unforgettable experience!"""greet_guests()table_number = prepare_table(2)for guest in range(0, 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()
Our first group of guests is a birthday party of 15 people. How would you modify the code to accommodate them (we’ll just change it from 2 to 15 people to start with - we can always generalize it to
Sounds easy - can’t we just change all of the 2s to 15s?
Sure, but let’s first double-check each function within the code to make sure that this would be correct:
greet_guests()table_number = prepare_table(15)lead_customers_to_table(table_number)
This tells the robot to prepare a table for 15 guests, and leads them to their table. All good so far.
The code doesn’t mention “2,” but it turns out that this fills a carafe with 800ml of water for the guests to share (400ml each). But that’s not going to be much for our group of 15! Better change this to:
fill_water_carafe(15 * 400)
for guest in range(0, 15):lay_spoons_on_table(15)
Okay, now things are starting to get silly - the robots will give each of the guests 15 spoons. Is there even enough space on the table for all this silverware?
lay_spoons_on_table() should always give two spoons; one for the soup, and one for the dessert.
This is independent of the number of guests - if we change the gentle background music volume from level 2 to level 15, we will deafen everyone. 🔊
Okay, guests need a menu each, so that makes sense!
wait_minutes(15)drinks_order = take_order(table_number)process_order(drinks_order)
Why are they waiting so long to start to take their order? Let’s keep it at 2 minutes, regardless of the size of the group.
So that’s everything finally fixed, just in time for the birthday party to arrive. 🥳 It would have been easier if the original developer wrote this function using the constant design pattern!
How to Use the Constant Design Pattern
The problem is that the code was full of unexplained numbers, so it wasn’t clear how a change in one value would affect others.
Here’s how you could fix it using the constant design pattern:
Identify any number (or other variable) used in multiple places, or whose meaning is unclear.
Declare its value as a variable with a clear name - even if you don’t intend to change it. E.g.,
number_of_guests = 2.
These constant values will often be used by multiple functions, classes, and files in a project, so according to PEP 8, these should be defined near the top of the file in capital letters, e.g.,
NUMBER_OF_GUESTS = 2.
Rephrase all statements that rely on this number using the new constant value.
Then, if a developer ever needs to modify the behavior in the future, they change the definition of the variable: e.g.,
NUMBER_OF_GUESTS = 15.
Let’s fix the original code so that it’s much easier to maintain in the future!
When to Use the Constant Design Pattern
It’s worth bearing this pattern in mind whenever you’re writing a fixed number or string in your code, because if it changes, a future developer will have difficulties!
What happens if I know that a value isn’t going to change? Is there any point in using the constant design pattern then?
You’d be surprised how often you have to change things that you thought were set in stone! But there’s another reason for using the constant design pattern.
Imagine my team is writing a Python module that performs lots of geometry with circles.
One of us uses 3.14159265 for the value of π, another one uses 3.14, and I use the continued fraction approximation 355/113.
We’re going to start getting inconsistent behavior because of these different approximations.
It would be better to use the constant design pattern for π by writing something like:
MATH_PI = 3.1416
Then every time that someone has to use π in a formula, they can use
MATH_PI . Problem solved!
def find_circumference(radius):return 2 * MATH_PI * radius
The constant design pattern is a simple pattern affecting a single value.
Repeated values can be defined once in the application.
Future developers can easily understand the significance of the value.
Future developers can easily modify the value if requirements change.
Many surprising bugs can be avoided using the constant design pattern.
In the next chapter, we’ll explore the decorator design pattern, which affects the design of entire functions.