Sunday, December 6, 2009

Bazooka: a generic shooter application


Bazooka is designed to test and debug APIs, retrieving a response for the provided request and configuration. The main idea is to allow developers to create plug-ins that will reuse a set of available libraries (mostly web services-related) through scripting languages (e.g. Groovy, Ruby, Javascript, Python, etc). However only Groovy is supported for now.


The web application is built with Google Web Toolkit and Guice. The back-end uses the Java Persistence API with Hibernate as concrete implementation targeting an H2 file-based database.

Write your own shooter

Let us create an HTTP shooter for example:
import org.apache.commons.httpclient.*
import org.apache.commons.httpclient.methods.*

method = new GetMethod(url)

new HttpClient().executeMethod(method)
response = new String(method.responseBody)

method.releaseConnection()

response
In the Groovy code above we import Jakarta Commons HTTP Client classes so we can use them straight away. A GetMethod is created with the provided URL (which is bound from the selected configuration) and then the method is executed with a previously created HttpClient. After releasing the connection, we return the response as String.


Notice in this example we define the URL as parameter in the configuration, but we could do the same by providing it as request. It is up to you, but usually I create requests for structured messages like XML and JSON.

Whenever you are ready you can take a shot and get a response. In this example I am targeting http://tiagofernandez.blogspot.com:


Bound variables

Each time you take a shot, the following variables are bound to the scripting context:

* request: the provided payload
* requests: a list containing the existing requests
* parameters: a map containing the given parameters

Additionally, as you probably guessed by now each parameter is individually set as binding variable (e.g. the URL in our HTTP shooter).

Embedding more libraries

You have 2 options to add more libraries. The first is to download the latest version and copy the dependencies you need to WEB-INF/lib. The second is to clone the main repository, add the runtime dependencies to the pom.xml and build the project using Maven.

Good shooting!

Thursday, November 12, 2009

Running EasyB Specs in IntelliJ IDEA 9.0 Beta


Yesterday I was trying to get IDEA's EasyB plug-in running my specifications, but since I am working with a pretty recent version I assume the plug-in is not compatible with it yet (build #IC-90.162). This is the exception I am stumbling on:
com.intellij.openapi.roots.ProjectRootManager.getFullClassPath()[Lcom/intellij/openapi/vfs/VirtualFile;: com.intellij.openapi.roots.ProjectRootManager.getFullClassPath()[Lcom/intellij/openapi/vfs/VirtualFile;
java.lang.NoSuchMethodError: com.intellij.openapi.roots.ProjectRootManager.getFullClassPath()[Lcom/intellij/openapi/vfs/VirtualFile;
at org.easyb.idea.runner.EasybRunProfileState.getProjectClasspath(EasybRunProfileState.java:72)
at org.easyb.idea.runner.EasybRunProfileState.addProjectClasspath(EasybRunProfileState.java:61)
at org.easyb.idea.runner.EasybRunProfileState.createJavaParameters(EasybRunProfileState.java:51)
at com.intellij.execution.configurations.JavaCommandLineState.getJavaParameters(JavaCommandLineState.java:35)
at com.intellij.execution.impl.DefaultJavaProgramRunner.doExecute(DefaultJavaProgramRunner.java:85)
at com.intellij.execution.runners.GenericProgramRunner$1.run(GenericProgramRunner.java:95)
at com.intellij.openapi.project.DumbServiceImpl.runWhenSmart(DumbServiceImpl.java:80)
at com.intellij.openapi.project.DumbService$2.run(DumbService.java:84)
at com.intellij.openapi.application.impl.LaterInvocator$FlushQueue.run(LaterInvocator.java:319)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:606)
at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:502)
at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:371)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
Here the work around I have found for the moment:

Run > Edit Configurations > Add New Configuration > Application:

Main class: org.easyb.BehaviorRunner
Program parameters: src/test/easyb/foo/bar/**.*
Working directory: /Users/tiago/Workspace/myapp
Use classpath and JDK of module: myapp

Before running your specs and stories, edit the project settings and add easyb-0.9.5.2.jar and commons-cli-1.1.jar to the module's dependencies (no need to export them though).

VoilĂ !

Wednesday, October 21, 2009

Taming Legacy Code


There are times you have to work with a code base uncovered by unit tests, and that can quickly become a nightmare. Specially if you let fear, uncertainty and doubt take over and influence your decisions. Sometimes you even need to perform a huge refactoring in order to add new functionalities simply because the code has became too complex and/or unmaintainable. Michael Feathers defines legacy code as code without tests. I have not read his book yet, but regarding the customer's review I assume it is a must-read book.

Unfortunately this kind of situation happens often everywhere for many reasons, but in my opinion the worsts are:

1 - Lack of test/behavior-driven development culture: a lot of people still think that coding unit tests is useless and will only slow development down. For the sake of brevity I will not get started at this one, since it has been discussed until exhaustion lately. Mario Gleichmann summarizes this point when he says writing code without tests is like mountain climbing without a safety rope.

2 - Lack of a "reproduce-isolate-fix" culture: programmers in general still believe that after finding a bug it is enough to implement a patch, instead of isolating the problem with an unit test and preventing it from reoccurring after fixing it.

Getting back to the main point, what do you do when you find yourself having to maintain legacy code? My advise is simple, just focus on filling number two's gap as a short term solution, i.e. each time you find a bug make sure to deliver an unit test with the patch. As mid-long term solution you should aim on filling number one's gap, i.e. every new feature you implement should be delivered with automatic tests and acceptable code coverage.

If you keep doing this for a reasonable amount of time there will be a day you will be able to do any refactoring you need, because you will have a good test suite that minimizes the risk of introducing regressions and eliminates the fear of dealing with legacy code.

Wednesday, August 26, 2009

BDD with Groovy and Scala


Nowadays the "right tool for the right job" idea became quite popular, and I strongly agree with that. You can always argue about the state-of-art tool and I think such discussion is healthy, but believing a special technology shall solve all your problems is naive. Experienced developers should be open enough to accept the fact there will be never a silver bullet.

In the past weeks I have been looking for a replacement for Maven as my default build system, then I have naturally stumbled on Gradle. Rather than making use of XML, Gradle defines a Groovy-based internal DSL which is really easy to use. Unfortunately I had to drop it for now because its Scala plugin will be released only within version 0.8, so I ended up with Apache Buildr. Buildr is Ruby all the way down, and it already includes support for Scala, Groovy and a growing number of JVM languages.

In a new experiment I am working on, I have decided to go ahead with Java and Scala for production code and Groovy for testing. Besides the learning part, that is mostly due to an evaluation I have done some time ago involving JVM languages.

Below how my project looks like:

- myapp/
+ buildfile
- module1/
- src/
- main/
- java/
- scala/
- myapp/
- module1/
- account/
+ Account.scala
+ AccountService.scala
+ AccountServiceImpl.scala
- spec/
- groovy/
- myapp/
- module1/
- account/
+ CompareAccountsBehavior.groovy
+ ManageAccountsBehavior.groovy
+ SignInBehavior.groovy

1 - Build script

Nothing special here, just concise Ruby code defining the build and putting Java, Scala and Groovy in the loop. For testing I am using EasyB, a behavior driven development framework for Java which allows to write specifications in Groovy.

require 'buildr'
require 'buildr/groovy'
require 'buildr/java'
require 'buildr/scala'

repositories.remote << 'http://www.ibiblio.org/maven2'

COMMONS = 'commons-lang:commons-lang:jar:2.4'

define 'myapp' do

project.group = 'module1'
project.version = '1.0-SNAPSHOT'
manifest['Author'] = 'Tiago Fernandez'

define 'module1' do
compile.with COMMONS
test.using :easyb
package(:jar)
end

end

2 - Specifications

The best part of BDD is the fact that specs and stories get pretty readable and self-explanatory, thus any comment I might do will end up being redundant.

CompareAccountsBehavior.groovy:

package myapp.module1.account

final accountId = 1

before "create two accounts with the same id", {
firstAccount = new Account(id: accountId)
secondAccount = new Account(id: accountId)
}

it "should make sure both accounts with the same id are the same", {
firstAccount.shouldBeEqualTo secondAccount
}

it "should make sure both accounts with the same id have the same hash code", {
firstAccount.hashCode().shouldBeEqualTo secondAccount.hashCode()
}

ManageAccountsBehavior.groovy

package myapp.module1.account

final accountSvc = new AccountServiceImpl()

it "should create a new account", {
username = 'tiago'; password = 'secret'
accountSvc.isUsernameInUse(username).shouldBe false
accountSvc.createAccount new Account(username: username, password: password)
accountSvc.isUsernameInUse(username).shouldBe true
}

it "should not create a new account with blank username", {
ensureThrows(RuntimeException) {
accountSvc.createAccount new Account(username: ' ', password: 'foo')
}
}

it "should not create a new account with blank password", {
ensureThrows(RuntimeException) {
accountSvc.createAccount new Account(username: 'foo', password: ' ')
}
}

it "should not create a new account with blank username and password", {
ensureThrows(RuntimeException) {
accountSvc.createAccount new Account(username: ' ', password: ' ')
}
}

SignInBehavior.groovy:

package myapp.module1.account

final accountSvc = new AccountServiceImpl()

it "should sign an existing user in", {
account = new Account(id: 1, username: 'tiago', password: 'secret')
accountSvc.createAccount account
accountSvc.signIn(account.username, account.password).get().shouldBe account
}

it "should not allow non-existing users to sign in", {
accountSvc.signIn('foo', 'bar').isEmpty().shouldBe true
}

3 - Production code

Here I use only Scala for now, but I plan to go ahead with Java as well when appropriated. Below the code drove by specifications:

Account.scala:

package myapp.module1.account

import java.io._

import org.apache.commons.lang.builder._

class Account extends Serializable {

var id: Int = _
var username: String = _
var password: String = _

override def equals(other: Any): boolean = {
val otherAccount = other.asInstanceOf[Account]
new EqualsBuilder()
.append(this.id, otherAccount.id)
.isEquals()
}

override def hashCode(): int = {
new HashCodeBuilder()
.append(id)
.toHashCode()
}

}

AccountService.scala:

package myapp.module1.account

trait AccountService {

def createAccount(account: Account): Account

def isUsernameInUse(username: String): boolean

def signIn(username: String, password: String): Option[Account]

}

AccountServiceImpl.scala:

package myapp.module1.account

import java.util._

import org.apache.commons.lang._

class AccountServiceImpl() extends AccountService {

val existingUsers = new HashMap[String, Account]

def createAccount(account: Account): Account = {
require(StringUtils.isNotBlank(account.username))
require(StringUtils.isNotBlank(account.password))
existingUsers.put(account.username, account)
}

def isUsernameInUse(username: String): boolean = {
existingUsers.containsKey(username)
}

def signIn(username: String, password: String): Option[Account] = {
var signedInUser: Option[Account] = None
if (isUsernameInUse(username)) {
val account = existingUsers.get(username)
if (passwordsMatch(account, password)) signedInUser = Some(account)
}
signedInUser
}

private def passwordsMatch(account: Account, password: String): boolean = {
password.equals(account.password)
}

}
I hope this quickstart project can be useful for someone rather than me.

Note: Since I am still a newbie to Scala, any suggestions for improving this code are welcome :)

Monday, June 29, 2009

4 Tips to Clean Code


Although these rules I'm used to follow can be considered quite obvious even for newbie developers, I keep seeing them violated often. When it comes to code review, I get even more disappointed while spotting sloppy code. I know this subject has been discussed over and over again, but I feel like giving my 2 cents anyway.

I think the following tips should be applied to any language:

1 - Write short and concise methods

It's sad when I'm at the beginning of a method and I have to scroll down to reach its end. It gets even worse when it has multiple exit points. At some point you don't even know what it's supposed to do anymore, simply because too much stuff is being done in a single place. Troubleshooting becomes harder because nobody can tell exactly what happens in there, and of course everybody is afraid of breaking it. In my opinion if you spend too much time debugging, something is really wrong: instead you should rely on test-driven development, focusing on small methods and aiming good code coverage.

2 - Pick self explainable names for methods and variables

Method names shouldn't be neither too long nor too short. Instead, they should be clear and speak for themselves. When a method name fails at describing the actual operation because in that scope a way lot more than expected happens, refactoring should be considered as soon as possible. Regarding variable names, they're supposed to be unambiguous and meaningful depending on the context.

3 - Write only relevant comments

Don't waste your time writing redundant comments just to follow guidelines or satisfy documentation generator tools (e.g. Javadoc). In other cases, having comments all around can be a sign of code smell, so if your code is clear enough, no additional comments are required. In other hand I don't think adopting an extreme posture of never writing comments at all makes sense: when wisely used they can save a lot of time, for example:

/*
[\\w\\.-]+ : Begins with word characters, (may include periods and hyphens)
@ : Must have a '@' symbol after initial characters
([\\w\\-]+\\.)+ : '@' must follow by more alphanumeric characters (may include hyphens)
[A-Z]{2,4}$ : Must end with two to four alphabets (this will allow domain names with 2, 3 and 4 characters e.g pa, com, net, wxyz)
*/
def emailRegex = '^[\\w\\.-]+@([\\w\\-]+\\.)+[A-Z]{2,4}$'
4 - Make your code readable

Always be the least verbose as possible, especially if the language you're using already demands a lot of ceremony and the compiler is right at your face. Stick to your company's commonly agreed coding style, and don't try to play the smart guy hacking around because nobody will understand your code later (probably not even you). Keep things simple and don't duplicate code, the rest will come naturally.

Your code is your craft, if you can't be proud of it then nobody will.
 
!-- Add-in Script for syntax highlighting -->