CSC/ECE 517 Fall 2012/ch2a 2w14 bb
Introduction
The purpose of the wiki is to introduce and show some example about pattern fragility. The contents include definition of pattern fragility and what does the concept cover. We also give some examples of mistakes in code that spoil the benefits of design patterns.
Design Patterns
A design pattern is a general reusable solution to a commonly occurring problem within a given context in software design. A design pattern is not a finished design that can be transformed directly into source or machine code. It is a description or template for how to solve a problem that can be used in many different situations. Patterns are formalized best practices that the programmer must implement themselves in the application. Object-oriented design patterns typically show relationships and interactions between classes or objects, without specifying the final application classes or objects that are involved. Many patterns imply object-orientation or more generally mutable state, and so may not be as applicable in functional programming languages, in which data is immutable or treated as such.
Why Design Patterns
A design pattern is a pattern—a way to pursue an intent—that uses classes and their methods in an object-oriented language. Developers often start thinking about design after learning a programming language and writing code for a while. You might notice that someone else’s code seems simpler and works better than yours does, and you might wonder how that developer achieves such simplicity. Design patterns are a level up from code and typically show how to achieve a goal using a few classes. A pattern represents an idea, not a particular implementation.
Categorization of Patterns
Intent | Patterns |
---|---|
Interfaces | ADAPTER, FACADE, COMPOSITE, BRIDGE |
Responsibility | SINGLETON, OBSERVER, MEDIATOR, PROXY, CHAIN OF RESPONSIBILITY, FLYWEIGHT |
Construction | BUILDER, FACTORY METHOD, ABSTRACT FACTORY, PROTOTYPE, MEMENTO |
Operations | TEMPLATE METHOD, STATE, STRATEGY, COMMAND, INTERPRETER |
Extensions | DECORATOR, ITERATOR, VISITOR |
Benefits of Design Patterns
Design patterns provide a way of encapsulating the experience of software developers in a form that can be communicated to other developers. They provide a higher level of abstraction than single classes and objects thus providing bigger building blocks in the construction of software designs.
The main benefits of design patterns are:
- They encapsulate and codify design experience.
- Provide a common vocabulary for software designers to use when communicating with their peers.
- Enhance maintainability of software systems whose designs are documented with patterns.
- Provide robustness to the design by copying or imitating proven design techniques.
- Reuse at the design level.
At first glance some of these benefits may not seem very powerful, but upon further inspection maybe we can gain new insight into the true nature of their value. Let us just consider the fact that we have given a design pattern a common name. We can now communicate an entire design principle or concept with other software developers by just using the simple name of the pattern. In one fell swoop we have drastically reduced the effort and time needed for a developer to discuss a concept with another developer. Taken one step further we can discuss the patterns and their interactions in the system and illustrate the system architecture in few sentences. Grouping design concepts with common names facilitates communication among developers and raises the conversation to a higher level of abstraction.
Pattern Fragility
Symptoms of Rotting Design
There are four primary symptoms that tell us that our designs are rotting. They are not orthogonal, but are related to each other in ways that will become obvious.
The four symptoms are:
- Rigidity -- the tendency for software to be difficult to change, even in simple ways.
- Fragility -- the tendency of the software to break in many places every time it is changed.
- Immobility -- the inability to reuse software from other projects or from parts of the same project.
- Viscosity -- viscosity comes in two forms: viscosity of the design, and viscosity of the environment.
In following passage of this wiki page, we will discuss over 'Fragility' with some examples.
Definition of Pattern Fragility
Fragility is the tendency of the software to break in many places every time it is changed. Often the breakage occurs in areas that have no conceptual relationship with the area that was changed. Such errors fill the hearts of managers with foreboding. Every time they authorize a fix, they fear that the software will break in some unexpected way. As the fragility becomes worse, the probability of breakage increases with time, asymptotically approaching 1. Such software is impossible to maintain. Every fix makes it worse, introducing more problems than are solved. Such software causes managers and customers to suspect that the developers have lost control of their software. Distrust reigns, and credibility is lost.
Examples
Singleton
The primary purpose of the singleton is to guarantee that at anytime there is only one instance for a given class and provide a global reference to it.
Factory
Create an interface for building an object, but let subclasses decide which class to instantiate. It allows a class to defer instantiation to subclasses.
Visitor
Visitor pattern represent an operation to be performed on the elements of an object structure. In GoF's word, "It let you define a new operation changing the classes of the elements on which it operates."
Command
The Command design pattern encapsulates commands (method calls) in objects allowing us to issue requests without knowing the requested operation or the requesting object. Command design pattern provides the options to queue commands, undo/redo actions and other manipulations.
There are two extremes that a programmer must avoid when using this pattern:
1. The command is just a link between the receiver and the actions that carry out the request 2. The command implements everything itself, without sending anything to the receiver.
We must always keep in mind the fact that the receiver is the one who knows how to perform the operations needed, the purpose of the command being to help the client to delegate its request quickly and to make sure the command ends up where it should.
One example is:
class FileDeleteCommand def initialize(path) @path = path end def execute File.delete(@path) end end fdc = FileDeleteCommand.new('foo.dat') fdc.execute
there is nothing simpler than just getting on with it: File.delete('foo.dat')