The Composition Kata

Friday, February 15, 2013

The Kata repository has new additions.

The Refactoring kata I pushed out last year now has a Java version available (thanks, Tom!).

Related to the previous post, I also added a Composition Kata.  Excerpt from the README:

One day a developer was writing some logic to perform calculations on a collection of Measurement objects with X and Y properties. The developer knew the business would need different types of aggregations performed on the collection (sometimes a simple sum, sometimes an average), and the business would also want to filter measures (sometimes removing low values, sometimes removing high values).

The developer wanted to make sure all algorithms for calculating a result would filter a collection of measurements before aggregation. After consulting with a book on design patterns, the developer decided the Template Method pattern would be
ideal for enforcing a certain ordering on operations while still allowing subclasses to override and change the actual filtering and the calculations.

public abstract class PointsAggregator
{
    protected PointsAggregator(IEnumerable<Measurement> measurements)
    {
        Measurements = measurements;
    }

    public virtual Measurement Aggregate()
    {
        var measurements = Measurements;
        measurements = FilterMeasurements(measurements);
        return AggregateMeasurements(measurements);
    }

    protected abstract IEnumerable<Measurement> FilterMeasurements(IEnumerable<Measurement> measurements);
    protected abstract Measurement AggregateMeasurements(IEnumerable<Measurement> measurements);
        
    protected readonly IEnumerable<Measurement> Measurements;
}

From this base class the developer started creating different classes to represent different calculations (along with unit tests).

Your job is to create a new calculation. A calculation to filter out measurements with low values and then sum the X and Y values of the remaining measurements. You'll find details in the comments of the code, and the unit tests.

You'll implement the calculation twice. Once by building on top of the Template Method approach (in the Inheritance folder), and once with a compositional approach (in the Composition folder).  When you are finished and all of the tests pass (9 total, you'll start with 6), take some time to reflect on the different approaches.


- Which are the drawbacks and benefits to each?
 
- Which one would you rather build on in the future?


Comments
gravatar Stephen Friday, March 1, 2013
Sensei, Stuck on the last test (named the same) , if I rename it and run, it passes.. please help me see the way. Stephen
gravatar Scott Allen Friday, March 1, 2013
@Stephen: Sorry, I renamed the test in the latest commit, feel free just to give it a different name in your local copy and keep working. The idea is to take the previous test one step further and create a new class to encapsulate the construction of the high pass filter. It's a way to point out that you can have cleaner code and a meaningful name while still using composition. Hope that makes some sense, if not, feel free to ping, replay, or open a an issue on the github project. Thanks!
gravatar Stephen Saturday, March 2, 2013
Scott, Yeah, I had renamed it, but then was surprised when this one passed on first run, and that is what I was alluding to on r the first post (BTW, please enlighten me with your version of the combined). The Inheritance and composition drills made me think, they both worked well once I started to get the hang of it, but in my opinion, the way the params are passed in with composition seemed more elegant and extensible.. More of these type of posts would be great. Thanks Scott. Stephen
gravatar Scott Allen Saturday, March 2, 2013
@Stephen: Great! I'm glad you liked it. The last test with the HighPassSummingAggregator class is just a way to show that if you need one, you can make a class that wraps up all the constructor parameters together to make a concrete class that looks just like the one built with inheritance. It's easy to use and just consists of a constructor with a call to the base: (_measurements, new HighPassFilter(), new SummingStrategy()). This hides the complexity of building the object. Hope that makes some sense.
gravatar w0lf Sunday, March 17, 2013
It's been great doing this exercise. It reminded me of one time I fell into the inheritance trap while working on a pretty complex problem. This resulted in an inflexible structure and led to duplicate/extra code in order to support some new scenarios that appeared. I wish I knew this piece of wisdom back then.
gravatar Scott Allen Monday, March 18, 2013
w0lf - glad you liked it. Some lessons can only be learned by experiencing them. :)
Comments are now closed.
by K. Scott Allen K.Scott Allen
My Pluralsight Courses
The Podcast!