Gratitude
We have learned a lot so far in the Modern Web Dev series, from understanding why we needed more web complexity to use learning about a bundler(Webpack) to learning design patterns modern internet companies used in writing their code.
I just want to tell you, that you are a STAR. Thanks for reading through, I appreciate it.
Pre-requisites
JavaScript Classes
JavaScript Objects
Introduction
Loosely Coupled Objects design is a design pattern idea closely related to the SOLID principles.
Loosely Coupled Objects are the opposite of tightly coupled objects, and to understand the importance of loosely coupled objects, we would take a brief description of both, a comparison, and the reasons why loosely coupled objects are better.
SOLID vs Loosely-Coupled Objects
Loosely coupled objects are a method that inspires both the Single Responsibility and Dependency-Inversion of SOLID.
It ensures that a piece of code does not depend too much on outside pieces of code and advocates for making code as modular as possible.
However, The main difference between loosely-coupled objects and the SOLID principles is that loosely-coupled objects are a general concept that can apply to any programming paradigm or design pattern, whereas the SOLID principles are specific guidelines for object-oriented programming.
In the context of the SOLID principles, loose coupling is typically achieved by adhering to the Dependency Inversion Principle (DIP), which states that modules should not depend directly on other modules, but instead should depend on abstractions.
This means that code should be designed in such a way that the implementation details of one module can be easily changed without affecting other modules that depend on it.
Coupling
Coupling refers to how closely two or more components(Classes, functions, etc.) are closely connected or dependent on each other.
When two components are tightly coupled with each other, it means they are highly dependent on each other and any change made on one will warrant an equal change in one or will lead to breaking.
On the other hand, when components are loosely coupled, they can still depend on each other vaguely. A change in one component might not lead to an entire failure.
If we were developing an app that takes in input and thanks customers after receiving input, tightly coupling this app could likely mean that for the app to take input from the customer, it has to thank the customer.
But what if the thank function was not working? It means our receiving input app will not work. Although there is not one way of loosely coupling objects, the key is to ensure that there is not a single point of failure, meaning that the failure of one component should not entirely lead to the failure of another.
There can be coupling between components, and our goal is to reduce the failures arising from their interaction. Let's look at some code examples of tight and loose coupling.
Tight Coupling
function addNumbers(num1, num2) {
return num1 + num2;
}
function calculateTotal() {
let num1 = 5;
let num2 = 10;
let total = addNumbers(num1, num2);
console.log(total);
}
- The
calculateTotal
function depends on theaddNumbers
function. If we were to change the parameters ofaddNumbers
or the way it calculates the result, it could break thecalculateTotal
function.
Loose Coupling
function addNumbers(num1, num2) {
return num1 + num2;
}
function calculateTotal(num1, num2) {
let total = addNumbers(num1, num2);
console.log(total);
}
- Although the
calculateTotal
function usesaddNumbers
in its code block, it is less likely to fail because it takes its own parameters, and you can add a change to theaddNumbers
function, and worry less about it breaking.
Error Demo
If you are like me, you are wondering what kind of errors could occur from an example as simple as this. Here's one using the same examples in the previous two sections:
Tight coupling error: Using the same code snippet for tight coupling
function addNumbers(num1, num2, num3) { //Change
return num1 + num2 + num3; // Change
}
function calculateTotal() {
let num1 = 5;
let num2 = 10;
let total = addNumbers(num1, num2);
console.log(total);
}
calculateTotal();
If you run the
calculateTotal
the function above, it doesn't work.What is returned is
NaN
, this happens because since thecalculateTotal
function is entirely dependent on theaddNumbers
function even for parameters, it has to have three numbers called inside it.
Solution: To solve this, we need to add a third num3
variable to the code snippet.
function addNumbers(num1, num2, num3) {
return num1 + num2 + num3;
}
function calculateTotal() {
let num1 = 5;
let num2 = 10;
let num3 = 12; // Solution
let total = addNumbers(num1, num2, num3); // Solution
console.log(total);
}
calculateTotal();
Loose coupling error: Now let's use the code snippet in the loose coupling section,
function addNumbers(num1, num2, num3) {
return num1 + num2 + num3;
}
function calculateTotal(num1, num2) {
let total = addNumbers(num1, num2);
console.log(total);
}
calculateTotal(3, 4);
Now run
calculateTotal
and you see, IT WORKS!!!calculateTotal
is only trying to access two parameters withaddNumbers
and it can do because of how it's designed.
There's no underlying algorithm that makes this happen, it's just design patterns. Now, this is amazing.
Conclusion
Loosely coupled objects are an important design pattern that advocates for code modularity, and it is a general concept that applies to any programming paradigm or design pattern.
In comparison, tightly coupled objects are highly dependent on each other, and any change in one component will lead to the breaking of another.
Our goal as developers is to reduce the failures arising from the interaction between components, and one way to achieve this is through loose coupling.
By implementing loose coupling, we can reduce the probability of a single point of failure in our code, which will make our applications more robust and resilient to changes.