Software Engineering for Smart Data Analytics & Smart Data Analytics for Software Engineering
By decomposing the system into subsystems we want to maximise the cohesion inside the subsystems and minimize the coupling between subsystems.
that certain parts of the system should be replacable by alternative implementations. It makes a lot of sense to have those parts represented by subsystems in your system decomposition. If your system has to communicate with other systems, there should be a subsystem that handles the communication with this other system.
For any subsystem, you should be able to describe in one short sentence the functionality offered by this subsystem. Look at the dependencies of classes outside the subsystem on classes inside the subsystem. Verify that these dependencies are consistent with your description of the offered services.
The granule of reuse is the granule of release. It is usually a good idea to think of subsystems as possible units of deployment. For instance, it makes perfect sense to sell car hifi systems separatly from cars. Therfore, if you think of a car as a system, the hifi should clearly be a subsystem of its own.
The classes in a subsystem are reused together. If you reuse one of the classes in a subsystem, you reuse them all. So it makes little sense for a subsystem to offer services that are not related to each other.
The classes in a subsystem should be closed together against the same kinds of changes. A change that affects a closed subsystem affects all the classes in that subsystem and no other subsystem .
Dependencies between subsystems should be acyclic and go in the direction of abstractness and stability. Abstractness means the degree of independence of a special application. Stability means the probability that the subsystem might be used unchanged for a time. Avoiding cyclic dependencies implies that if classes in subsystem A depend on classes in subsystem B, than there should be no classes in B depending on any classes in A.
If you have a complete analysis model, you should be able to tell for each association, whether it defines a dependency in one direction or the other or both. Here are some hints:
If the association in question is mentioned in some use case, draw a sequence diagram of the interaction described by the use case. If an object instantiates, sends a message to, or destroys another object then the class it belongs to is usually dependend on the class of the other object.
Entities may depend on each other, but they may never depend on control or boundary objects.
Controls typically depend on entities. Controls may depend on other controls. If you have two control classes that are associated, ask yourself if one of them instantiates the other one (which introduces a dependency). Note that control classes are typically induced by use cases. Therefore, an association between two controls typically corresponds to an association between the respective use cases. In the case of an extends relation, the direction of the dependency is usually reversed.
The relation between controls and boundaries may be a bit difficult. For example, if a control object updates some user interface elements (e.g. to display the amount to be paid…), then it seems that that the control depends on the boundary object. On the other hand, boundaries MUST depend on some control if an actor is to initiate any interaction through them. So very often, there will be dependency cycles involving a boundary and one or more controls. In most cases however, well known implementation techniques (observer pattern, model view controller architecture,…) can be applied during a later phase to inverse the dependency of the control on the boundary, so that in the end there are only dependencies of boundaries on controls.