Skip to content

Tag: solid

On unit testing private behaviours

TL;DR; every time I find myself in a situation where I need to unit test a private behaviour, I consider that a clear indication that I might need to rethink my design.

Let me tell you a story

Some time ago, in what now seems like a galaxy far far away, I was introduced to unit testing by means of someone adding the following requirement to the project my team was developing: “code must be unit tested”.

As you can probably guess by the hint of sarcasm in the previous paragraph, unit testing, like almost everything else in life, is something you learn, not something you are born with. Which was painfully obvious at that time, as I have already written about.

But the thing is, a couple days ago I finally had the opportunity, since I was trapped in a plane for 13 hours, to catch up with some reading. In particular I was finally able to devour Sandy Metz’s new book.

The book is still unfinished, but I highly recommend grabbing a copy, and reading it cover to cover, as soon as possible.

There are plenty of potential quotes in that book, but I would like to focus on one in particular:

… the first step in learning the art of testing is to understand how to write tests that confirm what your code does without any knowledge of how your code does it.

Tests always tell at least two stories.

Unit tests always tell at least two stories. One, specially if the tests are well written, is a cristal clear description of the expectations you have about the behaviour of the code under test.

The second story, though, is usually one that nobody likes to hear. If your tests need to manipulate internal behaviour of the code under test, in order to test your external expectation of that code, then you need to rethink your design. And allow me to illustrate this with an example, that links with the introduction to this very same post you are reading.

When testing goes wrong.

Back to my story: no one in our team had any experience testing, so at the time we did not recognise the code smell, but here is what we were trying to do.

We had this one class that was supposed to be a one to one mapping to a RESTful API, what in the classic three-tier architecture would correspond to the data tier, service layer, transport layer, whatever you call it. The point is, this was the class that performed networking operations against a RESTful API. Let’s call it MediaService.

Part of the expected behaviour of MediaService was that it should cache data, using a key-value cache. This data cache would expire after a given time.

So, the flow would be like this: with every request, we would first check if there was data cached and not expired. If there was data cached, MediaService would return it, if there was no previously cached data or the existing data was marked a expired, MediaService would attack the network, fetch data, and add it to the cache, associating a timestamp to each key-value pair.

So, the next time we wanted to request data to the same endpoint, we would check the cache again, providing a timestamp. The cache would calculate if data was expired or not… rinse and repeat.

In code, that looked similar to the following snippet (those still were the Obj-C times, so this is a rough translation to Swift of my recollection of the events):

Well, not very idiomatic Swift code, of course, but again, those were the dark days before generics.

Now, if you wanted to test that cache was ignored when cached object have expired… how would you do that?

Dependencies

I don’t recall who said it, but someone said that good software engineering is all about arranging the code in a way that complexity does not collapse on you.

That usually implies breaking down your codebase, organising it into separate subsets or structures. Since you are already breaking down your code and organising it in smaller chunks, you might as well make each of those chunks contain code that is related, that deals with one concern. So, instead of one big ball of code, you would end up having smaller balls, each one of them taking care of one and only one smaller part of the big problem your software is trying to solve. (That’s how I visualise cohesion, by the way)

But of course, the problem your software tries to solve is bigger than each and everyone of those small, cohesive structures that you have used to organise your code. So they need to collaborate with each other.

And here is where dependencies are born. One block of code needs to collaborate with another block of code. One part of your solution needs to collaborate with another part of your solution. Or, if you will, one part of your solution depends on another part of the solution.

The tricky part here is how to set up those dependencies in a way that do not defy the whole purpose of breaking down your code into smaller structures. The key is setting up those collaborations in a way that the collaborators are still independent from each other.

Depending on abstractions not concretions

Yep, that’s kind of the definition of the Dependency Inversion Principle.

In the previous code sample, MediaService needs TimeCache. The key here is that it actually depends on the existence of TimeCache, because MediaService creates TimeCache, therefore the behaviour provided by TimeCache is, in a way, embedded within MediaService. Or, the MediaService abstraction depends on the implementation details of TimeCache.

But, why does that matter?

Firstly, MediaService is tightly coupled to TimeCache. So coupled to it, that it actually needs to create it in order to make itself functional.

Secondly, and due to the previous point, it is not possible to modify the behaviour of TimeCache, without modifying MediaService.

Thirdly, there is a more subtle issue here. The fact that there is a cache, and the fact that said cache expires, is not part of the public API of the MediaService class. It is an implementation detail, buried into the MediaService class code, but an implementation detail that is so significant that leaks outside its container. Because we know MediaService handles a cache that marks items as expired, because we expect actually expect that, however, the expectation is not declared anywhere in MediaService’s public interface.

So now, when it comes to unit testing, we face a very interesting problem: we need to test a behaviour that is a private implementation detail, but since we need to test it, it is not private anymore, it is a well-known expectation, but an expectation that we can not test because it is a private implementation detail. You see the infinite loop here, right?

And notice how I have not even mentioned networking…

No worries, mocks, stubs and spies can help!

Well, not anymore. In the old Objective-C days, we could just declare a category in the testing bundle to expose and override any private property of a class with a mock (or stub, or spy, to be honest, I never really understood the difference).

In this case, we could override cache and network, provide mocks, set our tests, and go on our merry way.

The problem with that is that we would still be testing private behaviour. And why should not do that?

The reason, is again, subtle. When we test private behaviour we are basically coupling our tests to the production code very tightly, because we are not testing public APIs anymore, we are testing internal implementation details we should not even be aware of.

Have you ever heard anyone complaining about how unit testing is a waste of time and effort because if you change the production code there is always going to be a bunch of tests that need to be rewritten? I bet the reason is because of vey tight coupling between tests and the code under testing. Or, in other words, because the tests are not testing why they should (public expectations) but private details about how those expectations are fulfilled.

Also, in the age of Swift, doing that is not even possible anymore. If MediaService is final, we can not subclass and override, and if cache and network are declared as constants with let there is no way to override them.

So, what to do?

Invert the dependencies

This is not the first time I blog about dependency injection. Once even using the same example I am using today, another time in a different context. And I am afraid it won’t be the last time I blog about it.

But that’s for a reason. Inverting the dependencies, in my experience, only has upsides. It makes code more decoupled, easier to test, and therefore easier to maintain in the long term.

In this case, the best solution would be something along these lines:

Cache and networking behaviours can be provide now through the MediaService initialiser. Notice the shift in the way we refer to caching and networking now: as behaviours. Because for MediaService, that’s what they are.

The details on how caching and networking work are not known to MediaService anymore. MediaService is provided the behaviours it needs to rely on, the behaviours it needs to collaborate with.

And that’s the beauty of inverting the dependencies. By carefully setting the way collaborators know about each other, and by carefully hiding whatever is not necessary for collaborators to know, and by shifting from concretions to abstractions we make each of our building blocks rely on the expectations that the other building blocks publish about their own behaviours.

Leave a Comment

The Open-Closed Principle

Today we are going to go through one of the five tools that every Object Oriented Designer, or just anyone not wanting his code to become a loaded gun pointing at her head, should have in her toolset: the Open/Closed Principle.

The Open/Closed Principle is one of the most mentioned, but yet most misunderstood, of the five SOLID principles. I am sure you are fed up with reading the definition all around the interwebs, but here it is anyway:

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.

Say what!?

Open for extension, but closed for modification. Neat. But, what does that mean? Let’s rephrase the Principle a little bit:

We should be able to modify the behaviour of a piece of code without changing the actual code that implements it.

In other words, we should have magic powers, or superpowers, or be able to bend the space-time continuum.

Having superpowers would be neat. Can I have some?

Sure, it would be neat. But it is definitely out of the scope of this post.

Let me rephrase. How can my code be open for extension but closed for modification?

Let’s go through a real life example. Real life, like in “code extracted from an actual codebase my team has to maintain”. Let’s pretend that the fact that I personally wrote the offending piece of code does not matter.

The problem

I mostly work with OVPs (that’s Online Video Platforms). I build those pesky apps that some TV providers deliver to their subscribers, and allow said subscribers to watch TV on their devices.

So, I needed to display a Program Guide. An Electronic Program Guide, actually.

An Electronic Program Guide is a list of what is going to be broadcasted during a particular range of dates/times. Let’s pretend this is what I need to display:

Screen Shot 2015-04-03 at 8.29.42 pm

Bear with me on this one, please.

As you can see, the list needs to display Movies, TV Shows, and Live events. When the user taps a particular Program, the app needs to transition to a “details” view, which is, obviously, different (different content and different layout, and even different business logic) according to the type of Program the user selected.

For historical reasons, and some practical reasons, the model object that was provided with in order to build that listing looks similar to this:

Yes, you can argue than all my troubles will end if I looked at the right abstraction, and if I did not need to rely on that “type” property. And I would agree with you: remember, there are historical reasons behind this. Anyway, all this “look at the right abstraction” thing is probably matter of another post.

But, on the other hand, relaying on the right abstraction does not change the fact that I need to navigate to different views according to the type of content I need to display.

The simplest possible solution.

I am a big fan of keeping things simple. When you keep things simple, code smells, bad designs, and bad solutions just popup in front of you when you look at the code, jumping out of the monitor, waving their arms, screaming “refactor me, refactor me!”

So, the simplest implementation that would get the job done would be:

Riiiiiiiight, a switch.

Switch is bad

No matter what they tell you, no matter what you see, switch clauses are usually a code smell. And in this particular case, ermahgawd, it is just bad. I wrote that code, and I still want to punch myself in the face overtime I see it. But why?

Well, this will not escalate well. First, and most obvious, Program is poorly designed, it is the wrong abstraction, and to workaround that bad design, it exposes a type to help identify what it actually represents. That is clearly meant to change.

But, the worst is about to come. What if I need to deal with a new type of program? I would need to update that switch. There is no way to extend this code that does not imply editing the navigateToDetails function.

This code is not open for extension and closed for modification.

Again, the simplest possible solution clearly exposes two code smells: first, Program is the wrong abstraction, or at least it is poorly designed, and second, the initial design is not easy to extend.

The better solution, open for extension and closed for modification

Let’s assume that Program is not going to change now. It will, but not at this precise moment.

If you look at the first implementation of the navigateToDetails function, you will see how all the business logic that deals with navigation is in there. That function checks the program type, and launches the command needed to navigate to the desired destination. What I want, is find a way to delay those decisions as much as possible. That way, I can deal with the problem in a generic way here.

The first step to fix my problem (remember, I want to be able to navigate to different views according to the type of Program the user selects) starts with declaring a protocol that abstracts the details of how I want to perform that navigation.

Then, I will have different implementations of that protocol. Each of those concrete implementations will deal with the details of how to navigate to the desired destination, and more importantly, they will provide a way to decide if that particular implementation is supposed to handle a Program or not.

That last part is the key of the whole refactoring. Notice how I can inject (or in less fancy words, pass as a parameter) a list of all the available implementations of the Router. My navigateToDetails function will loop those, passing them the Program. If it finds any implementation that can deal with the Program passed as parameter, it will ask the implementation found to proceed and navigate to… where? That’s the thing! The navigateToDetails function does not know where, because it doesn’t need to know.

 

Delay all decisions!

I recall reading, some time ago, that good Object Oriented Design consisted in finding ways to delay decisions. I only agree with that up to a point (I guess I have been a victim of over-engineered systems more than once), but I think it makes a good rule of thumb. If a particular part of your system knows too much about others, maybe it is time to rethink it.

But I digress. The whole point of this post was implementing a solution to a problem in a way that allows easy maintenance, and simplifies scalability.

Summary.

Object Oriented Design is all about trade-offs. Simple code usually gets the job done, but sometimes simplicity in the code brings along poor maintainability. Sometimes, ten lines of code get the work done, but sometimes you need to substitute those ten lines by a hundred lines, as long as those hundred lines provide a solid, clean and maintainable solution.

And, did I mention that unit testing the second solution is way easier?

Code samples.

You can get a couple of Swift playgrounds containing the source code to this post on Github

Leave a Comment