Lots of little objects

I like to use abstractions that lead to lots of small objects that do little jobs communicating with each other to do bigger jobs. The common argument I hear against this is that it makes the code hard to change, for two reasons:

1. “The work is spread out into too many places”

The Single Responsibility Principle says that a class should have only one reason to change. The inverse of that is that if multiple things will change for the same reason, they should probably be in the same place. If you are making a change that requires editing lots of things in lots of different places, you’re either making a very high-level change – in which case, this is expected – or your design needs work – those things probably should have been in the same place.

This doesn’t contradict “lots of little objects”, it provides a counter-balance for taking it too far.

2. “It’s hard to find where I need to make my change”

“I’ll start in my view… ok that’s calling a method in this file… oh that’s calling a method in this file…” and so on.

This is sometimes true, but I prefer it to the alternative of everything happening in this one method so it’s easy to find, but when I want to make the change I’m terrified because this method does so much.

I’m willing to trade that anxiety and potential for bugs for the cost of a bit more upfront time looking for the right place to make the change. Because when I find it, it’s only doing one small thing. I can change it with confidence.

This is the main reason I think using lots of small objects enables change. And ability to change is the best indicator of a good design.

Sandi Metz has a great talk on this subject.

3 thoughts on “Lots of little objects

  1. When I am trying to land code with lots of little objects, this is the critique I most often face:

    Following the flow of the data through the fully extracted version is difficult because one needs to jump around the body of the class.

    Patterns in code are easier to see when things are not broken down into such small chunks. By decomposing the methods so fine, the context is lost and it is no longer evident how the method relates to accomplishing the goal of the class.

    I’m summarizing a reply found on Uncle Bob’s extract till you drop.

    The second point is what really hits home.

    Lots of little objects has lots of big benefits and is my preferred style; yet it seems like I’ve purchased those benefits at the cost of some readability.

    1. Following the flow of the data through the fully extracted version is difficult because one needs to jump around the body of the class.

      The idea behind these types of abstractions is that it gives you the freedom to see the flow at a high level without worrying about the details. If you do care about the details of a particular step, then you dive down into the object (function, method, whatever) responsible for that piece. Until then, you just trust your abstractions.

      You have to get rid of the desire to keep every single piece of logic in your head at the same time. My inability to do this actually why I prefer this style of abstraction. I’m terrible at keeping more than one thing in my head at once.

      Looking at any particular level, if it doesn’t make any sense without jumping around the class, I think that’s when you have a bad abstraction resulting in code that’s hard to read.

      Patterns in code are easier to see when things are not broken down into such small chunks.

      I don’t understand this statement, because I feel like patterns start to reveal themselves when I begin extracting named things for steps in a block of code. I’m probably missing the point of this argument.

      By decomposing the methods so fine, the context is lost and it is no longer evident how the method relates to accomplishing the goal of the class.

      With these types of abstractions, I usually end up with classes that have one public method, and a handful of private methods. The goal is for these abstractions to make that one public method easy to understand, making it clear how it accomplishes the goal of the class.

      If you look at any one of the private methods in isolation, yes, it’s not clear how it relates to the goal of the class, but that doesn’t matter. It’s a private implementation detail. It doesn’t make sense to look at a private method and want it to reveal how it relates to the rest of the class. You start at the high level public method. You end up looking at the private method when you see it being called and want to know the details. At which point you understand completely why it’s there.

      1. I’m terrible at keeping more than one thing in my head at once.

        So there is the rub. If one is able to load their brain with all of the code (an ability I lack), it is frustrating to jump into private members to comprehend the complete implementation.

        I’ve seen Uncle Bob try to make it easier for these folks:

        1 – define private members in the same block they are needed (and now the “jump” is not very far).

        2 – if the language does not support the required block-scoped definition, lament heavily, and use indentation to simulate nesting (I am not a fan of this style). Double lament if the language enforces proper whitespace

Leave a Reply (markdown is supported)