An environment and culture that promotes reuse can offer tremendous value to your company. Most developers think of reuse in terms of code reuse. In fact, that is usually the logical place to start. The major benefit to reusing code is that applications will be faster and less expensive to build. There should be no question that applications can be assembled from reusable objects faster than they can be built from scratch, so faster development time is a major benefit.
The second major benefit is improved quality. This results from the use of pre-tested objects. Reusable objects are more stable, deliver more predictable results, and are less prone to errors in production. Faster development time and higher quality from the start should also result in less expensive solutions. This is true on a project-by-project basis. For instance, each project will use less development time and money, and there is less testing required because you are using components that have been tested already.
However, there are increased costs for the entire organization because of the new processes and tools required to support the reuse environment. In fact, it is these overall environmental costs that typically spell doom for most reuse efforts. To really be successful in creating a reuse environment, you need to establish some rules on sharing, have a place to store the reusable components, have processes to help people find and use the components, etc. You will also find that components that are built for reuse take more time and effort to create, so although there is increasing value with each reuse, the original development time may, in fact, be longer and more costly.
One overall point to remember is that there are two basic aspects of the reuse culture. First, in almost every activity you do, you first think about whether there may be something already available that you can use. If you cannot use it entirely, can you at least use it as a starting point?
Secondly, for every piece of work that you create from scratch (there will still be a lot), always ask yourself whether this work is something that someone else may be able to reuse later. Of course, if you ask those questions today, they won’t do nearly as much good because you do not have an infrastructure in place to handle the reusable components. However, that is the whole purpose of putting the environment in place.
There are opportunities to reuse previous work in both the Planning and the Analysis Phase. For instance, you may be able to reuse similar process and data models from a previous solution. However, it is usually the Design and Construct Phases where reuse really comes into play.
Reuse Environment
As you are designing your solution, you will find many opportunities to consider whether the components you are designing and building could have reuse value to other projects in your organization. However, the decision on whether or not you actually build the component for reuse depends on whether you have an overall environment that supports reuse. Most organizations do not support a reuse culture. There is an incentive to get each project completed as quickly and as inexpensively as possible. Even if you build a component that can be reused, there is no repository to store the component, no way for others to find it, no way to update the component if an error is found, etc.
If your environment does support reuse, it must be based on a set of reuse standards and processes. From a design perspective, determine what these reuse standards are and build them into your design. Not all components are candidates for reuse. However, those components that are candidates for reuse can be designed to include your reuse standards. In that way, when the Construct process starts, these components can actually be built to be reused by other applications later.
Designing for Reuse
You can design some components in a way that allows them to be reused later by other applications. Here are some of the techniques and concepts to keep in mind.
- Partitioning. Partitioning is a fundamental technique to separate the code/logic into discrete service layers. These service layers start out very detailed and technical, and then get more abstract and understandable by humans as you get further out. For instance, you might separate a web application into a user partition that is controlled by a web browser, the business logic that runs on a server, and the data layer that resides on a separate database server. The actual partitions are all logical. In fact all three partitions in the prior example could reside on the same physical machine. Separating the logic into partitions provides the following benefits.
- Minimizes the impact of change. If a change is required in the overall business function, it is possible that it can be isolated to one of the partitions, which makes the change easier to code, test and implement.
- Physical implementation flexibility. Partitions allow different code to reside on different platforms, which provides extra flexibility in your technical architecture.
- Scalability. Partitions allow you to isolate business functions and scale them up or down without impacting the rest of the code. For instance, if you need more room for your database, you can move that function to a larger database server without impacting the rest of the code.
- Use inheritance, but don’t go overboard. Inheritance is a process where programs inherit characteristics from programs that call them. While inheritance is a powerful and useful feature, it has some drawbacks. For example, the more levels of inheritance an object has, the more complex it becomes. It can also become more difficult to understand the impact of having to change a reusable component if it is used in many embedded and inheritance situations. This is not to say that you should not use inheritance, but rather to say you should minimize the levels of inheritance to achieve optimal performance and also to minimize code complexity.
- Use encapsulation. Encapsulation means that you create a reusable component with everything that is needed for that component to run. You publish the interface details to describe the parameters. The component then executes and performs some well-documented function.
- Reusable artifacts must include adequate functionality. This is a very important design consideration if the component is to be reused as intended. If an object doesn’t have sufficient functionality, that object may not be reused again. For example, a routine that captures “5 4” zip codes will only be reusable in the United States. However, if the routine is abstracted at the higher level of “postal codes” instead of “zip codes”, it may be able to be reused around the world.