Best Practices
ContentsThis chapter is organized as follows:
- Goals of Team Development
- Sharing Within a Team Environment
- Protecting Configuration Items From Unintentional Changes
- Managing Relationships Between Configuration Items
- Managing and Delivering Configuration Items
- Improving Efficiency in Team Development
- Recommendations
- Advanced Concepts and Heuristics
Goals of Team DevelopmentDeveloping complex systems requires that groups of people, such as analysts, architects, developers, and testers, coordinate their efforts to produce the finished product. Consequently, they must ask themselves the following questions:
- What are we trying to accomplish in team development?
- What are the goals of team development?
- What do I need to do to have efficient and effective team development?
The purpose of this book is to outline the goals of team development, and recommend some best practices when using Rational Rose to help ensure success.
Team development touches on development, testing, configuration management, project management, and other disciplines such as engineering, analysis, and design.
This overview of team development helps provide your team with an overview of the challenges associated with team development, while specifically outlining the tools and mechanisms Rational Rose supports to aid in implementing a team development strategy.
The Guide to Team Development provides an overview of the basic team development concepts in Rational Rose and specifies how to configure and use Rational Rose in a team environment.
The goals of team development are to:
- Allow team members to share their work with a team. See Sharing Within a Team Environment .
- Protect configuration items from unintentional change. See Protecting Configuration Items From Unintentional Changes .
- Manage the relationship between configuration items. See Managing Relationships Between Configuration Items .
- Deliver specific versions of configuration items to interested parties. See Managing and Delivering Configuration Items
- Reduce or eliminate disruptions to team activities. See Improving Efficiency in Team Development .
Sharing Within a Team EnvironmentAfter a developer completes an activity (work), they require a mechanism to share that work with others. Integration is the mechanism that permits the integration of changes made by a team member into what is currently being shared.
A version control system can facilitate the work flow of team members. A team member working on a shared artifact acquires some type of implicit or explicit permission to check-in their work by performing a check-out prior to working on the artifact.
The check-out status for the artifact indicates to other team members that work is currently being done to change the artifact. A configuration manager or configuration system can monitor these operations and enforce any policies. The mechanism can involve the use of a version control system, or it may be an unsophisticated implementation whereby the check-in is a simple copy, and the communication is verbal between developers. Regardless of the mechanism used, an awareness of a change at the appropriate levels must be achieved, and you must assess the implications of the change.
A check-in does not necessarily imply that the artifact is immediately available to team members. Typically, it is useful to work with older versions of shared artifacts until such time as the team is ready to access the latest version.
A version control system allows the team to return to previous versions of work, while providing an audit trail of changes. The desire to associate work with specific requirements is a type of policy the Integrator can enforce at integration time.
Work produced by a member of a team can affect other members of the team; therefore, those effects must be intentional. A copy of the work is made available to a team member in an environment isolated from other team members.
The environment is only isolated one-way. The work environment can see shared team artifacts, but other environments are not effected by the isolated environment. The benefits of this type of implementation are:
- Development team members can produce builds in their isolated environment in an iterative, non-intrusive way. It also allows team members to see a read-only version of shared work.
- Testing teams can perform a series of tests on a specific lineup of work in their own test environment. A lineup is a collection of specific versions of files from a version control repository.
- Production users can use a particular lineup of work that has met quality control criteria.
Protecting Configuration Items From Unintentional ChangesThere are several ways revisions can cause unintentional changes:
- Direct conflicting change where one change overwrites another. See Overwriting a Modification .
- The source from one change conflicts with another change by removing a dependency that one of the changes relies on. See Adding Dependency Issues .
Table 1 shows the legend that explains some images found in Figure 7 through Figure 11.
Table 1 Image Legend
Image Description
Represents a unit of work or configuration item
Represents movement
Represents an unintended change
Overwriting a Modification
If a team member shares their work with the team, not realizing that someone else produced or edited some work with the same name, they may overwrite the changes of the other team member.
Figure 7 Overwriting a modification
Most version control tools provide adequate protection from this type of unintentional change through a process of obtaining permission to make modifications, called a check-out. The version control tool grants implicit permission when there are no check-outs currently in place. When one team member has an artifact checked out, other team members are denied permission to check out that same artifact until it is no longer required by the first team member. Figure 8 shows a scenario where a check-out is followed by a check-in, allowing the sequence of events to iterate.
Figure 8 Check-out and Check-in Scenario
This type of scenario may cause contention that is unacceptable for high traffic work items. The diagonal lines in Figure 9 indicate that a check-out cannot occur until the previous check-in process completes.
Figure 9 Checking Out an Artifact After it is Checked In
The problem illustrated in Figure 7 commonly occurs in strategies that do not use a version control system. Because previous versions of configuration items are always available to developers, the possibility of having this type of unintended change always exists. A developer may make changes to a private copy of an artifact without permission to do so. Subsequently, they may acquire the appropriate permission and check in the changes of the local copy that may not represent the latest version of the configuration item.
You can use a merge tool to apply a combined set of changes in situations when multiple team members have permissions to make changes to a single artifact. Figure 10 shows how you can merge two changes made to the same artifact.
Figure 10 Merging Changes Prior to Check-In
It may be difficult to remove a set of changes that occurred in a previous version of an artifact. The situation in Figure 11 shows us three versions of an artifact. If you want to remove all changes applied to the second version (the changes occurring between the two diagonal lines), you may encounter difficulties.
Figure 11 Comparison Between Versions
For example, the changes between version 1 and version 2 must be compared to the changes between version 1 and version 3.
Obtaining adequate permission to modify artifacts helps to ensure that unintentional changes do not occur. Configuration management can choose to implement and enforce this type of policy.
Adding Dependency Issues
Modifying an artifact may cause a conflict with another change if it removes a dependency that one or more other artifacts rely on. Figure 12 shows how this type of problem can occur.
Figure 12 Removing Required Dependencies
Developer A and B individually check out artifacts A and B respectively, and have access to the shared version of artifact A and B respectively.
Developer A creates a new dependency in foo() by adding myBar-> bar().
Developer B makes changes to bar() in class A by changing the parameter signature to integer.
Changes to bar - from bar() to bar(int) - cause any references to this function to fail. The changes made by Developer B to artifact B that are referenced by foo from artifact A are not valid.
Note: Most merge tools are unable to identify a conflict here because they compare items of work individually, and not against all referenced work.
This type of change is common and may have serious implications. Often, when product maintenance is underway and feature development is concurrently managed, the maintenance person or developer may be unsure or unaware of all dependencies involved in a proposed change. Rather than research all the dependencies associated with the artifact, they do not modify the original item. Instead, they create a new item with the proposed changes.
Managing Relationships Between Configuration ItemsTeam members must understand and use the dependencies between configuration items to reduce or prevent unintended changes in the system.
Because most configuration items do not work in isolation from other configuration items, a set of particular versions of configuration items has a set of dependencies. When a set of versions of configuration items changes, the possibility exists that the dependencies also change. It is useful to compare the set of dependencies from one set of versions to a previous set to ensure that dependency changes are intentional.
A set of versions of configuration items is also known as a lineup. Figure 13 shows a generated dependency report for a lineup identified by the label called ALabel. Later, a comparison is made between ALabel and another dependency report generated for the lineup identified by BLabel. Although the dependency reports themselves may be too large to be of any use, a good differencing tool can make it easy to see dependencies modified since a previous stable lineup of the project artifacts.
Figure 13 Comparing Dependency Reports
Specific to Rational Rose, there are several levels of dependencies that must be understood and managed:
- Dependencies between control units in a model.
The Rational Rose Toolset interprets what is loaded into memory as the entire model. When loaded from separate configuration items, the model elements stored on secondary storage must be loaded such that it creates a model where elements are consistent with any corresponding relationships.
- Model element relationships
Managing and Delivering Configuration ItemsA specific set of configuration items in their appropriate version (a lineup) must be accessible and reproducible. Protection of these version sets is important. Like most one-to-many relationships, a label is often stored many times; once with each configuration item.
Figure 14 Labelling Configuration Items
Figure 14 shows the following:
- The full set of configuration items are not all labelled at the same time.
- A configuration item may be overlooked or may not be associated with the label. Sometimes, it is better if the configuration item is not associated with the label. The label associated with a previous version of the configuration item would make the problem difficult to find.
A fixed label is the first primary use of a label, forever identifying a version of a configuration item with a specific label. It is also useful to include in your naming convention details, such as the date and time in a label name.
The two types of floating labels (logical and explicit) become associated with different versions of a configuration item.
Over time, a logical floating label is arbitrarily associated with the latest version of a configuration item on a particular branch or stream. For example, "LatestDevelopment" or "JanesLatest".
An explicit floating label is explicitly assigned to different versions over time, and it is almost always based on the associations of another label and not with the latest versions on a branch or development stream. This means that it is not necessary to "freeze" the configuration items to associate a label with versions already assigned to another label; only the state of the base model must be frozen. For example, Figure 15 shows that the SYSTEMTEST label is associated with version 3 of this particular configuration item.
Figure 15 Example of Labelling Items
When the test team for the system is ready, they can associate the label with all the versions associated with FUNCTIONALTEST. No changes should occur to the FUNCTIONALTEST label until the SYSTEMTEST label change is complete. However, assigning LATESTSTABLE with the current versions of all the files on the main branch of development requires that no new main branch versions are added to any of the configuration items until the LATESTSTABLE label change has completed the operation. Since labels can be moved, it is good practice to produce and keep a dated report on the versions associated with important labels for milestones.
Creating and comparing label reports of different dates on a regular basis can reveal trends and areas that require additional testing to ensure quality of volatile areas of the system. Figure 16 shows label reports for two consecutive weeks.
Figure 16 Comparing Reports
Teams looking at a particular lineup of configuration items should retrieve artifacts solely on the selection of configuration items associated with a specific label. Testing in this type of environment quickly identifies overlooked configuration items because of a missing association. It also ensures that all necessary configuration items are included as they are made available to other teams.
Improving Efficiency in Team DevelopmentThe implementation of some team development practices can hinder the implementation of other team development goals. Planned activities may be part of the strategy to deal with implementation issues in a team environment.
You can reduce unplanned activities by using an effective strategy that promotes handling conflicts up front. Your configuration management plan should implement a strategy that promotes team development goals with as little impact to team activities as possible. See Goals of Team Development for more information about specific team development goals.
The stakeholders of the configuration management plan are almost everyone, and their needs vary significantly. The description of the roles and tasks in this document is general and must be customized to suit your particular development organization.
Model Architect Role
The Model Architect establishes the overall structure of the model: the grouping of elements into packages, the separation of models into subsystems, and the interfaces between these major groupings. The Model Architect adapts the structure of the model to reflect the organization of the team.
RecommendationsProtection of configuration items and the ability to deliver a consistent set of configuration items are the main priorities of the configuration management plan. An implementation of a plan to achieve the other goals should support this ideal.
Use the source control operations supported through Rational Rose to facilitate the implementation of a greater configuration management plan. For complex projects, a large part of the configuration management strategy that deals with Rational Rose models, may be strict ownership of shared packages.
You may think of shared packages as the building blocks of the system. One Rational Rose model brings all the building blocks together in a coherent system. Many working models are used with the sole purpose of creating and testing those building blocks.
Source Control Fundamentals
In chapter 5, called Working with a Version Control System, specifies the source control operations supported from Rational Rose . It outlines some of the differences in view-based and file-based source control systems. There is also a discussion on versioning strategies.
The ability to associate labels and create a lineup exists in both types of source control systems. Using a parallel stream versioning strategy while maintaining a single stream versioning policy, provides the safety inherent in single stream versioning strategies, and also the ability to control parallel development of the same artifacts among different teams.
Any source control tool that allows branching is capable of supporting a parallel stream versioning strategy. An example of appropriate streams of development are:
- Development streams, where developers make changes to the configuration items.
- Integration stream (implementing requirements and features) managed by Integrators.
- Product version maintenance streams (providing fixes for bugs/defects identified after release date) also managed by Integrators.
Include a maintenance stream for every product version currently supported by your organization. When support for the specific product version is concluded, these streams should end.
Note: You can use merge tools, such as Model Integrator, for merging simple, non-conflicting changes. However, because of their limited semantic support, we do not recommend that you use automated merge tools when there are many conflicting changes.
Bugs and defects reported against a version of the product should be evaluated against the product under continued development in the new development stream. Other versions of the product that may be affected by the bug/defect are under continued support. Apply corrections to all affected versions through a manual merge, or through focused merges.
If you implement a parallel stream versioning strategy, maintain virtual single streams within the parallel streams. For example, Figure 17 shows a version tree history for a configuration item. A branching of development effort occurs at version 1.0, and version 2.0 of the configuration item
Figure 17 Parallel Stream Versioning Strategy.
Only one side of the branch is checked back into that integration stream. The Integrator uses the main streams of development and may be unaware of the details of individual changes. Therefore, from the perspective of these streams, they are a single stream of development only receiving updates from one source that has permission to modify the next version in the stream. If you require merging, perform it outside of these integration streams, and sanity test it before integrating it as a new version.
Do not associate product verification labels and packaging or deployment labels with versions outside these main integration streams of development. When working with files such as test scripts that are version controlled, consider these files as if they were in a separate project.
You may have separate streams for the development and maintenance of these scripts as well, but this should be thought of as a different project than the one it supports from a version control perspective. That supporting system may have logical ties or parallels with the product under development.
Preempting Conflicts
You want to minimize more than one concurrent check-out of a configuration item. If this strategy results in unacceptable contention for a configuration item, or a dead-lock occurs, put overrides in place to deal with the contention.
A dead-lock occurs when team member A requires a configuration item checked out to team member B to finish work, and team member B requires the configuration item that team member A currently has checked out. Because this is done up front, there is an awareness that changes are being concurrently made to the same configuration item, and these changes can be managed to minimize the likelihood of unintended change.
This type of concurrent work must occur outside the main development streams. When it occurs, resolve this type of situation as quickly as possible and provide adequate testing of the configuration item following the period of concurrent change, to ensure no unintended changes occurred as a result.
The Rational Rose shared package capability can implement an ownership strategy to limit the scope of implicit permissions to change configuration items.
Managing Dependencies
To effectively manage changes to the dependencies in your system, you must create and enforce your own team processes. For Rational Rose projects, you must identify the following dependencies:
- Dependencies between control units in a model.
- Model element relationships
If you do not have a formal reporting mechanism that automatically identifies these dependencies, every change must be addressed to ensure that dependencies are researched and assessed as a result of the change.
Labeling
When considering labelling, we recommend the following:
- Establish an environment for each group or individual that will work with a specific set of configuration items in isolation from other changes for any length of time. For most version control tools, this is established with directories containing a copy of the appropriate version of the configuration item identified through a movable label. The team member performs work on artifacts in these directories, and this set of directories is also called the sandbox. ClearCase users have the capability of achieving virtual directories through the configuration specifications of dynamic views.
- When using file-based version control tools in Unix systems, developers can configure a directory that references the shared work through soft links. When team members modify the reference in the directory, the link is broken and it is replaced in the sandbox by the modified file.
- Create dated reports for each floating label on a regular basis, listing all configuration items associated with the label and the associated version. We recommend that you add the report to your version control system. You can use the data from the report to identify how the set of configuration items changed over time, and to help you identify volatile and stable elements of the system. Fixed labels do not require this type of report. For a label associated with a set of configuration items that do not change often, you can reduce the frequency to some appropriate interval, or on an ad-hoc basis.
- Define your labeling strategy as much as possible before you begin. Use a naming convention so that everyone can understand the labels.
- Identify labels that may require protection from modification, and those labels that may require restricted access.
When Merging is Necessary
Merging is necessary when an awareness exists that concurrent development may result in conflicting changes. Perform the merge as often as possible. Each developer involved in a concurrent change must regularly work with a merged version of the ongoing work to identify adverse or unintended change.
The intention is to reduce the amount of lost work that can occur when conflicts arise. A conflict identified early reduces the amount of re-work necessary. This kind of concurrent work on the same artifacts must be done in isolation from other work.
The way ClearCase facilitates integration branches, it is wise to chose a special integration stream for the concurrent changes to a configuration item. This isolates the remaining artifacts in your system (which uses mutual exclusion) from these changes until the configuration item can go through extensive quality verification.
With other sandbox type systems, one developer merges other developer's work, and then provides the merged version to the other developer.
After every merge, assess changes to semantic relationships and other dependencies.
Advanced Concepts and HeuristicsThis section includes additional information about advanced concepts and heuristics in the following areas:
- Moving Controlled Units
- Parallel Development
- Model Integrator
- Using Rational ClearCase Multi-Site
- Additional Heuristics for Team Development
Moving Controlled Units
When a model element moves from one package to another, and the element is under configuration management (CM) control, Rational ClearCase does not move the file corresponding to the model element into it's new directory.
Some CM systems do not support moving history when moving a file from one directory to another. Consequently, if the file is not moved to it's corresponding directory as the element in the model is, the operations that involve labeling will not be done correctly.
When a UML package is assigned a Rational ClearCase label, ClearCase performs an operation on the directory and all it's contents. However, if the controlled moved, its corresponding element will not be labeled correctly.
When the name of a package, diagram (one that can be a separate control unit), or classifier changes, and that element corresponds to a controlled unit, the source control element in Rational ClearCase should also change.
What are some use-cases that relate to moving controlled units?
- Control to package level granularity: move an element from one package to another.
- Control to package level granularity: move an element from one package to a scratch-pad package.
- Control to package level granularity: move an element from a scratch-pad package to package under CM
- Delete a package from the model and the file exists in the CM repository. The script created to move a controlled unit could identify these files as well.
- A file is under CM, but an element with that name already exists. The tool currently generates a unique file name, and provides a warning.
- Changing from a controlled unit, to uncontrolled unit, and then back to a controlled unit.
Some solutions for these use-cases may include:
- Writing a script to move a controlled unit. Ensure that the script detects the controlled units who's locations do not match the model element, and then repairs the locations.
- Writing a script to rename the controlled unit, when required. Ensure that the script detects any name differences, and then repairs the names.
- Since Rational creates the CM scripts for ClearCase, and ClearCase supports moving history with a file, ensure that the scripts are fixed to address this issue.
- Ensure that the ClearCase move script can handle a move between VOBs.
Considerations
In ClearCase, the relationship between a file element and directory elements is such that an element may be in multiple directories at the same time, possibly even in the same view. This does not necessarily complicate things for the toolset, but requires careful consideration.
A Rational Rose model element may be saved as two distinctly named Rational ClearCase elements.
Heuristics
Use package-level granularity rather than class-level granularity. Class-level granularity helps reduce issues when moving classes, and issues with package ownership.
Parallel Development
Parallel Development is a term which sets high expectations regarding collaborative development, where there is a need for multiple users to work together on a common set of artifacts to achieve the same goals.
When collaborating on a common set of artifacts, consider the following approaches to collaborative development:
- When more than one user needs to make changes to the same artifact, they must share the artifact; the changes are made serially, one after the other. Although this is the most reliable approach, it is perceived by most users as not being most efficient. This approach can be managed using the check-in and check-out features of most CM systems.
- When more than one user needs to make changes to the same artifact, they can make the changes at the same time. The changes are merged back into one artifact at a later date. The benefit of this approach is that work goes on in parallel, and it saves time. The problem is that arbitrary and uncoordinated changes on the copies of the same artifact can be difficult to resolve during the merge process. And in fact, may never be resolved and the changes from only one contributor are accepted, and the other discarded.
The development process and tool chain can have a significant impact on the opportunity to use and the effectiveness of the second approach. The second approach is characterized as Parallel Development. For the purpose of this discussion, the term Parallel Development refers specifically to this second approach to collaborative development.
It is unrealistic to expect employ parallel development without any constraint or guidance. Too often, this technique is used without coordination or planning. Sophisticated tools, such as Rational ClearCase, may not be properly used and can lead to this misperception. The design artifacts at the center of collaborative development have complex interrelationships within them, and between them. These higher level abstractions and concepts are not easily, and cannot arbitrarily be, merged without some experience. Fortunately, when team members are working within a well-defined process, and there is a clear definition of roles and responsibilities, most changes made in parallel are done in a complementary manner. A certain amount of conflicting changes are inevitable. You can resolve the changes by choosing one or the other. These conflicting changes must be expected and their frequency should be minimized. If they are unexpected, it may be counterproductive and time is being wasted by changes that will not be discarded.
The following guidelines will help maximize the efficiency and productivity of a process that employs parallel development:
- Scrutinize and minimize the occurrence of every conflicting change in the merge.
- A well documented and communicated development plan helps ensure that every developer knows how they are contributing and what they will implement. This helps minimize duplication of effort, even at the lowest level of detail.
- Establish clear ownership of design artifacts, and use source control to enforce i.t
- Invest time into understanding what the Rational Rose Model Integrator will and will not do during a merge.
- Follow all guidance specific to the Rational Rose Model Integrator regarding the types of changes that it can reliably merge.
- Resolve all issues relating to merging parallel changes prior to integration.
Model Integrator
The Rational Rose Model Integrator is a powerful tool that manages the merging and differencing of models at the Rational Rose meta-model level. It is not a visual model or UML semantic-level merge tool, therefore it lacks a number of features that can make the merging of models more efficient and more accurate.
For every use-case of Model Integrator that fails to do what you may expect, there are many other use-cases that do add value or do what is expected, and will save time. When using Model Integrator, you must understand what it can do efficiently and properly, and what should be avoided.
When you plan for a graphical change (a layout change) to a diagram within a model, only one person should make this change. This ensures that during the merge process, all of the graphical changes are accepted by one contributor and merging at a lower level of detail is not allowed.
You can change most information associated with a model element as long as it is information not related to its identity. For example, the Action property or Documentation field.
Using Rational ClearCase Multi-Site
When a team follows best practices, for example, being careful about artifact ownership, they can use Rational ClearCase Multi-Site to work on separate branches.
Rational ClearCase Multi-Site is a powerful tool that can help you with the challenges of a distributed team development. When using Rational ClearCase Multi-Site, you must consider the following:
- Rational ClearCase Multi-Site has a restriction that a branch is owned by a site.
- Only developers on that specific site can check out to that particular branch.
Additional Heuristics for Team Development
- Begin with high level of granularity for controlled units when area of a model is immature. As the area of a model becomes more mature, then it's level of granularity can be lowered.
- During the architecture phase, the granularity is course. When the architecture is released to the designers, decrease the granularity to manageable pieces for efficient team development.
- Use a layered architecture, where the coupling between layers is minimal and well-defined. This kind of architecture is also called loosely coupled.
- Define the interfaces between layers of the architecture early and minimize changes to these interface elements.
- The interfaces and associated components at a layer boundary are released separately and have their own test and release schedule. There are one or more separately released components in each layer.
- Every controlled unit should have only one owner.
- Plan for conflicting merges and attempt to minimize them throughout the development life-cycle.
- Only merge controlled units with primary edits are back into the integration stream.
- If the system is sufficiently complex, divide each layer into subsystems.
- Ensure that subsystems have a well-defined and minimal interface to other subsystems.
- Subsystems are not necessarily confined to one layer. Interfaces at lower and higher levels of abstractions should coincide with one of the architectural layers. Subsystems may encapsulate their own set of layers which satisfy particular objectives.
- Employ at least three streams of development: release stream, integration, and developer.
- You can place a new part of a model under source control after it has had some (minimal) testing.
- Do not make frequent or large changes to a superclass.
- A process that employs parallel development should insure that
- Subsystem interfaces may need to be modified by both users, but changes should be planned, controlled, and authorized by owner (or group).
- Appoint one responsible person for each interface. This person is the only one that can change the interface. For example, all requests for changes must be sent to this single team member for them to make the required change.
Rational Software Corporation
http://www.rational.com support@rational.com techpubs@rational.com Copyright © 1993-2001, Rational Software Corporation. All rights reserved. |