Modifiability

  • Change happens

    • most of the cost of the typical software system occurs after it has been

      initially released

    • For

      • add new features

        • to change or even retire old ones.

      • to fix defects

      • tighten security

      • improve performance.

      • to enhance the user's experience

      • to embrace new technology, new platforms, new protocols, new standards.

      • to make systems work together, even if they were never designed to do so.

    • change can occur to any aspect of a system:

      • the functions that the system computes

      • the platform (the hardware, operating system, middleware)

      • the environment in which the system operates (the systems with which it must interoperate, the protocols it uses to communicate with the rest of the world)

      • the qualities the system exhibits (its performance, its reliability, and even its future modifications)

      • its capacity (number of users supported, number of simultaneous operations).

    • These changes can be done by a variety of actors

      • developers change source code

      • Users changing the screen saver is clearly making a change to one of the aspects of the system

      • Tech ops, changing stat of database to fix the system

      • Release team changing properties

    • Types of changes

      • made to the implementation (by modifying the source code)

      • made during compile (using compile-time switches)

      • made during build (by choice of libraries)

      • made during configuration setup (by a range of techniques, including parameter setting)

      • made during execution (by parameter settings, plugins, etc.)

  • Modifiability is about the cost and risk of making changes.

    • Modifiability deals with change and the cost in time or money of making a change, including the extent to which this modification affects other functions or quality attributes

    • Changes can be made by developers, installers, or end users, and these changes need to be prepared for.

    • There is a cost ofpreparing for change as well as a cost of making a change.

  • To plan for it

    • Need to know what can change?

    • What is the likelihood ofthe change?

      • Cannot plan for all possible changes

        • otherwise system would never get done, or cost too much, or other attributes might suffere

      • Need to decide what is important that could change and should be supported in the system to allow for that change to happen easily

    • When is the change made and who makes it?

    • What is the cost ofthe change?

      • the cost of introducing the mechanism(s) to make the system more modifiable

      • The cost of making the modification using the mechanism(s)

      • Example

        • The simplest mechanism for making a change is to wait for a change request to come in, then change the source code to accommodate the request. The cost of introducing the mechanism is zero; the cost of exercising it is the cost of changing the source code and revalidating the system

        • an application generator, such as a user interface builder. The builder takes as input a description of the designer user interface produced through direct manipulation techniques and produces (usually) source code. The cost of introducing the mechanism is the cost of constructing the UI builder, which can be substantial. The cost of using the mechanism is the cost of producing the input to feed the builder (cost can be substantial or negligible), the cost ofrunning the builder (approximately zero), and then the cost ofwhatever testing is performed on the result (usually much less than usual).

  • For N similar modifications, a simplified justification for a change mechanism is that

    • N x Cost of making the change without the mechanism =< Cost of installing the mechanism + (N x Cost of making the change using the mechanism).

    • N is the anticipated number of modifications that will use the modifiability mechanism. It's only a prediction

  • General scenario

    • Source of stimulus.

      • This portion specifies who makes the change: the developer, a system administrator, or an end user

    • Stimulus.

      • This portion specifies the change to be made

      • A change can be the addition of a function, the modification of an existing function (also seen as fixing a defect), or the deletion of a function

      • change can also be made to the qualities of the system: making it more responsive, increasing its availability detect etc

      • The capacity ofthe system may also change, to accomadate more users

      • changes may happen to accommodate new technology of some sort

    • Artifact.

      • This portion specifies what is to be changed: specific components or modules, the system's platform, its user interface, its environtnent, or another system with which it interoperates.

    • Environment.

      • This portion specifies when the change can be made: design time, compile time, build time, initiation time, or runtime.

    • Response.

      • Make the change, test it, and deploy it

    • Response measure

      • time and money are the most common response measures.

      • Others

        • Number, size, complexity of affected artifacts

        • Effort

        • Calendar time

        • Money (direct outlay or opportunity cost)

        • Extent to which this modification affects other functions or quality attributes

        • New defects introduced

  • Tactics to control modifiability have as their goal controlling the complexity ofmaking changes, as well as the time and cost to make changes

Coupling and Cohesion

  • Modules have responsibilities. When a change causes a module to be modified, its responsibilities are changed in some way.

  • Generally, a change that affects one module is easier and less expensive than if it changes more than one module.

    • if two modules' responsibilities overlap in some way, then a single change may well affect them both.

    • coupling

      • the probability that a modification to one module will propagate to the other

  • high coupling is an enemy of modifiability

  • Cohesion

    • measures how strongly the responsibilities of a module are related

    • measures the module's "unity ofpurpose."

    • The cohesion of a module is the probability that a change scenario that affects a responsibility will also affect other (different) responsibilities

    • The higher the cohesion, the lower the probability that a given change will affect multiple responsibilities.

    • low cohesion is bad

tactics

  • Framework

    • Size of a module

      • Tactics that split modules will reduce the cost of making a modification to the module that is being split as long as the split is chosen to reflect the type of change that is likely to be made.

      • Tactic: Split module

        • If the module being modified includes a great deal of capability, the modification costs will likely be high.

        • Refining the module into several smaller modules should reduce the average cost of future changes.

    • Coupling (increase it)

      • Tactics that reduce coupling are those that place intermediaries of various sorts between modules A and B

      • Tactic: Encapsulate

        • introduces an explicit interface to a module

        • This interface includes an application programming interface (API) and its associated responsibilities

        • reduces the probability that a change to one module propagates to other modules

        • The strengths of coupling that previously went to the module now go to the interface for the module

          • These strengths are, however, reduced because the interface limits the ways in which external responsibilities can interact with the module (perhaps through a wrapper).

        • The external responsibilities can now only directly interact with the module through the exposed interface

          • indirect interaction

        • Interfaces designed to increase modifiability should be abstract with respect to the details of the module that are likely to change that is, they should hide those details

      • Tactics: Use an intermediary

        • Given a dependency between responsibility A and responsibility B, the dependency can be broken by using an intermediary

          • ie carrying out A first requires carrying out B

        • ie a publish-subscribe intermediary will remove the data producer's knowledge of its consumers

      • Tactic: Restrict dependencies

        • restricts the modules that a given module interacts with or depends on.

        • restricting a module's visibility (ie private, public, protected, namespaces, java9 modules, mvn scopes for dep)

        • restricting a module by authorization

        • ie layered architecture

      • Tactic: Refactor

        • a tactic undertaken when two modules are affected by the same change because they are (at least partial) duplicates of each other

        • it is aslso a cleanup step to make sure that teams have not produced duplicative or overly complex code

        • Common responsibilities (and the code that implements them) are "factored out" of the modules where they exist and assigned an appropriate home oftheir own

        • By co-locating common responsibilities that is, making them submodules of the same parent module

      • Tactic: Abstract common services

        • the case where two modules provide not-quite-the-same but similar services, it may be cost-effective to implement the services just once in a more general/abstract fomr

        • Any modification to the (common) service would then need to occurjust in one place, reducing modification cost

        • A common way to introduce an abstraction is by parameterizing the description (and implementation) of a module's activities.

    • Cohesion

      • cohesion can be improved by removing responsibilities unaffected by anticipated changes

      • The purpose of moving a responsibility from one module to another is to reduce the likelihood of side effects affecting other responsibilities in the original module

      • Tactic: Increase semantic coherence

        • If the responsibilities A and B in a module do not serve the same purpose, they should be placed in different modules

          • ie moving to new or exsiting module

        • identifying responsibilities to be moved is to hypothesize likely changes that affect a module. if some responsibilities are not affected by these changes, then those responsibilities should probably be removed.

    • Binding time of modification

      • If we ignore the cost of preparing the architecture for the modification, we prefer that a change is bound as late as possible.

      • Changes can be made late in software lifecycle ie execution rather than compile time

      • cost will be lower

      • Because the work ofpeople is almost always more expensive than the work of computers, letting computers handle a change as much as possible will almost always reduce the cost of making that change.

        • designing artifacts with built-in flexibility, then exercising that flexibility is usually cheaper than hand-coding a specific change

      • Tactic: Parameters

        • Introduces flexibility

        • ie f(a,b) is more flexible than f(a) with b = 0 is set

          • f(a,b) bind values at runtime

          • f(a) where b = 0 bind values at compile time

          • f(a) where b = 1 is a new case, and needs to be done at code time

      • In general, the later in the life cycle we can bind values, the better.

        • putting the mechanisms in place to facilitate that late binding tends to be more expensive

      • We want to bind as late as possible, as long as the mechanism that allows it is cost-effective.

      • Tactis: to bind values at Compile/Build time

        • Component replacement

        • Compile-time parameterization

        • Aspects

      • Tactics: to bind values at deployment time

        • Configuration-time binding

      • Tactics: to bind values at startup or initialization time

        • Resource files

      • Tactics: to bind values at runtime

        • Runtime registration

        • Dynamic lookup (for services)

        • Interpret parameters

        • Startup time binding

        • Name servers

        • Plug-ins

        • Publish-subscribe

        • Shared repositories

        • Polymorphism

      • externalizing the change

        • Installing a mechanism so that someone else can make a change to the system without having to change any code

Design checklist to support modifiability

  • Allocation of Responsibilities

    • Determine which changes or categories of changes are likely tooccur through consideration of changes in

      • technical

      • legal

      • social

      • business

      • customer forces

    • For each potential change or category of changes

      • Determine the responsibilities that would need to be added, modifted, or deleted to make the change.

      • Determine what responsibilities are impacted by tile change

      • Determine an allocation of responsibilities to modules that places, as much as possible, responsibilities that will be changed (or Impacted by the change) together in the same module, and

        • places responsibilities that will be changed at different times in separate modules

  • Coordination Model

    • Determine which functionality or quality attribute can change at runtime and how this affects coordination

      • will the information being communicated change at runtime, or will the communication protocol change at runtime?

      • ensure that such changes affect a small number set of modules.

    • Determine which devices, protocols, and communication paths used for coordination are likely to change

      • ensure that the impact of changes will be limited to a small set of modules.

    • For those elements for which modifiability is a concern,

      • use a coordination model that reduces coupling such as publish/subscribe, - defers bindings such as enterprise service bus, or

      • restricts dependencies such as broadcast

  • Data Model

    • Determine which changes (or categories of changes) to the data abstractions, their operations, or their properties are likely to occur

    • determine which changes or categories of changes to these data abstractions will involve their creation, initialization, persistence, manipulation, translation, or destruction

    • For each change or category of change, determine if the changes will be made by an end user, a system administrator, or a developer

      • changes to be made by an end user or system administrator, ensure that the necessary attributes are visible to that user and that the user has the correct priviteges to modify the data, 'l1s operations, or its properties.

    • For each potential change or category of change:

      • Determine which data abstractions would need to be added, modified, or deleted to make the change

      • Determine whether there would be any ohanges to the creation, initialization, persistence, manipulation, translation, or destruction of these data abstractions

      • Determine which other data abstractions are impacted by the change

        • determine whether the impact would be· on the operations, their properties, their creation, initialization, persistence, manipulation, translation, or destruction.

      • Ensure an allocation of data abstractions that minimizes the number and severity of modifications to the abstractions by the potential changes

    • Design your data model so that items allocated to each element of the data model are likely to change together

  • Mapping among Architectural Elements

    • Determine if it is desirable to change the way in which functionality is mapped to computational elements (e.g. processes, threads, processors) at runtime, compile time, design time, or build time

    • Determine the extent of modifications necessary to accommodatethe addition, deletion, or modification of a function or a quality attribute

      • de1ermination of the following

        • Execution dependencies

        • Assignment of data to databases

        • Assignment of runtime elements to processes, threads, or processors

    • Ensure that such changes are performed with mechanlsms that utilize deferred blnding of mapping decisions.

  • Resource Management

    • Determine how the additi:on, deletion, or modification of a responsibility or quality attribute will affect resource usage.

      • Determining what changes might introduce new resources or remove old ones or affect existing resource usage

      • Determining what resource limits will change and how

    • Ensure that the resources after the modification are sufficient to meet the system requirements

    • Encapsulate all resource managers and ensure that the policies implemented by those resource managers are themselves encapsulated and bindings are deferred to the extent possible.

  • Binding Time

    • For each change or category of change:

      • Determine the latest time at which the chang.e will need to be made

      • Choose a defer-binding mechanism that delivers the appropriate capability at the time chosen

      • Determine the cost of introducing the mechanism and the cost of making changes using the chosen mechanism.

      • Do not introduce so many binding choices that change is impeded because the dependencies among the choices are complex and unknown.

  • Choice of Technology

    • Determine what modifications are made easier or harder by your technology choices

      • Will your technology choices help to make, test, and deploy modifications?

      • How easy is it to modify your choice of technologies (In case some of these technologies change or become obsolete)?

    • Choose your technologies to support the most likely modif1catlons

      • ie an -enterprise service bus makes it easier to change how elements are connected but may introduce vendor lock-in

Last updated