Maximizing the reuse of existing code is a fundamental part of the software development process in today’s landscape of complex applications and systems. The ability to implement and leverage existing code provides many real benefits to developers. The difficulty comes from having to choose from the plethora of available options and balancing the desire to create something new. Jeff Atwood (2007) once stated, “[T]he best code is no code at all.” For developers this does not mean that they should never create anything new, it means that they should attempt to use the available tools and strive to reuse as much code as possible (para. 6). With every new line of code written there arises a burden of potential defects and of having to support it over time.

The benefits gained from the reuse of existing code are substantial in both the initial development of an application and throughout its maintenance lifecycle. The two main benefits achieved from reuse are a reduction of the overall development effort and that a higher level of consistency is achieved. Through this consolidation of code, common processes and algorithms are coded once. By having one shared implementation, the testing required to prove the correctness of the process or algorithm is only done once. This consolidation allows for more comprehensive testing to be performed, which in turn leads to fewer defects in the code.

Object-oriented programming languages provide many built-in features to help facilitate and set constraints around code reuse. One such feature is the ability to assign visibility to created classes, methods, and variables. This ability allows developers to establish how their code can be interacted with and reused by others. The three common levels of visibility are public, protected, and private. Items flagged as public are openly visible and usable by others. Items that are flagged as protected are only visible and usable by items that inherit from or extend the item. The most restrictive is private visibility where items are only visible and usable by the containing item they where created in. By restricting access to a define set of interaction points, developers can encapsulate the internals of their code base from external consumers. This restriction allows for the protection of the integrity of the intended functionality of the code. The visibility constraints introduce a level of control by forcing interactions to occur in predefined ways. External interaction points are flagged as publicly accessible and internal functionality that is not intended to be used or interacted with directly is hidden. This allows the internal functionality to be changed without affecting external consumers. By applying different levels of visibility, a design and method for future reuse is built into the code base. Object-oriented methods provide a similar level of encapsulation of functionality when compared to modules in procedural programming. Both models facilitate code reuse by defining constraints on how to interact with the encompassed functionality and by defining both input and output data structure definitions.

Data and its handling within code can also benefit from encapsulation. Data can flow through a program in two main forms, either raw or encapsulated. An advantage of using encapsulated data is that all access to the data is controlled. This control is implemented in the form of access methods that act as gateways when setting or retrieving data. The gateways can enforce validation and constraints on the data in order to preserve the data’s integrity when setting and can provide a level of consistency when retrieved. This layer of abstraction also allows the internal handling of the data to be changed without affecting external consumers. The downside of data encapsulation is that it adds an extra step and a level of complexity to all interactions with the data. On the other hand, data can be passed around within a program in a raw form. This is typically done in one of two ways. The first way is that the raw data is passed by reference value. This reference value is initially created when the data is stored in memory. From that point all interactions done via the reference are done against data stored the single instance in memory. The second way is by passing a copy of the raw data to each consuming function. This method isolates any changes to the data to just the invoking consumer. The benefit of passing raw data around in a program is that it is easy to implement and performs fast at runtime. The downside is that each function that consumers or modifies the data must implement their own validation and constraints. Care must be taken as a consumer can easily modify the data in a way that breaks other downstream consumers.

Code reuse can also extend across many different programs. Common sets of functionality can be bundled together to create reusable libraries of code. Code libraries created with the general intent of being used by other applications are called application programming interfaces (APIs). API libraries are typically included directly with the invoking code base. Another type of reusable code base is a hosted service. A hosted service is similar to an API library in that it provides a standard means to interact with a defined set of functionality. Hosted services are typically controlled and executed externally from the invoking program.

In conclusion, code reuse has many benefits in today’s complex programming landscape. By leveraging existing code, new software can be created in a fast and efficient manner. In the end, developers should strive to leverage as much existing code as possible. However, if they do find themselves in a position that requires the creation of new code they should at least reuse an existing, tested model.

References


Published: June 18, 2013