Three Universal methods of reducing complexity.
Reducing the number of factors that have to be dealt with simultaneously.
Produces well-defined, Documented boundaries in a program. Narrows the focus of attention
Term modularity often used.
No guarantee of good structure by simply splitting system - it may increase complexity if not applied properly.
Directs our span of attention and allows for levels of detail
Aids in the later construction of systems
The shape of the hierarchy is important and should reflect the functionality of the system.
The most important idea behind a lot of structured design is "High Module Independence"
Objective is not simply partitioning a program into a hierarchy but determining the structure such that each module is as independent of all other modules as possible.
Achieved by minimising the relationships between different modules (Coupling) and
Maximising the relationships amongst the elements of a particular module (Strength/Cohesion).
Obstruct as much as possible each modules view and knowledge of the reminder of the system - Principle of "Data and Information Hiding (Parnas)" or "Need to know" basis of communication.
This leads to the development of Black Box program modules, derived from the Electronics idea.
These are characterised as follows:
- You know the inputs expected.
- You know the output it should return
- You know its function
- You donít need to know how it carries out its function in order to use it.
Such black box systems are:
- Easily constructed
- Easily tested
- easily corrected
- easily understood
- Easily modified and upgraded.
Form a device viewpoint think of HI-FI separates or low-level filters. From a programming viewpoint independent modules containing functions such as a "Generate Check digit" would be Black box.
Therefore in order to develop highly independent modules we would require modules to display individually high strength internally and that they would have weak relationships between other modules externally (weak coupling).
Coupling and Cohesion of modules
It is a scale giving the strength of relationships within a single module.
It is an indicator of the quality of partitioning and can be used to evaluate the quality of the software structure that has been designed.
It is important to note that it can be examined at the design stage of the project and does not have to wait until coding has been completed - but it should be rechecked after coding as well.
The main purpose is to provide an understanding of desirable and undesirable characteristics in modules.
It is also called Binding and Cohesion.
There are seven categories from Highest (Best to Lowest strength.
The scale is not strict and there is some overlap
1 and 2 are particularly good and 6 and 7 are particularly bad.
The measures were developed by Glenford Myers
"based on studying modules in each category and their relative effects on module reusability, error-proneness, independence and program maintainability and extensibility."
It is not a design standard as such as sometimes lower strength modules are required for good operational reasons. In any design the aim would be to maximise the strength and realise the trade-off when this cannot be done.
- its function cannot be defined (the only way to describe its function is to describe its logic i.e. Step down through what the code does from section to section)
- It performs multiple completely unrelated functions.
They are obviously a bad idea but are developed because of bad partitioning of existing programs and attempts at efficiency by storing duplicate code in a module. They are not independent and tend to be closely related to calling and called modules.
Their interfaces are normally large and the chances of reuse are small.
They degrade program maintainability and extensibility and require rewriting and restructuring.
Performs a set of related functions, only ONE of which is explicitly selected by the calling module using an argument.
There is a single interface for multiple functions.
More cumbersome to use and reuse and harder to change. E.g. to add an extra argument for a single function all other functions in the module have their calling interface changed.
They often involve the use of DUMMY parameters - even more confusing.
There is also a temptation for internal code to be "shared" between functions adding to maintenance problems.
The motivation of locating for example all functions that relate to single data structure in the one place is good but it can be better achieved with an informational strength module.
Also called Temporal strength.
There are multiple sequential functions with a weak but non-zero relationship between them e.g. initialisation, termination.
They are mainly related because they are carried out at the same time in execution terms. But they are related to many different external modules and these implicit relationships are hard to distinguish.
Where should initialisation occur? Just prior to use.
Higher on scale than Classical and the boundary between easy and hard to maintain modules.
Multiple functions with a sequential relationship between all the functions are implied by the problem statement: one must follow the other.
E.g. select next transaction, validate, calculate check digits print record and display error message (if any).
The order of execution is more important than with Classical.
Problems arise because functions tend to be coded together and have interdependencies and there are still multiple functions.
The elements of the module all share a data relationship but not a sequence relationship.
For example they all share access to the same data structure.
In each case all functions are carried out each time the module is called.
Problems occur when not all functions are required. This makes the module hard to reuse and maintain.
Plus there is the problem of sharing code between functions.
Here the module has both a data and a sequence relationship such that data is passed in an assembly-line approach as output of one function step to input of the next.
There is obviously a very close connection between the items.
It is generally easy to maintain but does not complete one full function by achieving all its parts so it is not so reusable.
This is the highest form of internal module strength.
They carry out a single specific function.
They are understandable from their name and argument list and they have excellent "black-box" features.
Functional strength modules may often be externally inter-related (coupled) due to referencing the same data structures.
Placing all such related functional strength modules within an overall module that hides the data structure creates an informational strength module.
It contains multiple entry points for calling each individual function separately. (i.e. not logical strength)
Each entry performs one specific function.
All of the functions are related by a concept, a data structure or a resource that is hidden within the module.
There are no control-flow connections between the logic of the separate functions. Although they can of course call each other.
It is the essence of object-oriented design as this data plus functions is an object.
It is viewed as slightly lower than functional because of the complexity of having several functions and the danger of coding them together,
Object -oriented enthusiasts would maintain that it is a more appropriate design approach for larger systems.
Checking Strength of modules:
Write a sentence describing the purpose of the module and examine the sentence structure.
Summed up with precise verb-object phrase.
Strong Imperative verb
Specific singular direct object
Description of both data and functions acting on the data - terms such as CLASS, MODULE, Abstract Data Type.
This Tree Class allows trees to be created searched, read from, written to, closed.
Note each function should be functional strength and separately callable.
A number of assembly line functions.
Read customer record, validate address details, enter details on order file.
A number of non-sequential functions working on the same data.
Calculate average and maximum overhead hours worked.
Names that describe the procedure or sound like a flowchart description indicate procedural strength.
Compute travel array values, and values of expenses array and write allowances table to file.
The description has time related terms.
Start-up. End of job. Initialise. Clean-up.
The name can be general purpose or else it indicates choice.
Validate all fields in record (enter filed number).
The name does not give any information about module contents.
Miscellaneous routines. Process-Module.
Overall Coupling between modules should be:
- Narrow (not broad) connections.
- Direct (not indirect).
- Local (not remote)
- Obvious (not obscure)
- Flexible (not rigid)
Describes the inter-module relationships. It again gives descriptions of desirable and undesirable relationships.
The links vary from no connection, which is obviously between modules, which do not need to interact to a very tight content connection. Overall the aim would be to have only data coupling between related modules. But the top three are acceptable in particular circumstances.
Data coupling is the main design goal and all communication between modules is through arguments. These arguments in the interface are simple. Again like cohesion the aim is to introduce some objectivity into design discussions.
- One module directly references the internals of another. It is a branch not a call.
- There is huge dependence. The worst form of coupling.
- It is recognised as bad practice.
- Despite the availability of GOTOs it is harder to recreate in higher -level languages due to scoping rules.
Modules reference a global data structure. (Named after the COMMON statement in FORTRAN)
Myers cites 8 problems:
- Inhibits readability.
- Gives modules side effects.
- Introduces dependencies among "unrelated" modules.
- Hard to use in multiple contexts.
- Hard to use in other programs due to fixed global names.
- May involve "faking a structure" to allow access to data.
- Exposes modules to more data than they need.
- Defeats the notion of controlling data access.
- It is never completely "necessary" to have global data.
- If there is a lot of access to the same data structures than it should be possible to create an informational strength module instead and hide the data.
- Global data does not significantly improve program efficiency through reducing the size of the argument list but it does increase the cost of maintenance etc.
Again there is global data shared but the data is simpler than in Common - only homogeneous data is required.
Homogeneous Data: Either:
- Scalar Variable (single item)
- List or table with only one field per entry.
- An array where each element is the same scalar type.
- External coupling avoids the problems 3, 6, 7 mentioned above but retains all the others.
Not any one of Content, Common or External and one module explicitly controls the code of another.
- Function codes sent to a logical strength module.
- Control-switch arguments
- Module name arguments (pointers to functions)
- Knowledge of the internal logic is shown
- If the sending module merely sends a parameter which is used to change control but the sending module is unaware of this then it is not control coupling.
- It is also possible for the called module to return parameter values which control, the execution of the original calling module whch is an even worse form of control coupling.
Not any of the above connections and modules reference the same non-global data structure.
For example: Using a complete record as an argument when only some of the fields are needed.
Does not have 1, 2, 4, and 5 above and reduces 8.
Retains 3, 6 and 7.
Problems arise when it is necessary to change part of the record structure that is unused by a module yet still the module is affected.
Also it can arise where data has been bundled together to form a "record" to simplify the interface thus obscuring the real data being used.
Tramp Data arises where data that is unused by a module is passed through the module for another to use later on. For example the record being read in and passed through several modules before particular fields of data are used.
Not any of the above.
Modules communicate directly with one another through explicit calls.
All Interface data are homogeneous data items.
- Example: Only those fields of the record that a module uses are sent.
- Increases the chance of the module being reusable.
- The name plus parameter list becomes good documentation.
- The scope of the coupling is reduced.
Whether to include their details where the error occurs (data coupling) or centralise them to benefit from standardisation etc. (control coupling of a limited scale) Such centralisation is often the best approach with an error number selecting a piece of text centrally.
Stamp versus Data
As the number of fields of a record used increases it becomes more sensible to send the record than a very long parameter list.
A simple rule of thumb is to base it on when the Majority of fields are needed