For my blog post I'm taking a simple problem from exercism.io and refactoring my first solution using East Orientation. Below I've put the exercise, my initial, dumb, solution and the refactored one. I think I've followed the rules of EO...but, honestly, the refactored version seems very confusing to me. Maybe it's just because I'm not used to the approach. Or maybe it's because I went totally off the rails.Your thoughts?
Some things I wonder about.
- For methods that return strings, I find myself inheriting from String so that I can follow the rule of returning self. That seems weird.
- SoundFactory both a) sounds like a 90s dance band and b) isn't exactly a factory. It's really more of a value object that I'm using for lookup. But splitting it off in this way seemed to be my best choice.
- I really dislike the whole
fallback
thing in RainSounds (again, these names are terrible), but I'd hit my mental limit for the day.
Oh, and yes I'm intentionally explicitly returning self even though I don't actually have to. It's for illustrative purposes.
Given that the goal of East-orientation is to tell objects what to do, this forces you to consider who needs to do what.
After some experimentation with this problem, I found that 1 object was responsible for determining the factors, and another responsible for outputting the sound.
I used BasicObject below just to limit the public API of the object as much as possible. This isn't really necessary. I kept the
convert
method on Raindrops but it's merely a pass-through for the initializer.The data for Raindrops is marked as private.
If you initialize Raindrops and tell it to drip on a template, the object you'll get back is the Raindrops.
The object which makes the sounds I called "TinRoof".
Its job is to determine what to do with the drops. If the drops fit within it's own understanding of what makes a sound, then it makes that sound. Otherwise it will output the number itself.
This template uses
DelegateClass
which comes from the 'delegate' library and merely defines all the methods one would expect from an IO object (such as STDOUT) to forward to that object. Any additional things we need our template to do will be defined in the class (likehit
andsounds
).To make this work, the main object (the running script) just needs to initialize the Raindrops, the template, and tell the raindrops to drip on the template.
The result of each of those commands (
convert
anddrip
) is a Raindrops object. The main script merely tells them what to do and thetin_roof
does what it does.If you change the template to something with different rules, you'd merely need to have Raindrops tell that template to do the same thing:
The rules for what makes a sound stay with the object making the sound (the template). The rules for determining the drops stay with the object making that decision (the raindrops). If you change the way you calculate the drops, the templates don't care; they merely apply their
sounds
rules.