views:

5179

answers:

16

I can't seem to grok the concept of "loose coupling." I suppose it doesn't help that the word "loose" usually has a negative connotation, so I always forget that loose coupling is a good thing.

Will somebody please show some "before" and "after" code (or pseudocode) that illustrates this concept?

+3  A: 

Definition

Essentially, coupling is how much a given object or set of object relies on another object or another set of objects in order to accomplish its task.

High Coupling

Think of a car. In order for the engine to start, a key must be inserted into the ignition, turned, gasoline must be present, a spark must occur, pistons must fire, and the engine must come alive. You could say that a car engine is highly coupled to several other objects. This is high coupling, but it's not really a bad thing.

Loose Coupling

Think of a user control for a web page that is responsible for allowing users to post, edit, and view some type of information. The single control could be used to let a user post a new piece of information or edit a new piece of information. The control should be able to be shared between two different paths - new and edit. If the control is written in such a way that it needs some type of data from the pages that will contain it, then you could say it's too highly coupled. The control should not need anything from its container page.

Tom
A: 

Loose coupling, in general, is 2 actors working independently of each other on the same workload. So if you had 2 web servers using the same back-end database, then you would say that those web servers are loosely coupled. Tight coupling would be exemplified by having 2 processors on one web server... those processors are tightly coupled.

Hope that's somewhat helpful.

Steve
I see what you are going for, but still not a very good way of explaining that tightly coupled is when two 'things' are interdependant on each other, compared to loosely coupled when two 'things' exists independently - where one 'thing' can be changed out without changes to the other 'thing'...
Redbeard 0x0A
Steve, you are EXACTLY right - you didn't deserve ANY of the down-votes. It's just your audience wasn't ready for your terminology and too many on this site have a habit of voting down what they don't understand or what is unfamiliar. -shrug-
Richard T
I think Steve missed the point. Loose coupling does not always imply 2 actors working independently on the same workload.
unforgiven3
+15  A: 

Sorry, but "loose coupling" is not a coding issue, it's a design issue. The term "loose coupling" is intimately related to the desirable state of "high cohesion", being opposite but complementary.

Loose coupling simply means that individual design elements should be constructed so the amount of unnecessary information they need to know about other design elements are reduced.

High cohesion is sort of like "tight coupling", but high cohesion is a state where design elements that really need to know about each other are designed so that they work together cleanly and elegantly.

The point is, some design elements should know details about other design elements, so they should be designed that way, and not accidentally. Other design elements should not know details about other design elements, so they should be designed that way, purposefully, instead of randomly.

Implementing this is left as an exercise for the reader :) .

David M. Karr
+9  A: 

Tightly coupled code relies on a concrete implementation. If I need a list of strings in my code and I declare it like this (in Java)

ArrayList<String> myList = new ArrayList<String>();

then I'm dependent on the ArrayList implementation.

If I want to change that to loosely coupled code, I make my reference an interface (or other abstract) type.

List<String> myList = new ArrayList<String>();

This prevents me from calling any method on myList that's specific to the ArrayList implementation. I'm limited to only those methods defined in the List interface. If I decide later that I really need a LinkedList, I only need to change my code in one place, where I created the new List, and not in 100 places where I made calls to ArrayList methods.

Of course, you can instantiate an ArrayList using the first declaration and restrain yourself from not using any methods that aren't part of the List interface, but using the second declaration makes the compiler keep you honest.

Bill the Lizard
This hardly relates to what "coupling" actually *is*. See http://stackoverflow.com/questions/39946/coupling-and-cohesion for some good answers.
Rogerio
@Rogerio: I think it relates. Maybe you're confused by other definitions of "coupling" but you you should read [Loose coupling](http://en.wikipedia.org/wiki/Loose_coupling). "Strong coupling occurs when a dependent class contains a pointer directly to a concrete class which provides the required behavior... Loose coupling occurs when the dependent class contains a pointer only to an interface, which can then be implemented by one or many concrete classes." In my example, my code would be loosely coupled to an ArrayList through the List interface.
Bill the Lizard
@Bill: Thanks for the link, but that article seems completely bogus to me. It appears to "reinterpret" ideas from another domain (organizational behavior), giving a definition of "loose coupling" that contradicts the original software-specific definition by Larry Constantine: http://en.wikipedia.org/wiki/Coupling_(computer_science).
Rogerio
@Rogerio: Constantine's paper was written in 1974. It's probable that a lot of reinterpreting has gone on in the last 36 years, but I don't think that Wikipedia article is its source. For example, patterns like [Dependency Injection](http://www.codeproject.com/KB/recipes/DendencyInjectionPattern.aspx) rely on interfaces to loosen coupling just as I describe in my answer.
Bill the Lizard
@Bill: Sure, Constantine's work on Structured Design is old stuff, but I fail to see any reason to invalidate or radically reinterpret it. The original concepts of cohesion and coupling are at the core of Object Oriented Design, just as much as inheritance and polymorphism. DI (a better article is http://martinfowler.com/articles/injection.html) is merely a technique for the external configuration of plug-ins (abstract interfaces with implementations selected at runtime through configuration code); another such technique is the Service Locator pattern. DI and coupling are independent concepts.
Rogerio
@Rogerio: This isn't invalidating it, nor is it "radical" reinterpretation. Yes, DI and coupling are independent. The point I was making is that DI *uses* interfaces in the same way that I'm illustrating in my answer. The Fowler DI article that you linked to uses the exact same pattern to decouple code from a concrete class using an interface as what I've shown here as well.
Bill the Lizard
+1  A: 

You can read more about the generic concept of "loose coupling".

In short, it's a description of a relationship between two classes, where each class knows the very least about the other and each class could potentially continue to work just fine whether the other is present or not and without dependency on the particular implementation of the other class.

Franci Penov
+12  A: 

I'll use Java as an example. Let's say we have a class that looks like this:

public class ABC
{
   public void doDiskAccess() {...}
}

When I call the class, I'll need to do something like this:

ABC abc = new ABC();

abc. doDiskAccess();

So far, so good. Now let's say I have another class that looks like this:

public class XYZ
{
   public void doNetworkAccess() {...}
}

It looks exactly the same as ABC, but let's say it works over the network instead of on disk. So now let's write a program like this:

if(config.isNetwork()) new XYZ().doNetworkAccess();
else new ABC().doDiskAccess();

That works, but it's a bit unwieldy. I could simplify this with an interface like this:

public interface Runnable
{
    public void run();
}

public class ABC implements Runnable
{
   public void run() {...}
}

public class XYZ implements Runnable
{
   public void run() {...}
}

Now my code can look like this:

Runnable obj = config.isNetwork() ? new XYZ() : new ABC();

obj.run();

See how much cleaner and simpler to understand that is? We've just understood the first basic tenant of loose coupling: abstraction. The key from here is to ensure that ABC and XYZ do not depend on any methods or variables of the classes that call them. That allows ABC and XYZ to be completely independent APIs. Or in other words, they are "decoupled" or "loosely coupled" from the parent classes.

But what if we need communication between the two? Well, then we can use further abstractions like an Event Model to ensure that the parent code never needs to couple with the APIs you have created.

64BitBob
This example still has quite a high level of coupling. Just now instead of being coupled to a single class, there are two to choose from. This example assumes there will be only ever two "Runnable" implementations available. In which case an interface isn't even required.
Owen
These Run* and Do* named methods are a huge code smell for me. You might as well refactor this into using IHandleStuff or IFrobnicateThings. Runnable is far, far too generic a term in this case.
Wedge
Owen, baby steps my friend. If he doesn't understand coupling, how is he going to understand what a factory pattern buys him? This code example puts him on the right track. The intent is that he'll better understand the problem and realize how to abstract out the creation of the objects.
64BitBob
Would this be more readable if ABC and XYZ were renamed something like `DiskAccessor` and `NetworkAccessor`? I dunno no java ...
MusiGenesis
+15  A: 

You can think of (tight or loose) coupling as being literally the amount of effort it would take you to separate a particular class from its reliance on another class. For example, if every method in your class had a little finally block at the bottom where you made a call to Log4Net to log something, then you would say your class was tightly coupled to Log4Net. If your class instead contained a private method named LogSomething which was the only place that called the Log4Net component (and the other methods all called LogSomething instead), then you would say your class was loosely coupled to Log4Net (because it wouldn't take much effort to pull Log4Net out and replace it with something else).

MusiGenesis
So, "loosely coupled" actually means less dependencies? Am I correct?
It's not really related to the total number of dependencies one particular class has. Coupling (tight or loose) is actually a property of the relationship between two classes. So you might have one class which is loosely coupled to 100 other classes, or another class which is tightly coupled to just 2 other classes (for example).
MusiGenesis
Bad example, I would say: what you have is code duplication, not tight coupling. And with a good refactoring tool, such duplication could be eliminated in seconds.
Rogerio
@Rogerio: it's probably not the best example. I like `64BitBob`'s answer better, myself.
MusiGenesis
+1  A: 

Consider a Windows app with FormA and FormB. FormA is the primary form and it displays FormB. Imagine FormB needing to pass data back to its parent.

If you did this:

class FormA 
{
    FormB fb = new FormB( this );

    ...
    fb.Show();
}

class FormB 
{
    FormA parent;

    public FormB( FormA parent )
    {
        this.parent = parent;
    }     
}

FormB is tightly coupled to FormA. FormB can have no other parent than that of type FormA.

If, on the other hand, you had FormB publish an event and have FormA subscribe to that event, then FormB could push data back through that event to whatever subscriber that event has. In this case then, FormB doesn't even know its talking back to its parent; through the loose coupling the event provides it's simply talking to subscribers. Any type can now be a parent to FormA.

rp

rp
+5  A: 

It's a pretty general concept, so code examples are not going to give the whole picture.

One guy here at work said to me, "patterns are like fractals, you can see them when you zoom in really close, and when you zoom way out to the architecture level."

Reading the brief wikipedia page can give you a sense of this generalness:

http://en.wikipedia.org/wiki/Loose_coupling

As far as a specific code example...

Here's one loose coupling I've worked with recently, from the Microsoft.Practices.CompositeUI stuff.

 [ServiceDependency]
 public ICustomizableGridService CustomizableGridService
 {
  protected get { return _customizableGridService; }
  set { _customizableGridService = value; }
 }

This code is declaring that this class has a dependency on a CustomizableGridService. Instead of just directly referencing the exact implementation of the service, it simply states that it requires SOME implementation of that service. Then at runtime, the system resolves that dependency.

If that's not clear, you can read a more detailed explanation here:

http://en.wikipedia.org/wiki/Dependency_injection

Imagine that ABCCustomizableGridService is the imlpementation I intend to hook up here.

If I choose to, I can yank that out and replace it with XYZCustomizableGridService, or StubCustomizableGridService with no change at all to the class with this dependency.

If I had directly referenced ABCCustomizableGridService, then I would need to make changes to that/those reference/s in order to swap in another service implementation.

rice
+11  A: 

Consider a simple shopping cart application that uses a CartContents class to keep track of the items in the shopping cart and an Order class for processing a purchase. The Order needs to determine the total value of the contents in the cart, it might do that like so:

Tightly Coupled Example:

public class CartEntry
{
    public float Price;
    public int Quantity;
}

public class CartContents
{
    public CartEntry[] items;
}

public class Order
{
    private CartContents cart;
    private float salesTax;

    public Order(CartContents cart, float salesTax)
    {
        this.cart = cart;
        this.salesTax = salesTax;
    }

    public float OrderTotal()
    {
        float cartTotal = 0;
        for (int i = 0; i < cart.items.Length; i++)
        {
            cartTotal += cart.items[i].Price * cart.items[i].Quantity;
        }
        cartTotal += cartTotal*salesTax;
        return cartTotal;
    }
}

Notice how the OrderTotal method (and thus the Order class) depends on the implementation details of the CartContents and the CartEntry classes. If we were to try to change this logic to allow for discounts, we'd likely have to change all 3 classes. Also, if we change to using a List collection to keep track of the items we'd have to change the Order class as well.

Now here's a slightly better way to do the same thing:

Less Coupled Example:

public class CartEntry
{
    public float Price;
    public int Quantity;

    public float GetLineItemTotal()
    {
        return Price * Quantity;
    }
}

public class CartContents
{
    public CartEntry[] items;

    public float GetCartItemsTotal()
    {
        float cartTotal = 0;
        foreach (CartEntry item in items)
        {
            cartTotal += item.GetLineItemTotal();
        }
        return cartTotal;
    }
}

public class Order
{
    private CartContents cart;
    private float salesTax;

    public Order(CartContents cart, float salesTax)
    {
        this.cart = cart;
        this.salesTax = salesTax;
    }

    public float OrderTotal()
    {
        return cart.GetCartItemsTotal() * (1.0f + salesTax);
    }
}

The logic that is specific to the implementation of the cart line item or the cart collection or the order is restricted to just that class. So we could change the implementation of any of these classes without having to change the other classes. We could take this decoupling yet further by improving the design, introducing interfaces, etc, but I think you see the point.

Wedge
+1 Great example.
Rogerio
+4  A: 

Coupling has to do with dependencies between systems, which could be modules of code (functions, files, or classes), tools in a pipeline, server-client processes, and so forth. The less general the dependencies are, the more "tightly coupled" they become, since changing one system required changing the other systems that rely on it. The ideal situation is "loose coupling" where one system can be changed and the systems depending on it will continue to work without modification.

The general way to achieve loose coupling is through well defined interfaces. If the interaction between two systems is well defined and adhered to on both sides, then it becomes easier to modify one system while ensuring that the conventions are not broken. It commonly occurs in practice that no well-defined interface is established, resulting in a sloppy design and tight coupling.

Some examples:

  • Application depends on a library. Under tight coupling, app breaks on newer versions of the lib. Google for "DLL Hell".

  • Client app reads data from a server. Under tight coupling, changes to the server require fixes on the client side.

  • Two classes interact in an Object-Oriented hierarchy. Under tight coupling, changes to one class require the other class to be updated to match.

  • Multiple command-line tools communicate in a pipe. If they are tightly coupled, changes to the version of one command-line tool will cause errors in the tools that read its output.

Parappa
+3  A: 

The degree of difference between answers here shows why it would be a difficult concept to grasp but to put it as simply as I can describe it:

In order for me to know that if I throw a ball to you, then you can catch it I really dont need to know how old you are. I dont need to know what you ate for breakfast, and I really dont care who your first crush was. All I need to know is that you can catch. If I know this, then I dont care if its you I am throwing a ball to you or your brother.

With non-dynamic languages like c# or Java etc, we accomplish this via Interfaces. So lets say we have the following interface:

public ICatcher
{
   public void Catch();
}

And now lets say we have the following classes:

public CatcherA : ICatcher
{
   public void Catch()
   {
      console.writeline("You Caught it");
   }

}
public CatcherB : ICatcher
{
   public void Catch()
   {
      console.writeline("Your brother Caught it");
   }

}

Now both CatcherA and CatcherB implement the Catch method, so the service that requires a Catcher can use either of these and not really give a damn which one it is. So a tightly coupled service might directly instanciate a catched i.e.

public CatchService
{
   private CatcherA catcher = new CatcherA();

   public void CatchService()
   {
      catcher.Catch();
   }

}

So the CatchService may do exactly what it has set out to do, but it uses CatcherA and will always user CatcherA. Its hard coded in, so its staying there until someone comes along and refactors it.

Now lets take another option, called dependency injection:

public CatchService
{
   private ICatcher catcher;

   public void CatchService(ICatcher catcher)
   {
      this.catcher = catcher;
      catcher.Catch();
   }
}

So the calss that instansiates CatchService may do the following:

CatchService catchService = new CatchService(new CatcherA());

or

CatchService catchService = new CatchService(new CatcherB());

This means that the Catch service is not tightly coupled to either CatcherA or CatcherB.

There are several other stratergies for loosly coupling services like this such as the use of an IoC framework etc.

Owen
+2  A: 

Two components are higly coupled when they depend on concrete implementation of each other.

Suppose I have this code somewhere in a method in my class:

this.some_object = new SomeObject();

Now my class depends on SomeObject, and they're highly coupled. On the other hand, let's say I have a method InjectSomeObject:

void InjectSomeObject(ISomeObject so) { // note we require an interface, not concrete implementation
  this.some_object = so;
}

Then the first example can just use injected SomeObject. This is useful during testing. With normal operation you can use heavy, database-using, network-using classes etc. while for tests passing a lightweight, mock implementation. With tightly coupled code you can't do that.

You can make some parts of this work easer by using dependency injection containers. You can read more about DI at Wikipedia: http://en.wikipedia.org/wiki/Dependency_injection.

It is sometimes easy to take this too far. At some point you have to make things concrete, or your program will be less readable and understandable. So use this techniques mainly at components boundary, and know what you are doing. Make sure you are taking advantage of loose coupling. If not, you probably don't need it in that place. DI may make your program more complex. Make sure you make a good tradeoff. In other words, maintain good balance. As always when designing systems. Good luck!

phjr
+1  A: 

In computer science there is another meaning for "loose coupling" that no one else has posted about here, so... Here goes - hopefully you'll give me some votes up so this isn't lost at the bottom of the heap! SURELY the subject of my answer belongs in any comprehensive answer to the question... To wit:

The term "Loose Coupling" first entered computing as a term used as an adjective regarding CPU architecture in a multi-CPU configuration. Its counterpart term is "tight coupling". Loose Coupling is when CPUs do not share many resources in common and Tight Coupling is when they do.

The term "system" can be confusing here so please parse the situation carefully.

Usually, but not always, multiple CPUs in a hardware configuration in which they exist within one system (as in individual "PC" boxes) would be tightly coupled. With the exception of some super-high-performance systems that have subsystems that actually share main memory across "systems", all divisible systems are loosely coupled.

The terms Tightly Coupled and Loosely Coupled were introduced before multi-threaded and multi-core CPUs were invented, so these terms may need some companions to fully articulate the situation today. And, indeed, today one may very well have a system that encompases both types in one overall system. Regarding current software systems, there are two common architectures, one of each variety, that are common enough these should be familliar.

First, since it was what the question was about, some examples of Loosely Coupled systems:

  • VaxClusters
  • Linux Clusters

In contrast, some Tightly Coupled examples:

  • Semetrical-Multi-Processing (SMP) Operating systems - e.g. Fedora 9
  • Multi-threaded CPUs
  • Multi-Core CPUs

In today's computing, examples of both operating in a single overall system is not uncommon. For example, take modern Pentium dual or quad core CPUs running Fedora 9 - these are tightly-coupled computing systems. Then, combine several of them in a loosely coupled Linux Cluster and you now have both loosely and tightly coupled computing going on! Oh, isn't modern hardware wonderful!

Richard T
+1  A: 

Some long answers here. The principle is very simple though. I submit the opening statement from wikipedia:

"Loose coupling describes a resilient relationship between two or more systems or organizations with some kind of exchange relationship.

Each end of the transaction makes its requirements explicit and makes few assumptions about the other end."

Ben Aston
+4  A: 

iPods are a good example of tight coupling: once the battery dies you might as well buy a new iPod because the battery is soldered fixed and won't come loose, thus making replacing very expensive. A loosely coupled player would allow effortlessly changing the battery.

The same, 1:1, goes for software development.

Konrad Rudolph