Saturday, April 18, 2015

Kata: Gilded Rose in Clojure (III) -> Updating conjured items by decoration

After the two previous posts (Clarifying conditional logic and Replacing conditional with polymorphism using multimethods), I had this version of the code:

that was being used from the gilded-rose.core name space:

Then I started introducing the new conjured items functionality using TDD.

These are the new tests for conjured items:

and these is the resulting code of the gilded-rose.item-quality name space:

Notice the change in the update multimethod dispatch function: Now instead of being :name as before, it's a function that returns the dispatch value "Conjured" if the item is a conjured one (if its name contains "Conjured"), or just :name otherwise.

I also added a defmethod for the "Conjured" dispatch values which decorates update by calling it twice passing the not conjured version of the item.

This simple decoration made all the tests shown before pass, except the "Conjured Sulfuras is still immutable" one. For this test to pass I had to modify the degradable-item? query in the gilded-rose.core name space:

That's all. You can follow the whole process I've just described having a look at the commits I did after every small refactoring (look at commits from Conjured items quality decreases by two each day before sell date on)

Starting from the polymorphic version of update, we had got through refactoring, made it easy to add the new conjured items functionality as a decoration of update.

Compare this Clojure version of Gilded Rose with the Java version I did some time ago.

This is the last post in this series about the Gilded Rose kata in Clojure:
  1. Clarifying conditional logic
  2. Replacing conditional with polymorphism using multimethods
  3. Updating conjured items by decoration

Kata: Gilded Rose in Clojure (II) -> Replacing conditional with polymorphism using multimethods

At the end of the previous post (Clarifying conditional logic), I had this version of the code:

Even though the conditional logic in the update-item-quality function read much better than the original one, I completely got rid of it using the replace conditional with polymorphism refactoring. I used multimethods which is one of the ways of achieving polymorphism in Clojure.

To start this refactoring, I first renamed the update-item-quality function to update-item-quality-old. Then I created a multimethod called update-item-quality with :name as dispatch function and with a method associated to its default dispatch that called the update-item-quality-old function:

This new version behaved exactly like the previous one and it was a good base to do the refactoring in small steps (one branch at a time) because every dispatch value not associated yet with a function was calling the old code thanks to the default dispatch.

Next I wrote a defmethod associated to the Age Brie item, copied the code from the Age Brie branch in update-item-quality-old into it and deleted the branch and the aged-brie? query helper. After this change all the tests were still passing.

Then I continued eliminating the rest of the branches in the cond of the update-item-quality-old function and their associated query functions.

Once I finished wit all the branches, I had replaced the conditional with polymorphism and could safely delete update-item-quality-old. I also changed the method associated with the default dispatch to make it just returned the received item (this was what got executed for the Sulfuras item and it corresponded to the :else branch of the cond in the old code).

To finish the refactoring I extracted the update-regular-item-quality helper to remove some duplication in some defmethods and moved the code that updated the quality into a separate name space, gilded-rose.item-quality:

You can follow the whole process I've just described having a look at the commits I did after every small refactoring (look at commits between Introduced a multimethod which now it's defaulting to the old update item quality function and Added helper to make all items age one day)

After this refactoring I had a nice polymorphic solution that made it easier to add the new conjured items functionality.

The next and last post will show how I modified the multimethod dispatch function to decorate the update quality behavior when it was updating a conjured item.

This is the second post in a series of posts about the Gilded Rose kata in Clojure:
  1. Clarifying conditional logic
  2. Replacing conditional with polymorphism using multimethods
  3. Updating conjured items by decoration