Saturday, December 18, 2010

What is loose coupling?

This weekend, I started to wonder what loose coupling is. I came to the following conclusion: the degree of coupling is in proportion to the amount of knowledge required to use a specific implementation of an interface. Let me explain how I came to this definition.

For the purpose of this discussion, I define the concepts of a client and a provider. A client is a piece of software that uses the services of a provider. In some cases, a client needs to be able to switch between different providers. A client can also use more than 1 provider at the time.

An example of a provider is a database provider, which provides access to a particular type of database (Oracle, SQL server). Usually, an application uses one database provider at the time. Another example is an error handling provider. An application often uses more than one error handling provider, for example, a provider which writes to a log file and a provider which shows an error message to the user. In this example, loose coupling allows the client to swap database providers and add/remove error handling providers with few or no changes to the clients source code.

I think many developers understand the merits of loose coupling. The question is: how do we achieve loose coupling? I think there are some concepts that are related to loose coupling, but do not necessarily influence or guarantee loose coupling.

Sometimes the degree of coupling is confused with the method of invocation. Methods can be bound early or late or they can be invoked via some type of messaging system. The method of invocation has nothing to do with loose or tight coupling. The fact that I can invoke a method through a messaging system or through reflection does not have any relation to the amount of knowledge I need to use a specific provider.

An example is the way a connection string is passed to a database provider. The connection string is passed as a string (of course), so the API is very generic. However, the contents of the string is usually dependent on a specific database provider. Each database provider accepts a different set of parameters in the connection string. So, the content of the connection string causes tight coupling between the client and the database provider.

Another point is the physical deployment: monolothic (1 EXE) vs. componentized (EXE + DLLs) vs. distributed (multiple processes or machines). Internally, a monolothic application can be composed of loosely coupled classes. A componentized application can have a lot of coupling between the client code and specific provider implementations.

As an example, consider an application that calls a webservice. A webservice usually implements a very specific set of methods and the application depends on it. The coupling would be no different if the same interface was implemented as part of a monolothic application.

The last point I want to make is about narrow interfaces (few methods) vs. rich interfaces (many methods). It is sometimes thought that a narrow interface promotes loose coupling. However, the way a connection string is passed to a database provider could be seen as a narrow interface. We know that a connection string increases coupling. This is also true for any SQL query being passed through an ODBC interface: the SQL query must be compatible with the flavor of SQL supported by the database provider. My conclusion is that there is no direction relationship between narrow interfaces and loose or tight coupling.

Another point I want to make is that it doesn't seem to make sense to say that an entire application must be loosely coupled. It has to be more concrete than that: loosely coupled from the database provider, error handling, operating system, web browser, etc. To try to be loosely coupled from everything will be an overkill and may lead to overly complicated and poor performing software.

As an example of loose coupling, I will give NHibernate as an example. NHibernate allowed me to switch between Oracle and Sql Server without changing any code. NHibernate enabled my application to be loosely coupled from the database provider (at least those 2 providers).

I am not saying that messaging systems, componentized software and narrow interfaces are useless. My point is that these concepts do not guarantee a loosely coupled system. The devil is in the details: how to define and implement interfaces that can be used in a way that the client software requires limited knowledge of the specific implementations of those interfaces.

Tuesday, March 25, 2008

Customer satisfaction

I have just recently worked on 2 software projects where the primary goal has been ignored in the beginning. The first project was the development of a website for renting out holiday properties. The primary goal was to get customers to go to the website and to get them to rent the properties. Instead of focusing on this goal, we worked on creating a great system for entering many details about properties and to provide extensive search functionality. Getting the publicity was an afterthought, and this was hard to correct.

A second project I've worked on was a research project where data analysis played a key role. Instead of focusing on this ultimate goal from the beginning, the focus had been on the collection of data. The data analysis part became a nagging issue at the end of the project and caused a lot of confusion and conflict.

My assumption is that it should be possible to sit down with a customer at the beginning of a project and ask them: what are your main goals for this project? What is the critical path? This is not always the most natural thing to do, because a customer usually asks for a particular piece of software. However, if you take a step back and ask these questions you can both see the big picture. In that way, it should be possible to attain real customer satisfaction.