Pizza's going great! We've got our system in place; we've cleaned up our code! We have µObjects everywhere!
In my ideal; there aren't enough tests. All behavior is still covered; test coverage is at 100% for everything except our Money object. Which was pulled in from another source; so not all of it's Equals/GetHashCode lines are hit.
I use code coverage to figure out what methods may be up for deletion. It's a good practice to go prune code before starting in on new requirements.
One of the most powerful things you can do when developing - delete code. It's a skill that needs to be developed.
After nuking a few classes and unused code - 98%. I could get it to 100 from a few tests to cover the pulled in code. And the unused IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
methods.
100% code coverage isn't a requirement; and this is a demo of µObjects. :)
OK; onto the changes!
We'll add a new size: Medium @ $13
As part of adding a new size; we'll rebrand the Family to a Large.
... Yep. That's it. It's not a huge change; and honestly; the way I've done everything... Probably pretty quick... Let's go with these; and if I'm short word count, we'll bring in something more.
Simple change here is to rebrand. ... Uhh... Whoops. Apparently the Fammily Pizza inherited from PersonalPizza
instead of Pizza
. We'll fix that too.
There's a very simply fix to this; which is just "Rebranding". In our PizzaType
we have
public static readonly IPizzaType Family = new PizzaType("Family");
which we can just update to
public static readonly IPizzaType Family = new PizzaType("Large");
and call it good.
While this would work; it's not a clean modification. It's a minimal modification. I've had to work on plenty of systems that didn't make a complete change. Little bits would get changed. Classes start to get out of sync with each other. This degrades the code. It makes it harder to understand. It makes it less likely to do a sweeping change later.
We want to sweep. We don't want any "Family" reference left. We need to purge.
First thing; let's update our "Family" description tests to be "Large". This is the Test driving the change in our code.
With that done in commit 9155b56 (also included some file moving) we can move onto refactoring naming.
FamilyPizza
-> LargePizza
and the type rename in commit d647fd4.
That's a very simply refactor... Which I'm kinda disappointed in. I wanted slightly more challenge. In my defense... µObjects make it really easy to refactor. :)
Let's add a medium pizza now. Which I add a test for the description. Bascially C&P the LargePizza
- Yes, it smells.
And then my test for the description fails. I'll need to add PizzaType#Medium
with a string of "Medium" - and BAM! works in commit a23679e.
The next piece to update is the Money; or BasePrice of the pizza. I've set it as $13. So... Change the new Money(18)
to be new Money(13)
. ... Woooo...
Now to add a topping. There's a few ways these methods could do. I C&P'd from large. A better way would be to throw exceptions in each before a test is making us implement it.
Let's add a topping and check the price. My quick math says that the cost should be 14.95. 13 times 1.15. 10% is 1.3; plus 1/2 of that, .65; together 1.95.
If I had exceptions; this would be throwing. NewPizza
is still returning a new LargePizza
; shifting that to a Medium gets us the desired result in commit 7a6f82c.
This has been a pretty simple requirement update. I see µObjects as fascilitating changes to be this simple.
Having been working with this style deeply for the past 6 months; it's like any skill - You get better. It takes less time to produce the foundations; to break out the simple behaviors. It's quicker and easier over time to model a bunch of reusable simplicity into a complex result.
I could pull in some more changes - but... I don't see any coming that are going to trip us up. Not because they are simple - but because I'm doing µObjects.
I do know everything that's coming up, so MAYBE there's some bias towards solutions for that. I've never implemented this before (some hacking at it at the SCSC doesn't count) and don't KNOW what it could look like. Definitely never in µObjects.
I think doing this in JUST OOP; probably also pretty easy to update. That's the point of the kata really - the power of OOP for changes. µObjects take it even further.
µObjects make refactoring EASY
µObjects make changes to code easy to do. Maintaining the code as µObjects takes some skill and some time. The payoff is clean, elegant and; most importantly; maintainable code.