Skip to content

Looking at the wrong abstraction

Warning! The post title might be a little bit misleading. Or not. Read on, and decide.

In the coming paragraphs I am going to look at a few different issues like Swift-Objective-C interoperability, Swift extensions, and the one that actually provides the post title: how relying upon the right abstractions improves code quality and therefore maintainability.

The problem

Wait! Sexy Software Engineers do not have problems, Sexy Software Engineers have difficult solutions!

The difficult solution

I hate (not) to make this about me, but I spend most of my time dealing with native clients that consume content from online video platforms (aka OVPs). In other words, I spent an awful lot to time building lists of Movies, TV Shows and whatnots.

For this particular difficult solution, I need to display a list like this:

Screen Shot 2015-02-23 at 13.10.47

The list contains two different kinds of “stuff”: movies and tv shows. To make things a little bit more (opening air quotes) interesting (closing air quotes), both Movies and TVShows are objects modelled as good old Objective-C classes, and I am not allowed to modify the source code of any of those two classes.

The difficult solution solved: the ugly way

This is the simplest possible solution. In the implementation of the listing datasource, I can do something like:

Ugly, yes, but Marines don’t do, Marines make do, and so on and so forth.

Now, seriously, this is more evidence supporting a concept I am trying to get across in almost every post. Start with something simple, something that gets the job done. Then look at it carefully, with a critical eye, and you will see all the code smells and bad design decisions jump off the screen, right towards you.

What’s wrong with that? Why is that ugly?

Here is the culprit: isKindOfClass. If you write Java for a living, it would be instanceof. In Swift, it would be the is operator.

YMMV, but I am going to say it as clear as I can: checking for a type at runtime is a code smell. A nasty, stinky code smell.

I know, in theory, there is a reason why isKindOfClass, instanceof and similar are part of the frameworks. In practice, I still have to find myself in a situation where relying on checking the actual type of an object does not stink, and I still have never found myself in a situation where checking the type at runtime was the best possible solution.

How can this be solved in an elegant way?

Well, as usual, taking a step back, and looking at the big picture. What is it that I am trying to achieve? Displaying Movies and TV Shows in the same listing, right?

Yes, and no. What I actually want to do is list a collection of strings. I should not care about what is actually producing those strings, about what it actually is, I should only care about how it behaves.

That is the key concept here: your abstractions would not focus on what things are, but on how things behave.

So, back to my example. If I shift from Movies and TVShows, to something-that-holds-the-data-needed-to-be-presented-in-the-listing, my listing would only have to use one entity, one abstraction.

Step 1. Declare a protocol.

I assume naming might be off. The goal is providing a method that returns the content that we want to display in the cells, already formatted properly as a single string.

Step 2. Declare a couple of extensions to Movie and TVShow

Extensions can be used to enforce protocol compliance. This is what The Book has to say about that:

Extensions add new functionality to an existing class, structure, or enumeration type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling).

That is just what we did. Without touching Movie and TVShow, we enforced them to implement a protocol. Even better, notice how Movie and TVShow are written in Objective-C, while the extension is Swift. Neat!

Step 3. Implement the listing data source in Swift.

This is necessary. Only Swift code can use the new features in Swift (like Generics or Extensions). So this one is kind of a no brainer. But Swift is fun, so I call that a win-win!

Step 4. Consume the protocol type, instead of the previous object types

That means, that in the listing’s datasource you can just do:

No casting, no if branches. The listing deals with just one type, that type being the ListItemPresenter protocol.

Step 5. Review the solution

Is this a better solution? Indeed, it is. Checks for instance types are flaky and easy to break. Also, what would happen if we needed to display another entity in the same listing?

We have certainly increased the amount of code, but by doing so we have made the solution more robust and easy to maintain.

Summary

Sometimes the trees do not let you see the forest. Sometimes seeing the forest hides the fact that we are looking in the wrong direction, staring at abstractions that make things more complex for us.

Usually, what your entities expect are other entities that behave in a particular way, without actually minding about what those other entities actually are.

When building your abstractions, look for behaviours.

4 Comments

  1. […] discuss is not the only possible solution. And that would be true. And we have already discussed an alternative solution to a problem very similar to this, by relying on plain-old polymorphism. So, one thing we could do here would be having a bunch of […]

Leave a Reply

Your email address will not be published. Required fields are marked *