CLEAN CODE IN ANGULAR.JS : GETTING STARTED

Chances are that somewhere along the line, you’ve written yourself into a big pile of spaghetti code and you’re left wondering:

Why do I write messy code?

It’s a decent question, and the answer probably has to do with our brain’s working memory and other things we can’t really help. So if you’re trying to develop clean code and you’re asking yourself that question,  it’s not really the right thing to be asking yourself at all. There’s nothing wrong with writing messy code. In fact, we need to write messy code before we can write clean code. The answer to clean code development is refactoring.

Every time we finish a section of code, we should stop and ask “How can I refactor this?”. We should be asking ourselves that question continuously as we develop new code. That being said, the following is a short tutorial on how to refactor in AngularJS. First things first:

 

THE EXAMPLE

The following is a controller with a single function createSessions(). It is part of a larger application that is responsible for managing reservations at different events throughout the year. The function takes a list of reservations, a list of events, and populates a list of available events:

Screen Shot 2014-03-16 at 6.53.05 PM

At a glance, we can see a couple of unnerving things. First, the function is doing too much on it’s own. It’s trying to solve the whole problem, while working at every level of abstraction. It’s using basic functions, such as getTime(), while also trying to solve higher level problems, such as getting the places left for each event. In order to do that, we resort to four levels of nesting (bad). Finally, there’s inconsistency in the function and variable names.

With these problems in mind, let’s get to refactoring.

 

WHERE TO START

Unit tests. Before touching anything, write some tests. Unless you have passing tests, you can’t be sure that the changes you make won’t break your application. For this example, we’ll be using Karma and Jasmine to run our tests. If you’re using npm, you can install both with a single command:

npm install karma-jasmine --save-dev.

To create karma’s config file, run the following:

karma init

Karma will ask you a series of questions to set up your karma.conf.js file. Once you’ve answered these, you’re ready to start testing.

Jasmine’s tests are written using nested describe() and it() blocks. The describe() block tells us the type of tests we’ll be running, while the it() block tells us what we expect the code to do. We can use beforeEach() functions to instantiate variables that will be accessible throughout the describe() block. Here is a stripped down version of what our tests will look like:

Screen Shot 2014-03-16 at 8.00.08 PM

We’ll use the beforeEach() blocks to define our controller, scope, and the list of reservations. Inside the it() blocks, we’ll create different event times and test that our function works as intended.

The following is one of a series of tests written for createSessions(). In practice, we should write a test for each scenario we might encounter, but for brevity we only show one:

Screen Shot 2014-03-16 at 8.15.44 PM

Now that we have our tests written, we can run them using:

karma start

This gives us the following output:

Screen Shot 2014-03-16 at 3.38.24 PM

We see that the green lights are on, which means we’re ready to start cleaning up the code. As we refactor, Karma will watch for changes in our test suite and application and will rerun our tests each time we save our modifications. We’ll want to continuously be checking the tests to see that the changes we make aren’t causing the tests to fail.

 

CLEANING UP

Step 1: Rename any variables names that aren’t descriptive enough. This will help you decipher the code, and will make it more readable in the future. Keep in mind that it’s better to have long variable names than short ambiguous ones. For example, the function name in our example code is createSessions(). To make this more descriptive, we could name the function getAvailableEvents(). This name implies that we’re checking to see if the event is available, and it’s consistent with our use of the word ‘event’.

Step 2: Remove any unnecessary nesting. In this case, the majority of the function has been wrapped in an if statement. The extra level of indenting makes the function harder to understand, and forces us to keep track of what condition we’re in throughout the function. Move the if statement to the top of the function and use continue to skip the event if the condition fails.

Step 3: Break the code down into smaller functions, each having a single responsibility and a single level of abstraction. In many cases, this will be the most important step in refactoring. Small functions make your code easier to test, easier to read, and easier to reuse.

Once we finished these steps, we end up with the following code:

Screen Shot 2014-03-16 at 8.44.58 PM

Taking a look at our initial function, which we’ve renamed to getAvailableEvents(), we can see that it more or less reads like a sentence. We’ve removed two levels of nesting and clarified the function by using consistent naming. As for the other functions, each works at a single level of abstraction, and does one thing. The function name says exactly what it is doing.

At this point, we can double check to make sure that our tests are still passing. If everything is still green, we’re ready to move on.

 

LAST BUT NOT LEAST

Our final step of cleaning up will be to move any functions that are reusable into services. Services will help us encapsulate blocks of code and will keep our controllers tidy. Looking at our four functions, there are two that are clearly reusable, namely dateIsInPast() and getPlacesLeftAtEvent(). Since the two functions are performing tasks that are quite distinct, it makes sense to create separate services for each of these functions. We’ll name these services Date and Event. Here they are:

Screen Shot 2014-04-24 at 8.49.52 PM

Screen Shot 2014-04-24 at 8.50.47 PM

Note that each service is returning an object that contains a function. This allows us to easily add related functions later on. On the controller side, we just need to inject these services and we’re then able to use them in our functions. Here’s the final state of our controller:

Screen Shot 2014-04-24 at 8.58.47 PM

 

CONCLUSION

Although there is no surefire way of developing clean code, there’s a few important points to take away from this example:

Be consistent. If you use ‘update’ in one place, don’t use ‘edit’ in another.

Write short functions. They should only do one thing.

Write unit tests. They’re the safety net that gives us the ability to improve our code without the fear of introducing new bugs.

Use descriptive names. Don’t try to shorten variable and function names at the expense of losing clarity.

Keep reusability in mind. Services are your friend. Move any reusable code out of your controller and into a service.

19 thoughts on “CLEAN CODE IN ANGULAR.JS : GETTING STARTED

  1. Thank you for your Post.

    I think the code would be even clearer if there were no coupling between the Controller part of AngularJS and management sessions.

    This code can be moved in a AngularJS Service.

    In addition, the code does not seem to use the correct naming conventions of the JS community. (eg rather than put events_times eventsTimes)
    https://github.com/rwaldron/idiomatic.js/

  2. Hmm it appears like your website ate my first comment (it was extremely long) so I guess I’ll just sum it up what
    I had written and say, I’m thoroughly enjoying your blog.
    I too am an aspiring blog writer but I’m still new to everything.
    Do you have any suggestions for beginner blog writers?

    I’d certainly appreciate it.

    • Anything in particular you’re trying to write about, or that you’d like to improve on in your posts? A few general things that I can suggest are to continue reading other blog posts, to write about things that you’re opinionated about, and to find some niche topics that you can really dig into and find some interesting ideas!

  3. I simply could not leave your web site prior to suggesting that I extremely enjoyed the usual information a person provide in your guests?
    Is gonna be again ceaselessly to investigate cross-check
    new posts

  4. I simply want to say I am new to weblog and honestly enjoyed your blog. Probably I’m likely to bookmark your blog post . You surely have fantastic writings. Kudos for revealing your webpage.

  5. When I originally commented I clicked the “Notify me when new comments are added” checkbox and now
    each time a comment is added I get three e-mails with the same comment.
    Is there any way you can remove me from that service?

    Thanks a lot!

Leave a Reply

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



You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>