Tuesday, April 26, 2011

Getting Lombok to Play!

The approach in this post works, but I created a Play! module that makes is easier. You can find it here: https://github.com/aaronfreeman/play-lombok

Recently I've been getting back in to using Play! for web development. I've built something small with it before, and it definitely is my favorite Java web framework. But there are still some things about Java that bug me. One of them is a complete lack of type inference. Static typing can be useful, but becomes a real annoyance if the compiler doesn't help you out a lot. In C# they have some basic type inference using the 'var' keyword and I have long wished Java would have something like that.

Then today I came across Project Lombok. It makes use of the AST transformations in the Java compiler to add features to Java. It can do some pretty cool stuff, and even integrates into your IDE so everything works as expected. And one of the features it has... yep, a 'val' keyword that does basic type inference. Nice! So you can do things like this:

val aList = Arrays.asList("Hello", "World");
for(val s : aList)
  System.out.println(s);

Behind the scenes Lombok turns the first 'val' in to "final List<String>" and the second into "final String". This is great!

One my first thoughts after seeing this was, can I get it to work with Play! Since most frameworks simple compile with javac Lombok is pretty simple to get working, you just have to have it on the compile class path. But Play! is a little different. It actually has a built in compiler (it uses the Eclipse compiler) and it compiles your code at runtime. This is great in development because it mean you and change Java code and just refresh our window and Play! will recompile the code and run the updated code. So no more restarting the server, or having to run in debug mode (which doesn't work for a lot of code changes anyway). It really makes things so much easier. But it also means in order to get Lombok to work, you have to get the Play! compiler to know about it. I couldn't find anyone saying how to do this, which is why I'm writing this.

I'll spare you the gory details of how I figured it out, because it took quite a while, but once I figured it out it's pretty simple to do.

First what you have to do it get Lombok into you Play! project. If you're using Play! 1.2, it's pretty simple (if you aren't yet using 1.2, you should really consider upgrading, lots of good stuff there). Just go to your dependencies.yml file and add Lombok. Like this:

require:
  - play
  - org.projectlombok -> lombok 0.9.3

Now this will work just fine, but if you're like me and you want the val keyword, you have to use the beta version of Lombok, which is in the maven repo. So you'll have to down load it and put it in your project. Easy enough, I put it in a jars folder under my project root and changed the dependencies.yml file to look like this:

repositories:
  - local:
    type:       local
    artifact:   "${application.path}/jars/[module]-[revision].[ext]"
    contains:
      - org.projectlombok -> *

Now we've got the jar, we just have to let Play! know about it when it compiles. I figured this out by reading what Lombok says it does to Eclipse to get it to work, and then duplicated it with Play! In order for Lombok to work, it has to be registered as a java agent, and be on the boot classpath. This can be done using JVM arguments -javaagent and -Xbootclasspath/a. The difficulty is in figuring out how to add these JVM arguments to the Play! startup process. The only way I know of is by making use of the jvm.memory config param in the applicaiton.conf file. This param just gets appended to the call to start the JVM, so you can really put any JVM arguments in there. So I added this line to my application.conf:

jvm.memory=-javaagent:lib/lombok-0.10.0-BETA2.jar -Xbootclasspath/a:lib/lombok-0.10.0-BETA2.jar

That almost does the trick. The only problem now is you'll get an error at startup saying it can't find the Eclipse compiler. That's because Lombok is now referencing it, but it's not at the right level in the classpath to be accessed. So we just need to add it to the bootclasspath, too. So now the arguments look like this:

jvm.memory=-javaagent:lib/lombok-0.10.0-BETA2.jar -Xbootclasspath/a:lib/lombok-0.10.0-BETA2.jar -Xbootclasspath/a:/opt/play/1.2/framework/lib/org.eclipse.jdt.core-3.6.0.jar

Now when you run Play! from the command line it will have Lombok available when it compiles your app. If you are using Eclipse and the eclipse launch configurations generated by Play!, you just need to add the parameters above to the VM arguments of the launch configuration and it should work fine.

Now go and use some type inference!

Wednesday, April 20, 2011

Overemphasizing technical practices

I've been wondering lately if overemphasizing technical practices might be detrimental to a company in the long run. I'm not saying you don't need talented people, I certainly believe you do. I mean as a company (or department), making a big deal about whether a team/person does TDD, CI, or some other good practice. In the short run you'll probably get an increase in good habits among your developers. However, my concern here is that in the long run I think you're likely to create a culture that cares more about whether you're doing those practices than whether you're creating great products. Once a company switches to caring more about how it's doing things than what it's doing, problems start escalating rapidly. (Incidentally this one of the points that Jim Collins makes in How The Mighty Fall, great book!)

We have to remember that customers don't pay for or care about stories, TDD, CI, and many other good software development practices. They want, and pay for, awesome products! (Or as Kathy Sierra would say, products that make them awesome) I'm not saying you can't encourage good practices. You can! I just think you need to first make it clear that the goal is to build awesome products, and then let/help people gravitate to the practices that best allow them to achieve that goal. That way they are never confused about what is really important.

Tuesday, June 8, 2010

On Design

The most important thing to learn about design is that it’s all about trade-offs. There are no perfect designs. Every design has a down side, some draw drawback that will cause difficulties. The is true for all kinds of design whether it’s a building, an organization, a user interface, or software.

Since all designs have problems, the designers job is not to get rid of all problems in the design, it’s to decide which problems are the least costly to have, or which problems are most likely to cause the least damage to the goal of the product. So, to do design well you have to be able to understand what the options are, what the issues are with each option, and in the particular context you are operating in, which issues are the least harmful.

It’s important to understand this when it comes to software design patterns. Design patterns are just common ways of trading one set of problems for another, with the belief that the new set of problems is better than the old. The only time it makes sense to use a pattern is when you have the particular set of problems it was designed to fix, and you’re better off with the new set of problems it leaves you with. But, in order to make good decisions on this, you’ve got to understand what the problem sets are, and how they affect your particular context.

This is not easy! And it takes experience to do it well. Often, the only way to know what the issues are with a particular design choice is that you’ve done it that way before, and seen what issues came from it. However, studying, practicing, and learning from others can take you a long way. The important thing is to never to be fooled into thinking that there are no drawbacks to a particular design decision.

Tuesday, June 1, 2010

Auto injection in jUnit

After doing Java for many years, and TDD for several, I’ve settled into a fairly consistent way of designing and testing my classes. Any time you start to following a pattern in your code, if you’re paying attention, you’ll notice you’re writing the same code over and over. Now, it usually isn’t exactly the same or you’d easily just move it into a class and use the class. No, it’s usually code that is different every time, but it’s essentially doing the same thing, just with different classes. This is one example of what is generally referred to as boilerplate code. It’s aso one of the subtle forms of code duplication, and it’s something you want to avoid as much as possible.

I recently noticed that due to how I write my classes and tests, around 95% or more of my setup methods in my tests consisted of creating the class to be tested, creating some mocks, stubs, or fakes, and then injecting them into the class. Sure, technically every setup method was different, but this was boilerplate code for sure. And it was starting to get on my nerves. The setup usually looked something like this:

public class TestFoo {
   private Foo foo;
   private DependencyOne dependencyOne;
   private DependencyTwo dependencyTwo;

   @Before
   public void setup() {
      foo = new Foo();
      dependencyOne = new DependencyOneMock();
      dependencyTwo = new DependencyTwoMock();
      foo.setDependencyOne(dependencyOne);
      foo.setDependencyTwo(dependencyTwo);
   }
   ... then all the tests
}

One of the best ways to attack boilerplate code is by using the concept of convention over configuration. Basically all my setup methods were just configuration of the class I was testing, so what I needed to do is come up with a convention that made the configuration unnecessary, and some way to act upon the convention.

The convention starts with the @Target annotation. The idea is that you put this annotation on a field to signify that the field is the target of the test class that will need to have dependencies injected into it. You can also put @Target on a method, and whatever is returned from the method will be used as the target for injection.

Secondly, when you define a field on the test class if it matches a setter method on the target class, then it will be injected into the target using the setter. If no setter is found, but there is a field with the same name on the target, then the value will be copied to the field on the target.

In order to actually act on this convention I used the jUnit @Rule annotation. I called my rule AutoMockAndInject. If you aren’t familiar with how this annotation works, you can read about it here. I will put the code for my rule and the target annotation at the bottom of this post.

So, following the convention and using the rule my test class now looks like this:

public class TestFoo {
@Rule public AutoMockAndInject autoInject = new AutoMockAndInject();
@Target private Foo foo = new Foo();
private DependencyOne dependencyOne = new DependencyOneMock();
private DependencyTwo dependencyTwo = new DependencyTwoMock();

   ... then all the tests
}

One thing to remember here is that jUnit creates a new instance of the test class for each test method it runs. Otherwise, doing it this way could cause some problems.

I also use Mockito when I don’t want to make a hand written mock. The AutoMockAndInject rule works with the @Mock annotation from Mockito. It will create the mock object and inject it into the target. So if I want to use Mocito for my dependencies instead of hand written ones, the test class would look like this:

public class TestFoo {
@Rule public AutoMockAndInject autoInject = new AutoMockAndInject();
@Target private Foo foo = new Foo();
@Mock private DependencyOne dependencyOne;
@Mock private DependencyTwo dependencyTwo;

   ... then all the tests
}

I just started doing this a couple weeks ago, and so far I like it. It’s cut down on a lot of boilerplate code. But, in my experience, it usually takes at least a few months of doing something before you really see if it was a good idea or not. So, we’ll see if in the long run it really makes thing better.

Here is the code for my annotation and the jUnit rule I used for doing this.

@Retention(RetentionPolicy.RUNTIME)
public @interface Target {
}

public class AutoMockAndInject implements MethodRule {
   private static final String specialFields = "$VRc,serialVersionUID";
   private Object target;

   public final Statement apply(final Statement base, FrameworkMethod method, final Object target) {
      return new Statement() {
         @Override public void evaluate() throws Throwable {
            before(target);
            base.evaluate();
         }
      };
   }

   protected void before(Object source) throws Throwable {
      createMockitoMocks(source);
      if (hasTargetAnnotation(source))
      autoInject(source);
   }

   private void createMockitoMocks(Object source) {
      MockitoAnnotations.initMocks(source);
   }

   private boolean hasTargetAnnotation(Object source) throws Exception {
      return hasTargetFiled(source) || hasTargetMethod(source);
   }

   private boolean hasTargetMethod(Object source) throws Exception {
      for (Method method : source.getClass().getMethods()) {
         if (method.getAnnotation(Target.class) != null) {
            target = method.invoke(source);
            return true;
         }
      }
      return false;
   }

   private boolean hasTargetFiled(Object source) throws Exception {
      for (Field field : getAllFields(source.getClass())) {
         if (field.getAnnotation(Target.class) != null) {
            target = getFieldValue(source, field);
            return true;
         }
      }
      return false;
   }

   private Object getFieldValue(Object target, Field field) throws Exception {
      field.setAccessible(true);
      return field.get(target);
   }

   private Set<Field> getAllFields(Class<?> clazz) {
      return getAllFields(new HashSet<Field>(), clazz);
   }

   private Set<Field> getAllFields(Set<Field> fields, Class<?> clazz) {
      for (Field field : clazz.getDeclaredFields())
         if (notSpecialField(field))
            fields.add(field);
      if (clazz.getSuperclass() != null)
         getAllFields(fields, clazz.getSuperclass());
      return fields;
   }

   private boolean notSpecialField(Field field) {
      return !specialFields.contains(field.getName());
   }

   private void autoInject(Object source) throws Exception {
      ensureTargetExists();
      Set<Field> targetFields = getAllFields(target.getClass());
      for (Field field : getAllFields(source.getClass()))
         if (!callSetterIfExists(source, field))
            setFieldIfExists(source, targetFields, field);
   }

   private void ensureTargetExists() {
      if (target == null)
         throw new RuntimeException("Target value is null, did you forget to create it?");
   }

   private boolean callSetterIfExists(Object source, Field field) throws Exception {
      Method method = getMethod(target, getSetterName(field));
      if (method != null) {
         method.invoke(target, getFieldValue(source, field));
         return true;
      }
      return false;
   }

   private Method getMethod(Object target, String setterName) {
      for (Method method : target.getClass().getMethods())
         if (method.getName().equals(setterName))
            return method;
      return null;
   }

   private String getSetterName(Field field) {
      return "set" + StringUtils.capitalize(field.getName());
   }

   private void setFieldIfExists(Object source, Set<Field> targetFields, Field field) throws Exception {
      Field destField = getField(field.getName(), targetFields);
      if (destField != null)
         setField(target, destField, getFieldValue(source, field));
   }

   private Field getField(String name, Set<Field> fields) {
      for (Field field : fields)
         if (field.getName().equals(name))
            return field;
      return null;
   }

   private void setField(Object target, Field destField, Object fieldValue) throws Exception {
      destField.setAccessible(true);
      destField.set(target, fieldValue);
   }
}

Thursday, May 27, 2010

Code duplication is evil

As you’re programming, have you ever had the sense that a great evil was lurking in your code base? Well, most likely there is, and it’s name is: code duplication! This monster will sneak it’s way into your code with the promise of “fast” implementation and a “simple” solution. But make no mistake, once it has a foothold in your code base, what you thought was your friend will turn on you with a vengeance and destroy you. The code will rot in it’s place, and you’ll be cursed with recurring bugs that come back because you only fixed them in one place. Then your friends will laugh at your plight and make up nick names for you like “Mr. Duplication” or “Copy and paste Man.” In the end you’ll be left homeless and penniless. Then you will rue the day that you ever gave in to the subtle and poisonous promises of code duplication.

I’m not sure everyone sees it this way, though. I’ve said for a while now that the best way I know of to get to a well factored system is to have an acute aversion to code duplication. Both the obvious and subtle forms of it. However, despite the fact that the DRY principle is well known, I find that many developers (perhaps most) not only often repeat themselves in their code, but they also seem to be unconcerned when they find duplicated code and have to modify it. Personally I think the latter is the biggest issue.

We all write bad code some times, and we do stupid things like giving in to the temptation to duplicate. Many strange and terrible things can be done in the heat of the moment while programming and trying to implement a feature (even if you are pairing). To ere is human and it’s perfectly understandable. However, to come across blatant duplication and not only do nothing about it, but to be unmoved by it, that my friends is inexcusable.

Of all the code smells there are, code duplication is one of the most telling. So much can be learned from it, if you’re paying attention. Some times it can tell you that your design is not quite right. Or that you’re missing an abstraction. Or that you’re thinking about the problem in the wrong way. Often a lot of code duplication can be removed by solving the coding problem from a different angle.

There’s more that can be learned than just the few things I mentioned, but you will see none of these things if, when you encounter code duplication, you merely make the required changes in multiple places. You have to learn to hate it! You should be outraged by it. Don’t stand for it! When you see blatant code duplication, leap out of your chair, grab your keyboard and start slamming in on the table while yelling at your monitor, “NO! NO! NO! NO!” Sure, everyone will think you’re crazy, and I suppose you might even get fired, but after an out burst like that you’ll be determined to do something about the duplication. And, who knows, after a few of them, maybe others will be more careful about it, being frightened by what you might do next time.

When you see the evil of code duplication, don’t let yourself be unmoved by it. Be outraged if it helps, but do something about it. How long will we allow this great evil of our time to endure? As the saying goes: all that is necessary for the triumph of evil is that good programmers do nothing.

Wednesday, February 24, 2010

Good article on Gradle

I happen to come across this great introductory article about Gradle:

http://www.javaexpress.pl/article/show/Gradle__a_powerful_build_system

It’s a lot better than the one I wrote, and should get you going in no time.

Tuesday, February 23, 2010

Gradle: building with bliss

I’ve used Ant for years, and though the XML can get annoying, it’s a great tool. It’s so flexible, and once you understand it, you can do anything with it. Gant addresses the XML issue by introducing a Groovy syntax for writing Ant scripts. But one of the biggest issues with Ant, in my opinion, is the amount you have to write just to get a basic build that compiles some classes, runs some test, and builds a JAR or WAR.

One solution to this is Maven. Another nice tool, though it uses XML also. With Maven you can have a build up and running in minutes. But Maven takes a rather radical approach. With Maven, you don’t have a build file, you have a Project Object Model (POM). You use the POM to declaratively describe your project. Then all the Maven plugins use that information and fallow a build lifecycle to do the actual build. So, you don’t have a build file anymore, the build is just something that happens based on what you have in your POM. The Maven people are pretty big on the whole declarative POM describing your project. This line of thought is illustrated by a quote from the Maven AntRun Plugin page:

It is not the intention of this plugin to provide a means of polluting the POM, so it's encouraged to move all your Ant tasks to a build.xml file and just call it from the POM using Ant's <ant/> task

In other words, “don’t defile our beautifully declarative POM with your dirty procedural Ant scripts.”

The declarative concept is really neat in theory, but builds are a procedural process. So at times it feels to me like Maven is forcing something unnatural. And any time you want to add just a bit of logic to your build, you have to go through the effort of writing your own Maven plugin or do it in Ant and use the AntRun plugin. Seems like it should be easier than that, to me.

So, what I really want is a tool as powerful as Ant, as easy to add logic to as Gant, and as quick to setup as Maven. That’s exactly what Gradle is. It has tight integration with Ant, so anything you can do in Ant you can do in Gradle. It uses Groovy for the build scripts like Gant, so adding a bit of logic is easy and natural. And it has a build by convention concept (via plugins) like Maven that allows you to have a build running with a minimal amount of effort.

The most basic build

Here is the most basic Gradle build file you can have for a Java project. In your project root directory create a file called build.gradle and put this line in it

usePlugin 'java'

If you follow the Gradle convention (meaning you put your source code in src/main/java), this one line build file will allow you to compile and JAR your project. By default the name of your project that Gradle uses (and the name on the JAR) is the name of the folder that contains the build.gradle file. To learn how to actually run the build, check out the Gradle user guide.

Running some test

To actually run some tests, we’ll have to add some more too our build. Again, we’ll follow the Gradle convention of putting test in the src/test/java folder and change the build file to look like this:

usePlugin 'java'

repositories {
   mavenCentral()
}

dependencies {
   testCompile 'junit:junit:4.4'
}

With this build file we can now compile our code, compile our tests, run the jUnit tests, and create a JAR. Not bad for just a few lines of Groovy.

Changing the source locations

If you don’t want to follow the Gradle conventions, you can change the locations of your source files and test files. To do this you use the Source Sets concept from the Gradle Java plugin. Adding this code to the build file will change you source location to the src folder under the project root, and the tests to the test folder under the project root:

sourceSets {
   main {
      java {
         srcDir 'src'
      }
      resources {
         srcDir 'src'
      }
   }
   test {
      java {
         srcDir 'test'
      }
      resources {
         srcDir 'test'
      }
   }
}

There’s a lot more to learn about Gradle, and I may post more about it in the future. If you want to learn more, check out the user guide. But honestly the best thing I can say about Gradle is that I barely spend much time working with it. It’s so flexible and easy to work with that most of the time when I need to add something to a build file I can get in there add the logic I need quickly and get it all working in a few minutes, then get back to working on my software. Which is really what you want from a build tool because customers don’t care about builds! So you want a build tool that allows you to accomplish what you need as quickly and easily as possible, so you can get back to doing the work that your customers actually care about. To me, that’s where Gradle really shines.