Gilded Rose Kata in Python
This is a refactoring exercise based on the famous GildedRose-Refactoring-Kata repository maintained by Emily Bache. This kata contains simple code in many different programming languages that need to be refactored and improve code quality.
The source program has two classes
Item class describes the properties of an item and contains the attributes –
quality. The GildedRose class has a method
update_quality() that updates the
sell_in date and
quality of the items on a regular basis.
The existing codebase provides support for three products, however, the addition of a new product Conjured breaks the existing business logic and hence needs remodeling. There are a few business rules and constraints that need to be taken care of while refactoring the code.
- All items will have the three attributes as follows:
name– Name of the item.
sell_in– The number of days within which the item should be sold off.
quality– The quality of the item; denoted by an integer.
- Every day, the method
update_quality()is executed, which lowers the values for
- Once the
sell_indate has passed, the value for
qualitydegrades twice faster.
- There are also rules for each of the items that are currently present which are as follows.
- AgedBrie increases its
qualitywith a decrease in
- BackstagePasses has the following two rules:
sell_invalue is more than 10,
qualityincreases by 1.
sell_invalue is less than 10,
qualityincreases by 2.
sell_invalue is less than 5,
qualityincreases by 3.
sell_invalue is less than 0,
qualityis set to 0.
- Sulfuras is legendary, so
qualityis always 80 and
sell_invalue never decreases.
- A new item – Conjured is to be added with the following rule:
- Conjured items degrade
qualitytwice as fast as normal items.
- Conjured items degrade
- AgedBrie increases its
There are a few constraints that we need to consider before refactoring.
- We are not allowed to alter the
Itemclass or the attributes of the
- The minimum and maximum values for
qualitycan only be 0 and 50 respectively.
For more detailed requirements, you can refer to the original text.
Reason to Refactor
If you browse through the existing code, you can see that all the business rules are implemented in a single class and inside a complex nested if-else statement. Following are a few reasons why I think the code should be refactored and developed in a modular way.
- Readability – The current logic is very difficult to read as everything is contained in a single class with multiple nested if-else statements.
- Duplicate logic – There are a few logics that are duplicated. This can be written in a better way by using a parent-child class relationship.
- Implementation of the new item Conjured will need to modify the current if-else statements and that might cause harm to the existing logic.
My approach to implement and refactor the program would be as follows.
- Writing extensive unit test cases to preserve and validate the existing business logic.
- For the codebases to be modular, I would break down the project structure into multiple files as follows under the
gilded_rose.py– This is the refactored base file that contains the
GildedRoseclass and the
update_quality()method. I have removed the complex if-else statements from this class and implemented them separately.
product_list.py– This file contains the
ProductListclass which is an enumerated list of all the available items. New items can be added to the list without affecting the business logic for other products.
item.py– This is the definition of the class
Item. It is the parent class of any item and contains methods to update the values for
quality. Any regular product which satisfies the normal business rules can be inherited from this class and if there are some specific rules, then the inherited child classes can modify the logic for the
products.py– This file contains a
Productclass that will basically route the call to the respective product classes when the instances are created. In addition to that, I have added a separate class for each of the existing items that do not follow the normal business rules. All these child classes inherit from the parent
UML Class Diagram
The UML class diagram of the refactored code is provided below.
In order to validate the existing logic and new business rules, several unit test cases have been written which are found under the
tests directory. It contains several test files as follows.
|Test cases for regular products||test_gilded_rose_regular.py|
|Test cases for specific products||test_gilded_rose_brie.py|
|Test cases for specific products||test_gilded_rose_backstage.py|
|Test cases for specific products||test_gilded_rose_sulfuras.py|
|Test cases for specific products||test_gilded_rose_conjured.py|
|Test for other products||test_gilded_rose_other.py|
Executing the test cases
First, you need to create a python virtual environment for the program.
python -m venv .venv source .venv/bin/activate pip install --upgrade pip
This will start the virtual environment and update the pip. Once the virtual environment is up and running, the test cases can be executed from the terminal as follows.
python -m unittest discover tests
If the tests are configured within the IDE (VSCode or PyCharm), then the tests can be executed from within the IDE itself.