Tuesday, 29 March 2011

Links - Q1-11

Some links that have caught my eye in the last 3 months:


  • Steve Losh - a stunningly clean blog design and thoughtful posts that make me suspect he's one of those sickening characters that can both make it work and make it beautiful...

  • CSS: Specificity Wars - a great (if geeky) explanation of CSS specificity that leverages your existing Star Wars knowledge (!)

  • XKCD on Good Code - funny because it's absolutely true

  • Cucumber - yes, it's Ruby-based, and it's a bit slow, but it's nice

  • CSS Innovations - you'll need a cutting-edge browser, but oh the things these guys will make it do!

  • XKCD on Servers - how can one guy be so deeply knowledgeable in so many areas?

  • Uncle Bob's Transformation Priority Premise - some pretty deep thinking from Mr. Clean Code. A quite fascinating theory about test-driven refactorings that makes a whole lotta sense.

Friday, 25 March 2011

Hot Skills or Not Skills?

A colleague sent me an intriguing email last week - Mixtent is a hot-or-not? website in the style of Mark Zuckerberg's first foray into social networking, as seen at the start of The Social Network.


Except Mixtent is aimed at rating your professional colleagues (via LinkedIn's API) on certain skillsets. It asks you to compare two of your LinkedIn connections based on a certain skill (e.g. Java Development), and then repeats the comparison process about twenty times.


The really clever bit is the Google PageRank-style weighting that is placed on each survey participant, based on how they have been rated against others. This elegant twist makes good common sense and should hopefully prevent the system from being "gamed" by "bots" or rooms full of 10c-a-click fleshbots.


I'll be keeping an eye on this great idea - as a "global top 5%" Java developer I'll also be looking out for recruiters eager to utilise a potentially-outstanding new tool!

Tuesday, 22 March 2011

Vale Nokia

Farewell Nokia, you have completed the final stage in your reverse-metamorphosis from elegant butterfly to wriggling larva.


You reigned in the 1990s, producing phones that everyone wanted and everyone could use.


You gave us phones that had a consistent and ubiquitous AC adapter, saving waste and countless millions of consumers who were able to borrow some electrons and stay contactable.


You gave us the first phone with no antenna to get caught on things and break off.


You gave us a "corporate phone" so good people are still using them almost ten years later.


You even gave us the phone Neo used in The Matrix!


And then you lost the plot. Along came practicable touchscreens, and your lovingly-honed, real-button-oriented OS looked simplistic (which was the main reason why you were so popular). So you desperately played catch-up and failed. Other technologies snuck up on you and you failed there too (I had the misfortune to have to develop for/work on an early N97 which actually "poisoned" any WiFi network it touched).


And now, in desparation, you've jumped into bed with another giant that has lost its way. They will carry on, as their name is now synonymous with mediocrity, but this will be the final straw for you, Nokia.


End Call

Tuesday, 15 March 2011

Long Weekends ...

[

... Like the one just passed in Victoria, are great. The short week that follows a Monday off is also extra-good; who doesn't love having to insert a leap-day in one's mental work-week calendar?!


I think my dream Optimal Office™ would have to feature a 9-day fortnight system just to get that feeling, every second week :-)

Friday, 11 March 2011

Getting Edgy

Us software developers, we're used to living on the edge. We need to be constantly thinking about the "seams" where we can make our code testable, we have to expend considerable brain-fuel on "edge cases" in our algorithms, and, let's be honest, as far as society goes, we're generally typecast as being outliers there too ... :-)


But probably the most important edges are the ones we expose to our fellow weirdos developers - our APIs.


A good API is one you can learn fast and completely. It should be lean and mean, exposing the minimum number of objects and methods to get the job done. It should use a consistent vocabulary and have a consistent approach (for example static void methods, "fluent" methods that return "this" for chaining, or conventional POJO/Manager interactions)


Some good examples:

  • Google Guava's Lists, Iterables, Sets and Maps utility classes, which offer very consistent static methods for dealing with their namesake Collection classes
  • Mockito and Hamcrest offer very readable and discoverable fluent interfaces: Mockito.when(mockThing.isReady()).thenReturn(false).thenReturn(true);

And some bad ones:
  • I always find Commons Lang's StringUtils.isBlank() vs StringUtils.isEmpty() to be a bit confusing!
  • JUnit's Assert.assertEquals(String, String, String) always requires a sneak peek at the javadoc to get the arguments right. They fixed it with the Assert.assertThat(String, T, Matcher<T>) style though!

Tuesday, 8 March 2011

Flip-The-Switch Deployment

The most recent website release at my current site and only be described as une grande débacle.


The reason was an incompatibility between the newly-deployed webapp and an (in-house, but non-local) service it depended on. It wasn't until the webapp refused to start in production that the incompatibility was detected.


Now I'm a very big fan of service-oriented architectures, particularly if they are of a lightweight (i.e. no XML/Schemas/SOAP Envelopes/WSDLs) nature, but they also require a greater level of diligence than a traditional big-ball-of-code when it comes to environments.


The problem here was that each project made its way through development→test→staging→production while connecting to other projects doing exactly the same thing. So in staging, our webapp pointed to the staging version of that other service. And because our website released to prod on its own, the versions didn't line up and a frenzy of finger-pointing began.


So how do we simultaneously avoid future débacles and lower the collective blood-pressure on deployment-day? Well for the comprehensive answer, I can only point you towards Continuous Delivery, but in short:


  • Make staging and production physically identical and interchangeable
  • Run up your environment (your code and everyone else's services) in staging in a code-frozen environment as release day approaches
  • Belt staging with regression tests, performance tests, whatever you've got
  • On release day, "flip the switch" on your router, making staging the "live" environment
  • Keep the old prod "warm", ready to flip it back if any problems are found

This strategy dissipates the stress and risk of releasing new software over the entire "we're in staging" period, rather than one horrible day.


Needless to say, I'll be recommending a Continuous-Delivery approach in our next retro!

Friday, 4 March 2011

Tidier Varargs, part 3

Tidying up the loose ends

Some of you might have been a little incredulous at my earlier statement that no existing library offers methods to neatly deal with possibly-null varargs.


I stand by my position - it's the possibly-null aspect that is the kicker. Google Guava offers methods that almost get over the line:

My varargs methodGoogle's almost-the-same method
Iterable<T> VarargIterator.forArgs
(T... optionalArgs)
ArrayList<E> Lists.newArrayList
(E... elements)
Iterable<T> VarargIterator.forCompulsoryAndOptionalArgs(T t, T... ts) List<E> Lists.asList
(E first, E[] rest)

BUT they explode when fed nulls - making them pointless for this particular wart-removing exercise!


So the only thing left now is to clean up the implementation a little, because I think it's failing two of the rules of clean code:

  1. Runs all the tests
  2. Contains no duplications
  3. Expresses the intent of the programmers
  4. Minimizes the number of classes and methods


Here's the entire class as it stands (imports removed):

public class VarargIterator {
    /**
     * @return an {@link Iterable} of a suitable type. 
     * Null-safe; passing a null varargs will simply return
     * an "empty" {@code Iterable}.
     */
    public static final <T> Iterable<T> forArgs(T... optionalArgs) {
        if (optionalArgs == null) {
            return Collections.emptyList();
        } else {
            return Arrays.asList(optionalArgs);
        }
    }

    /**
     * @return an {@link Iterable} of a suitable type.
     * Null-safe; passing a null {@code optionalArgs} will simply return
     * a single-element {@code Iterable}.
     * @throws IllegalArgumentException if {@code compulsoryArg} is null
     */
    public static final <T> Iterable<T> forCompulsoryAndOptionalArgs(
        final T compulsoryArg, final T... optionalArgs) {

        Validate.notNull(compulsoryArg,
            "the first argument to this method is compulsory");
        if (optionalArgs == null) {
            return Collections.singletonList(compulsoryArg);
        } else {
            List<T> iterable = new ArrayList<T>(optionalArgs.length + 1);
            iterable.add(compulsoryArg);
            iterable.addAll(Arrays.asList(>optionalArgs));
            return iterable;
        }
    }

}

The bits that I don't like are the repetition of the optionalArgs null check in both methods, and the code in the else case of the second method. It's working at a "different level" to the other code in the method, losing the intent, and there's too much of it - it's made the whole method too long.


Of course I have a full suite of unit tests so I can be confident that I'm not breaking anything when I do this refactoring work. I use Cobertura in its Maven and Eclipse plugin forms to ensure I'm achieving 100% coverage from these tests.


The first step is easy - extract out a well-named method for the else case:

    /**
     * @return an {@link Iterable} of a suitable type.
     * Null-safe; passing a null {@code optionalArgs} will simply return
     * a single-element {@code Iterable}.
     * @throws IllegalArgumentException if {@code compulsoryArg} is null
     */
    public static final <T> Iterable<T> forCompulsoryAndOptionalArgs(
        T compulsoryArg, T... optionalArgs) {

        Validate.notNull(compulsoryArg,
            "the first argument to this method is compulsory");
        if (optionalArgs == null) {
            return Collections.singletonList(compulsoryArg);
        } else {
            return createListFrom(compulsoryArg, optionalArgs);
        }
    }

    private static <T> Iterable<T> createListFrom(
        T compulsoryArg, T... optionalArgs) {

        final List<T> list = new ArrayList<T>(optionalArgs.length + 1);
        list.add(compulsoryArg);
        list.addAll(Arrays.asList(optionalArgs));
        return list;
    }
    

I dithered a bit about the null check. Doing some kind of is-null/is-not-null closurey-interfacey thing seemed like pretty major overkill, so in the end I just extracted out the logic into a method. As a bonus, I realised I could also check for a zero-length (as opposed to null) array and save some cycles in that case. One last tweak was to drop the explicit else branches - because the methods are now so short there seems little point. So here's the final version - enjoy!

public class VarargIterator {
    /**
     * @return an {@link Iterable} of a suitable type. 
     * Null-safe; passing a null varargs will simply return
     * an "empty" {@code Iterable}.
     */
    public static final <T> Iterable<T> forArgs(T... optionalArgs) {
        if (isEmpty(optionalArgs)) {
            return Collections.emptyList();
        } 
        return Arrays.asList(optionalArgs);
    }

    /**
     * @return an {@link Iterable} of a suitable type.
     * Null-safe; passing a null {@code optionalArgs} will simply return
     * a single-element {@code Iterable}.
     * @throws IllegalArgumentException if {@code compulsoryArg} is null
     */
    public static final <T> Iterable<T> forCompulsoryAndOptionalArgs(
        T compulsoryArg, T... optionalArgs) {

        Validate.notNull(compulsoryArg,
            "the first argument to this method is compulsory");
        if (isEmpty(optionalArgs)) {
            return Collections.singletonList(compulsoryArg);
        } 
        return createListFrom(compulsoryArg, optionalArgs);
    }

    private static boolean isEmpty(Object... optionalArgs) {
        return (optionalArgs == null) || (optionalArgs.length == 0);
    }

    private static <T> Iterable<T> createListFrom(
        T compulsoryArg, T... optionalArgs) {

        final List<T> list = new ArrayList<T>(optionalArgs.length + 1);
        list.add(compulsoryArg);
        list.addAll(Arrays.asList(optionalArgs));
        return list;
    }
}