Through experience, I have come to realize that writing Google Web Toolkit Generators is far from being easy. In fact, when it comes time to improve the existing code base or add features, it turns into a nightmare. I’ve found all sorts of GWT Generators. Some were easier to understand than others, but every single time, it took me hours before I could do anything useful. That made me wonder, how can we improve the readability and the maintainability of a piece of infrastructure that inherently is hard to maintain due to its design?
- The answer
- Example: Cell Table
- The code generator
- What’s next?
The answer was quite simple. We actually see the solution pattern all around us in one form or another. It’s templates. I first thought I’d create my own template engine optimized for GWT, but then I came across Harald Pelh’s Piriti project and saw that he was already using the Velocity template engine for this purpose. My team is already using Velocity for other reasons, and I was stunned that I hadn’t considered using it for GWT Generator templates myself. Good on ya’, Harald!
Example: Cell Table
To introduce you to Velocity and demonstrate how I write code generators, I’ll go through a simple case that everyone has experienced in GWT: column definition in cell table widgets. They are redundant, tedious to write, and could be simplified by the smart application of abstraction and code generation. First let’s review how a simple table is written:
Extracting the column definition
It is clear to see how a bit of abstraction would let us extract the column definition. We will extract the column creation logic to its own interface and class. Looking more closely at the view, it’s also clear that it is burdened with too many responsibilities. Delegating the column creation logic to another object is a lot more elegant and better respects the Single Responsibility Principle.
Now that we extracted around 40 lines of code from the view to its own class, let’s use this class in our view:
Extraction of the creation logic to another class tidies up the view a lot. This is the key to my procedure: FIRST write real use cases before attempting to write ANY code generators. If you don’t, you will fail to truly understand your problem and will end up overengineering the solution. I’ve seen that countless times through the years. Even experienced developers skip the mandatory step of writing several use cases before implementing their code generators. It may seem redundant, but its not. It’s iterative, and clarity grows as your iterate. You first start by just writing out the case, then write it a second time, and abstract it. Write it a third time, abstract again, simplify; and only then should you write the generator, based on the actual use cases you’ve developed, which after several iterations is now at its most simple expression.
Transforming the column definition
With a real use case to guide us, let’s transform our column definition as an interface:
There are far fewer lines of code now! And the beauty is, if I want to remove or add a column, I only have to alter a single line! Does this remind you something? Bingo! This is exactly how Proxies with request factories are written! That being said, that also means that some rules need to be followed. Each method name has to match the method name in the POJO We could change this by adding an annotation argument, but this class already isn’t refactor-friendly, and an annotation argument would make that worse, so let’s keep it simple. Going even further, the interface could refer to a template like UiRenderer, ui.xml and be generated using the XML definition instead! Let’s keep that as food for thought.
The code generator
From this interface, you can now create your code generator. Since I know what the output will be because I have already written a working column definition class, I’ll use this code inside a Velocity template:
Before going further, I need to wire up all the needed classes for my generator. I find that using Google Guice really helps in creating classes that are simple, yet uncoupled, which leads to better readability as each class only has one responsibility. Now the fun begins, as we add the glue that GWT will use to transform this Velocity template into java.
This generator serve as my entry point for instantiating my Velocity Generator through Guice. Its only purpose is to set up the context and kick off generation. Nothing else. When it kicks off the generation, the generator will use the Velocity generator to start the code generation process:
It is really straightforward, I populate the ColumnsInitializerDefinitions class with all the information I need and that will be used inside the Velocity template. Then I give it as an additional argument in the Velocity context map. I’ve also made an abstraction of this Velocity setup that I use all across my projects to avoid repeating myself over and over.
This process may be a bit counterintuitive because to create generators that are easy to maintain and read, while being flexible enough to evolve, you need to repeat yourself! But consider this – in software engineering, when does it make sense to repeat yourself? When instantiating Design Patterns!
Design Patterns are architectural motifs that are repeated over and over with different parameters, to fit the specific requirements of your system. Some good candidates for code generation are Business Design Patterns, that resolve recurring system requirements in your application context.
You don’t have to be Martin Fowler or the Gang of Four to invent design patterns. Building software architecture for a specific business will require you to think out of the box about patterns that may not exist, but solve recurring problems in the context of your system.
Now we only need to wire the generator to the interface that needs to be generated:
First, we could add a lot of functionality for sorting, action cells, editable cells, and the like. I have only scratched the surface above, but even so, we can already see a big gain in productivity. Furthermore, we could use annotation processors instead of GWT Code Generators! While GWT gives a lot of goodies, we can’t really use those generators with anything else but GWT. Using annotation processors or any other java code generator framework, we can build code generators that are portable and, with a little bit of what I shared with you, maintainable.
If you’re looking for the sources and some of the missing classes, I invite you to take a look at the GWTP-CarStore sample. Have fun! 😀