Plug-in Best Practices for RCP

I just finished giving a talk at Eclipse World entitled Plug-in Best Practices for Rich Client Applications. For those who attended, and anyone else who’s interested, here is a summary list of the practices discusses. Feedback is obviously welcome and much appreciated.

Encapsulation

  • Design plug-ins to maximize encapsulation. Expose packages only when forced to.
  • Use a package structure that maximizes your ability to hide code.
  • Never mix public and private classes in the same package.
  • Consider incorporating the “internal” keyword into your package naming convention.

Cohesion and abstraction

  • Start thinking of plug-in contracts in addition to traditional class/type contracts.
  • Your plug-in should have a coherent API. In some cases, this can be composed of a set of factories that return a set of interfaces.
  • A plug-in should represent a coherent concept or subsystem.
  • A plug-in should do one thing and do it well.
  • Add a “New plug-in” refactoring to the list of design refactorings you look for.
  • Many fine-grained plug-ins should be preferred to a few large-grained ones. Don’t worry about plug-ins with a small number of classes.

Dual use code

  • If code is going to be used both inside and outside of an OSGi framework, make it into a plug-in. It’s still just a JAR!
  • If running plug-in code outside of an OSGi framework, remember that your encapsulation mechanisms will no longer be enforced at runtime. The “internal” keyword in package names can help here to inform non-OSGi developers that they should not access certain code.

Third party libraries

  • Third party libraries should always be distributed as separate plug-ins. Do not embed these libraries into plug-ins that also contain your own code.
  • When using third party libraries, look at repositories like Orbit to see if there is already a version packaged as a plug-in.
  • Move third party plug-ins out of your workspace and into your development and build targets.

Activators

  • Activators should be used strictly for lifecycle management. Do not let them become a dumping ground for factory methods.

Plug-in dependencies

  • Visualize plug-in dependencies as a stream, not as a hierarchy.
  • Use Require Bundle to declare dependencies when you want to hard code a dependency to a specific plug-in.
  • Use Import Package to declare dependencies when you want to allow multiple plug-ins to provide an implementation.
  • Minimize the coupling between plug-ins, just as you do with classes.
  • Use extension points and OSGi services to help minimize coupling.
  • Avoid reexporting dependencies unless the exporting plug-in represents a coherent API. Unnecessary reexporting leads to dependency leaks and makes issues like circular dependencies hard to track down.

RCP-related

  • Always create development and build targets for your application. Version those targets.
  • Place RCP product definitions (Application, advisors and branding) in separate plug-ins, Do not mix products into your other code.
  • Use features to wrap your plug-ins and simplify your product configurations.
  • Place unit tests in a separate plug-in or, better yet, a plug-in fragment.