'Coupling' is a term that describes the relationship between two entities in a software system (usually classes).
When a class uses another class, or communicates with it, it's said to 'depend' on that other class, and so these classes are 'coupled'. At least one of them 'knows' about the other.
The idea is that we should try to keep the coupling between classes in our systems as 'loose' as possible: hence 'loose coupling' or sometimes 'decoupling' (although in English 'decoupling' would mean 'no coupling at all', people often use it to imply 'loose coupling' between entities).
So: what is loose-coupling versus strong coupling in practice, and why should we make entities loosely-coupled?
Coupling describes the degree of dependency between one entity to another entity. Often classes or objects.
When ClassA depends heavily on ClassB, the chances of ClassA being affected when ClassB is changed are high. This is strong coupling.
However if ClassA depends lightly on ClassB, than the chances of ClassA being affected in any way by a change in the code of ClassB, are low. This is loose coupling, or a 'decoupled' relationship.
Loose coupling is good because we don't want the components of our system to heavily depend on each other. We want to keep our system modular, where we can safely change one part without affecting the other.
When two parts are loosely coupled, they are more independent of each other and are less likely to break when the other changes.
For example, when building a car, you wouldn't want an internal change in the engine to break something in the steering wheel.
While this would never happen by accident when building a car, similar things happen to programmers all the time. Loose coupling is meant to reduce the risk of such things happening.
Strong coupling usually occurs when entity A knows too much about entity B. If entity A makes too many assumptions about how entity B operates or how it is built, then there is a high risk that a change in entity B will affect entity A. This is because one of its assumptions about entity B are now incorrect.
For example, imagine that as a driver, you would make certain assumptions about how the engine of your car works.
The day you buy a new car with an engine that works differently (or for some reason your engine was replaced), your previous assumptions would be incorrect. If you were code in a computer, you would now be incorrect code that doesn't work properly.
However, if all the assumptions that as a driver you made about cars is that: A- they have steering wheels and B- they have brake and gas pedals, then changes in the car won't affect you, as long as your few assumptions stay correct. This is loose coupling.
An important technique to achieve loose coupling is Encapsulation. The idea is that a class hides its internal details from other classes, and offers a strictly defined interface for other classes to communicate with it.
So for example, if you were defining a class Car, it's interface (public methods) would probably be
getSpeed(). These are the methods other objects can invoke on Car objects.
All of the other details of the Car class: how the engine works, kind of fuel it uses, etc. are hidden from other classes - to prevent them from knowing too much about Car.
The moment class A knows too much about class B: we have a strongly coupled relationship, where class A is too dependent on class B and a change in class B is likely to affect class A. Making the system hard to expand and maintain.
A relationship between two entities, where they know little about each other (only what's necessary) - is a loosely coupled, or decoupled relationship.