CSC/ECE 517 Fall 2012/ch1b 1w44 as

From Expertiza_Wiki
Revision as of 13:12, 16 November 2012 by Skillam (talk | contribs) (→‎Tips for a good OOD)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Introduction

Object Oriented Design (OOD) is a methodology to develop a solution by creating structured objects which interact with each other through well defined interfaces. The object interaction involves invocation of required services and exchange of corresponding data. An object contains data and set of methods or procedures which act on that data. Access to data can be controlled based on access specifiers. The input to the problem is passed to the object through method invocations which are defined by the interfaces. Interfaces define the procedure name and the parameters. The object implements the methods of the interfaces and also encapsulate data needed for solving the problem which can include instances of other objects.

An example of Object Oriented Design

Class Person {
    String id;
    String name;
}

Class Course {...}

Class Student extends Person {
    List<Course> registeredCourses;
    Instructor advisor;
    int semester;
    ...
}

Class Instructor extends Person {
    List<Course> coursesTaught;
    List<Student> students;
    ....
}

Student student = new Student(...);
student.getRegisteredClasses();
student.getAdvisor();
Instructor instructor = new Instructor(...);
instructor.getCoursesTaught();
instructor.getStudents();

In above example, two objects are created, one for the Student and another for Instructor. The main observation to be made is that the Student object interacts with the Instructor object to obtain the advisor's information. Similarly, the Instructor object interacts with the Student object to obtain the student information.

Advantages of Object Oriented Design

  • Code Reusablility
  • Real-World Modeling
  • Robustness and Reliability
  • Less Maintenance

Traits of a poor Object Oriented Design

  • Not following Single Responsibility Principle (SRP).
  • Violating the DRY principle (DRY).
  • Anti-Patterns (Anti-Patterns).
  • Misnomer: The name of variables, methods, Classes and instance objects are not indicative of the data and functionality that they represent.
  • More functionality in a single method.
  • Repeated use of switch/case statements on the same enumerated member (sign of sub-classes needing extraction).
  • Lots of member variables that are used for processing, not to capture state (might indicate need to extract a method object).
  • Long chains of member access.
  • Use of too many design patterns in a small space.
  • Some repeated pattern of action, process or structure that initially appears to be beneficial, but ultimately produces more bad consequences than beneficial results.
  • A base class down-casting itself to a derived class. Like, excessive use of switch statements, or derived classes that override everything
  • Overuse of inheritance mechanisms.
  • No proper documentation.

Next, we will define the success and failure of a Software and discuss basic concepts involved of Object Oriented Design. In the later part, we discuss in-depth with examples of how poor designs lead to software failures. Finally, we discuss about methodology to avoid poor object oriented designs.

Software success and failure

What is software success

The general definition of software project success is - projects delivered on time, in scope (software quality is satisfied) and within planned costs. [1] It is just a most simplistic definition of software project success because it merely relies on the schedule and budget. In fact, it is hard to tell whether software is a success or failure one, because business success, at sometime, is more essential than technical success. [2] This means that the software which is being implemented must create value that business needed, such as making profit, rather than simply achieve the software goal and requirement.

In The Strategic Project Office, written by J. Kent Crawford, [3] we can find some more specific success criteria mentioned to address alignment between project goals, business requirements, and outcomes:

The organization’s strategies are executed according to plan. The organization’s shareholders are satisfied. The organization is financially successful. Projects are completed on schedule and on budget. Project customers are satisfied. Project resources are allocated optimally. Projects are aligned to the organization’s business strategy. The organization works on the right projects.

What is software failure

Compared with software success, it is relative easier to define software failure. It can be definite as “(1) being over-scheduled by more than 30% and/or, (2) being over-budget by more than 30% and/or, (3) the end product did not meet user requirements. These three criteria cover the schedule, budget, and requirement, all surrounded by quality that should comprise all projects.”[5].

Factors leading to software failure

Most software project can be considered partial failures since only few of them meet the schedule, cost and requirement objective. According to many studies, failure rate of software projects is between 50% - 80%. [6] In most of the cases, the software projects fail because we do not recognize that good engineering principles should be applied to software projects similar to building office buildings. Below are some factors that may lead to the software failure in no particular order:

Poor user input
It is possible that a titanic project which meets all the requirements ultimately may fail because the system did not meet the user's needs.

Vague requirement
People cannot design a process that assumes the requirement is stable. Projects can be headed for trouble if architectures and processes are not change-friendly, or if there are poorly established guidelines that determine how and when requirements can be added, removed, and implemented—and who will shoulder the cost of the changes.

Poor cost and schedule estimation
Although it is unfair to call software project a failure when it cannot meet the budget and scheduled goals that were inherently unattainable, every software project has a minimum achievable cost and schedule.

Skills that doesn't match the job
This is an obvious reason; Example: Managers can perform poorly if they lead projects that do not match their strengths.

Communication breakdown
Communication breakdown may lead to low efficiency and even the project failure. Especially large software project which is done by different groups in various sites, same code may be tested two times because no one knows the other exist.

Poor architecture
This is because people never think ahead about what is likely to change. Once the software is developed in an inflexible way, it may be outdate quickly after it is released and may cause problems because it cannot deal with the continue change incomes. For this reason, we come to realize why OOD is so important in software development.

Object Oriented Design (OOD)

Object Oriented Design (OOD) is the concept that forces programmers to plan out their code in order to have a better flowing program [7]. Simply speaking, OOD is all about objects. An object can be considered as a “black box” which receives and sends messages. Code (sequence of computer instructions) and data (information that instructions operates on) are included in this “black box”. [8] Interface is used in the object and everything an object can do is represented by its message interface. OOD mechanisms such as inheritance, polymorphism, information hiding and coupling, can influence quality characteristics like reliability or maintainability [19].

Language Concepts

The 5 Basic Concepts of Object Oriented Design are the implementation level features that are built into the programming language. These features are often referred to by these common names:

Encapsulation refers to a tight coupling or association of data structures with the methods or functions that act on the data. This is called a class, or object (an object is often the implementation of a class).

Abstraction is the ability to protect some components of the object from external entities. This is realized by language keywords to enable a variable to be declared as private or protected to the owning class.

Inheritance defines the ability for a class to extend or override functionality of another class. The so called child class has a whole section that is the parent class and then it has its own set of functions and data.

Interface is a definition of functions or methods, and their signatures that are available for use to manipulate a given instance of an object.

Polymorphism refers to the ability to define different functions or classes as having the same name but taking different data types.

Programming Concepts

There are several concepts that were derived from the new languages once they became popular. The new standards that came around pushed on three major things:

Re-usability is the ability to reuse code for multiple applications. If a programmer has already written a power function, then it should be written that any program can make a call to that function and it should work exactly the same.

Privacy is important for large programs and preventing loss of data.

Documentation is commenting of a program in mark up that will not be converted to machine code. This mark up can be as long as the programmer wants, and allows for comprehensive information to be passed on to new programmers. This is important for both the re-usability and the maintainability of programs.

How to achieve a good OOD

“Good design and programming is not learned by generalities, but by seeing how significant programs can be made clean, easy to read, easy to maintain and modify human-engineered, efficient, and reliable, by the application of good and programming practices. Careful study and imitation of good designs and programs significantly improves development skills.”--Kernighan & Plauger

At the heart of great design are a set of principles and patterns. Design principles form the foundation of good object-oriented design and design patterns provide general repeatable solutions for common software problems. [10]

Design principles

Design principles are guidelines and heuristics for a good object oriented designs. There are many different design principles of Object-Oriented Design. Here are 4 major principles of them:

Encapsulation
In a nutshell, Encapsulation is the hiding of data implementation by restricting access to accessors and mutators. An accessor, usually in the form of properties in OOP, is a method that is used to ask an object about itself. Accessor has a get method, which is an accessor method. Mutator is used to modify the state of an object. It is a public method, and hides the implementation of exactly how the data gets modified.

Abstraction
Abstraction is the development of a software object. It denotes a model, a view, or some other focused-representations for an object we can actually find in the real world. It can be used to decompose complex systems into smaller by software developers.

Inheritance
Objects can relate to each other with either a “has a”, “uses a” or an “is a” relationship. “Is a” is the inheritance way of object relationship.[11]

Polymorphism
Meaning one name, many forms, polymorphism manifests itself by having multiple methods all with the same name, but slightly different functionality. There are two basic types of polymorphism: overriding, also called run-time polymorphism, and overloading, which is referred to as compile-time polymorphism.

Design patterns

Design pattern is a general reusable solution to a commonly occurring problem within a given context. It is a template describing how to solve a problem, which cannot be transformed directly into code. 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. [12]

There are many types of design patterns, like

Creator
As one of the most common activities in an object-oriented system, creator pattern maintains a fundamental property of the relationship between objects of particular classes: class is responsible for creating objects. That is to say, creator pattern is responsible for creating an object of class.

Controller
The Controller pattern assigns the responsibility of dealing with system events to a non-UI class that represents the overall system or a use case scenario. A Controller object is a non-user interface object responsible for receiving or handling a system event. [13]

High Cohesion
High cohesion means that the responsibilities of a given element are strongly related and highly focused. It is an evaluative pattern generally used in support of Low Coupling, which can keep objects appropriately focused, manageable and understandable.

Indirection
By assigning the responsibility of mediation between two elements to an intermediate object, the Indirection pattern supports low coupling and reuse potential between them. An example of this is the introduction of a controller component for mediation between data (model) and its representation (view) in the Model-view-controller pattern. [13]

Protected Variations
By wrapping the focus of instability with an interface and using polymorphism to create various implementations of this interface, the Protected Variations pattern protects elements from the variations on other elements, like objects, systems and subsystems.

Effective Use Cases

Essential use cases are abstrat, lightweight, technology-free dialogues of user intension and system responsibility, that effectively capture requirements for design ofa system [22]. Working with essential use cases yeilds further benefits: analysts can take advantage of recurring patterns in essential use cases and the crucial common vocabulary of responsibilities lets designers trace directly from the essential use cases to the objects in their design.[22]

Tips for a good OOD

There are some tips that can be used in designing to enhance and improve the object-oriented projects.

Use Lots of Objects
By adding lots of objects, it is easy to make each object has and only has one job. Once you understand the architecture, it helps to avoid changing massive amounts of code when we modify the code.

Use Interfaces to Make APIs Predictable
Interfaces allow for strict type hinting, and by type hinting you can ensure that certain methods are always available for your use. [14]Each interface will provide the model to utilize. The utilization of a particular interface will cause the implementations of a few methods.

Use Dependency Injection
Using dependency injection can make testing and feature addition easier. While, it makes testing impossible by instantiating objects directly in the code, or grabbing objects out of singletons.

Create Loosely Coupled Classes
When a developer gives each object only one responsibility, they tightly couple objects together. Objects will often request information from other objects, and while this is not avoidable in all situations, these tightly coupled classes that rely on one another’s functionality makes pulling those objects apart impossible.[14]

Poor OOD Leads to Software Failures

In technical term, software failure is possibly due to software bugs or the poor software design, such as bad OOD. In the figure 2, we can see the cyclic behavior of failure. A fault or bug will cause errors. And errors in the system lead to the subsequent failure. In most of the cases, the software system comprises multiple components in which one failure may result in bugs or errors in another component.

Figure 2 cyclic Fault behavior


Factors leading to Poor OOD

Bad practice in code will always lead to the poor OOD. Here are some common ones[15]:

Violating the Single Responsibility Principle (SRP)

Goal of Design: A class should have only one reason to change
Consider the example below:

Class TravelDetails {
  List<String> modes; //a list of modes of transport used for corresponding 'locations'
  List<String> locations; //locations along the travel. First entry is the source and the last entry is the destination

  List<String> getViaTouristPlaces() {...}
  double getDistance(String location1, String location2) {...}
  double calculateCost() {...}
}

In above example, TravelDetails class is responsible for the modes of transport, locations and the cost of travel violating the single responsibility principle. Instead, it can be redesigned as shown below:

Class Location {
  String name;
  ...
}

Class TransportMode {
  TransportType type;
  double getCost(double distance) {...}
  ...
}

Class Journey {
  Location source, destination;
  TransportMode mode;
  double getDistance() {...}
  double getCost() { mode.getCost( getDistance() ) }
  ...
}

Class TravelDetails {
  List<Journey> journey;
  List<Location> getViaTouristPlaces() {...}
  ...
}

The system is now split into multiple classes - Location, TransportMode, Journey, TravelDetails. 'Location' is only concerned with details of a particular location. 'TransportMode' represents details about the type of transport used. Any changes to the cost of transport mode, availability is confined to this class. A 'Journey' represents travel from a source to a destination through the 'mode' type of transport. Finally, the whole trip consists of a list of 'Journey'.

Violating the Don't Repeat Yourself principle (DRY)

Consider example below:

Class Employee {
  String name, id;
  String getDetails() {...}
  ...
}

Class Manager {
  String name, id;
  String getDetails() {...}
  ...
}

It is clear from the example above that Employee class and Manager class have common functionality between them. This can be extracted out as a separate class as shown below.

Class Person {
  String name;
  ...
}

Class Employee extends Person {...}

Class Manager extends Person {...}

Overuse of Inheritance

Too much inheritance instead of composition, i.e. Classes that derive from a sub-type purely so they get functionality for free.

Class Location {
  String name;
  ...
}

Class Journey {
  Location source, destination;
  double getDistance() {...}
  ...
}

Class Flight extends Journey {...}
Class Bus extends Journey {...}

In the above example, instead of having a sub-class for Flight, class Journey can have a new field which is TransportMode which represents different modes of transport such as flight, bus, train etc.

Class Location {
  String name;
  ...
}

Class TransportMode {
  TransportType type;
  double getCost(double distance) {...}
  ...
}

Class Journey {
  Location source, destination;
  TransportMode mode;
  double getDistance() {...}
  double getCost() { mode.getCost( getDistance() ) }
  ...
}

Software design anti-patterns

In software engineering, an anti-pattern (or anti-pattern) is a pattern that may be commonly used but is ineffective and/or counterproductive in practice[16].Many anti-pattern ideas amount to little more than mistakes, rants, unsolvable problems, or bad practices to be avoided if possible.

Anti-patterns, like their design pattern counterparts, define an industry vocabulary for the common defective processes and implementations within organizations.[17] In OOP, the anti-patterns of software design and object-oriented design are dangerous. They will result in bugs and errors in practice, and then finally lead to the failures of software. Here are the examples:[18]

  • Abstraction inversion: Not exposing implemented functionality required by users, so that they re-implement it using higher level functions
interface foo {
      int bar();
  }
  
class myClass1 implements foo {
    // No member variables.

    int bar() {
        // Implementation
    }

    // No other methods.
}
  
class myClass2 implements foo {
    // No member variables.

    int bar() {
        // Implementation
    }

    // No other methods.
}
  • Ambiguous viewpoint: Presenting a model (usually Object-oriented analysis and design (OOAD)) without specifying its viewpoint
For example, defining a class model for a telephone exchange system will vary significantly depending upon the focus provided by the 
following perspectives:

  -  Telephone user, who cares about the ease of making calls and receiving itemized bills.
  -  Telephone operator, who cares about connecting users to required numbers.
  -  Telephone accounting department, which cares about the formulae for billing and records of all calls made by users.
  • Big ball of mud: A system with no recognizable structure
"Big ball of mud" systems have usually been developed over a long period of time, with different individuals 
working on various pieces and parts. Systems developed by people with no formal architecture or programming training 
often fall into this pattern.
  • Database-as-IPC: Using a database as the message queue for routine interprocess communication where a much more lightweight mechanism would be suitable
Storing a list of messages to send: whether it’s emails, SMS messages, or friend requests, if you’re storing a list 
of messages in a table and then looking through the list for messages that need to be sent, you’ve created a job queue.

In this type of structure, Polling, Locking and Data growth cause problems
  • Gold plating: Continuing to work on a task or project well past the point at which extra effort is adding value
After having met the requirements, the developer works on further enhancing the product, thinking the customer would
be delighted to see additional or more polished features, rather than what was asked for or expected. The customer 
might be disappointed in the results, and the extra effort by the developer might be futile
  • Inner-platform effect: A system so customizable as to become a poor replica of the software development platform
Example: In plugin-based software such as some text editors and web browsers which often have people creating plugins that 
recreate software that would normally run on top of the operating system itself. The Firefox add-on mechanism has 
been used to develop a number of FTP clients and file browsers, which effectively replicate some of the features 
of the operating system, albeit on a more restricted platform
  • Input kludge: Failing to specify and implement the handling of possibly invalid input
For example, if a computer program accepts free text input from the user, an ad hoc algorithm will mishandle many 
combinations of legal and illegal input strings. Input kludges are usually difficult for a programmer to detect in 
a unit test, but very easy for the end user to find. The evidence exists that the end user can easily crash software 
that fails to correctly handle user input
  • Interface bloat: Making an interface so powerful that it is extremely difficult to implement

Example:

  • Magic pushbutton: Coding implementation logic directly within interface code, without using abstraction

Boreland Delphi example

procedure TForm1.Button1Click(Sender: TObject); 
var
 reg:TRegistry;
begin
 reg:=TRegistry.Create;
 try
   reg.RootKey:=HKey_Current_User;
   if reg.OpenKey('\\Software\\MyCompany',true) then
   begin
     reg.WriteString('Filename',edit1.text);
   end;
 finally
   reg.Free;
 end;
end;
  • Race hazard: Failing to see the consequence of different orders of events
If the two threads run simultaneously without locking or synchronization, the outcome of the operation could be wrong

Integer i = 0;
T1 reads the value of i into a register : 0
T2 reads the value of i into a register : 0
T1 increments the value of i : 0 + 1 = 1
T2 increments the value of i : 0 + 1 = 1
The final value of i is 1 instead of the expected result of 2.
  • Stovepipe system: A barely maintainable assemblage of ill-related components
A simple example of a stovepipe system is one that implements its own user IDs and passwords, instead of relying on 
a common user ID and password shared with other systems.

Object oriented design anti-patterns

  • Anemic Domain Model: The use of domain model without any business logic. The domain model's objects cannot guarantee their correctness at any moment, because their validation and mutation logic is placed somewhere outside (most likely in multiple places).

Example

  • BaseBean: Inheriting functionality from a utility class rather than delegating to it
  • Call super: Requiring subclasses to call a superclass's overridden method

Example

  • Circle-ellipse problem: Subtyping variable-types on the basis of value-subtypes

Example

  • Circular dependency: Introducing unnecessary direct or indirect mutual dependencies between objects or software modules
class A
{
  public A()
  {
    myB.DoSomething();
  }

  private B myB = new B();
}

class B
{
  public B()
  {
    myA.DoSomething();
  }

  private A myA = new A();
}
  • Constant interface: Using interfaces to define constants
public interface Constants {
 
        double PI = 3.14159;
        double PLANCK_CONSTANT = 6.62606896e-34;
}
 
 
public class Calculations implements Constants {
 
        public double getReducedPlanckConstant() {
                return PLANCK_CONSTANT / (2 * PI);
        }
}

Alternative:

public final class Constants {
 
        private Constants() {
                // restrict instantiation
        }
 
        public static final double PI = 3.14159;
        public static final double PLANCK_CONSTANT = 6.62606896e-34;
}
  • God object: Concentrating too many functions in a single part of the design (class)
public void ExporterExcelParFonds(ParametresExecution parametres)
    {
        ApplicationExcel appExcel = null;
        LogTool.Instance.ExceptionSoulevee = false;


        bool inclureReferences = parametres.inclureReferences;
        bool inclureBornes = parametres.inclureBornes;
        DateTime dateDebut = parametres.date;
        DateTime dateFin = parametres.dateFin;

        try
        {
            LogTool.Instance.AfficherMessage(Variables.msg_GenerationRapportPortefeuilleReference);

            bool fichiersPreparesAvecSucces = PreparerFichiers(parametres, Sections.exportExcelParFonds);
            if (!fichiersPreparesAvecSucces)
            {
                parametres.afficherRapportApresGeneration = false;
                LogTool.Instance.ExceptionSoulevee = true;
            }
            else
            {  .....................
    }


Call :  PortefeuillesReference pr = new PortefeuillesReference();
        pr.ExporterExcelParFonds(parametres);
  • Object cesspool: Reusing objects whose state does not conform to the (possibly implicit) contract for re-use

Example

  • Object orgy: Failing to properly encapsulate objects permitting unrestricted access to their internals
  • Poltergeists: Objects whose sole purpose is to pass information to another object

Example

Class PEACH_CANNER_CONTROLLER is a Poltergeist because:

    -   It has redundant navigation paths to all other classes in the system.
    -   All of its associations are transient.
    -   It has no state.
    -   It is a temporary, short-duration class that pops into existence only to invoke other classes through temporary associations.
  • Sequential coupling: A class that requires its methods to be called in a particular order
C program where set of procedure calls must take place in a particular order

Overall(...)
{
p1(...) ;
p2(...) ;
// ...
pN(...) ;
}
  • Yo-yo problem: A structure (e.g., of inheritance) that is hard to understand due to excessive fragmentation

How to Prevent Bad OOD

One of the major causes of limited success in adopting object-oriented methodologies is the failure of management and design teams to riecognize and plan for the scope of this change [23]. If preventive measure are taken software failure can be avoided and organisations can benefit from OOD. Assessing quality of sojtware at the design level will provide ease and higher accuracy for users[25]

Some of the methods are listed below.

Identifying Code Smells

Code Smellsor Bad smells are used to identify problematic classes in object-oriented design[20]. They can also be used to measure the evolvability of software [21]. code smells are broadly classified into 5 categories [21].

An image showing classification of code smells
An image showing classification of code smells
Figure 1: An image showing classification of code smells



Group Name Smells in Group Discussion
The Bloaters -Long Method
-Large Class
-Primitive Obsession
-Long Parameter List
-DataClumps
Bloater smells represents something that has grown so large that it cannot be effectively handled.

It seems likely that these smells grow a little bit at a time. Hopefully nobody designs, e.g., Long Methods.

Primitive Obsession is actually more of a symptom that causes bloats than a bloat itself. The same holds for Data Clumps. When a Primitive Obsession exists, there are no small classes for small entities (e.g. phone numbers). Thus, the functionality is added to some other class, which increases the class and method size in the software. With Data Clumps there exists a set of primitives that always appear together (e.g. 3 integers for RGB colors). Since these data items are not encapsulated in a class this increases the sizes of methods and classes.
The Object-Orientation Abusers -Switch Statements
-Temporary Field
-Refused Bequest
-Alternative Classes with Different Interfaces
The common denominator for the smells in the Object-Orientation Abuser category is that they represent cases where the solution does not fully exploit the possibilities of object-oriented design.

For example, a Switch Statement might be considered acceptable or even good design in procedural programming, but is something that should be avoided in object-oriented programming. The situation where switch statements or type codes are needed should be handled by creating subclasses. Parallel Inheritance Hierarchies and Refused Bequest smells lack proper inheritance design, which is one of the key elements in object-oriented programming. The Alternative Classes with Different Interfaces smell lacks a common interface for closely related classes, so it can also be considered a certain type of inheritance misuse. The Temporary Field smell means a case in which a variable is in the class scope, when it should be in method scope. This violates the information hiding principle.
The Change Preventers -Divergent Change
-Shotgun Surgery
-Parallel Inheritance Hierarchies
Change Preventers are smells is that hinder changing or further developing the software

These smells violate the rule suggested by Fowler and Beck which says that classes and possible changes should have a one-to-one relationship. For example, changes to the database only affect one class, while changes to calculation formulas only affect the other class.

The Divergent Change smell means that we have a single class that needs to be modified by many different types of changes. With the Shotgun Surgery smell the situation is the opposite, we need to modify many classes when making a single change to a system (change several classes when changing database from one vendor to another)

Parallel Inheritance Hierarchies, which means a duplicated class hierarchy, was originally placed in OO-abusers. One could also place it inside of The Dispensables since there is redundant logic that should be replaced.
The Dispensables -Lazy class
-Data class
-Duplicate Code
-Dead Code
-Speculative Generality
The common thing for the Dispensable smells is that they all represent something unnecessary that should be removed from the source code.

This group contains two types of smells (dispensable classes and dispensable code), but since they violate the same principle, we will look at them together. If a class is not doing enough it needs to be removed or its responsibility needs to be increased. This is the case with the Lazy class and the Data class smells. Code that is not used or is redundant needs to be removed. This is the case with Duplicate Code, Speculative Generality and Dead Code smells.
The Couplers -Feature Envy
-Inappropriate Intimacy
-Message Chains
-Middle Man
This group has four coupling-related smells.

One design principle that has been around for decades is low coupling (Stevens et al. 1974) . This group has 3 smells that represent high coupling. Middle Man smell on the other hand represent a problem that might be created when trying to avoid high coupling with constant delegation. Middle Man is a class that is doing too much simple delegation instead of really contributing to the application.

The Feature Envy smell means a case where one method is too interested in other classes, and the Inappropriate Intimacy smell means that two classes are coupled tightly to each other. Message Chains is a smell where class A needs data from class D. To access this data, class A needs to retrieve object C from object B (A and B have a direct reference). When class A gets object C it then asks C to get object D. When class A finally has a reference to class D, A asks D for the data it needs. The problem here is that A becomes unnecessarily coupled to classes B, C, and D, when it only needs some piece of data from class D. The following example illustrates the message chain smell: A.getB().getC().getD().getTheNeededData()

Of course, I could make an argument that these smells should belong to the Object-Orientation abusers group, but since they all focus strictly on coupling, I think it makes the taxonomy more understandable if they are introduced in a group of their own.
Table 1: Code Smells Clasification

MOOD (Metrics for Object Oriented Design)

Impact of Object-Oriented design on software quality characteristics can be experimentally evaluated. A suite of metrics for OO-design, called MOOD, was adopted to measure the use of OO design mechanisms [24]. The FCM (Factors, Criteria, Measurement) model indicates that software quality depends on the software quality measurement.[25]

                                       Factors ---> Criteria ---> Measurement


Motivations behind the MOOD set definition include:

  • Coverage of basic structural mechanisms of the object-oriented paradigm such as encapsulation, inheritance, polymorphism and message-passing.
  • Formal definition to avoid subjectivity of measurement and thus allow replicability.
  • Size independence to allow inter-projecl comparison,thus fostering cumulative knowledge.
  • Language independence to broaden the applicability of this metric set by allowing comparison of heterogeneous system implementations.


MOOD includes the following metrics:

  • Method Hiding Factor (MHF)
  • Attribute Hiding Factor (AHF)
  • Method Inheritance Factor (MIF)
  • Attribute Inheritance Factor (AIF)
  • Polymorphism Factor (POF)
  • Coupling Factor (COF)


Each of these metrics refers to a basic structural mechanism of the object-oriented paradigm as encapsulation (MHF and AHF), inheritance (MIF and AIF), polymorphism (POF) and message-passing (COF). The MOOD metrics definitions make no reference to specific language constructs. However, since each language has its own constructs that allow for implementation of OO mechanisms in more or less detail.

Well-Known Software Failures

  • Microsoft Zune's New Year Crash. Article Bug
  • Air-Traffic Control System in LA Airport. Article
  • Northeast Blackout. Article
  • NASA Mars Climate Orbiter. Article
  • Denver Airport Baggage-handling System.
  • USS Yorktown Incident Article
  • Ariane 5 Explosion Article

References

[1] http://www.zdnet.com/blog/projectfailures/cio-analysis-defining-it-project-success-and-failure/12524
[2] http://www.42spikes.com/post/What-is-Software-Success.aspx
[3] http://www.crcpress.com/product/isbn/9781439838129
[4] J. C. Laprie (Ed.). Dependability: Basic Concepts and Terminology. Springer-Verlag, Wein, New York, 1992.
[5] http://ac-support.europe.umuc.edu/~meinkej/inss690/wilson.htm
[6] http://www.it-cortex.com/Stat_Failure_Rate.htm
[7] http://www.selectbs.com/process-maturity/what-is-object-oriented-design
[8] http://softwaredesign.com/objects.html
[9] http://www.selectbs.com/process-maturity/what-is-object-oriented-design
[10] http://www.objectmentor.com/omSolutions/oops_what.html
[11] http://codebetter.com/raymondlewallen/2005/07/19/4-major-principles-of-object-oriented-programming
[12] http://webcache.googleusercontent.com/search?q=cache:TwYgDNxgxUMJ:en.wikipedia.org/wiki/Design_pattern_%28computer_science%29+object+oriented+design+patterns&cd=3&hl=en&ct=clnk&gl=us
[13] http://en.wikipedia.org/wiki/GRASP_%28object-oriented_design%29
[14] http://www.brandonsavage.net/five-tips-to-make-good-object-oriented-code-better
[15] http://stackoverflow.com/questions/345698/what-are-the-tell-tale-signs-of-bad-object-oriented-design
[16] Budgen, D. (2003). Software design. Harlow, Eng.: Addison-Wesley. "As described in Long (2001), design anti-patterns are 'obvious, but wrong, solutions to recurring problems'"p. 225. ISBN 0-201-72219-4.
[17] http://sourcemaking.com/antipatterns
[18] http://en.wikipedia.org/wiki/Anti-pattern
[19] Evaluating the Impact of Object-Oriented Design on Software Quality. Fernando Brito e Abreu and WalcClio Melo. 0-8186-7364-8196 0 1996 IEEE, Proceedings of METRICS ’96
[20] An Investigation of Bad Smells in Object-Oriented Design, Raed Shatnawi and Wei Li, Proceedings of the Third International Conference on Information Technology: New Generations (ITNG'06) 0-7695-2497-4/06 © 2006 IEEE
[21] Subjective evaluation of software evolvability using code smells: An empirical study, Mika V. Mantyla & Casper Lassenius Published online: 27 May 2006
[22] Essential Use Cases and Responsibility in ObjectOriented Development, Robert Biddle, James Noble, Ewan Tempero, Copyright © 2001
[23] The Reality of Ob j ect-Oriented Technology in the Corporation, Jean Scholtz
[24] Evaluating the Impact of Object-Oriented Design on Software Quality, Fernando Brito e Abreu and WalcClio Melo, 0-8186-7364-8196 0 1996 IEEE Proceedings of METRICS ’96.
[25] Quality Metrics of Object Oriented Design for Software Development and Re-development, K. Liu, S. Zhou and H. Yang, 0-7695-0825-i/00 © 2000 IEEE