TL;DR – Don’t use categories. They just create different problems.
Categories in Obj-C are a way to add (or expose) functionality to a class without subclassing it.
You can see why this might be tempting, right? File getting a bit big, too many pragma marks, stick that bit in a category.
I want to expose this method just for testing… make a category and voila I have it.
This class someone else made does nearly everything I want, I just want this extra thing… make a category.
I have two big problems with categories. The first is that they make the code less testable. The second, that they obscure control flow.
Say you moved some code into a category because the file was getting too long. You still have all the same problems of testing a really large class… but now that class is split out over multiple files.
If categories are sensible, then they actually suggest sub-objects that could be owned by your class. Objects that can be injected, and mocked, and unit tested.
People throw around the phrase “composition over inheritance” without I think really knowing what it means. Categories are composition in the same way that Frankenstein’s monster is composition.
Objects with Categories are Frankenstein Monster objects. You don’t know what you have unless you look at the import statements. And what if you’ve imported a bunch of them?
And then they murder you, but it’s kind of your fault because you should have known better than to make such a thing and subject it to the torture of existence. Or something.
Sometimes inheritance is a perfectly reasonable answer.
Categories are a fix that is used way more than warrented, over other options. Defaulting to no doesn’t mean never using categories, it just means being critical before you do.
If a class is getting large, look for functionality you can move out into a separate object.
If you want to expose a method for testing why not… just stick it in the header file with a comment to that effect? And then as you write your tests think critically if it really does need to be exposed.
If you want a slight improvement on an existing class, why not just subclass (or compose it) into a new object? Bonus – you can make something that is better to inject and mock, and then you can improve testability. Wrapping library objects so that they have a better interface for testing is often a good way to go.
There’s a bunch of interesting stuff in Obj-C, but with a lot of these things – just because you can doesn’t mean you should.
When I was ranting about this on Twitter some people asked about Swift Extensions. Dot suggested that because of Protocol-oriented programming, Swift Extensions are intended for a different use.
I am not familiar enough with Swift to have a strong opinion here, but I would say that just the general idea of adding functionality to a class without subclassing it is one I have reservations about and independent of language, you should think carefully about the ramifications to the testability and maintainability of your project codebase doing it.
3 replies on “Categories Considered Harmful”
[…] Furthermore, the Category pattern can easily get out of hand. It tends to become a dumpster for code that you don’t know where else to put. Soon, there is so much there, you don’t even know why it’s there and where it’s supposed to be used. A bit more on why Categories are considered harmful here. […]
[WORDPRESS HASHCASH] Snoopy failed to fetch results for the comment blog url (https://www.natashatherobot.com/protocol-oriented-views-in-swift/) with error ” and so is spam.
[…] there, you donâ€™t even know why itâ€™s there and where itâ€™s supposed to be used. A bit more on why Categories are considered harmful here […]
[…] Categories Considered Harmful. Technical post about iOS architecture. I wrote about using Categories and why they create Frankenstein Monster objects. […]