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.