Important considerations for effective Collaborative Software Development (CSD)

With the rapid progress of software engineering, software development has become so complex that no one person can master all the necessary skills. Collaboration is essential for efficient and effective product design and implementation. Without collaboration, it would be impossible to manage such a complex effort effectively.

Collaborative software development (CSD) is about people – specifically, how developers work together during the entire life cycle of a piece of software. Consequently, this must be an iterative process where each iteration produces some key deliverables (e.g., code modules). Planning is important but cannot provide results until products are actually built; CSD requires products on which to collaborate on their way to becoming fully functional systems. This article first discusses why collaboration matters, what its goals are, and what some of the challenges are. It then discusses how to apply CSD principles in an iterative development process.

Collaboration matters because it is the only way for developers to manage the complexity that accompanies rapid advances in computer science and technology, which have made it possible to build powerful software systems that were once thought impossible. Collaboration also matters because product development requires more than just building a system – it requires involving customers while design decisions still can be made easily. Furthermore, today’s software has become so complicated that no individual can fully comprehend its behavior; understanding such complex products requires multiple people working together (and using tools) over extended periods of time. Finally, collaboration matters because each person brings unique skills and insights into the process.

Collaboration is crucial to ensuring that complex software systems are designed effectively and built in an optimal way. Without collaboration, developers would not be able to address the numerous design issues that arise when building complex software systems, which would result in products that are more difficult to use, are less reliable, are harder to maintain, or may even be impossible to build. Finally, without collaboration it would be difficult for managers to ensure that lower-level decisions are consistent with higher-level goals or reflect customer expectations and needs.

Collaborative development also ensures that customers get what they want and need from a product and helps them feel comfortable with major design decisions before work on implementation begins. The process of designing a system with customers need not be restricted to a stage in the life cycle. Rather, customers can contribute throughout development and continue to do so even after initial release of a product. In fact, later customer influence is extremely important because it may encourage changes that improve the product over time or make it more suitable for future applications.

In addition, when developers work together from design through construction, they often find opportunities for significant cost reductions by eliminating redundancies in the resulting system. Finally, working in teams with various specialties ensures that tasks are completed quickly and effectively because different people have unique skills that complement each other’s abilities. This synergistic effect is what makes collaboration effective: With multiple minds working on a problem simultaneously, the probability increases dramatically that successful solutions will be found.

Collaborative development is also important because it provides a mechanism for developers to learn from past experience, as well as learning about new and better ways of doing things. Devoting time and effort to reflect on and gain insight into problems that arise during development can pay great dividends by helping future efforts proceed more rapidly and with higher-quality results. Some of these insights may result in significant cost reductions or higher-performing systems; others may point out subtle flaws in the original approach, which permit elimination of potential obstacles before they become major impediments. The participants in such discussions must be knowledgeable enough about the software system’s internals to be able to contribute meaningfully to the discussion. Not everyone will have an equal voice – those who are best equipped to contribute are most likely to be heard.

The process of collaborative development also involves the creation and use of tools that help people perform their activities more effectively (e.g., documenting requirements, creating simulations, developing models). For example, using tools to easily share information among developers about important design decisions can ensure consistency in approach. Furthermore, when team members work separately on different parts of a system but need to coordinate their efforts with each other, the ability to access documents containing systemwide knowledge is invaluable. Collaboration can thus reduce unnecessary duplication of effort and possible inconsistencies in the resulting product by defining common data structures and including them in many modules rather than duplicating information in every module where it is used.

Collaborative development also reduces risks by ensuring that the activities of its participants complement and reinforce each other. When no communication exists among developers, both interdependencies and redundancies can easily arise between tasks and modules as developers make up for missing information or shared knowledge through guesswork or temporary specification documents. These guesses must be verified later; if they are incorrect, significant time may be lost as problems are uncovered and fixed.

When communication takes place, however, such problems may become immediately evident because people can compare their current views of a system with those of others. The time spent early in the development process clarifying problems that might otherwise manifest themselves much later is well worthwhile: It ensures that rework will not be required simply to resolve inconsistencies created by developers working independently. If everyone can come to an agreement about how a system should be developed, there will be no need for guesswork.

User-Driven Software Development
When users are involved in software development from the beginning – by specifying their requirements and participating throughout the process – better results are achieved. Not only do user-driven projects result in systems that meet real needs, but they cost less to develop because fewer development resources are wasted on unnecessary features or functions.

Early involvement of customers ensures that the product’s scope is defined properly within realistic time and budget constraints. Furthermore, early project milestones can provide opportunities for customers to give developers feedback, enabling them to revise design decisions as necessary before construction begins. Feedback is likely to be enthusiastic because the users’ needs are accounted for.

Iterative Development Processes
An iterative development process is one in which objects are defined, designed, implemented, and tested repeatedly over time, with each cycle serving as a basis for refining system specifications. This approach can be used effectively to reduce risks by allowing developers to begin testing early, rather than waiting until all components have been constructed before discovering interface or performance problems that require significant rework. The risk of object-oriented design is reduced by identifying the most complex parts of the program first – those parts requiring the most planning and design effort – so that detailed knowledge of them can influence decisions made about less complex objects later on. Iterative development processes thus increase productivity by ensuring that design and implementation errors are discovered early, when their impacts on schedules and budgets are least severe.

The iterative approach is also advantageous in that it helps avoid a “big-bang” development approach, in which all design is completed at the outset before any coding begins. In a big-bang approach, a team of developers works in relative isolation from each other until the final stages. Little communication exists between designers and coders because they may bear no responsibility for objects designed by others on the team; consequently, integration problems unnecessarily delay testing with users. In an iterative process this problem does not occur because interaction occurs throughout construction rather than being limited to integration or test activities toward the end of the project.

Laboratory Workbenches
An effective way to facilitate interaction among developers is with a software workbench that supports direct manipulation of objects, including graphical views of the artifacts to be constructed. Laboratory workbenches use special-purpose tools to help developers understand the objects they are working with and to enable them to make design changes as necessary. This approach can be used effectively to ensure that system specifications are well defined and will not require extensive rework once development begins.

What is a Laboratory Workbench?
While traditional programming systems support straightforward code generation, laboratory workbenches support a model-driven approach to software development. This approach enables developers to work with models of the objects they are constructing, rather than working directly with source code. The models can be implemented in any formalism that supports explicit object definitions, including the Unified Modeling Language (UML).

Laboratory workbenches typically provide a number of tools that support the development process. These include:

Parameterized objects, which abstract a design from specific instances and allow variations in object behaviour [e.g., parameterized classes]. Developers can use parameters to vary an object’s behaviour without changing its code or interface. For example, in a two-player game represented as a class in a programming language, the type of player (human or computer) could be used as a parameter so that players could have different characteristics when human versus computer is selected.
Action languages enable users to implement operations on objects by specifying their behaviour rather than writing procedural code [e.g., rule-based programming]. Users specify rules for modifying values within the context of an object. The rules can be used to update the object’s values when events occur, such as a user selecting an option from a menu. For example, if a customer is identified from a database and then placed in an order within the system, rule structures specified by the developer would update the customer record with information about their new order.
Module interconnection languages offer diagrams that can specify how different components of a system interact [e.g., hypertext]. These languages describe how modules are interconnected and allow developers to document these interactions. Since they do not encode implementation details, developers need only understand the specification, not all of its implementations. This allows changes in underlying implementations to occur without affecting existing code or documentation [see also Component Software].

The benefits of laboratory workbenches are that they support the definition of models early in the development process, thus facilitating communication between designers and developers. The models help ensure that system requirements are understood by everyone on the team, including users if necessary. Laboratory workbenches also provide tools to make changes once construction begins, minimising rework at integration or testing stages. Models can be quickly redefined without changing existing code or documentation since underlying implementations are encapsulated within model definitions. This speeds up debugging because only objects associated with a problem need to be examined rather than all objects in the system. Finally, these systems allow developers to explore new ideas since design decisions can easily be refined during software construction.

Testing Methodologies
Testing is a critical part of the software development process as it provides an opportunity to find errors before users do. In an object-oriented system, testing can be performed at various levels depending on how much detail is required. Testing should begin with unit tests that break down components into their smallest parts and examine interactions between individual units for correctness. Additional tests should build up from this foundation by increasing the level of abstraction appropriate for any given component or group of components. For example, if a high-level abstract class fails a test, there may be a problem with its definition rather than one of its subclasses defined below it in the inheritance hierarchy. Similarly, if a low-level concrete subclass fails, perhaps the problem lies either with another subclass or a different object altogether.
Testing the interactions between components is generally much more difficult than testing individual units because it requires a broader knowledge of the system as well as a way to test objects outside their intended context. The latter can be difficult since dependencies or other kinds of relationships between objects may not be exposed through public interfaces. Because this type of testing often relies on knowledge about concrete classes, it offers less general coverage across all clients and therefore should be targeted to those cases where higher-level tests have failed.

Hopefully this has given you some things to ponder about Collaborative Software Development. If your business is considering a bespoke software development project then we would like to help, want to chat?