Design Patterns and Principles

Designing

A creative process where the designer has a goal given by the customer, no construction work or algorithm. Object oriented way of dividing a complex whole into independent, co-operating components. The challenge is to find a natural division. System is a task automatized by software. The scope is normally defined by the customer.

Agile

  • Individuals and interactions over processes and tools
  • Working software over comprehensive documentation
  • Customer collaboration over contract negotiation
  • Responding to change over following a plan. (XP)

Reduces overhead of process management to minimum.

Planning

  • Initial exploration(developers and customers identify all significant user storiesestimate the cost of the stories.
  • Release planning(a crude selection of stories to be implemented in the first release.
  • Iteration planning(developers and customers agree on the iteration length, typically 2 weeks.

Testing

Writing unit tests is an act of design, documentation, verification. Test driven development: design tests before you design the program.

Unit tests

White-box tests that verify individual mechanisms, do not verify that the system works as a whole documents the internals of a system.

Acceptance tests

Black-box tests that verify that customer requirements are being met, written by people who do not know the internal mechanisms of the system, documents the features of a system.

Refactoring

Altering the source code systematically to improve its design: easier to understand, cheaper to modify, does not change its observable behavior, the goal is not better performance. Creates the design in the existing code, adjusts the design piece by piece to changing functionality, Helps in finding bugs.

Design smell

Sign that the design process is out of control.

Rigidity

The design is hard to change – changes propagate via dependencies to other modules, no continuity in the code. Management reluctance to change anything becomes the policy.

Fragility

The design is easy to break – changes cause cascading effects to many places, the code breaks in unexpected places that have no conceptual relationship with the changed area, fixing the problems causes new problems.

Inmobility

The design is hard to reuse – the code is so tangled that it is impossible to reuse anything.

Viscosity

Viscosity of the software – changes or additions are easier to implement by doing the wrong thing. Viscosity of the environment – the development environment is slow and inefficient high compile times, long feedback time in testing, laborious integration in a multi-team project.

Needless Complexity

Design contains elements that are not currently useful, too much anticipation of future needs,agile principles state that you should never anticipate future needs.

Needless repetition

The same code appears over and over again, in slightly different forms, developers are missing an abstraction, bugs found in a repeating unit have to be fixed in every repetition.

Opacity

The tendency of a module to become more difficult to understand, every module gets more opaque over time, a constant effort is needed to keep the code readable.

SRP (single-responsibility)

A class should have only one reason to change. Cohesion: how good a reason the elements of a module have to be in the same module. Cohesion and SRP: the forces that cause the module to change. Responsibility = a reason to change. Violation of SRP causes spurious transitive dependencies between modules that are hard to anticipate → fragility.

OCP (open-close)

Software entities should be open for extension, but closed for modification. ‘Open for extension’: the behaviour of a module can be extended with new behaviours to satisfy the changing requirement. ’Closed for modification’: extending the module must not result in changes to the source or even binary code of the module. Reduces rigidity. Make all object-data private, no global variables.

LSP (liskov substitution)

Subtypes must be substitutable for their base types. Functions that refer to base classes must be able to use objects of both existing and future derived classes without knowing it. Inheritance must be used in a way that any property proved about supertype objects also holds for the subtype objects. Violation of LSP is a potential violation of OCP.

DIP (dependency-inversion)

High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions.

ISP (interface-segregation)

Clients should not be forced to depend upon methods that they do not use. Many client-specific interfaces are better than one general purpose interface. Fat interface = general purpose interface ≠ client-specific interface. Break a fat interface into many separate interfaces. 

Pattern

Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice. A pattern is a rule that expresses a relation between a context, a problem and a solution.

Software design pattern

Reusable solutions to general design problems. Represent solutions to problems that arise when developing software within a particular context. Not specific to any language, environment etc. Described as a semiformal document. Addresses a common problem. Reusing the solutions, Estabishing a common terminology.

Command

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations. command, receiver, invoker and client.

Active object

Decouples method execution from method invocation that reside in their own thread of control. The goal is to introduce concurrency, by using asynchronous method invocation and a scheduler for handling requests.

Template method

Defines the program skeleton of an algorithm in a method. Let subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.

Strategy

Define a family of algorithms, Encapsulate each algorithm, Make algorithms interchangeable, Let the algorithm vary independently from clients that use it.

Facade

A unified interface to a set of interfaces in a subsystem, encapsulates a complex subsystem within a single interface object makes the subsystem easier to use. Decouples the subsystem from its clients, if it is the only access point, it limits the features and flexibility. Imposes a policy ‘from above everyone uses the facade instead the subsystem.

Mediator

Imposes a policy from below. Promote loose coupling: objects do not have to refer to one another. Problem -> monolithism.

Singleton

Ensure a class has only one instance, and provide a global point of access to it. Useful when exactly one object is needed to coordinate actions across the system. Preferred to global variables. applicable to any class, lazy evaluation: if not used, not created, not inherited: a derived class is not singleton, can be created through derivation, non-transparent: the user knows…

Monostate

Another way to achieve singularity: All data members are static, All instances use the same (static) data, Multithread safe. inherited: a derived class is monostate, polymorphism: methods can be overridden, normal class cannot be converted through derivation • transparent: the user does not need to know…

Null object

Avoid null references by providing a default object. A Null Object

is an object with defined neutral (“null”) behavior.

Package: use to organize large applications. Size and complexity -> high level organization. Cohesion within a package: ’bottom–up’ view of partitioning, classes in a packages must have a good reason to be there, classes belong together according to some criteria. Coupling between packages: dependencies accross package boundaries, relationships between packages. REP (reuse-release equivalence): The granule of reuse is the granule of release. Anything we reuse must also be released and tracked. software must be partitioned so that humans find it convenient. Reusable package must contain reusable classes either all the classes in a package are reusable or none of them are. CRP (common-reuse): The classes in a package are reused together. If you reuse one of the classes in a package, you reuse them all. If one class in a package uses another package, there is a dependency between the packages. Classes that are tightly bound with class relationships should be in the same package. CCP (common-closure): The classes in a package should be closed together against the same kind of changes. A change that affects a closed package affects all the classes in that package and no other packages. partition so that a change is limited to one package only. ADP (acyclic-dependecies): Allow no cycles in the package dependency graph. SDP (state-dependencies): Depend in the direction of stability. A volatile package should not be depended on by a package that is difficult to change. ‘Stable’ = not easy to change.  Afferent couplings C the number of classes outside this package that depend on classes within this package Efferent couplings Ce number of classes inside this package that depend on classes outside this package. Instability I=Ce/(Ca+C). I = 1: maximally instable package. The I metric of a package should be larger than the I metrics of the packages that depends on. SAP (stable-abstraction): A package should be as abstract as it is stable. The number of classes in the package Nc The number of abstract classes in the package N. Abstract class = at least one pure interface and cannot be instantiated. Factory: DIP: prefer dependencies on abstract classes avoid dependencies on concrete (and volatile!) classes, any line of code that uses the new keyword violates DIP.


Composite: Partitioning pattern, Compose objects into tree structures to represent part-whole hierarchies. Observer: An object (subject), maintains a list of its dependents (observers), and notifies them automatically of any state changes, by calling one of their methods. Use Observer when: an abstraction has two aspects, one dependent on the other, a change to one object requires changing others, and you do not know how many objects need to be changed, an object should be able to notify other objects without assumptions about these objects. Adapter: Allows the interface of an existing class to be used from another interface. Often used to make existing classes work with others without modifying their source code. Bridge: Decouple an abstraction from its implementation so that the two can vary independently. Uses encapsulation, aggregation, and can use inheritance to separate responsibilities into different classes. Proxy: Allows to cross a barrier without either of the participants knowing about it (3rd party APIs). Theory: PROXY can be inserted in between two collaborating objects without them knowing about it. Starway to heaven: Achieves dependency inversion (like PROXY). Employs a variation on the class form of ADAPTER. Only useful in languages supporting multiple inheritence. Completely seperates knowledge of the database away from the business rules of the application


VISITOR family allows new methods to be added to existing hierarchies without modifying the hierarchies. Every derivative of the visited hierarchy has a method in VISITOR. Dual dispatch: two polymorphic dispatches. Acyclic visitor: or a volatile hierarchy, new derivatives are created, quick compilation time is needed. ACYCLIC VISITOR breaks the dependency cycle by making the visitor base class degenerate. Decorator: Allows attaching additional responsibilities to an object dynamically. Provides a flexible alternative to subclassing for extending functionality. Allows adding responsibilities to an object without adding methods to its interface. Extension object: More complex than VISITOR but more powerful. Each object in the hierarchy maintains a list of special extension objects and provides a method that allows the extension object to be looked up by name. Extension object provides methods that manipulate the original hierarchy object. State: Allows an object to alter its behaviour when its internal state changes the object will appear to change its class. Typically used to change the behaviour according to a state transition diagram.