What’s The Difference Between Tightly-, Loosely-, and De-Coupled ?

In a tweetstorm that spun up late last week, Taylor Otwell produced the following commentary:

look guys I’m “decoupled” because this package doesn’t have composer dependencies!!! HAHAHAHA LOL

how many composer packages a given package has does NOT affect YOUR code’s decoupling.

that is a matter of programming to an interface, etc.

you people seriously do not understand decoupling. at all.

if you type hint AuraAnything that is a HARD, CONCRETE dependency. THAT is coupling.

IlluminateContracts are all interfaces. abstractions. not concretions. THAT’s decoupling.

IlluminateContractsViewFactory could be a Laravel view factory, could be an Aura one. That’s decoupling.

how many composer pkgs the IMPLEMENTOR needs is an implementation detail my consuming code need not care about

consuming code ONLY cares about programming to an interface for decoupling.

you [@philsturgeon] and brandon [savage] and paul [jones] don’t understand basic programming concepts like coupling

and think somehow coupling is tied to composer

Aura ships hard concretions = you are tightly coupled to Aura.

which should my consuming code give a shit if Aura is decoupled AMONGST ITSELF. Nobody gives a shit.

i only care if MY code is coupled to Aura.

and since Aura makes you depends on hard concretions, it promotes hard couplings.

I’m saying if you type-hint a class dependency, you are coupled to that implementation (cont)

regardless of that package’s internal dependencies

While some of Taylor’s rant is correct for as far as it goes, much of it glosses over important distinctions in subtle misdirection, and the remainder displays some misunderstandings. He is also flat wrong in his assertions of other peoples’ understanding of “basic programming terminology.” As such, I think his words demand a careful response for future reference.

First, I’m glad to see Taylor paying attention to the proper use of terminology in a software context. This is something he’s not always been great at in the past, and I encourage him here.

But I can’t quite tell if Taylor thinks the developers who use Aura believe their code is decoupled by virtue of using Aura. Or maybe it’s that the Aura marketing phrase “fully decoupled libraries” is the target of his ire. I infer allusions to both from his tweets, so I’ll attempt to address both possibilities. (Perhaps there is some other interpretation I have missed.)

It should be so obvious as to not require stating, but for the sake of explicitness: If your code has a dependency on classes in a particular thrid-party package, your code is tightly coupled to the code in that package. This is true for any classes in any library, framework, or other package code. So, if you believe that depending on an Aura library in your code makes your code “decoupled” then you are mistaken. As far as I know, I have never attempted to state or imply otherwise. I don’t think any Aura users have this misperception, but if so, consider this a corrective.

The fact that your code could be tightly coupled to another package does not mean that the other package is coupled to anything else. That is to say, the other package might have no couplings of any sort to any other code outside itself. The other package in that case is de-coupled.

The Aura library packages are designed with that kind of decoupling in mind. That is, no Aura library package depends on anything at all in any other Aura package. Each of the Aura libraries is thus fully decoupled from the others, and incidentally from any framework that is composed of them. (Note that the *_Kernel and *_Project packages are coupled to other packages; the decoupling principle applies only to the Aura library packages.)

But why would you care if a particular library package is itself decoupled from other packages? I assert that one reason (of many) you want libraries that are themselves decoupled is so that, if you have to swap one out in your own code, you only have to worry about the one library, not about all the dependent libraries that it is coupled to (and all the dependent libraries they are coupled to). Swapping out is still tedious: you will need to work through your code, change all the typehints from that library’s classes to those in another, and change all the injections that specify classes from the library. But at least it’s only the one library; the fact that the library is itself decoupled reduces the swapping-out work.

Taylor points out another level of coupling called “loose” coupling. This means that, instead of your code depending on a particular class, you instead depend on an interface. This couples you to the interface, but not to any particular implementation. If your code depends on interfaces, your code is loosely coupled to the implementations of those interfaces (although I don’t think this means you are de-coupled – there’s still some knowledge necessary for interactions).

Being loosely coupled is a good situation to be in compared to being tightly coupled. If you need to swap out an implementation of an interface, you won’t need to change your typehints (unless you swap to another set of interfaces). However, you will still need to change all your injections to the new implementation. Overall, being loosely coupled makes for less work when swapping out libraries.

How can you tell if a package is coupled to another package? Provided that composer.json is not lying, it’s easy enough to examine the “require” element to see if there are other packages listed there. If there are, then it seems likely that the package is coupled to whatever is required. You need to exercise a little judgment, though. If the required package contains only interfaces, then the coupling is “loose”. Otherwise, it is “tight”. If there are no other required packages at all, then the package has no coupling of any sort; it is fully decoupled from anything outside of it.

However, that’s only if you assume composer.json is not lying. To really discover the coupling of a particular package, you would need to examine its code. Any uses of interfaces defined outside the package indicates loose coupling, uses of classes defined outside the package indicates tight coupling, and no uses of interfaces or classes outside the package indicates full decoupling.

(Note that this discussion is of inter-package coupling. Even if the classes inside a package may still be coupled to each other, the package as a whole may still be decoupled from any other package.)

Having said all this, Taylor is trying out a “contracts” package that exposes the Laravel interfaces independently of the implementations. I think this is a neat idea. It’s the only truly new thing I’ve seen introduced to the PHP community by the Laravel codebase, and I think it is worthy of emulation.

Even so, if the “contracts” include anything besides interfaces, I think coupling to them might be defined as “tight”. I am thinking specifically of the Exception classes included in the “contracts” package. Although it may be fair to think that Exceptions are exempt from coupling rules, perhaps they would be better provided as interfaces to Exceptions, instead of classes proper. I will reserve my judgment on that for a later time.

Are you stuck with a legacy PHP application? You should buy my book because it gives you a step-by-step guide to improving your codebase, all while keeping it running the whole time.

25 thoughts on “What’s The Difference Between Tightly-, Loosely-, and De-Coupled ?

  1. A question if I may. On the Aura website, your masthead states “fully decoupled libraries and truly independent packages”. Are you not claiming in this post that both are the same thing?

    And perhaps in the interest of stopping this boring dick measuring between you and Taylor, you should both arrange to get on PHP Townhall and debate in a medium that isn’t Twitter or blog posts.

    • That’s an interesting observation. It makes me wonder, what kind of “coupling” is involved if an interface definition specifies a parameter type or return type that is a class, and not an interface? (Especially if that class lives outside the package in which that interface resides.)

      • Well I’m not sure if any of its interfaces do, but many classes in Laravel are directly tied to Symfony2. You literally must have Symfony2 to use Laravel. To me, that’s coupling. Even if “loose” … It’s goes over like an anchor (these are both heavy frameworks).

        You can’t simply say, “Oh I like this Eloquent ORM” thing or “razor template engine” (gotta take a jab at blade, heh) and then say, “Let me use it with Aura” or Lithium or Bear.Sunday or FuelPHP, etc. You just can’t (easily). Not without bringing (parts of) Symfony2 along for the ride.

        Actually. You can’t even say use Eloquent without using some Doctrine. How crazy sounding is that??

        Laravel has always confused me. I understand a little bit about the origins and the desires. Things came from a good place. I just can’t understand why it was architected the way that it was.

        • Doctrine is not required by Eloquent. Doctrine is suggested if you want to use SQLite dbs and need column renaming and dropping in the migrations package… but it’s entirely optional and not always necessary.

          To my knowledge it doesn’t require “all” of symfony either. It uses symfony libraries in much the same way that Aura is intended to be used as far as I can tell. As a collection of foundational libraries to avoid NIH. Surely if this is good for any framework built on Aura components, its good for any framework built on symfony components, Laravel included?

  2. I don’t give a shit about how uncoupled the framework of my choice is. As long as it fits my needs and makes my day a pleasure of coding. And I hope everyone does enjoy the framework of his/her choice. I’m a Laravel user and I like it a lot. But everyone knows how it goes with frameworks; after a certain time something else will replace it. And again, and again.

  3. I think both Paul and Taylor are right from their respective context.

    AuraPHP provides de-coupled libraries while the developer’s code is coupled to that libraries.

    illuminate/contracts package provides Interfaces and a developer can create a de-coupled application without a concrete dependecy to classes, according to Taylor.

    This is what understood from the tweetstorm. And that Taylor tried to defend it with an appropriate way.

    The fact that Laravel uses thirt party packages like Symfony, it is another story. And it is a little ambigious to me since illiminatecontracts can not help you to develop de-coupled applications.

    And maybe the fisrt tweet from Brandon is the sparkle for that debate and not the ‘de-coupling’ … i wonder.

    • Hi Andreas — I appreciate your sincerity, but I don’t see “HAHAHAHA LOL” and “you people seriously do not understand decoupling. at all.” and “you don’t understand basic programming concepts” as especially appropriate.

    • Andreas, I feel the same way about IlluminateContracts. Although it will be useful in terms of swapping implementations coupled between Laravel’s packages, I don’t see why a “consumer” project would abstract any of its code through an external package.

      Decoupling is about making my arrows point inwards, not outwards. If I want to be decoupled from a package, I need to hold interfaces and abstract that package, else I’d be dependent to just another package.

      • I agree Guido. If i have to use a package for my project, the first think i look is if this package fits my needs.
        Then to check if it is extendable via Intefaces or extensions.
        I will not care if my code will be coupled to this package.

        And to be honest, if this package is de-coupled it will be a bonus for me.

  4. I agree with most of the topic, but I find that all of this coupling debate a bit mislead.

    If I choose a framework, I’m probably choosing some implementations of code I want to use. If it was just interfaces, then why would I depend on anyone elses? (I’m talking about projects here, not libraries).
    So, when I’m worried about coupling to a specific set of implementations… say an ORM or a template engine, I need to encapsulate it and abstract it. Probably with some sort of Adapter or Facade (the GoF Facade, of course.)
    Say, I’d use a ORMEntityInterface that defines methods I need, and then implement an EloquentORMEntity that wraps Laravel’s ORM and, if I need to, I can just switch out my ORMEntity implementation through my IoC container to another ORM implementation.

    If I depend on an external package that has only interfaces, I’m choosing to abstract myself with the definitions of another person. I don’t know why I’d choose that for MY code, because I’ll probably have another requirements not met by this framework / library, and those interfaces won’t be enough for my use cases.
    BUT, I can see value in abstracting coupling inside a library, and letting an end-user swap out implementations in runtime (we tend to do that through configuration files and hard-coded strings that build us objects, but abstracting to interfaces would be a far better approach…)

    Anyway, I’m glad this things are starting to emerge on PHP and hope all this ranting can be lead somewhere productive for everyone.

  5. As long as the package I want to use does not cause me to have a hard dependency on it, then it doesn’t matter what dependencies that package has. It is as simple as that. This is even less of a problem when that package is written from the beginning using dependency injection in such away that it is possible to inject what goes in and what comes out.

  6. taylors mention of interfaces in their own packages is not really a “true new” idea either, and its a good practise for loose coupling in a modular environment, why he calls it “decoupled” is beyond me though.

    what i find really disturbing about the whole story is the aggressiveness of both, Brandons original tweet as well as taylors tweets..

  7. Interesting discussion which seems to eschew completely the benefits and use cases of loose coupling.

    Many years ago, in a galaxy far far away, loose coupling was all the rage in the Java galaxy.
    All java standards mandated interfaces, implementation being left to the vendor. Coders would just develop an app on top of “jmx” messaging and using “standard” logging.
    The idea was that the particular implementation could be swapped out at will, when one vendor came along with a better/cheaper/faster implementation. Recompile, redeploy and go.
    But guess what?
    This (almost) never happened!
    Because when all vendors implement the same interface, their code capabilities are pretty much the same. So swapping out one for another has little incentive.
    And when a library offers significantly better capability, it generally extends the base interface. And code which uses it is not loosely-coupled anymore.

    The typical scenario of this is: devs use Tomcat on their machines – it is faster, no licensing hassles. When they deploy on eg. Weblogic, their code takes advantage of no weblogic specific feature. In the end the PM realizes there is no value in the costly licenses and stops paying them.

  8. illuminateContracts is just a misuse of a programming science concept approach about interface and contracts. If the application’s client code have to consume external interface provided by one guy, one framework, and one vision about how things have to be think, and probably done.
    In this case, your application is clearly tightly coupled to external interfaces, even if it sounds weird.
    The article’s composer exemple was good enough. Uninstall any package required by your app, and see what is broken: implementations, implementations definitions, concrete dependencies ? You should stick to the first answer, at least for you business logic, to make it portable.
    The application’s developers must expose and consume their own set of interfaces as possible, or, wait for that new smart PSR-* that can guaranty some level of interoperability. I’m not saying that framework’s must not provides interfaces, this is far better than concrete implementation, but if your application is coupled to a full set of foreign interface, you’re stuck with them.

Leave a Reply

Your email address will not be published. Required fields are marked *