Wednesday, December 5, 2012

Reflections on writing an Eclipse plugin

For a personal project I'm working on, the language choice is C++. Now that's probably going to make a lot of readers cringe because C++ has some bad rep, especially with the black magic voodoo that goes by the name of Templates. However due to the requirements of the app, C++ was a good fit. It's not too bad if you apply SOLID principles, design patterns, and above all good naming conventions. IMO a major contributor to C++'s bad reputation is the extremely poor names people use (the STL doesn't help either). We can see the porting back to C++ of good design concepts, most notably in the tools. Libraries like Qt make it almost like having a JDK at ones fingertips (but with a decent UI system). Did you know you can do TDD in C++?

I use the Eclipse CDT for my IDE which when coupled with the Autotools plugin makes it really easy to edit and build my code with most of the features I get out of the Java tools in Eclipse. You don't get everything, but it does a good job.

One thing I was really missing was a way to generate test classes quickly. I use the Google C++ testing framework as it's the best I've found that matches JUnit or TestNG. It's a bit clunky given the state of Java test tooling, it's style is very much on par with JUnit 3, but given C++ doesn't have annotations, it does really well with some macro magic. One can still use BDD style testing with a few compromises to get your code to compile. What I was missing was a "Create test class" option to keep my productivity from getting bogged down in making sure my #includes were correct.

I've been wanting to write an Eclipse plugin for a while, so I thought I'd use this itch as a chance. Turned out it was a lot easier than I had thought.

I downloaded the RCP version of Eclipse as it comes with all the development tools for making plugins. I personally like to keep my Eclipse installs separate for different purposes. About the only common plugin I use across all of them is my Mercurial plugin. I installed the CDT on top of the RCP so that I had access to all the CDT JARs since I was developing a CDT focused plugin.

Starting on writing the plugin was really simple. Of course I googled around first and came across a few helpful links:

The thing that made the plugin development easy IMHO was the plugin configuration editor. I was dreading writing XML and getting it wrong (try debugging that), or writing properties to configure the build (and finding reference documentation to do what I want). Thankfully I didn't get any obscure errors, the editor did it all. Took the fear out of the project. Coupled with some extra helpful documentation on plugin terminology and what not to do; I got my first wizard up and running very quickly.

Since I was making a CDT based plugin, I needed to set my API baseline. This helps the compiler figure out if you've been doing naughty things. This is a real strength, because by letting you know when you've violated API boundaries, you're able to future proof your plugin against changes to internals; or at least tell (via your plugin conf) that you're willing to risk the consequences.

Since I was wanting to create a special instance of the "New Class" wizard option, I subclassed the relevant wizards and wizard pages classes. The one big frustration was that protected methods in these classes used private members, or private inner classes. Which meant that to override the behaviour (but still keep parent behaviour) some nasty reflection hacks were needed. I think the design moral there is that if you are going to allow your methods to be overridden make the data accessible (most likely through protected accessors). Either that or mark the methods as final so that the compiler lets you know that "you can't do that Dave". Unfortunately these CDT classes violate the whole Open Closed principle. Other than that it was actually pretty easy to debug my way through the "New Class" wizard to get an idea of how I could create a specialised class geared towards being a test class and writing the behaviour.

The bulk of the code was written on the train going to/from the YOW 2012 conference so hopefully that conveys just how easy it was once I got going. It's a credit to the PDT guys that banging out a plugin is that easy; in terms of the infrastructure code required to hook it in; I mainly had to work on application logic which is how it should be.

The final result is the Google Testing Framework Generator, so if you can make use of it, please download it and make suggestions/patches. I have a few other extra ideas of code this plugin can generate, but for now I'm just going to TDD my way faster through some new features for my C++ project.

No comments:

Post a Comment