Architecture Council/Top Ten Recommendations
This is a work in progress by the Eclipse Architecture Council to collect a "top ten" list of architectural recommendations for Eclipse developers. (Started in August 2008)
There is a similar top ten list from a UI Guidelines perspective (Top Ten Lists Working Page).
It is the nature of such a top ten list that it is not exhaustive but only highlights issues that tend to come up more frequently.
Eclipse Architecture Council members are invited to add items to the lists, or comment on existing items. We can use the monthly phone meetings to discuss relative priorities and what the final "top ten list" should look like. Please try to come up with fairly concrete items on which we can give good advice.
Top Ten Good Practices (work in progress)
- Minimize plug-in dependencies. You will end up with easier to maintain, evolve, and easier to reuse components if you find the right granularity. One good rule of thumb is to separate UI and non-UI code into different plug-ins. Another principle is to define layers along which you can split your plug-ins. For example, put custom widgets that only depend on SWT in one plug-in, use a separate plug-in for code that additionally requires JFace, and then another plug-in that additionally requires the Workbench APIs.
- Be asynchronous. Where possible, seek temporal decoupling between components. This means using asynchronous communication or events, and avoiding unnecessary dependencies or contractual promises about when particular actions or state changes will occur. In traditional software development the decision between using synchronous or asynchronous mechanisms is not so clear. Asynchronous APIs can be more difficult to program and use, and developers often favour simpler synchronous APIs. However, in the highly extensible and modular world of Eclipse development, asynchronous mechanisms are much more compelling. In particular, locking is highly deadlock prone because any interaction with another bundle can result in arbitrary third party code being called which may in turn acquire its own locks. Writing more asynchronous code also maximizes opportunities for concurrency, which avoids blocking the end user, and allows for better exploitation of the capabilities of modern multi-core hardware.
- Don't assume your bundle is the center of the world. When developing a bundle it is easy to adopt the mindset that your bundle is terribly important and must always be visible/loaded/available. When developing software in Eclipse it is important to think about how your bundle fits into applications where thousands of other bundles are present. This means imposing minimal or no overhead on memory/CPU/screen real estate until your bundle is concretely needed by the user or application. In Eclipse the user and/or the application are boss, and all other bundles are just along for the ride. In other words, don't speak until spoken to.
- Be lazy. (probably a duplicate of above, but perhaps "be lazy" is a better name)
- Long-running operations should report progress and be cancelable.
Top Ten Bad Practices (work in progress)
- Don't acquire locks or do interesting work in the UI thread. The responsiveness of an Eclipse-based application will be negatively affected by this. As a rule of thumb, anything that takes longer than 200ms is noticeable as a delay by end-users and thus should not be done on the UI thread where it will block the UI. Code that acquires a lock does not belong on the UI thread because this may block the UI for an indefinite amount of time. It can also easily lead to deadlock situations, or other dangerous side-effects such as a dialog that pops up telling the user that their current operation is waiting on a background thread. This dialog is dangerous because it spins the event loop, and thus potentially runs asyncExec code that can alter the state of the operation that is waiting on a lock.