Top 10 Component Mistakes
It is pretty well accepted now in development circles that systems usually can be built with components, especially pre-existing components, more efficiently than they can without. As a result, component development and the building of systems with those components has become the focus of more developers than ever before.
As more people work with components, examples of the common pitfalls and problems start to come to light. In this article, you are presented with ten of the most common mistakes made when developing component-based systems and the components that make them up. Although the focus is on Java-based components, most of these problems occur within other languages as well.
1. Fitting the Wrong Design into Components
The first, and perhaps most common, component mistake seen is when developers attempt to "force" a design into a component pattern when it was not originally thought out that way. Although it is quite possible to occasionally find a section of an existing system that can be "broken out" into a component or service, it is more common to find a retrofit involving components that attempts to preserve too much of the existing design at an implementation level. This is true even if you're only starting from a design, rather than an existing system. This often happens when the specifications of the system are followed too literally, or followed from a user-interface point of view rather than a perspective of components and services interacting to provide functionality. When thinking components for services, the user interface is not normally that closely tied to the component structure behind the scenes, whereas some older systems might have a module for each user "screen" or "page."
Sometimes, components are force-fit onto a back end in an attempt to gain the benefits of components, only resulting in another developer thinking components aren't worth the trouble!
Design of component-based systems is covered extensively elsewhere, and I won't try to describe it heresuffice it to say that if the design doesn't take components into account, no amount of code can make up the difference.
The solution is not to "postpone" components in your system, but take them into account from the initial design. Then, the coding will flow more naturally from the design. When retrofitting an existing system, isolate the areas where component-based design can be applied, and consider creating an API to the remainder of the system, maintaining the distinctiveness of the new components.
2. Writing an "Almost Component"
The second common problem I see is the "near miss"a chunk of code that started off right, and nearly became a functional component, but then somehow went astray. This often happens when the final stages of development are rushed for budget or time constraints, and developers need to "make it work" rather than "make it right." A few sections of an otherwise good component are hard-wired to, say, an underlying database layer, or a last-minute interdependency is injected into an otherwise well-isolated design.
This is much more common than we'd like to believe, and again results in components in general getting a bad name when the project is finished. A "near miss" ends up being just as much (if not more) work than a "good" component, but with few of the benefits.
3. Tight Coupling
A feature of a well-written component is its independencenot only from the remainder of the system, but also from other components. Of course, it is often valuable to have components use other components, but an over-reliance on this capability can result in a tangled web of dependencies that reduces the re-usability and maintainability of many componentsand conspires to defeat one of the major advantages of component-based development.
As a general rule, components should never depend on other componentsalthough they might depend on the interface to other components (or services). The difference here is large: A direct dependency is very hard to change later, whereas a dependency on an API allows a component simply to be swapped out with another that implements the same API.
Now, dependencies at this level (designed component dependencies) are a different animal than library dependencies (for example, where your application relies on the presence of certain JAR files to compile/run). External library dependencies, however, should also be minimized wherever possible, and definitely recorded formally in conjunction with the components they support (for example, JAR file X is required by component Y). An excellent system for organizing such things is the Apache Maven project.
4. More Plumbing than Pipes
Another frequent mistake when working with components is spending too much time building the stove, and not enough time cooking the meal. It is easy to get caught up in the ongoing debate about what component framework to use, and to decide that the right decision is not to use anybut to build your own. Although there may be rare circumstances where this is appropriate, in the vast majority of projects there are simply too many excellent choices out there for component frameworksavailable under a wide selection of licenses, from commercial to open source to free softwareto make it worthwhile building your own.
Also, the apparent simplicity of some frameworks might fool you into thinking they're quick and easy to build. Perhaps some arebut not the good ones. The small optimizations and discoveries that come about once a component framework has been in use for a while, and has been used for a number of different projects all contribute much to its utility. Re-discovering these subtleties is expensive and time-consuming work; be sure you have a good reason to do it before you decide to re-invent any wheels.
At the opposite extreme from trying to "roll your own" component framework is the mistake of trying to make use of components with essentially no framework at allor with custom code trying to "glue" components together into a cohesive system. The advantages lost when making use of a non-standard mechanism for working with components are considerable.