sexta-feira, 6 de maio de 2016

Software Design: Design Principles (and how they could help us in partitioning the system)

With a good decomposition (into modules and submodules):
  • The overall system Design is improved (anticipating and solving earlier performance or scalability bottlenecks, better preparation for change and evolution, etc.) and... 
  • It is easier to maintain (Maintainability) as well as... 
  • It easier to Develop (during the following activities of software construction: easier to split tasks between developers, easier to integrate new technologies and new team members, easier to forecast the impact of new requirements with good accuracy, etc.). 

But how exactly should it be performed? For some principles, jump here (*).

CHANGE IS PART OF LIFE: So we should design systems that cope with it "elegantly"
- The customer can change it's mind
- The market needs can change during the project (with impact on our scope)
- We could have got requirements wrong and have the need to rework them (as well as all dependencies on them, etc.)
- Reused components could have to be replaced (due to lack of support, stability, etc.) along the way
- etc.

Modules

A module can be defined variously, but generally must be a component of a larger system, and operate within that system more or less independently from the operations of the other components of the system. A module is a subdivision of complexity that has evident benefits.

Decomposition Levels

  • The first partition shall be determined by selection or design of an Architectural Archetype (system type, e.g. Web App)
  • The archetype establishes tier and layer separation and, in the physical tier perspective, a clear and unavoidable packaging and coupling isolation criterion.
  • The archetype is a structural technical view of the solution regardless of business domain and particularities. As such, it is a very stable and reusable specification.
  • The archetype is also a technological determinant decision as it clearly points to the usage of specific technologies, frameworks, development environments, etc.

  • The second level partition shall address decomposition of the archetype’s parts into Package Components (UML Package Diagrams; package = namespaces that group classes and interfaces)
  • The Packaging Components represent the binary outputs of the solution (in .Net for instance these correspond to the .EXE and .DLL)
  • Their decomposition criteria are based on coupling, deployment and tier placement.
  • The Packaging Component represents a single reference point for the functionality and is an aggregation for further decomposition (Component).


  • The third level partition shall address decomposition of the Package Components into Components and Interfaces and establish third-party dependencies (reuse process) - UML Component Diagrams
  • Remember that Components may be nested into each other to produce sub-levels of decomposition and reduce complexity of the overviews.
  • This is a pure conceptual view that is not directly concerned with packaging and deployment.
  • This view is oriented by “information-hiding” in Parnas sense. The goal here is to represent the system with as few major concepts as possible. Of course each of those concepts may be further detailed (by sub-components) as needed.


      • The fourth level partition shall address Component decomposition in Classes - Detailed Design; physical data tables could be also modeled (it the system is database-oriented) and traced to classes.

      All elements of the decomposition should trace to the upper level elements they are related to (traceability) in the analysis model.

      Principles for module decomposition 

      • Strong cohesion and loose coupling (goals to be achieved): 
      • Cohesion is a measure of how strongly related and focused the responsibilities of a single module are. That is, how homogeneous and simple is the goal of a software module.
      • Coupling (or dependency) is the degree to which each program module depends on each other module.
      • Package Cohesion Principles: Classes are a necessary, but insufficient, means of organizing a design. The larger granularity of packages is needed to help bring order. But how do we choose which classes belong in which packages
      • Release Reuse Equivalency Principle: The granule of reuse is the granule of release (and that should be the package).
      • Common Closure Principle: Classes that change together, belong together.
      • Common Reuse Principle: Classes that aren’t reused together should not be grouped together.
      • Package Coupling Principles: Applications tend to be large networks of interrelated packages. The rules that govern these interrelationship are some of the most important rules in object oriented architecture
      • Acyclic Dependencies Principle: The dependencies between packages must not form cycles.
      • Stable Dependencies Principle: Depend in the direction of stability.
      • Stable Abstractions Principle: Stable packages should be abstract packages.

      Architectural Principles

      • Abstraction gears towards comprehension
      • Encapsulation gears towards protection from outside interference
      • Information Hiding gears towards containment of design changes
      • Open Closed Principle – OCP: “A module should be open for extension but closed for modification.” i.e. “We should write our modules so that they can be extended, without requiring them to be modified. In other words, we want to be able to change what the modules do, without changing the source code of the modules.”
      • Inversion of Control (or Dependency Inversion Principle) is an important object-oriented programming principle that can be used to reduce coupling inherent in computer programs: “Depend upon Abstractions. Do not depend upon concretions.” [Martin]
      • Interface Segregation Principle – ISP: “Many client specific interfaces are better than one general purpose interface” i.e. “If you have a class that has several clients, rather than loading the class with all the methods that the clients need, create specific interfaces for each client and multiply inherit them into the class.” [Martin]

      Along with OOP Principles, some Design Patterns (which is a well known, very good solution for a recurrent problem) are also very useful while performing the decomposition of a system.


      (*) Additional References and Further Reading



      Also remember to learn - at a second stage - about:

      (2016-05-12: Added link for enterprise integration patterns; 2016-07-21: formatting, typos)