Monthly Archives: October 2014

There is No Such Thing as Maturity…

There is no such thing as maturity. There is instead an ever-evolving process of maturing. Because when there is a maturity, there is a conclusion and a cessation. That’s the end. That’s when the coffin is closed.

– Bruce Lee

Advertisements

Guava: Reducing Cyclomatic Complexity with Objects.firstNonNull(…)

PROBLEM

Ever written code like this?

Employee employee = employeeService.getByName(employeeName);

if (employee == null) {
    employee = new Employee();
}

While it works, it has several minor problems:-

  • The above code has cyclomatic complexity of 2 due to the if logic.
  • We cannot define final on employee object.
  • Too many lines of code, and seriously, it looks very 2003.

SOLUTION

Guava provides a much cleaner solution to address these problems:-

final Employee employee = Objects.firstNonNull(employeeService.getByName(employeeName),
                                               new Employee());

Guava: FluentIterable vs Collections2

PROBLEM

Guava’s Collections2 is great when dealing with collections, but it quickly becomes rather clumsy and messy when we try to combine multiple actions together.

For example, say we have userIds, which is a collection of user IDs. For each user ID, we want to retrieve the Employee object and add it into an immutable set if the lookup is successful. So, we essentially want to perform a “tranform” and “filter” here.

By using strictly Collections2, we ended up with the following code:-

final ImmutableSet<Employee> employees = ImmutableSet.copyOf(
        Collections2.filter(
                Collections2.transform(userIds,
                                       new Function<String, Employee>() {
                                           @Override
                                           public Employee apply(String userId) {
                                               return employeeService.getEmployee(userId);
                                           }
                                       }),
                new Predicate<Employee>() {
                    @Override
                    public boolean apply(Employee employee) {
                        return employee != null;
                    }
                }));

While it works, it may be confusing to those reading the code due to the nested functions.

SOLUTION

A better approach is to use FluentIterable that allows us to write more natural top-to-bottom code:-

final ImmutableSet<Employee> employees = FluentIterable
        .from(userIds)
        .transform(new Function<String, Employee>() {
            @Override
            public Employee apply(String userId) {
                return employeeService.getEmployee(userId);
            }
        })
        .filter(new Predicate<Employee>() {
            @Override
            public boolean apply(Employee employee) {
                return employee != null;
            }
        })
        .toImmutableSet();

Combining and Minifying JavaScript Files with Google Closure Compiler

GOAL

The goal is to combine and minify several JS files into one JS file in the right order.

PROBLEM

Let’s assume we have the following directory structure with three JS files.

Directory Structure

appdev
└── src
    ├── appdev.blackcow.js
    ├── appdev.js
    └── appdev.whitesheep.js

appdev.js

var AppDev = {
    modules : [],

    start : function () {
        var moduleName;
        for ( moduleName in AppDev.modules ) {
            if ( AppDev.modules.hasOwnProperty( moduleName ) ) {
                AppDev.modules[moduleName]();
            }
        }
    }
};

appdev.blackcow.js

AppDev.modules.blackcow = function ( config ) {
    console.log( 'in black cow module...', config );
};

appdev.whitesheep.js

AppDev.modules.whitesheep = function ( config ) {
    console.log( 'in white sheep module...', config );
};

SOLUTION

To pull this off, we will leverage Google Closure Compiler.

There are multiple ways to use this compiler, but if you are using Mac, the easiest approach, in my opinion, is to install this compiler using Brew.

brew install closure-compiler

Once installed, navigate to the appdev directory and run the following command:-

closure-compiler --js `find src/**/*.js` --js_output_file appdev.min.js

Now, a new file called appdev.min.js will be created.

appdev
├── appdev.min.js
└── src
    ├── appdev.blackcow.js
    ├── appdev.js
    └── appdev.whitesheep.js

The reformatted file content looks like this:-

AppDev.modules.blackcow = function ( a ) {
    console.log( "in black cow module...", a )
};
var AppDev = {
    modules : [], start : function () {
        for ( var a in AppDev.modules ) {
            if ( AppDev.modules.hasOwnProperty( a ) ) {
                AppDev.modules[a]()
            }
        }
    }
};
AppDev.modules.whitesheep = function ( a ) {
    console.log( "in white sheep module...", a )
};

The generated code is going to cause problem because the Closure Compiler basically appends each file content based on the order of the JS file names.

To fix this, we have to specify the dependencies so that the Closure Compiler will auto-sort the files correctly.

appdev.js

goog.provide('AppDev');

var AppDev = {
    modules : [],

    start : function () {
        var moduleName;
        for ( moduleName in AppDev.modules ) {
            if ( AppDev.modules.hasOwnProperty( moduleName ) ) {
                AppDev.modules[moduleName]();
            }
        }
    }
};

appdev.blackcow.js

goog.require('AppDev');

AppDev.modules.blackcow = function ( config ) {
    console.log( 'in black cow module...', config );
};

appdev.whitesheep.js

goog.require('AppDev');

AppDev.modules.whitesheep = function ( config ) {
    console.log( 'in white sheep module...', config );
};

After rerunning the compiler, the file content for appdev.min.js now looks correct.

var AppDev = {
    modules : [], start : function () {
        for ( var a in AppDev.modules ) {
            if ( AppDev.modules.hasOwnProperty( a ) ) {
                AppDev.modules[a]()
            }
        }
    }
};
AppDev.modules.blackcow = function ( a ) {
    console.log( "in black cow module...", a )
};
AppDev.modules.whitesheep = function ( a ) {
    console.log( "in white sheep module...", a )
};