Loosely Coupled Architecture
In computing and systems design a loosely coupled system is one in which each of its components has, or makes use of, little or no knowledge of the definitions of other separate components. The sub-areas include the coupling of classes, interfaces, data, and services.
In loosely coupled architecture, services and applications:
Serve a single purpose or have a single responsibility
Have a clear interface for communication
Have less dependencies on each other
Can be agnostic to outside concerns
Can change their underlying technology without affecting the rest of the application
Are easier to automate tests
Can be deployed independently without affecting the rest of ecosystem
Can scale independently
Can fail independently
Allow your teams to work independently, without relying on other teams for support and services
Allow small and frequent changes
Have less technical debts
Have a faster recovery from failure
Difference Between Tight Coupling and Loose Coupling:
The loose coupling has better test-ability than tight coupling.
Loose coupling follows GOF principles of the program to interface and not implements whereas tight coupling does not provide the concept of interface.
It easy to swap a piece of code/objects between two classes in loose coupling whereas it isn’t that easy in tight coupling
Loose coupling is very changeable whereas tight coupling isn’t.
How to write loosely coupled code?
it all starts here. what are some techniques for writing loosely-coupled code?
1. Interfaces:
Interfaces are probably the easiest way to decouple your code. If you are writing code with classes directly, you have to make changes into the code to replace the class with other implementation. The interface defines the contract but doesn't expect an implementation making it easier to create various type of objects that perform different implementations. Using interfaces, by making this simple change, we have the ability to pass in any kind of abstract type.
2. Dependency Injection (di):
Dependency Injection (DI) basically is a design pattern which allows the creation of dependent objects outside of a class and provides those objects to a class through different ways. Using Dependency Injection, we move the creation and binding of the dependent objects outside of the class that depends on them.
The Dependency Injection pattern involves 3 types of classes:
1. Client Class: It depends on the service class
2. Service Class: It provides service to the client class.
3. Injector Class: It injects the service class object into the client class.
Types of Dependency Injection:
The injector class injects the service (dependency) to the client (dependent). The injector class injects dependencies broadly in three ways:
1. Constructor Injection: In the constructor injection, the injector supplies the service (dependency) through the client class constructor.
2. Property Injection: In the property injection (aka the Setter Injection), the injector supplies the dependency through a public property of the client class.
3. Method Injection: In this type of injection, the client class implements an interface which declares the method(s) to supply the dependency and the injector uses this interface to supply the dependency to the client class.
3. Publish as a library or artifact:
if you have a library of routines, a great exercise is to create and publish a nuget package. This forces you to examine your code, refactor it, and isolate it into a reusable (or decoupled) package.
4. Web services:
This can be consider this to be the holy grail of highly decoupled code. You cross domains when making a web service call and receive a loosely typed json object.