As you may have noticed, few things are changing around this blog. After I haven’t any written any posts for a while I decided it’s time to start again. And as start again means starting fresh, I migrated the blog from Wordpress to Jekyll and Pixyll, hosting now on Amazon S3. Few things happened within this 18 months of silence and I’ll take my time to share what I’ve learnt. In the meanwhile I hope you enjoy the new layout!
A primitive is not enough
note: I know
String is not a primitive. At least not technically - but the concept equally applies.
String is a nice class. When I was learning to program in C, I was quite annoyed by the fact that standard C didn't have a
String type, but you had to use
char* instead. Then I discovered C++ and Java, and I was happy with my String. I could do lots of things with a String. I could search for a character in them, replace it, and passing it around happily. I could have objects with lots of Strings to store information. For example, an
User could have a password stored as a
String. After all, a password is a
String, isn't it?
Well, not quite!
In every classic Object Oriented Programming book/article, an object will be defined more or less as an entity that has got data fields and methods that can be called from the outside (i.e. other objects). A primitive, instead, holds a value but doesn't have any methods.
Every respectable password should at least have some very basic security enforced (no less than 6 characters, for example). A password may be valid (for example "notsosecret") or invalid ("dog") following that criteria. A password has a value ("notsosecret", "dog", "password") and a way of checking whether it's invalid (less than 6 characters). Doesn't it seem like the definition of an object? It is indeed!
By having a
Password object, you will be allowed to write a
validate() method on that object - the method will do all the checks needed with the added value that the validation logic will stay inside the
Password object, not polluting other parts of the code (why another class should know about how to validate a password, clearly violating the SRP?), but it will make adding more checks easier (we know exactly what to modify and where).
Another example that comes to my mind is when a method accepts a parameter like
int intervalInSeconds. Even if you're lucky and nobody changes that argument name (and you know sooner or later will happen), what if you decide to convert all intervals to milliseconds? Wouldn't it be better to pass a
Interval refreshInterval and then use all the utility methods to operate with interval that a class such as Interval provides?
Primitive Obsession (the obsession of using primitives for much more information than needed, losing the possibility to give more information to values) is a code smell that's present in a huge number of projects. By refactoring out and wrapping primitives in first class objects, you both make your code more readable and extensible.
Maintain your tests
First of all - I haven't been writing here for a while. Various things kept me busy, and I didn't think I had anything new to talk about. Probably this topic isn't very new either, but recent events made me elaborate on it.
Refactoring is probably one of the most practiced activities nowadays - specially if you're aiming to be good at writing software. More domain knowledge and experience will make that beautiful piece of code you wrote a couple of months ago look terribly ugly now. Modern IDEs and a good safety net provided by our tests make this task easy and enjoyable.
However, and specially when you're working (like I am at the moment) on a very big project, maintaining your tests is actually as much important as maintaining your production codebase.
Code sometimes may not be crystal clear at first sight (and in some cases not even after reading it a couple of times), so what really helps us understanding code is tests. Tests should express requirements - exactly what the code is supposed to do. But happens quite often that, even with a proper test coverage, tests are the dusty corner of our codebase: people tend to write them, but seldom refactor them. This makes really difficult both understanding the test itself but also to extend it, if there's a need to.
Few problems I usually come along, and how I try to solve them:
- Poorly named tests: lots of people start their test names with
test...in reminiscence of the old JUnit 3.x days. A test name describes one of the requirement our tested part of the system needs to implement. A test name should make sense as read in plain English, and it should describe one of the capabilities of the system (i.e.
- Tens of assertions, sometimes unrelated to what the test is testing: people usually say that you should have only one assert per test. I'm not that strict, but assertions that are in the same test should be related (yeah, that's the same high cohesion thing!). If a test is checking whether some additional work is done in case of a particular input, as long as you've covered the other work your method will always do in another test there's no need to repeat the assertions. It will mislead the reader from the real purpose of your test. Remove them: it will make the test clearer and shorter.
- Mocks, mocks everywhere: again a controversial topic. I read many people that tell that mocks are useless - I think that they are a powerful tool when doing unit testing. Some units of work won't change state of objects, while they will produce side effects (e.g. call a DAO). By mocking dependencies (I should rather say by creating stubs, but some tools like Mockito made the name mock more universal) and verifying invocations, we test that our code is really doing what we want. But lots of times I've seen mocking value objects owned by the application, and even setting answers to getters. Interactions on value objects should be always tested by checking the state of the objects: it's easier and less error prone (you remember that guy that added some hidden logic in a getter, don't you...). As a rule of thumb, if a dependency is mocked to return something, that something probably shouldn't be a mock itself.
I like my objects immutable
Having practiced a lot of functional programming recently (I've just finished the Functional Programming Principles in Scala online course on Coursera, and I loved it!), I came (again) across the topic of immutability
For those who don't know the word, an immutable object is an object whose state can't change after it has been built (i.e. you cannot add elements to a collection). In some languages such as Scala, immutability is achieved without too much hassle (actually Scala collections are immutable by default, unless you specifically choose to import their mutable version), for other languages such as Java there are few tricks to make objects immutable (using constructor / builder objects for setting up state, using Immutable Collections to build your collections, have no setters / all final fields, marking its class as final and so on).
Even if constructing an object to be immutable is not immediate, I always try to make the objects I wrote immutable, and I think you should as well! There are few reasons for this:
- An immutable object is inherently thread-safe. Since its state cannot be changed, there are no race conditions when trying to access the object concurrently, hence it can be shared freely without the need for any synchronisation on it.
- An immutable object is constant. This leads to various advantages, such as it can be used as a key to a map. If you're using a map that calculates the hash of its key, an immutable object will always have the same hash. It can be cached, and it allows you to truly rely on the hash to retrieve an object (what would happen if you use a mutable object as a key then you change your state?)
- It's easier to reason with an immutable object, as you know that once it's been created its state will be always the same. You can avoid defensive code practices (copy constructors, copy of fields) when you deal with immutable objects.
- It forces you to write methods which don't have side effects: if you pass an immutable object as a parameter to a method, you are certain that the object won't be in a different after the method has been executed. This makes debugging issues much easier!
As I said before, there are libraries such as Guava that makes this task easier. Unfortunately, in some situations making an object immutable is not possible, but in that case we should aim to reduce mutability as much as we can.