Post migration best practices

In a small software project where a single model is independent of other models, you can consider the migration complete once the model is compiled and runs in the new environment. In large enterprise organizations, this case is extremely rare. Most models are very large and need to be maintained by developers in smaller sub-component models. These models often depend on models developed by other teams and/or have sub-components that are consumed by other teams. These scenarios make the migration process more complex because parts of the model may need to be separated into their own projects to allow for sharing. When multiple teams are involved, the migration process may need to be staggered to allow one team to migrate before another team. If this is the case, then there is a need to support linkages between components in Rational Rose RealTime (RoseRT). This is accommodated through shadow elements, which can be synchronized (this functionality is available only for shadow packages) from a corresponding RoseRT element. These elements are volatile by nature and will eventually migrate as normal elements, or they will be removed and have all their references changed to a migrated element. Therefore, there is a need to support management of the migration process after import of a single model for synchronization, refactoring for reusability, and finally removing shadow elements as other models come online in DevOps Model RealTime.



An Example of a Post-Migration Scenario

Consider two teams which have models Model1 and Model2 with two shared elements: a class and a package. The model of the first team owns the class (SharedClass) and uses the package (SharedPackage) of the second team model. The second team model owns the package and uses the class shared by the first team.

Step 1. The first team starts migration first by importing Model1 and using the default "Convert to" choices in the Controlled Unit Conversion Page:

After the import, the first team can edit the owned shared class, but it may not be able to modify SharedPackage since it is owned by the second team.

Step 2. The first team gets an updated version of the SharedPackage.rtplog file and wants to reimport this package into the already imported Model1. To achieve this, the command "Synchronize with RoseRT Controlled Unit…" should be invoked from the context menu of SharedPackage.

If there were no changes in the original .rtplog file, the user gets the following message.

Otherwise, the process of reimporting of SharedPackage is started.

Step 3. Model2 is imported into the same workspace. The following settings are provided by default.

SharedClass is imported as a Shortcut to the class of Model1:

After the import of Model2 is complete, the shadow package in Model1 can be updated to a shortcut to the imported package. This can be achieved by the command "Migrate Shadow Model Element…" in the context menu of the SharedPackage of Model1.

The command "Migrate Shadow Model Element" is available for both packages and classes, but the command "Synchronize with RoseRT Controlled Unit" is supported for packages only.

Incremental Migration

Theory

Software tooling and development environments are evolutionary in that they typically change over time. These changes can be minor, which don’t require any considerable effort, or they can be major, which causes the file format schema to change and consequently precipitates a major migration effort to move the legacy tooling model artifacts to the new tooling. As observed in the technology mapping, all aspects of the underlying tooling and file format have changed in this migration. The mapping from the UML 1.4 to 2.2 specifications is different enough that there is no backward compatibility; therefore, you must perform a concentrated import for the UML 1.4 artifacts to be converted to UML 2.2.

One way to tackle this incompatibility is called a "Big-Bang" theory of operation. This means simply that the legacy tooling (RoseRT) is shut down and migrated all at once to the new tooling (Model RealTime) using tools that convert any relevant artifacts to the formats understood by the new tooling. Realistically, though, the legacy tooling is usually kept in production for maintenance purposes and is still required while verification of the new tooling continues.

If we examine the activity diagram above, it describes two partitions of the workflow: one for RoseRT and one for Model RealTime. First, the legacy tooling data is prepared for the migration, which may entail some clean-up or refactoring before it is imported into the new tooling. From there, the content is usually verified and tested to ensure model integrity before it can be brought back into production. During this time, the legacy tooling is shut down and not available. After the migration, the legacy may be brought back up for read-only access or to support data streams not being migrated to the new tooling. This "downtime" of the tooling can be costly to an organization since it implies they aren’t developing their models during this time.

System software architecture is usually divided into components that represent different aspects or functionality within the tooling. The components will depend on each other in a layered fashion, where the core components are at the bottom of the dependency chain and the leaf or product components are at the top. The core components, by their nature, are reusable across different product-level components and are critical to the execution of the different models. Different product components may have different release cycles that require them to have schedules that aren’t in sync. Since they may depend on the same core components, one product stack may be ready to migrate to the new tooling, but other product stacks may not be because of schedule or release concerns. This means that the core components are, by nature, synchronized with the slowest moving product stack since they have to support all dependent components above them. Consequently, the core components wouldn’t be ready to migrate at the same time as the more progressive product components at the top of the dependency chain.

In the above example, all the product (leaf) components depend on "Core1". If "Product3" is ready to migrate, but "Product1" is not, since they are both dependent on "Core1" then "Product3" must wait for "Product1" to be in an appropriate stage in order for migration to proceed.

It is perhaps naive to think that once the migration to the new tooling is complete, the legacy tooling will no longer be needed. In an ideal situation, the data can be 100% migrated, and there is no longer a need to support the data or a subset of data in the legacy tooling. This will probably not happen often. If the legacy tooling is supporting a particular release of software, then it would need to support that release for its entire life cycle. It would be too risky to release the software from the legacy tooling and immediately migrate it to the new tooling and subsequently support bug fixes. Issues from the field would not map directly into the new tooling, and migrating data in a fix pack that is supposed to address particular issues would be foolhardy at best. So this implies that the legacy tooling and new tooling need to co-exist for a period of time (and it could be a considerable amount of time, depending on release schedules). Fixes or changes in data/software on the legacy side would need to propagate into the new tooling. If the differences between the data structures are considerable between the two systems, then a file system merge is not sufficient. Generally, these changes would need to be integrated manually through code or data inspection.

Legacy Tooling Maintenance

To address these concerns, we need to provide a way to do incremental migration of the different sub-components within a model. This means that we need to introduce the concept of "mastership" where a package can exist in Model RealTime, but is still mastered in RoseRT. By allowing a sub-package to exist as a read-only ghost or shadow in the new tooling, and still be mastered/edited in the legacy tooling, we can provide a one-way bridge so that the two models can interact. Then, if the synchronization of the legacy tooling package is managed so that the ghost package is automatically updated when changes are made, there is little to no maintenance that you need to do to create the bridge between the two models.

Migration of a single component using auto-synchronization

Considering the example from the figure "Product component stacks", it is now possible to migrate only the "Product3" component into Model RealTime by creating a shadow component to "Core1". "Core1" is still mastered in RoseRT and has no knowledge of the shadow component, which exists in the new tooling. When changes occur to "Core1" in the legacy tooling, this invokes an auto-synchronization where the component is re-imported into the new tooling transparently.

Therefore, the "Big-bang migration" is no longer necessary since individual components can be migrated as needed. Based on release cycles or stability evaluation, specific components can be chosen to migrate, given some criteria. At any given time during the incremental migration, the legacy tooling is still functional and can continue to be maintained. Auto-synchronization between the shadow components and their master ensures that changes to the legacy tooling are propagated into the new tooling.

Auto-synchronization implies that there is a discoverable mapping from the legacy format into the new tooling. To facilitate this, often assumptions will be made that are acceptable in the process of the migration. This allows for a transparent import between the two tooling environments without any user intervention or prompting. This is a prerequisite for this paradigm to be operational. It is also possible to perform a manual synchronization from a legacy component to a fully migrated component. In this case, the migrated component may have been edited in the context of the new tooling. The synchronization will then need to merge the changes made on the legacy side into the new tooling instead of merely replacing it. This merge will invoke some UI to resolve any conflicts, similar to a team-based scenario where two different developers modify the same source file.

Incremental Migration Theory of Operation

Refactoring

In software development, architecture is rarely a static entity. As projects scale larger, the requirements change related to how components get consumed, which then requires new projects to be created and/or make project dependencies to be changed. Or it’s possible that it wasn’t clear at import time how certain packages would be shared in the new Eclipse-based modeling environment. To accommodate this, has a rich set of refactoring capabilities that can be performed at a fragment level. New fragments can be created or existing ones absorbed, and they can be moved to different projects entirely. In addition, packages that exist in the context of a model can be extracted into a "root package" that can be opened by itself, independently of any owning model. This is a powerful feature for sharing individual packages. These root packages can then be moved (or extracted to a specific location) into a new project that can be brought into new workspaces as part of a different project set permutation.

This is all very well for regular owned packages, but shadow packages are not modifiable by design, so that changes in RoseRT are synchronized one way into the shadow package. Hence, the default refactoring functions won’t operate on them. The caveat is that synchronization relies on the package unit remaining intact in RoseRT, which means refactoring will potentially break the synchronization link to the shadow package. To get around this, a specific refactoring "Extract to Top-Level Package" command is supported. This command can operate on shadow packages and allows them to be made a root package and moved into a different project at the same time.

Migration Scenarios

A model shares a package from another model that is not migrated

Since teams have different timelines that define when they can adopt new development processes and tooling, one team may be ready to migrate when another isn’t. When a model is imported that has dependencies on a model that isn’t in the workspace, the package that is shared will be set as a "Shadow Package". If it isn’t (for example, the "owned" attribute is not representative), then you may change it to be a "Shadow Package" in the "Controlled Unit Conversion" page. When the original RoseRT package is modified, the "Shadow Package" can be resynchronized to bring in those changes.

Package structure of the model with the Shadow Package

At some point, the team that owns the package being depended upon may be ready to migrate their model. Once migrated, the dependent team will bring those projects of the newly migrated model into their workspace. Next, the team can migrate the shadow package to the actual package brought into their workspace. All references to the shadow package and its contents are adjusted to point to the actual package, and the shadow package disappears and is replaced by an element import in its place.

A package in a model that isn’t migrated is shared by multiple models that are migrated

The same situation is magnified where multiple models share the same package that hasn’t been imported yet. The workflow is the same as the model shares a package from another model that is not migrated above. However, when subsequent models are migrated, the same package will be a shadow package in multiple models. This is redundant and wastes memory, disk space, and requires extra work to keep each of the shadow packages synchronized separately. To avoid this, the originally imported shadow package can be extracted into its own project as a root package. This can be done at import time or by using the refactoring command "Extract to Top-Level". When the other models that share the package are imported, the package should be imported as a shadow package. To avoid the redundancy, these shadow packages can be migrated to the original shadow package such that all references are replaced and packages removed with an Element Import relationship in their place.

Package structure of multiple models elements importing the same shadow package

A model owns a package that is shared by other models that aren’t ready to migrate

Another scenario that is similar but has different ramifications is when a team has a model that has a shared owned package unit with other models not owned by that team. In this case, the team would like to migrate the package, but if they do, they need to maintain two versions of the package for the dependent teams (one in RoseRT and one in). Alternatively, they can make the package a shadow package until dependent teams are ready to migrate themselves. This allows them to change the package only in RoseRT.

Package structure of the model that owns a package shared by models not been migrated yet

Since this package is owned by the team, it makes sense to extract this package into its own project so the team can eventually include this project in their project set after migration. This is convenient because they don’t have to bring in the whole other model into their workspace; they only have to bring in the dependent package. Once all the dependent teams are ready to migrate, it is no longer necessary for the package to remain a shadow package. It can be migrated to itself, so that it becomes a regular package. Then the other teams can either proceed with their migration, and their reference to that package will be replaced by an Element Import relationship. It should be noted that this represents an exception to the workflow described in Decisions since the package is owned by the migrating team and is the primary editing context. However, since it is shared by other models not yet ready to migrate, it must remain a shadow package.

A model shares a package that is owned by another model that is migrating at the same time

Since these models are migrating at the same time, the package doesn’t need to be a shadow package to accommodate any synchronization with the corresponding RoseRT package. The order in which these models are imported is important because it could mean less migration effort. Also, does it make sense for the models to co-exist in the same workspace, or should they be separated further to isolate the specific package dependencies? If we import the model that has the shared package first, then that package will be imported initially as a shadow package because the other model doesn’t exist in the workspace yet. After importing the second model, it is now possible to migrate the shadow package to the actual package in the second model.

Model that shares the package is migrated first

If the second model is imported first and then the other model imports afterwards, then the package, if specified as shared, will automatically detect on import the actual package existing in the workspace and import as an Element Import relationship to that package. This saves time and effort because the extra step of "migrating" the package to the actual package in the original model import ordering is eliminated.

Model that owns the package is migrated first

In this example, since only a single package is shared by the other model, it may make sense to extract that package into its own project so that the project can be referenced independently of the original owning model. This can be done either on import of the owning model on the "Controlled Unit Conversion" wizard page to specify the project where the fragment is created or, after import, by utilizing the "Extract to Top-Level" refactor command.

In summary, the enterprise architect needs to consider closely how particular components are used currently in the RoseRT world and how they will be used in the new Model RealTime tooling context. Considering these permutations will allow their software to scale well in the future and ease the migration process to Model RealTime.