I happened across the post Why coupling is always bad / Cohesion vs. coupling, which of course set off my bullshit meter immediately (as does anything with the terms “always” or “never”). I think Vidar makes some good points and I generally agree with a lot of what he says, but I find it silly to say “Coupling is always bad”.
Code doesn’t exist without coupling. Any time you construct an object and use it from another object, you’ve created a coupling between those two objects. Without coupling, objects can’t be strung together to build useful things. Therefore, it can’t possibly be inherently bad.
I think what Vidar is really getting at is that coupling (and dependencies) must be managed in any software system. And by “managed”, I more specifically mean that the dependencies you create should be chosen to facilitate evolution and maintenance. I think we could agree on that.
Part of the gulf in the last two paragraphs is the scale – in the former, I’m talking at object/instance level and in the latter, Vidar is talking about “components”. He doesn’t define “component” but for me a component is a chunk of software that is identifiable by an interface (in abstract terms). I think of “components” as scale-free – they may exist as a class or a set of of classes or a whole system depending on context. I completely agree that as a rule of thumb at the component level, systems with low coupling and high cohesion are easier to maintain and evolve.
But within a component, things are murkier. At some point, you’ve actually gotta get some objects to talk to each other and that will involve strong coupling. At that level, coupling is necessary and beneficial. Within a well-defined and cohesive component, high coupling is actually often a good thing as it is the simplest and best way to build the component.
Even at the component level, I’d argue that coupling is not inherently “bad”. Every piece of code is bound to many external things (interfaces, methods, values, etc) and that’s ok. Even if you’re using an interface, you are dependent on (coupled to) that interface. Sometimes we create interfaces that explicitly commit to very little. For example a DSL passed as a string (see regex or even SQL) commits explicitly to being a string but implicitly to a whole API packed into a language. Or a map of key/value string properties as configuration may actually be hiding all sorts of type information, units, etc. [This is one technique for “reducing” coupling, but with potentially big tradeoffs in clarity, maintenance, and other areas.]
For me, architecture and design are a matter of balancing tradeoffs to serve a higher aesthetic or set of principles while building something that satisfies the external requirements. I don’t see coupling as something good or bad, but as one force to be managed (along with cohesion, simplicity, evolvability, performance, etc, etc).