Logo

dev-resources.site

for different kinds of informations.

Decoupling Dependencies in Clean Architecture: A Practical Guide

Published at
4/4/2024
Categories
cleancode
cleanarchitecture
solidprinciples
dependencyinjection
Author
ijash
Author
5 person written this
ijash
open
Decoupling Dependencies in Clean Architecture: A Practical Guide

In software development, adhering to clean architecture principles is essential for creating applications that are scalable, maintainable, and flexible. One of the foundational rules within clean architecture is the decoupling of dependencies, which aligns closely with the SOLID principles, particularly the concept of "separation of concerns."

Understanding Dependency Decoupling

Before delving into examples, let's briefly explore the concept of decoupling dependencies. Dependency decoupling involves designing components in a way that reduces interdependence between them. This separation enhances modularity, making it easier to replace or modify components without affecting the entire system.

Example in TypeScript Express

Before Implementing Decoupling:

In a typical Express.js application written in TypeScript, components often tightly couple dependencies, leading to issues with scalability and maintainability. Take, for instance, the following code snippet:

import express, { Request, Response } from 'express';
import { v4 as uuidv4 } from 'uuid';
import { UserRepository } from './repositories/UserRepository';

const app = express();
const userRepository = new UserRepository();

app.use(express.json());

app.post('/register', (req: Request, res: Response) => {
  const userId = uuidv4();

  const newUser = {
    id: userId,
    name: req.body.userName,
    password: req.body.password,
    email: req.body.email
  };

  const user = userRepository.createNewUser(newUser);

  res.json({ message: "Success creating user" });
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

Enter fullscreen mode Exit fullscreen mode

After Implementing Decoupling (Using Dependency Injection):

By introducing dependency injection, we can decouple dependencies effectively. Here's how it looks in TypeScript:

import express, { Request, Response } from 'express';
import { v4 as uuidv4 } from 'uuid';
import { UserRepository } from './repositories/UserRepository';

class UserController {
  private userRepository: UserRepository;

  constructor(userRepository: UserRepository) {
    this.userRepository = userRepository;
  }

  registerUser(req: Request, res: Response): void {
    const userId = uuidv4();

    const newUser = {
      id: userId,
      name: req.body.userName,
      password: req.body.password,
      email: req.body.email
    };

    const user = this.userRepository.createNewUser(newUser);

    res.json({ message: "Success creating user" });
  }
}

const app = express();
const userRepository = new UserRepository();
const userController = new UserController(userRepository);

app.use(express.json());

app.post('/register', (req: Request, res: Response) => {
  userController.registerUser(req, res);
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});
Enter fullscreen mode Exit fullscreen mode

Example in Go and Echo

Before Implementing Decoupling (Without Dependency Injection):

In Go applications using Echo framework, dependencies are often tightly coupled, hindering flexibility and testability. Consider the following code snippet:

package main

import (
    "github.com/labstack/echo/v4"
    "github.com/google/uuid"
)

type UserRepository struct {}

func (repo *UserRepository) CreateNewUser(newUser map[string]string) map[string]string {
    // Logic to create new user
    return newUser
}

func registerUser(c echo.Context) error {
    userId := uuid.New().String()

    newUser := map[string]string{
        "id":       userId,
        "name":     c.FormValue("userName"),
        "password": c.FormValue("password"),
        "email":    c.FormValue("email"),
    }

    userRepository := UserRepository{}
    user := userRepository.CreateNewUser(newUser)

    return c.JSON(200, map[string]string{"message": "Success creating user"})
}

func main() {
    e := echo.New()
    e.POST("/register", registerUser)
    e.Logger.Fatal(e.Start(":3000"))
}

Enter fullscreen mode Exit fullscreen mode

After Implementing Decoupling (Using Dependency Injection):

With dependency injection, we can achieve decoupling in Go and Echo applications. Here's an example:

package main

import (
    "github.com/labstack/echo/v4"
    "github.com/google/uuid"
)

type UserRepository interface {
    CreateNewUser(newUser map[string]string) map[string]string
}

type UserRepositoryImpl struct {}

func (repo *UserRepositoryImpl) CreateNewUser(newUser map[string]string) map[string]string {
    // Logic to create new user
    return newUser
}

type UserController struct {
    userRepository UserRepository
}

func (controller *UserController) RegisterUser(c echo.Context) error {
    userId := uuid.New().String()

    newUser := map[string]string{
        "id":       userId,
        "name":     c.FormValue("userName"),
        "password": c.FormValue("password"),
        "email":    c.FormValue("email"),
    }

    user := controller.userRepository.CreateNewUser(newUser)

    return c.JSON(200, map[string]string{"message": "Success creating user"})
}

func main() {
    e := echo.New()

    userRepository := &UserRepositoryImpl{}
    userController := &UserController{userRepository}

    e.POST("/register", userController.RegisterUser)
    e.Logger.Fatal(e.Start(":3000"))
}

Enter fullscreen mode Exit fullscreen mode

Key Points:

  • Decoupling Dependencies: Decoupling dependencies enhances modularity and flexibility, allowing for easier maintenance and scalability.

  • Dependency Injection: Dependency injection promotes loose coupling by passing dependencies as arguments, making components more testable and maintainable.

  • Clean Architecture Principles: Adhering to clean architecture principles, such as separation of concerns, fosters the development of robust and scalable applications.

Conclusion

In summary, decoupling dependencies through dependency injection is crucial for building clean and maintainable software architectures. By following these principles, developers can create applications that are easier to test, maintain, and extend, ultimately leading to a more efficient and sustainable development process.

By incorporating these practices into your projects, you can significantly improve the quality and longevity of your software applications.

Thank you for reading! If you found this article helpful, please consider sharing it with your network.

Keywords: Clean Architecture, Dependency Decoupling, SOLID Principles, Dependency Injection, TypeScript Express, Go, Echo Framework.

cleanarchitecture Article's
30 articles in total
Favicon
Unit Testing Clean Architecture Use Cases
Favicon
The best way of implementing Domain-driven design, Clean Architecture, and CQRS
Favicon
Microservices Clean Architecture: Key Design Points and Migration Strategies
Favicon
Code Speaks for Itself: Métodos Bem Escritos Dispensam Comentários
Favicon
Clean Architecture: The Missing Chapter
Favicon
Framework agnostic Avatar component
Favicon
Usecase: TumbleLog
Favicon
Understanding Clean Architecture Principles
Favicon
1 - Clean Architecture: A Simpler Approach to Software Design
Favicon
Clean Architecture Demystified: A Practical Guide for Software Developers
Favicon
Screaming Architecture
Favicon
Registro 002 - Organizando el Código: Clean Architecture en Acción para tu Proyecto Flutter
Favicon
Your Laravel application with Repository doesn't make any sense
Favicon
Small Clean Application
Favicon
Building Your First Use Case With Clean Architecture
Favicon
Introduction to the principles of clean architecture in a NodeJs API (Express)
Favicon
Demystifying Clean Architecture: Fundamentals and Benefits
Favicon
Clean Architecture no NestJS 🏛️🚀
Favicon
Finding the Right Balance: Clean Architecture and Entity Framework in Practice
Favicon
Decoupling Dependencies in Clean Architecture: A Practical Guide
Favicon
Kotlin Clean Architecture and CQRS 🚀👋👨‍💻
Favicon
Don't go all-in Clean Architecture: An alternative for NestJS applications
Favicon
Fundamentals of Clean Architecture
Favicon
#4 Estudos: Explorando a Evolução das Arquiteturas de Software
Favicon
#3 Estudos: Arquitetura Limpa
Favicon
#1 Estudos: Arquitetura Limpa
Favicon
Além dos Templates: Uma Crítica Construtiva à Arquitetura Limpa e a Adaptação Pragmática no Design de Software
Favicon
Screaming Architecture
Favicon
Building a Clean Architecture with Rust's Rocket and sqlx
Favicon
Unveiling the essence of Clean Architectures 🫣

Featured ones: