Plugins are arguably the killer feature for Atlassian products, as they allow you to tweak a theme or deploy full-blown applications within a familiar environment and infrastructure. The number of plugins available, especially for established products like Confluence and JIRA, is huge and the amount of extension points available to plugins basically give you full control of the host application. That much power comes with a price – your plugin is heavily tied to the product, and anyone who has done something similar, like tried to write an application on top of Microsoft Excel with a ton of VBScript, knows how sensitive your Frankenstein application is to host application changes and upgrades, let alone bugs and stability issues.
In JIRA Studio, we are working with the common platform of JIRA, Confluence, Fisheye/Crucible, Crowd, and Subversion, but the applications the user will visually interact with are JIRA, Confluence, and Fisheye/Crucible. If we want to add a new feature like, say, a top navigation bar, we have to add it to each product as a plugin. Since plugins are tightly coupled to each product’s APIs, we have to basically write three different plugins. Here are a few of the differences in the latest version of Atlassian products we have encountered so far:
|Components||Setter injection via Spring 2.0.6||Constructor injection via PicoContainer||Setter injection via Spring 2.5-m1, only used in a few places|
|Web actions||Uses WebWork 2.1.5||Uses WebWork 1.4 (forked)||Uses WebWork 2.1.7|
|Settings persistence||Bandana allows you to store any serializable object globally or against a space||PropertySets only support Strings globally or against a project||XML (via XMLBeans) can be added to the main Fisheye config file globally or per repository.|
|Logging||Log4J 1.2.8||Log4J 1.2.7||Log4J 1.2.11|
|HTTP calls||Nice HttpRetrieverService that abstracts HttpClient, deals with authentication automatically (between Atlassian products)||Nothing provided, includes HttpClient 3.0||Nothing provided, includes HttpClient 3.1|
As you can see, when writing even a moderately complex plugin, you have to be very aware of the differences across the applications, even in fundamental areas like logging. Furthermore, the differences will force you to write three plugins instead of one: three times the code, unit tests, functional tests, and potential for bugs.
For our own sanity, we’ve created the Studio Application Access Layer (SAAL), which is a set of service provider interfaces for infrastructure-level features that allow a plugin to rely on key services provided by a single API without having to deal with the multiple implementations. SAAL includes interfaces for the following features:
- Service object lookup
- Settings persistence
- HTTP calls
- Internationalised message passing
- Plugin upgrade framework
Our thought is to grow this layer organically for our needs when writing plugins for JIRA Studio. This allows us to a) minimize the amount of code to maintain and b) minimize the conceptual surface area for plugin development. The end game is to have the code interfaces and classes put into Atlassian Plugins, with the individual products responsible for the product-specific service implementations.
This is a good example of how creating JIRA Studio is actually helping the core products as much as creating a new one. You’d think that every product at Atlassian would follow the same development practices, use the same libraries, or even implement individual features the same way if developed at the same time, but alas, that is not the case. Different teams have different leads with different developers, which all amounts to slightly different interpretations of Atlassian ideals, and of course it isn’t always feasible or even advisable to, for example, spend months rewriting your web layer with no customer benefit because WebWork 2 was released. A secondary goal of JIRA Studio is to confront those technical differences and try to wrangle them into alignment for the benefit of the customers of both the Atlassian product and JIRA Studio.