The pizza shop is expanding it's offerings! CALZONES!
We'll do a 1/2 calzone and a full calzone! $8 and $14 respectively.
Based on how we did the Medium pizza last time... Not expecting much work for these. Which... THAT'S THE POINT! µObjects make this easy.
Removing a topping... Excellent. A new behavior. New behaviors are where modificaations get interesting. Medium Pizza and Calzones; that's more of the same behavior.
Let's get the calzone's out of the way... I mean... Let's implement our clients new offerings!
Then do the new stuff... I mean... Then allow customers to change their mind.
Looking through the code I see that the "pizza" in the descriptions is hard coded pretty deep in. This will need to be changed for calzones. Not hitting it quite yet; but wanted to point it out here. Checking through some code before you begin may help later identify places where you'll have to make changes.
OK - Code time.
I'm starting with the 1/2 calzone.
Doing the price first.
I'm going to C&P a pizza; throw exceptions for each non-implemented piece. Unlike when I did the medium and left the large values in. Didn't like that much.
Which made my first test fail. Good. So much nicer when it's Red first. I am still cheating a bit by the copy and paste; I know that. The focus here is on the µObjects more than the TDD aspect. We have tests. It's the only way to develop. But as I do in kata's - I pick a focus to do very strictly, a secondary to include. This time; µObjecting is the primary. Testing is going to be let a little loose for these examples.
I've created the HalfCalzone
and have the price working in commit e2012bf where I also moved a bunch of files.... which I forgot to commit first.
Next up is the larger required change - Description. Not sure how this will play out... EXCITING!
First we need to add a type. I use NCrunch to run tests real time. It's nice enough that I've bought a personal license for it. Much like I have for Resharper. I have the JetBrains All Products Pack and, for me, totally worth it.
OK - Back to pizza... errr.... Calzones.
NCrunch is showing where the exception is; and it's on trying to get the type. Which makes a bit of sense since the type is what the description is built off of.
Adding a HalfCalzone
to PizzaType
gets rid of the exception; but we're not the right result.
I think the simplest would be to pull pizza
into the PizzaType
. Simple is the way to go... Let's try it.
It makes a bit more sense this way, now.
Changed PizzaType
slugs to have "pizza" in their descriptor. Fixing the HalfCalzone
to be "1/2 Calzone"
and now passing.
We had to take out pizza
from the NoToppingsPizzaDescriptionAction
and ToppingsPizzaDescriptionAction
as seen in commit f068583
The last bit for our 1/2 calzone is adding toppings.
Done with 1/2 calzone in commit 1bbf5c0. For the Full Calzone; it's a C&P of the 1/2 calzone and it's tests.
I'm gonna do the entire batch for focus reasons. I want to get to the new behavior in this example.
Did the quick addition of a Full Calzone. Updated everything... Works. All test pass. This is a cheat - Do this working production code; there's some hand slapping.
Check out commit 8aeb3f8 for the cheaty details.
Remove a topping
And now... Removing a topping! Which is mostly just like adding a topping. But let's get a test in place... which looks like a add topping test...
Using a test for adding three toppings; I remove one via the RemoveTopping
method... which doesn't exist.
Hmm... going into this. I'm adding a method to both Pizza
and Toppings
via one test. While... Yes. This will work. It's not right.
I can cheat a bit; but I need to write tests around Toppings for this addition. It's not refactoring behavior into a class and confirming by existing tests; it's new behavior. It needs TDD.
A git reset --hard
later; and we'll write some ToppingsTests
.
A test to ensure removing something not already present does not throw.
Simple enough
If you looked at that you may notice that I have some lines commented out - mostly lazy.
But I need them commented out so my next test goes red. We're adding a topping, removing a topping; and the added-pizza should not change. We're dealing with strict immutability in this project.
... Always interfaces. Just now added Remove(ITopping)
to the interface... Always interfaces.
We successfully remove a topping from the toppings in commit f090d15
We extend the successful to removing a topping from a pizza w/immutability in commit b5bfbbf.
A bit of refactoring... and our second change set to our Pizza Shop is complete.
Summary
This is showing the power of µObjects to adapt to changes to a system. While not extensive examples; single changes aren't.
If you are dealing with an extensive change - It's too big. Break it down. Keep breaking it down until there's a small change that can be done.
Don't break tests during changes. :) If you do, you're doing too much.
Next change set is a little more hefty. I added a couple twists to it. I want to see if it highlights what µObjects can do for maintainability of the code.