Sunday, October 13, 2013

Iterations Rules

As I've mentioned previously, I've been working lately on a side project called Iterations. At the moment, I'm the only back-end developer which means I get to make the rules, something that I don't often get to do. :) And my rules have been formed based on pains that I've experienced first-hand on work-related projects, pains born from mistakes made by both myself and others; pains that I want to avoid this time around.

In general, Iterations is a web app that will allow Agile projects to be tracked...basically to provide functionality that vendors usually charge a pretty penny for, for free, and hosted on your own server pointing to your own database, instead of someone else's.

So what's the technology stack being used? Well, it's a Maven project that uses RESTEasy to allow the front-end to make calls to the back-end, Guice is used for dependency injection, while MyBatis takes care of the database side of things. On the UI side, we're using CoffeeScript and Sass to make things look pretty, which is all being taken care of by the rather talented UI guru Mike Munsie.

Architecturally, there are three main layers to the app; a resource layer which acts as the entry point to the back-end, a service layer where the main logic lies, and a data-access layer that provides all database related functionality. There are other layers that provide things like security and exception handling, but for the main part, it's these three layers that provide the majority of the grunt work. So with that, here are my four simple rules that I apply in order to keep the design as clean as possible:

The resource layer can only talk to the service layer
Each resource is allowed to talk to one or more services only. It seems pretty reasonable that resources cannot talk to DAOs, but let's tighten things up a bit and say that resources cannot talk to other resources either. The reason being that talking to other resources, to me, implies that there is common functionality that should be abstracted out instead.

Resources must not pass HTTP specific information to the services
As requests come in, each resource should extract the information from the HTTP request, and provide that to the services. This way, a service may be reused by some future layer that isn't HTTP based. For example, let's imagine that we're going to start using a scheduler like Quartz to send out emails each night; it would be pretty much hosed if a service that it depends on requires an HttpServletRequest to be passed to it. In order to be reusable, a service must be unaware of who is calling it.

The service layer can only talk to the data-access layer
This is similar to the first rule, and for the same reason; services cannot talk to other services as that implies common functionality that we can abstract out. Services also cannot talk to resources (and if we follow the previous rule, they probably can't anyway). This helps to avoid any entanglement of code, which is a good thing (the avoidance that is, not the entanglement ;).

The data-access layer cannot talk to any other layer
Each DAO is tasked with simply making calls to the database, that's all, so as to keep things simple. A DAO cannot talk to another DAO.

And that's it. Following these four simple rules has so far kept the design pretty simple, as it should be. They've helped prevent the beginnings of spaghetti code from happening, and helped avoid broken windows from appearing in the first place.

I like rules. Especially when they're my rules. :)

Saturday, October 5, 2013

Code Coverage

I've long been a fan of unit tests; they just make sense, and there's really no argument for not having them on production-ready code other than sheer laziness and not giving a crap about quality in general.

Code coverage appears to be a different issue though.

My stance, before I go on, is that I like to get as much code coverage as possible from my unit tests. A full 100% is just not possible these days as I tend to reduce boilerplate code by using Lombok, but I still strive for the most I can get.

Now I've worked with some very talented guys over the years, and one guy in particular is someone who I admire for his sheer level of technical ability. However, he would question my zest for code coverage, asking that just because the code coverage tools showed that a unit test had run through some code, how could you be sure that that piece of  code was actually tested, and not just executed for the sake of code coverage?

And he had a very valid point. And not only that, it was a point that I had difficulty providing any kind of logical answer to that didn't make me come across as sounding like I had OCD or something. Then I started working on a side-project called Iterations, and it was here that I finally found the answer.

With no time constraints on the project, and with no deadlines to hit, I was free to take my time to unit test everything and maintain the highest level of code coverage possible.  And here's what I found:

Increasing code coverage forces more unit tests to be written. Writing more unit tests helps enforce a cleaner design.

As I was working on Iterations, I would find that if unit-testing a piece of code proved to be a pain, then there was something fundamentally wrong with the design of that particular component.  Either a class was becoming too large, or starting to do too much, or inheritance was beginning to make things difficult, or whatever...the key point was that I obviously needed to re-think things, and refactor.

And so I would refactor the design to make the tests much simpler and easier to implement. Lather, rinse, and repeat enough times, and you end up with one heck of a clean design.

So to answer his question, he is absolutely right in that increasing code coverage does not necessarily ensure that the code is really being tested. But the real benefits lie in the overall increase in the quality of the underlying design itself, and that is something that is most definitely something a developer should always strive for.