Sunday, December 29, 2013

Reducing complexity in Java using Groovy closures

While coding, do you ever get that feeling deep in your gut that the code you've just saved is good enough to get the job done, but you feel that it might have been over-engineered or probably is a bit too complex for the problem at hand.  That happened to me recently after saving some Java code I was using to test a web application.  I had just added another method (very similar to the half dozen other methods within the same class), when it occurred to me that if I continued down the path I had laid out for myself, the code could soon become too verbose.

Before delving into the code and the solution I came up with, there's a bit of context I'd like to share about the application under test.  The code in question revolves around filtering content displayed on certain web pages by entering a value.  The idea here, is to use Selenium to enter the specified value into the designated filter (Figure 1).

Figure 1. Example of web page displaying the filters

So, to handle this I came up with a number of methods that looked like
filterByTitle(enteredValue);
filterByStatus(enteredValue);
filterByReleaseDateOnFilm(enteredValue);

These methods send the enteredValue to the appropriate Selenium page object class for further processing -- i.e., sending the text value to the correct filter.  Each of the above methods were associated with the Films web page.  

However, another web page, labelled the Releases page, also displayed a release date filter.  This resulted in another release date filter method -- one specific to the Releases page.
filterByReleaseDateOnRelease(enteredValue);
As you can see, in order to differentiate between the two methods, I added an OnFilm and OnRelease suffix to each method, thereby identifying which web page each filter was associated with.  This solution was good enough to test the filters on each web page, however, it just did not feel right.

So, I started toying around with the idea of improving the code by implementing the functionality in Groovy. But how?  Each of the filter methods resembled the following Java code.  How could I improve on this kind of code?
private void filterByTitle(String enteredValue) {
        filmsPage.sendTitle(enteredValue);
}

private void filterByStatus(String enteredValue) {
        filmsPage.sendStatus(enteredValue);
}
Enter Groovy closures!

First, I identified what was common to each of the existing methods --  the enteredValue parameter.  Then, I asked myself what varied between each method -- it was the implementation (e.g., filmsPage.sendTitle(enteredValue)).  With this in mind I created the following method

void filterBy(String enteredValue, Closure closure) {
        closure.call(enteredValue)
}

This method takes 2 parameters -- the enteredValue and a closure.  The implementation of this method is designed to call the closure, passing it the enteredValue parameter.  Once, I had this in place, I replaced the existing methods with something like

filterBy(enteredValue) { value ->
 filmsPage.sendTitle(value)
}

filterBy(enteredValue) { value ->
 filmsPage.sendStatus(value)
}
The end result leads to less verbosity (in the way each method is named) and more maintainable code.
Post a Comment