# Decoupling

**Decoupling** in software engineering refers to the process of reducing dependencies between components, systems, or layers in a software application. The goal is to ensure that changes in one part of the system have minimal or no impact on other parts, promoting modularity, scalability, and maintainability.

* **Low Coupling**: Components interact with each other minimally and in well-defined ways. Dependencies between components are reduced or abstracted.
* **High Cohesion**: Each component focuses on a single responsibility or closely related tasks.
* **Abstractions**: Interfaces, design patterns, or APIs are often used to separate concerns and decouple components.
* **Communication through Contracts**: Components interact using well-defined protocols or contracts, such as interfaces or messages.

## Benefits

* **Ease of Maintenance**: Changes in one module are less likely to affect others.
* **Reusability**: Decoupled components can be reused in other projects or contexts.
* **Testability**: Isolated components are easier to test independently.
* **Scalability**: Decoupled systems can scale by replacing or upgrading individual components without disrupting others.
* **Flexibility**: Easier to swap out or replace one component with another.

## Decoupling Techniques

* **Abstraction:**
  * Use interfaces to define behaviors.
  * Example: Decouple business logic from data access logic by defining repository interfaces.
* **Event-Driven Architecture:**
  * Components communicate through events instead of direct calls.
  * Example: Publish/subscribe systems.
* **Dependency Injection (DI):**
  * Inject dependencies into components instead of instantiating them internally.
  * Example: Pass the database dependency into the service constructor.
* **Message Queues**:
  * Use messaging systems (e.g., RabbitMQ, Kafka) for asynchronous communication between decoupled components.

## Real-World Examples

* **Microservices**: Each microservice is a self-contained unit with its own database and logic. Services communicate via APIs or messaging systems, not direct calls.
* **Frontend and Backend**: Decoupled via RESTful APIs or GraphQL, allowing independent development and scaling.
* **Plugins and Extensions**: Decoupled systems allow new features to be added without altering the core application.

## When Decoupling May Be Overkill

* **Small Applications**: Decoupling may add unnecessary complexity.
* **Performance Concerns**: Additional abstractions or message passing can add latency.

## Golang Example

Before Decoupling (Tightly Coupled System)

```go
type MySQLDatabase struct{}

func (db MySQLDatabase) Connect() {
    fmt.Println("Connecting to MySQL...")
}

type UserService struct {
    Database MySQLDatabase
}

func (s UserService) GetUser(userID int) {
    s.Database.Connect()
    fmt.Printf("Fetching user with ID: %d\n", userID)
}

func main() {
    service := UserService{Database: MySQLDatabase{}}
    service.GetUser(1)
}
```

**Problem**: The UserService is tightly coupled with MySQLDatabase. If we want to switch to another database (e.g., PostgreSQL), we must modify the UserService code. After Decoupling (Using Abstraction)

```go
type Database interface {
    Connect()
}

type MySQLDatabase struct{}

func (db MySQLDatabase) Connect() {
    fmt.Println("Connecting to MySQL...")
}

type PostgreSQLDatabase struct{}

func (db PostgreSQLDatabase) Connect() {
    fmt.Println("Connecting to PostgreSQL...")
}

type UserService struct {
    Database Database
}

func (s UserService) GetUser(userID int) {
    s.Database.Connect()
    fmt.Printf("Fetching user with ID: %d\n", userID)
}

func main() {
    // Switch between different database implementations without changing UserService
    mysql := MySQLDatabase{}
    postgres := PostgreSQLDatabase{}

    service := UserService{Database: mysql}
    service.GetUser(1)

    service.Database = postgres
    service.GetUser(2)
}
```

**Solution**: The UserService is now decoupled from specific database implementations. It relies on the Database interface, making it easy to replace or add new databases.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://bagus-cahyono.gitbook.io/programming-notes/programming/decoupling.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
