Fabrizio Giudici is a Senior Java Architect with a long Java experience in the industrial field. He runs Tidalwave, his own consultancy company, and has contributed to Java success stories in a number of fields, including Formula One. Fabrizio often appears as a speaker at international Java conferences such as JavaOne and Devoxx and is member of JUG Milano and the NetBeans Dream Team. Fabrizio is a DZone MVB and is not an employee of DZone and has posted 67 posts at DZone. You can read more from them at their website. View Full User Profile

A Cleaner MVC Inspired by Continuation-Passing Style

06.22.2011
| 19675 views |
  • submit to reddit

2. General design

So, let's start with a look at the UML diagram of the API:

The News API

Figure 1. The News API


Applying the standard patterns, we have a service providing data, an MVC and one support class:

  1. NewsService: the headless «service» that retrieves the feed in backgroud and eventually caches it;

  2. NewsView: the «view» that interacts with the user;

  3. NewsViewController: the «controller» of the view;

  4. RssFeed: a class representing a RSS feed and all its properties (the «model»);

  5. NewsPreferences: an interface exposing the preferences needed by the NewsService

3. NewsService

NewsService exposes two methods:

public interface NewsService
  {
    
    public void eventuallyCheckForUpdates();

    public void getNewsFeed (@Nonnull AvailabilityNotifier availabilityNotifier);
  }
  1. eventuallyCheckForUpdates() can be invoked at the initialization of the application and, if networking connections are allowed, it searches for a fresh copy of the feed in background. It allows to save time and eventually have already loaded the data when the user will ask for them. We can safely ignore it in the scope of this exercise as it doesn't interact with the other classes we've introduced.

  2. getNewsFeed() is the method that retrieves the feed: it is called by the NewsViewController when it wants to render the data onto the NewsView.

There are two characteristics of getNewsFeed() that we must pay attention to:

  1. it can have multiple outcomes (e.g. the feed might be available or not, for different reasons);

  2. it can be completed in a very different amount of time (the feed might be available immediately, or it could be downloaded from the network, an operation that might require some time)

One of the first things that comes to mind is to implement that method as a plain "getter" so it returns different values representing the outcome. For instance, a RssFeed instance if data are available, null if not; or an enumerative type for the different outcomes, and the caller would then retrieve the actual feed with a getRssFeed() method in case of positive outcome; or perhaps negative outcomes would be represented by throwing an exception which describes the reason for which data are not available. In all of these cases the method would block until completion.

We should see some problems already on these premises. For instance:

  1. null / non null outcomes must be handled with an if / else and an enumerative result encourages the use of a switch. Both approaches should be avoided in a good OO design since they don't scale: after an evolution of NewsService that added a new outcome we could easily forget to update all the switches in the application adding the required new case.

  2. Blocking methods cannot be directly called by a view component in many technologies, for instance Swing, Android, or some web frameworks; other technologies (mostly web based) would have no problems. Usually there are specific library functions for dealing with this issue, such as the well known SwingWorker in Swing or the similar AsyncTask in Android, that split the sequence of operations in parts bound to the proper thread. These solution work, but the programmer must remember to apply them when needed (and somewhat create a strong coupling of the design to the technology); which in turn requires that services properly document that some exposed methods are blocking. If during the evolution of the project a method changes its blocking behaviour you'll likely have a user interface not behaving properly. In other words, I don't want to see a SwingWorker or an AsyncTask in portions of code that is independent of technology.

But there's a subtler issue. Reviewing the specifications, let's focus on the one saying that network connections must be enabled by means of a preference or the system must explicitly ask for a confirmation to the user. Let's imagine how we're going to write the NewsViewController: it calls getNewsFeed() and, if it is answered that a network connection is required, opens a confirmation dialog. The user eventually confirms that he wants to connect and at this point the NewViewController calls... what? Perhaps another method of NewsService, such as getNewsFeedWithoutConfirmation(), which connects without asking for a feedback.

Is it all right? In the end it would work and I've seen (and written) many pieces of code like that. The problem is: what prevents a distracted developer from directly calling getNewsFeedWithoutConfirmation(), thus bypassing any check and violating the specifications? The point is that we would expose methods in a service that shouldn't be called but under precise preconditions. I think you've seen lots of times, in the JavaDocs, comments warning you that "THIS METHOD SHOULDN'T BE CALLED UNLESS...". Of course, many don't read the JavaDocs and, to tell the truth, more often than not such preconditions aren't properly documented. This usually ends up with a lot of headaches. Sure, the application must be tested and a properly written test would detect the bug. But robust code enforces policies (for what is possible): preventing errors from occurring by construction is better than allowing errors to happen and later hunting for them.

Seen in another perspective, let's verify whether we have properly distributed responsibilities to classes. Which class should own the responsibility of enforcing the connection confirmation policy? Undoubtedly NewsService, which encapsulates the network connection; for sure it's not a responsiblity of NewsViewController, that only has to properly coordinate the control flow between NewsService and NewsView. Now, in the hypothetical implementation that we have sketched, the responsibility is split between the two classes: NewsService notifies the need for a confirmation (correct), but NewsViewController is capable to directly command a download without a further confirmation. Instead, it should just tell NewsService it has got the confirmation (how to get a confirmation is a UI matter), and let the latter to decide how to continue (not a UI matter).

Let's try a better design to deal with the issues we've found so far - for the sake of clarity, let's recall them:

  1. we don't want to use a switch or a if / else in the NewsViewController implementation;

  2. we don't want to take special care in case getNewsFeed() blocks for a long time and we don't want to introduce technology-specific solutions in modules designed to be independent of the UI technology;

  3. we want to encapsulate the whole responsibility of the connection confirmation policy into NewsService.

AttachmentSize
it.tidalwave.bluebill.mobile.news_.png32.91 KB
it.tidalwave.bluebill.mobile.news_.ui_.png13.07 KB
package.png12.46 KB
UserNotificationWithFeedback.png21.21 KB
Published at DZone with permission of Fabrizio Giudici, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)