Access Keys:
Skip to content (Access Key - 0)

James McGivern Blog from Dec 07, 2009

  2009/12/07
A Way To Better Code?
Last Changed by James McGivern, Dec 07, 2009 11:47

Like any good developer I'm aware there is always more I can do to improve my code, be it style or substance, however I can also not deny that since having been to Devoxx this year my drive to improve both myself as a coder and my code has increased fourfold. In particular Uncle Bob's evangelising talk about professionalism and his book "Clean Code" which he shamelessly plugged and I subsequently bought and have already burned my way through the first half with glee. Before I go any further a disclaimer:

Disclamer
This article will NOT review "that book" or provide any answers of the definitive prescriptive sort.

So you might be asking what is the point of this article? Well its a kind of open question - What can we (Adaptavist) do to improve code quality both individually and as a team?

There are many angles you can attack this questions from, for example looking at the problem either bottom-up (individual to team) or top-down, however while as useful as that method may be if you have a book to fill we have a whistle-stop tour of some of the tools that can help us all on the path to better code. (The following is not guaranteed to be in a logical order)

Maven

I guess this is my turn to evanglise; Maven is an awesome tool with awesome power, however as with many such powerful tools its greatest strength proves to be part of its greatest flaw: Maven can be tricky. This is exposed most frequently during the early phases of learning/using, and also shortly after you have become confident enough with Maven to use it in a complex project (e.g integrating xDoclet output from several modules) or in an unusual situation (such as trying to convert a legacy ant-build project to Maven). That caveat aside, once you have (been forced) to dive in to the (sometimes not so good) documentation and figured out exactly how it works start to think less about maintaining your build script and more on maintaining your build. Jonathan Mort, our very own Dr Death for Bad Code, has written a few articles on Maven, and I intend to try and add to these in the coming months. For now a few pointers

  • Keep your POMs clean! Maven's XML is quite verbose and if you let your IDE autogenerate dependency declarations it will quickly lose any chance of readability. If you are using a multimodule project take advantage of inheritance and the <xxxManagement> tags for consistent versioning of dependencies across the modules.
  • Version your projects correctly using the SNAPSHOT modifier when necessary. This should encourage smaller incremental versioning (e.g 4.1.1.3, 4.1.2) whose use is defined by some policy (e.g only xxx.xxx maybe released to the public).
  • When a version release is made the core Maven plugin versions should be explicitly defined in the POM. A full explanation why is in Don Brown's Your build uses Maven 2.0.8 ... or does it?

The other great thing about Maven is the fact that it is supported by or integrates with so many other tools, for example all of the other tools mentioned here.

Testing

Some people find this the most contentious issue still out there in the programming world. Still! I could go on and on about why I think we should strive for as much testing as possible, why writing unit tests doesn't cost time, why all other tests are pointless unless you have good unit test coverage as it is akin to the way grand mathematical theorems are built on smaller theorems and lemmas allowing us to build with confidence higher and higher levels of tests (e.g integration tests). And yet despite all these cogent arguments there are some out there that will defend their untested code, offering mitigations such as log statements, or various types of manual checking (visual inspection, "giving the UI a pike").

There are a cornucopia of books and blogs by renown Developers (e.g. Martin Fowler, Bob Martin, Brian Goetz and Andy Hunt) and each author will present their reasons for asserting testing is Good Practice, and often you will find vast amounts of agreement between them all. If you already agree with this view you have probably read several of these books already, and if you don't then all I can ask is that you read several of these books, not because I believe they will "convert" you but because it is good to challenge your ideas and re-evaluate constantly - that's what I do.

Do I always write the test first? No. Do I always have a test for every statement (method, or class)? No. Am I trying tot improve this? Constantly. The more I use tests, and the more I start to rely on them, particularly when refactoring projects that are not in the same source tree (i.e two different projects rather than modules/subprojects in a Maven build). Will tests prevent me from writing bad code? No. Do tests give me a false sense of security about my code's reliability, robustness or correctness? No, but they do give me a degree of confidence - if a problem occurs on a method or class I can tell by looking at the test what "cases" have an haven't been tested (for example maybe you forgot the possibility of negative integers), and I can then writing a test that produces the bug and fails, fix it, and know that should other people change the code if that bug returns you'll know at compile-time *steps away from the lectern*.

Code Analysis & Metrics

In the beginning there was the punched card and the only meaningful metric you could take was how many constituted a particular program, as VDU and teletype style interfaces became common place it became more logical to talk about LOC (Lines of Code). "Ahha", you say, "but that's not true what about profiling?", by which I assume you mean metrics such as execution time. These can be perfectly valid metrics to caputre, but our focus will be on metrics that can be measured before run-time. This still leaves a plethora of possible metrics, however a metric used without knowledge or purpose is a waste of time and often serves to diminish the clarity of the information derived, i.e you can't see the wood for the trees. Again rather than discuss the merits, or lack of, for particular metrics we will cast our eyes over some tools that execute them.

FindBugs, PMD, Checkstyle, and JDepend

These tools focus on: conventions (Checkstyle), bad practices (PMD), potential bugs (FindBugs), and "desgin quality" (JDepend). PMD watches for things like dead code, overly complex methods, and other common bad practices and oversights, whereas FindBugs checks for potential bugs such as the dreaded NullPointerException and dead-lock scenarios. JDepend on the other hand analyses the relationships (dependencies and coupling) between classes, packages, and projects; it "allows you to automatically measure the quality of a design in terms of its extensibility, reusability, and maintainability".

We turn to Checkstyle last because it has the potential to cause great harm and discontentment among developers. Every developer has their own style, but when working in a team it is necessary to come to some compromise as to which styles to use (or have pointless commit-battles changing the positions of opening braces). Reaching these through amicable consent and hence non-obligatory conformance is often the best way forward, however it is generally not possible when the project team is not constant, and where the project has a long life (as new committers will need to be told rather than read these "rules"). The common solution is the provision of a checkstyle document which was set in time immemorial, that is intended to be used in the build to strongly enforce the rules. I have worked for companies where the source control repository had a checkstyle gate which would prevent any commit containing non-conformist code. The solution is a carefully picked set of rules that enforce code clarity while not generating work (e.g all methods, properties, classes must have Javadoc). Furthermore this set of rules must be revised constantly, and where necessary "subclassed" for particular project's requirements thus helping maintain a team-wide style.

Clover

Clover is Atlassian's test coverage tool, which integrates with Maven easily, as well as having graphical integration with IDEA and Eclipse. Clover works by intrumenting the Java bytecode of both your test and main Java classes to determine which elements of your code were tested (covered) by the tests. For example, if you have a method with an if statement inside but only ever evaluate the true consequences in your unit test, Clover will highlight that the method is only 50% covered and highlight which code needs to be tested. It also gives you coverage for your projects as a whole, allowing you to drill-down through the packages to discover where the testing is lacking. For unit tests to be truly effective they must cover 100% of each and every class, however you will encounter some problems acheiving this (e.g if you use the double-check lock idiom for singletons, and other multi-threaded behaviour).

SoNaR

Sonar is something I really want to play with. It offers nearly all of the above tools, or will integrate with them to provide a detailed metics "at a glance" dashboard for each project. This could help promote the project code quality as a team responsibility, especially as you can step back through the project's builds and see how each commit affected the quality metrics. It also has a number of JIRA gadgets for use in JIRA dashboards.

Documentation

There are three types of code documentation:

  • in-line comments - these are not seen except in the source code (e.g. /** comment */)
  • generated - for example Javadoc
  • printed - developers guides, user manuals, etc

The use of the first two is covered in-depth in "Clean Code" and I can not say much of worth on them in a few lines except that both should be used sparingly (your tests and clean code should be enough most of the time), except in Javadoc's case where any class the public (including plugin developers) will interact with should be well documented.

Printed documentation is what most people will see first when approaching the project, either as a developer or a user, and so it is important that this has the same level of quality management as the code itself, this means ensuring that it is consistent with the project version (no references to outdated features or funtions). Developers, either new to the project or working with the public APIs, require very different documentation to users and this adds further to the burden of maintaining printed documentation. Things are further complicated when the various types of documentation are managed separately, e.g source code in SVN, developers guide in HTML, and the user guide in docbook.

Maven steps in here to simplify things by providing the site-plugin capable of generating a website based on files in the source tree, as well as pulling in the Javadoc, checkstyle, FindBugs, and other reports. However this plugin has a distinct and limited appearance (like the Maven one), an there is no real integration with any wiki system such as Confluence. Incidentally Maven also has an docbook plugin.

Bamboo

The final pin in the framework, the CI server Bamboo from Atlassian. Continuous Integration allows us to pull all these tools together, it does nothing a developer could do from his workstation, but it provides a central and common build allowing the team to see as each build is generated (including the new metrics). In some cases the CI server will also execute tests that would otherwise be too expensive in a developer's daily cycle such as a suite of web UI tests, or testing against multiple platforms. Edward Robertshaw made a great effort to improve the use of Bamboo inside the company but we could still do better by exploiting integration with other systems.

So Where Next?

Those who've had their morning coffee shot, or Relentless if that way inclined, will probably have spotted a common element running through these tool: Maven. More generally the build system. Perhaps we could find a way to better use and integrate these tools with each other within the company to aid us in producing better code while minimising the overheads of doing so by having more consistent builds across all of our projects?

For me the next step is to replace my existing local build system with something that uses these tools, I want to see Bamboo working with Nexus to automatically deploy artifacts, I want to see whether having SoNaR gadgets on a JIRA project dashbaord is any help? How we can improve printed documentation, and in particular any reports that might have otherwise been deployed with the mvn:site we do not use. I said it at the beginning and I'll say it again: I do not have the answers but I'm looking...

Posted at 07 Dec @ 11:39 AM by James McGivern 6 Comments
Toggle Sidebar
Adaptavist Theme Builder Powered by Atlassian Confluence