Commit #4 : My top seven clean code practices

Hi there, fellow readers! It’s been more than a month from¬†my latest commit, where I promised this post will be published a week after ūüėÖ Sorry for the delay! I got my hands full for a month ūüėď

As I said before, the Clean Code book got tons of useful practices. In this post, I want to show you how I applied a few¬†of them in my code – which mostly¬†is¬†Objective-C, hence the examples on this post ūüėČ I believe I don’t always get it right either, so I’d love to hear from you if I got something wrong on how I applied it! ūüėĀ

So,¬†here’s the top seven clean code practices I mostly use! ūüėÜ

1. Use Comments Where Appropriate

Programming languages (most of the time) provide ways for us¬†to write words that won’t be compiled¬†by the machine, which were known as comments. We normally use them to communicate with other developers¬†when our code fails to do it, such as:

  1. Giving legal and authorship information of the written code,
  2. Writing TODO notes on parts that need to be enhanced on next iteration, or
  3. Giving emphasis why an algorithm/decision was taken to tackle an issue.

Alas,¬†there’s no one stopping us to use comments inappropriately – which is¬†using it as our primary way to convey message to others, instead of our code. Here’s an example code of inappropriate use of comments:

(It might be hard¬†to read – even I have a hard time intentionally writing code this bad ūüėď)

The above code generates this simple view:

Commit #4 Sample Code Result
Oh hi there! I’m your simple, two-colored view.

Now, let’s take a look at¬†the code. The comments in it were used to:

  1. Add limiters between chunk of code (the top most view, title, and bottom view),
  2. Explain what does the variable used for, and
  3. Storing a piece of code by commenting it out.

Huh, those comments turns out to be helpful, no? Not¬†really. The only way to make sense what is ‘both’¬†variable in line 39 (the ‘copy’¬†variable declaration, doh) was to¬†read line 30‘s comment,¬†which¬†was bottom view’s height.¬†There’s a good chance that we’ll waste our time scrolling through the code to make sense what does each variable do when we’re fixing a bug or adding another feature (e.g. another view below the blue one). Rest assured, there’s a better way to this! ūüėČ

To make this code better (read: clean¬†it up), we need to remove all the comments (except the section-separator ones, for the sake of this post ūüėĀ). Yep, the commented-out code is included, since we can easily revert it back using version control software¬†such as Git. After removing all those comments, we need to¬†use meaningful names¬†for our variables.

2. Use Meaningful Names

After all of those comments removed, we need to use¬†variable names¬†that¬†describes what kind of data the variable holds. That way, we’ll still be able to make sense out of it without the comments.¬†Here’s an example:

Now, we can directly know how¬†copyright label’s Y position is calculated in line 39 – without all the unnecessary scrolling! ūüėČ

Just like variables, concise and meaningful names also needed for¬†functions and¬†classes.¬†A good name will tell the¬†purpose of a function or class without forcing the readers¬†to re-read the implementation. This simple practice is important – important enough, since¬†the book has¬†a dedicated¬†chapter to¬†about it.¬†Alas,¬†coming up with a good name isn’t always easy.¬†¬†There’s a quote regarding two hard things in computer science from this post:

There are only two hard things in Computer Science: cache invalidation and naming things.

— Phil Karlton

(It seems Mr. Karlton passed the CS classes with flying colors, no?)

Take heart, though –¬†a¬†good dose of knowing your project’s domain, reading good naming samples, and a little experiment here and there will help you better at it! ūüėČ

3. One Level of Abstraction

On our latest code, we have ‘viewDidLoad’¬†method that¬†executed when the view is loaded to memory. If we narrate the current code, it would be something like this:

When this class’ view loaded to memory, it will call the superclass method first. Then it will create a top¬†view with same¬†width and 100 points high, at (0,64). It will set the new view’s background color as red. Then, it will create a title label with 50 points wide and 100 points high, at … etc.

While it’s perfectly fine to load another view on this class’¬†viewDidLoad, we got a problem. What if we need to call the retrieveData¬†method (that was removed before) on viewDidLoad? It will work just fine, of course. But it wouldn’t be so pleasant to narrate:

… Then it will create a top view same width and 100 points high, … and finally, it will check if current data is stale. If it is, it retrieves data from server.

The method itself will also be harder to read, since it has multiple level of abstractions. At some point, the¬†viewDidLoad¬†method code has fine details about creating the sub-views, and suddenly a more abstract code about reloading data.¬†And folks, that’s when functions (or methods, in this case) come to the rescue! ūüėÜ

To make the¬†viewDidLoad method¬†only has one level of abstraction, we need to move each section of code (which marked with limiter comments) to their¬†own methods. Here’s an example:

On this version, the viewDidLoad method is easier to be narrated:

When this class’ view loaded to memory, it will call the superclass’ method first. Then it will configure view-related properties, then add top and bottom views. Finally, it will validate any stale data.

The¬†methods that called by it should be easy to be narrated, too! You can try it by yourself ūüėČ

4. Reveal Temporal Couplings

Now, imagine that we’re working on a team. There’s another developer¬†that merged his/her feature¬†git branch and merged it to the develop branch. After several merge conflicts, the ‘[self addBottomView]’ called before the ‘[self addTopView]’, and they (hypothetically) doesn’t bother to check how it does:

They thought that everything is gonna be alright, since the methods will add the top and bottom view regardless on their call sequence. The problem¬†is it isn’t – here’s the result if we run the code:

Oh no, the copyright label's gone! Oh its OK, it's below the red view... WAIT THATS NOT OK!
Oh no, the copyright label’s gone! Oh its OK, it’s below the red view… WAIT THATS NOT OK!

The cause of this mess was ‘addTopView’¬†method that increases¬†Y offset variable¬†after it added the top view. This creates a temporal coupling, where addTopView¬†should¬†be called before¬†addBottomView¬†. Temporal coupling itself isn’t bad, but it gets bad if the dependency is not mentioned explicitly. To fix this issue, we can add parameters to addTopView and addBottomView method:

On that latest implementation, we don’t have to worry about¬†adding top or bottom¬†view sequence juggled again, since the dependencies is declared¬†explicitly through the method arguments. It also reveals that bottom view’s position depends on the top view’s height, which is the temporal coupling in this code! ūüėČ

5. Reduce Number of Function Arguments

From the latest example, we saw how function (or method) arguments could work as dependency declarators. Yet, having a lot of arguments is never a good idea. Uncle Bob said that:

  • No arguments (niladic) is the most ideal,
  • One (monadic) and two (dyadic) arguments are the second and third best,
  • Three arguments (triadic) should be avoided where possible,
  • More than that (polyadic) requires very special justification.

Number of arguments matters¬†because it increases abstraction – it’s easier to use functions with less arguments, since we didn’t need to know the related dependencies. I normally found functions with massive parameters when somebody trying to jumble-up a lot of things into one, e.g. a network request with multiple parameters like below:

This method is hard to use, since the user need to know a lot of dependencies. Plus, it will be hard to test, since there’s a lot of combinations that could happen. How should the code behave¬†if ‘address’ passed as null value? What if all of them are a null values? There are so many edge cases that should be validated in this method. To fix this, we should move all the parameters (and validation) to a¬†model, for example:

That way, we can leave¬†the parameter checking and payload¬†creation to the¬†RPSUser class, and just use the payloadDictionary¬†on the networking method. Plus, it’ll easier to test since the edge cases for creating parameter was moved to the model class! ūüėČ

6. Do One Thing

Phew, we discussed a lot with code samples, no? Now, I want to discuss about practices that’s more philosophical¬†– ¬†“Do One Thing”.¬†Originally, this concept was introduced by Uncle Bob for functions, per this quote:

Functions should do one thing. They should do it well. They should do it only.

This principle matters because it assures that a function do only one thing,¬†without any side effects. The “copyright label not found” issue point #4 happened because the¬†‘addTopView’¬†method¬†does more than one thing – it adds top view¬†and increases the yOffset property.¬†In a way, it deceives those who use it since it does¬†more than what stated in the method name.

On the later chapters, I found this principle resonates in classes (Chapter 10), but in a different name –¬†responsibilities.¬†A class should only have one responsibility. There are some ways to check if a¬†class has more than one responsibility:

  1. There’s a conjunction word (e.g. and, or, but) when we explained what’s the class¬†for. For each conjunction, it got one more responsibility.
  2. The class name includes weasel (misleading) words like¬†Manager, Processor, or Super. And oh – Jeff Atwood also wrote a great blog post regarding this. Check that out! ūüėĄ
  3. The class have too many methods and variables / properties. Having too much of those two could be a smell of too many responsibilities.
  4. The number of other class that imported. Unless its a Factory / Builder / Provider class, a long import line could be a smell of too many responsibilities, too.

Having a single-responsibility class helps us to maintain it, since it only have one reason to change. It will result in small, cohesive classes that easier to be changed – instead of a¬†brittle thousand-lined class, where a single change in one function will create a bug in another. ūüėĪ

That being said, on the latest ViewController sample,¬†we could¬†move the view-creation code to a single¬†UIView subclass. We could¬†apply¬†this if the view got more complex, so¬†the view¬†class will handle how it will layout itself. Later on, we can simply use it on the ViewController’s¬†loadView¬†method! ūüėČ

7. The Boy Scout Rule

And we’re on my top 7th clean code practice, the boy scout rule! Putting it on my #7 does not mean it less important than the others – it’s just I need to practice it more.¬†This rule was summed up in¬†this quote from The Boy Scouts of America (which was taken from the book):

Leave the campground cleaner than you found it.

This rule was present because¬†people not always write clean code. As for me, finishing the Clean Code book doesn’t mean I always¬†write one. I always strive to do so, though.

There are times when I lumped one big bugfix¬†to a single function on deadlines. Or wrote a big ball of mud¬†because I didn’t know the common design patterns of a new language. When¬†I¬†voluntarily not writing clean code, I put a¬†TODO comment and revisit it later to clean it up. Since I’m not the only one who applies this principle, sometimes¬†my¬†TODOs were cleaned up by someone else, and vice versa, too! ūüėČ

Another reason why¬†this principle is important is to¬†prevent “broken windows”. Thanks to entropy (if you agree with physics), we tend to make the¬†code worse if¬†we left it unclean. In my junior years, I tend to¬†put a lot of logic code in UIViewController subclasses since others also did it ūüėÖ When we clean up our code frequently, we set a good path to keep it clean for those who will maintain the code after us.

Phew! Well, that’s my top seven clean code practices! It turns out that this post has become longer the last one ūüėź I hope this post commit turns out helpful for you! I’d also love to hear your comments (and¬†your favourite clean code practice) on the comments section! ūüėČ

Thank you for reading! ūüôā

3 Comments Add yours

  1. Wah lumayan nih tipsnya. Biar code kita readable dan enak kalau mau kolaborasi ūüėÄ


    1. edopelawi says:

      Wah, makasih udah membaca, kak Adam! ūüôā semoga artikelnya bermanfaat untuk tim Arsanesia ūüėÄ


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s