CSC/ECE 517 Summer 2008/wiki2 6 a: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
 
(12 intermediate revisions by the same user not shown)
Line 10: Line 10:
'''Coupling''' is a qualitative measure of the degree to which the classes, modules or subsystems are connected to one another. It can be defined as the amount of interaction of one object with another object, or one module with another module. For a good software design, it is always advisable to minimize coupling. Strong coupling means that one object or module is dependent on other object or module to perform an operation or task. It simply means that the object or module is strongly coupled with the implementation details of another object or module. With low coupling, a change in one module will not require a change in the implementation of another module. It is important to understand that low coupling does not mean no coupling, rather the goal is to minimize the coupling not eliminate it. A system with no coupling is, by definition, not a system. Low coupling indicates that each object or module performs independent tasks. In general, low coupling can be well explained by ''[http://en.wikipedia.org/wiki/Law_of_Demeter Law of demeter]''. It states that classes within a module or subsystem should have only limited knowledge of classes in other modules or subsystems. In simple terms, 'Law of Demeter' says "Each unit should only talk to its friends; don't talk to strangers".
'''Coupling''' is a qualitative measure of the degree to which the classes, modules or subsystems are connected to one another. It can be defined as the amount of interaction of one object with another object, or one module with another module. For a good software design, it is always advisable to minimize coupling. Strong coupling means that one object or module is dependent on other object or module to perform an operation or task. It simply means that the object or module is strongly coupled with the implementation details of another object or module. With low coupling, a change in one module will not require a change in the implementation of another module. It is important to understand that low coupling does not mean no coupling, rather the goal is to minimize the coupling not eliminate it. A system with no coupling is, by definition, not a system. Low coupling indicates that each object or module performs independent tasks. In general, low coupling can be well explained by ''[http://en.wikipedia.org/wiki/Law_of_Demeter Law of demeter]''. It states that classes within a module or subsystem should have only limited knowledge of classes in other modules or subsystems. In simple terms, 'Law of Demeter' says "Each unit should only talk to its friends; don't talk to strangers".


====Measuring Coupling====
===Types of Coupling===
While it is impossible to avoid some level of coupling within systems, the goal is to reduce coupling as much as possible.  Below are three metrics that can be used to determine the level of coupling within a system.
 
'''Coupling Between Objects (CBO)'''
 
  CBO = sum(t)
 
  t = Total number of types that are referenced by a particular class, not including any possible super-classes,
  primitive types or common framework classes.
 
Lower CBO values indicate lower coupling.
 
'''Data Abstraction Coupling (DAC)'''
 
  DAC = sum(a)
 
  a = Total number of types that are used for attribute declarations, not including primitive types, common framework classes,
  or types that are inherited from any possible super-classes.
 
Lower DC values indicate lower coupling.
 
'''Method Invocation Coupling (MIC)'''
 
  MIC = nMIC / (N – 1)
 
  N = Total number of classes defined within the project.
  nMIC = Total number of classes that receive a message from the target class.
 
Lower MIC values indicate lower coupling.
 
====Demeter's Law====
[http://en.wikipedia.org/wiki/Law_of_Demeter Demeter's Law] is a design principle that when applied to object-oriented programming means that object A can reference object B but object A cannot use object B to reference object C.  Complying with this principle prevents object A from knowing that object B uses object C thereby reducing coupling.  If object A needs to access a function of object C then it is up to object B to expose an operation encapsulating the reference to object C.  The following example [http://javaboutique.internet.com/tutorials/coupcoh/index-2.html] illustrates how this could be done.
 
  public float calculateTotal(Order order) {
    return order.getProducts().getTotalCost();
  }
 
In the example object the object which implements <code>calculateTotal()</code> is calling <code>getTotalCost</code> on a <code>Products</code> object which is exposed through <code>order</code>.  An alternative to this approach would be for the order object to expose this functionality as suggested by the following example.
 
  public float calculateTotal(Order order) {
    return order.getTotalCost()
  }
 
  public class Order {
    // ...
 
    public float getTotalCost() {
      return products.getTotalCost();
    }
   
    // ...
  }
 
=====Content coupling=====  
=====Content coupling=====  
Content coupling occurs when one or more modules access the internals of another module.  The following example illustrates content coupling.
Content coupling occurs when one or more modules access the internals of another module.  The following example illustrates content coupling.
Line 282: Line 230:


In this example, <code>Client</code> and <code>CustomerInfo</code> interact using only primitive types of data.  This is a desired form of coupling.
In this example, <code>Client</code> and <code>CustomerInfo</code> interact using only primitive types of data.  This is a desired form of coupling.
===Measuring Coupling===
While it is impossible to avoid some level of coupling within systems, the goal is to reduce coupling as much as possible.  Below are three metrics that can be used to determine the level of coupling within a system.
===='''Coupling Between Objects (CBO)'''====
  CBO = sum(t)
 
  t = Total number of types that are referenced by a particular class, not including any possible super-classes,
  primitive types or common framework classes.
Lower CBO values indicate lower coupling.
===='''Data Abstraction Coupling (DAC)'''====
  DAC = sum(a)
 
  a = Total number of types that are used for attribute declarations, not including primitive types, common framework classes,
  or types that are inherited from any possible super-classes.
Lower DC values indicate lower coupling.
===='''Method Invocation Coupling (MIC)'''====
  MIC = nMIC / (N – 1)
 
  N = Total number of classes defined within the project.
  nMIC = Total number of classes that receive a message from the target class.
Lower MIC values indicate lower coupling.
====Demeter's Law====
[http://en.wikipedia.org/wiki/Law_of_Demeter Demeter's Law] is a design principle that when applied to object-oriented programming means that object A can reference object B but object A cannot use object B to reference object C.  Complying with this principle prevents object A from knowing that object B uses object C thereby reducing coupling.  If object A needs to access a function of object C then it is up to object B to expose an operation encapsulating the reference to object C.  The following example [http://javaboutique.internet.com/tutorials/coupcoh/index-2.html] illustrates how this could be done.
  public float calculateTotal(Order order) {
    return order.getProducts().getTotalCost();
  }
In the example object the object which implements <code>calculateTotal()</code> is calling <code>getTotalCost</code> on a <code>Products</code> object which is exposed through <code>order</code>.  An alternative to this approach would be for the order object to expose this functionality as suggested by the following example.
  public float calculateTotal(Order order) {
    return order.getTotalCost()
  }
 
  public class Order {
    // ...
 
    public float getTotalCost() {
      return products.getTotalCost();
    }
   
    // ...
  }
===Advantages of high coupling===
* Coupling allows interaction between different modules so more complicated tasks can be done.
* Coupling to minimum extent helps system's scope to extend.
=== Disadvantages of high coupling===
* Decreases the flexibility of the application software. Developers / maintenance programmers need to understand potentially the whole system to be able to safely modify a single component.
* Object interaction complexity associated with coupling can lead to increased error generation during development.
* Decreases the scalability of the application software. Changing requirements in one part of software will potentially require wide ranging changes in the entire application.
* Decreases the maintainability of the application software. More thought need to go into choices at the beginning of the lifetime of a software system in order to attempt to predict the long term requirements of the system because changes are more expensive.
* Testability is likely to degrade with a more highly coupled system of objects.
==Agile approach==
"Agile software development is a group of software development methods based on iterative and incremental development, where requirements and solutions evolve through collaboration between self-organizing, cross-functional teams". It promotes adaptive planning, evolutionary development and delivery, a time-boxed iterative approach, and encourages rapid and flexible response to change. It is a conceptual framework that promotes foreseen interactions throughout the development cycle. [http://en.wikipedia.org/wiki/Agile_software_development]
===How using agile approaches maintain cohesion and coupling ?===
Agile methods use refactoring the code to continuously improve the structure and understandability of source code, this is an integral part of development process.
Frequently refactored code is believed to be easier to understand, correct and adjust to new requirements.
As software evolves new code keeps on getting added in the already existing code which leads to redundancy and the new code may not be in alliance with the code that particular class was responsible for and hence the cohesion in the class decreases as new code gets added. Using Agile methodology we keep on refactoring the code at every step i.e. before, while and after adding the new code and hence the programmer has the idea what the class was originally responsible for and whether the new code is in alliance with the responsibility of the class and hence Agile methods help in improving cohesion.In the very same way as the developer knows about the functionality of a class , he knows well in advance that the new code he is going to add should be a part of which module or file and hence coupling between the modules in the application is reduced.
=== Quality Metrices===
There are many metrices wich help us estimate the quality of software delivered like Coupling Between Objects, Lack of Cohesion in Methods,Weighted Methods per Class, Response For a Class, Number of Java source code statements per method , Time in seconds spent for coding a method. Findings of many researches and studies indicate that refactoring improves some low-level quality metrics like coupling and cohesion measures. A visual inspection of studies performed for these metrics proves that from one iteration to the next for the Coupling Between Objects decreases and quality indeed increases on refactoring. This is an indication that refactoring could help in limiting the overall decrease of cohesion and increase of coupling and complexity metrics that we expect to occur as software evolves. [http://en.wikipedia.org/wiki/Extreme_programming]Extreme Programming (XP) is a agile software development methodology which focuses on improving software quality and responsiveness to changing customer requirements and incorporates the practice of refactoring so that the side effects of adding new code to application can be minimized.

Latest revision as of 05:32, 23 October 2012

Aim

This article aims at highlighting the new areas been explored in the fields of cohesion and coupling and how using agile methodologies help attain highly cohesive classes and to maintain loose coupling between those classes. Following these approaches we can get code which is more readable and maintainable. We encourage reader to visit the references provided at the end of the article to explore more on the research work done in this field.

Introduction

Cohesion and Coupling are concepts often discussed when referring to object-oriented programming. In fact, one of the primary goals of object-oriented programming is “to build highly cohesive classes and to maintain loose coupling between those classes” [1]. In the first section of this article, we provide the basic definition of cohesion, different types of cohesion, how it is measured, advantages and disadvantages of high cohesion and some examples showing implementation of this concept in real life scenarios. Next, we explain the concept of coupling, different types of cohesion, how it is measured, advantages and disadvantages of high coupling and some examples showing implementation of this concept in real life scenarios. In the third section of this article, we highlight we include a section on how using agile approaches maintain cohesion and coupling, and why this is important, it also discusses the importance of quality metrics, and how agile teams help support the same. In next section we discuss the vast research going on in this field and hence we have included a section on new work been done in this field. Lastly, we provide a conclusion to the topics discussed herein along with some recommended further reading and references.


Coupling

Coupling is a qualitative measure of the degree to which the classes, modules or subsystems are connected to one another. It can be defined as the amount of interaction of one object with another object, or one module with another module. For a good software design, it is always advisable to minimize coupling. Strong coupling means that one object or module is dependent on other object or module to perform an operation or task. It simply means that the object or module is strongly coupled with the implementation details of another object or module. With low coupling, a change in one module will not require a change in the implementation of another module. It is important to understand that low coupling does not mean no coupling, rather the goal is to minimize the coupling not eliminate it. A system with no coupling is, by definition, not a system. Low coupling indicates that each object or module performs independent tasks. In general, low coupling can be well explained by Law of demeter. It states that classes within a module or subsystem should have only limited knowledge of classes in other modules or subsystems. In simple terms, 'Law of Demeter' says "Each unit should only talk to its friends; don't talk to strangers".

Types of Coupling

Content coupling

Content coupling occurs when one or more modules access the internals of another module. The following example illustrates content coupling.

 public class Rectangle {
 
   public int Top = 0;
   public int Left = 0;
   public int Width = 0;
   public int Height = 0;
   
   public Rectangle(int top, int left, int width, int height) {
     this.Top = top;
     this.Left = left;
     this.Width = width;
     this.Height = Height;
   }
    
   public int getArea() {
     return this.Width * this.Height;
   }
 }
 public class FloorPlan {
   Rectangle rectangle = null;
 
   public FloorPlan(int width, int height) {
     rectangle = new Rectangle(0, 0, 50, 100);
   }
 
   public void modifyDimensions(int width, int height) {
     rectangle.Width = width;
     rectangle.Height = height;
   }
   
   public int getArea() {
     return rectangle.getArea();
   }
 }

In this example, FloorPlan is able to directly modify the Width and Height fields of the Rectangle object. This coupling creates a dependency from FloorPlan on the internals of the Rectangle object that inhibits maintenance of the Rectangle class. If someone wanted to go back and change the Width and Height fields of Rectangle class to use a different data type they would also have to update the FloorPlan class.

Common coupling

Common coupling occurs when two or more modules modify the same same global variable. The following example illustrates common coupling.

 #include <stdio.h>
 #include <string.h>
 
 #define NUM_FIELDS 3
 
 class EmployeeRecordParser {
   public:
     EmployeeRecordParser(char* strRow, int nFields) : m_nCount(nFields), m_aryFields(0) {
 
       m_aryFields = new char*[m_nCount];
 
       char* strField = strtok(strRow, ",");
   
       for (int ct = 0; ct < m_nCount && strField; ++ct) {
 
          m_aryFields[ct] = new char[strlen(strField) + 1];

          memcpy(m_aryFields[ct], strField, strlen(strField));
 
          m_aryFields[ct][strlen(strField)] = 0;
 
          strField = strtok(NULL, ",");
       }
      }
  	
     ~EmployeeRecordParser() {
        if (m_aryFields)			
          delete [] m_aryFields;
      }
 
      int GetCount() { return m_nCount; }
      char* operator[](int nIndex) { return GetField(nIndex); }
      char* GetField(int nIndex) { return nIndex < m_nCount ? m_aryFields[nIndex] : ""; }
  
    private:
      char**	m_aryFields;
      int	m_nCount;
 };
 void ParseRecords(char* strFile) {
   int nRecords = 0;
   char* strRow = strtok(strFile, "\n");
 
   while (strRow) {		
 
     EmployeeRecordParser record(strRow, NUM_FIELDS);
 
     printf("\nEmployee Record %d\n------------------------\n", ++nRecords);
 
     for (int i = 0; i < record.GetCount(); ++i)  {
       printf("Field %d: %s\n", i, record[i]);
     }
 
     strRow = strtok(NULL, "\n");
   }
 }
 
 int main() {
   char str[] = "Tom,Frank,919-777-2333\nMikel,Dundlin,919-234-5512\nRobert,Skoglund,919-232-2904";
 
   ParseRecords(str);
  
   return 0;
 }

In the C++ example above, both the ParseRecords method and the EmployeeRecordParser class make use of the globally accessible strtok function. Internally, strtok uses a static variable to track the position of the current string being tokenized, which is also used to determine when the whole string has been parsed. In this particular example, the coupling on this common function has a side effect that causes a bug that prevents all the records from being correctly parsed.

Control coupling

Control coupling occurs when one module controls the execution flow of another module. The following example [2] illustrates control coupling.

 enum InfoType { id, name, balance }
 
 public class CustomerInfo {
   public Object getCustomerInfo(InfoType type) {
     Object returnVal = null;
     switch (infoType) {
       case InfoType.id:                    
         returnVal = getCustomerId();
         break;
 
       case InfoType.name:
         returnVal = getCustomerName();
         break;
 
       case InfoType.balance:
         returnVal = getCustomerBalance();
         break;
     }
     
     return returnVal;      
   }
 
   // ...
 }
 public class Client {
   private customerInfo = new CustomerInfo();
 
   public void execute() {
     int id = (int)customerInfo.getCustomerInfo(InfoType.id);
     // ...
   }
 }

In this example, the Client class controls the flow of execution within the CustomerInfo module. This form of coupling requires modules calling CustomerInfo to know about the flow of execution within its class.

Stamp coupling

Stamp coupling occurs when two or more modules access or modify the same data of a shared object. The following example illustrates stamp coupling.

 public class Customer {
   private int id = 0;
   private String name = "";
   private float balance = 0.0f;
 
   public int getId() { return id; }
 
   public void setId(int _id) { id = _id; }
 
   public String getName() { return name; }
 
   public void setName(String _name) { name = _name; }
 
   public float getBalance() { return balance; }
 
   public void setBalance(float _balance) { balance = _balance; }
 }
 public class CustomerInfo() {
   public void save(Customer customer) {
     int id = customer.getId();
     String name = gustomer.getName();
     // ...
   }
 }
 public class Client {
   private customerInfo = new CustomerInfo();
 
   public void execute() {
     Customer customer = new Customer();
 
     customer.setId(5);
     customer.setName("Example");
     customer.setBalance(100f);
     
     customerInfo.save(customer);
   }
 }

In this example, the Client and CustomerInfo classes share the common Customer class. This is a desired form of coupling.

Data coupling

Data coupling occurs when one module passes primitive type or simple data structure to another module as an argument. The following example illustrates data coupling.

 public class CustomerInfo
 {
   public float getCustomerBalance(int customerId)
   {
     // implementation details
   }
 }
   
 public class Client
 {
   private customerInfo = new CustomerInfo();
   
   public void execute(int customerId)
   {
       float balance = customerInfo.getCustomerBalance(customerId);
 
       // ...    
   }
 }

In this example, Client and CustomerInfo interact using only primitive types of data. This is a desired form of coupling.

Measuring Coupling

While it is impossible to avoid some level of coupling within systems, the goal is to reduce coupling as much as possible. Below are three metrics that can be used to determine the level of coupling within a system.

Coupling Between Objects (CBO)

 CBO = sum(t)
 
 t = Total number of types that are referenced by a particular class, not including any possible super-classes, 
 primitive types or common framework classes.

Lower CBO values indicate lower coupling.

Data Abstraction Coupling (DAC)

 DAC = sum(a)
 
 a = Total number of types that are used for attribute declarations, not including primitive types, common framework classes, 
 or types that are inherited from any possible super-classes.

Lower DC values indicate lower coupling.

Method Invocation Coupling (MIC)

 MIC = nMIC / (N – 1)
 
 N = Total number of classes defined within the project.
 nMIC = Total number of classes that receive a message from the target class.

Lower MIC values indicate lower coupling.

Demeter's Law

Demeter's Law is a design principle that when applied to object-oriented programming means that object A can reference object B but object A cannot use object B to reference object C. Complying with this principle prevents object A from knowing that object B uses object C thereby reducing coupling. If object A needs to access a function of object C then it is up to object B to expose an operation encapsulating the reference to object C. The following example [3] illustrates how this could be done.

 public float calculateTotal(Order order) {
    return order.getProducts().getTotalCost();
 }

In the example object the object which implements calculateTotal() is calling getTotalCost on a Products object which is exposed through order. An alternative to this approach would be for the order object to expose this functionality as suggested by the following example.

 public float calculateTotal(Order order) {
   return order.getTotalCost()
 }
 
 public class Order {
   // ...
 
   public float getTotalCost() {
     return products.getTotalCost();
   }
   
   // ...
 }


Advantages of high coupling

  • Coupling allows interaction between different modules so more complicated tasks can be done.
  • Coupling to minimum extent helps system's scope to extend.

Disadvantages of high coupling

  • Decreases the flexibility of the application software. Developers / maintenance programmers need to understand potentially the whole system to be able to safely modify a single component.
  • Object interaction complexity associated with coupling can lead to increased error generation during development.
  • Decreases the scalability of the application software. Changing requirements in one part of software will potentially require wide ranging changes in the entire application.
  • Decreases the maintainability of the application software. More thought need to go into choices at the beginning of the lifetime of a software system in order to attempt to predict the long term requirements of the system because changes are more expensive.
  • Testability is likely to degrade with a more highly coupled system of objects.

Agile approach

"Agile software development is a group of software development methods based on iterative and incremental development, where requirements and solutions evolve through collaboration between self-organizing, cross-functional teams". It promotes adaptive planning, evolutionary development and delivery, a time-boxed iterative approach, and encourages rapid and flexible response to change. It is a conceptual framework that promotes foreseen interactions throughout the development cycle. [4]

How using agile approaches maintain cohesion and coupling ?

Agile methods use refactoring the code to continuously improve the structure and understandability of source code, this is an integral part of development process. Frequently refactored code is believed to be easier to understand, correct and adjust to new requirements. As software evolves new code keeps on getting added in the already existing code which leads to redundancy and the new code may not be in alliance with the code that particular class was responsible for and hence the cohesion in the class decreases as new code gets added. Using Agile methodology we keep on refactoring the code at every step i.e. before, while and after adding the new code and hence the programmer has the idea what the class was originally responsible for and whether the new code is in alliance with the responsibility of the class and hence Agile methods help in improving cohesion.In the very same way as the developer knows about the functionality of a class , he knows well in advance that the new code he is going to add should be a part of which module or file and hence coupling between the modules in the application is reduced.

Quality Metrices

There are many metrices wich help us estimate the quality of software delivered like Coupling Between Objects, Lack of Cohesion in Methods,Weighted Methods per Class, Response For a Class, Number of Java source code statements per method , Time in seconds spent for coding a method. Findings of many researches and studies indicate that refactoring improves some low-level quality metrics like coupling and cohesion measures. A visual inspection of studies performed for these metrics proves that from one iteration to the next for the Coupling Between Objects decreases and quality indeed increases on refactoring. This is an indication that refactoring could help in limiting the overall decrease of cohesion and increase of coupling and complexity metrics that we expect to occur as software evolves. [5]Extreme Programming (XP) is a agile software development methodology which focuses on improving software quality and responsiveness to changing customer requirements and incorporates the practice of refactoring so that the side effects of adding new code to application can be minimized.