مقدمه

معماری Clean (یا Clean Architecture) یک الگوی طراحی نرم‌افزار است که توسط Robert C. Martin (معروف به Uncle Bob) معرفی شده و هدف آن تفکیک مسئولیت‌ها، کاهش وابستگی‌ها و افزایش تست‌پذیری در پروژه‌هاست. این معماری مخصوصاً برای پروژه‌های زبان Go که ساختار ماژولار دارند بسیار مناسب است.

اصول کلیدی معماری Clean

  1. استقلال از فریمورک‌ها: فریمورک‌ها باید قابل تعویض باشند بدون آنکه منطق اصلی تغییر کند.
  2. قابل تست بودن: امکان تست منطق بدون نیاز به دیتابیس یا UI.
  3. استقلال از UI: UI می‌تواند بدون تأثیر بر لایه‌های دیگر تغییر یابد.
  4. استقلال از دیتابیس: انتخاب دیتابیس نباید منطق را تحت تأثیر قرار دهد.
  5. استقلال از اجزای خارجی: منطق باید مستقل از اجزای زیرساختی باشد.

ساختار معماری Clean در Go

project/
├── cmd/               # نقطه ورود
├── internal/          # لایه‌های معماری
│   ├── entity/        # مدل‌های دامنه
│   ├── usecase/       # منطق کسب‌وکار
│   ├── repository/    # اینترفیس‌های ذخیره‌سازی
│   └── delivery/      # لایه ارائه (HTTP, CLI, gRPC)
├── pkg/               # کتابخانه‌های عمومی
└── go.mod             # ماژول و وابستگی‌ها

نمونه پیاده‌سازی

1. Entity

// internal/entity/user.go
package entity

type User struct {
    ID        int
    FirstName string
    LastName  string
    Email     string
}

2. Repository

// internal/repository/user_repository.go
package repository

import "project/internal/entity"

type UserRepository interface {
    FindAll() ([]entity.User, error)
    FindByID(id int) (*entity.User, error)
    Save(user *entity.User) error
    Delete(id int) error
}

3. Usecase

// internal/usecase/user_usecase.go
package usecase

import (
    "project/internal/entity"
    "project/internal/repository"
)

type UserUsecase struct {
    userRepo repository.UserRepository
}

func NewUserUsecase(repo repository.UserRepository) *UserUsecase {
    return &UserUsecase{userRepo: repo}
}

func (uc *UserUsecase) GetUser(id int) (*entity.User, error) {
    return uc.userRepo.FindByID(id)
}

4. Delivery

// internal/delivery/http/user_handler.go
package http

import (
    "net/http"
    "project/internal/usecase"
    "strconv"

    "github.com/gin-gonic/gin"
)

type UserHandler struct {
    userUsecase usecase.UserUsecase
}

func NewUserHandler(uc usecase.UserUsecase) *UserHandler {
    return &UserHandler{userUsecase: uc}
}

func (h *UserHandler) GetUser(c *gin.Context) {
    id, _ := strconv.Atoi(c.Param("id"))
    user, err := h.userUsecase.GetUser(id)
    if err != nil {
        c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})
        return
    }
    c.JSON(http.StatusOK, user)
}

مزایای Clean Architecture در Go

  • نگهداری آسان
  • تست‌پذیری بالا
  • انعطاف در تعویض تکنولوژی‌ها
  • مقیاس‌پذیری پروژه در طول زمان

چالش‌های رایج

  • طراحی اولیه پیچیده‌تر
  • نیاز به کدنویسی بیشتر
  • نیاز به درک مناسب معماری از سوی تیم

توصیه‌ها برای موفقیت در Go

  • استفاده گسترده از اینترفیس‌ها
  • مدیریت صحیح وابستگی‌ها با DI
  • استفاده از ابزارهایی مانند Wire
  • رعایت اصل تک مسئولیتی در پکیج‌ها

جمع‌بندی

اگرچه معماری Clean در ابتدا پیچیده به نظر می‌رسد، اما در پروژه‌های واقعی، ارزش خود را با افزایش کیفیت، ساختار و مقیاس‌پذیری اثبات می‌کند. پیاده‌سازی صحیح این الگو در Go منجر به کدی تمیز، منعطف و قابل توسعه خواهد شد.