مقدمه
معماری Clean (یا Clean Architecture) یک الگوی طراحی نرمافزار است که توسط Robert C. Martin (معروف به Uncle Bob) معرفی شده و هدف آن تفکیک مسئولیتها، کاهش وابستگیها و افزایش تستپذیری در پروژههاست. این معماری مخصوصاً برای پروژههای زبان Go که ساختار ماژولار دارند بسیار مناسب است.
اصول کلیدی معماری Clean
- استقلال از فریمورکها: فریمورکها باید قابل تعویض باشند بدون آنکه منطق اصلی تغییر کند.
- قابل تست بودن: امکان تست منطق بدون نیاز به دیتابیس یا UI.
- استقلال از UI: UI میتواند بدون تأثیر بر لایههای دیگر تغییر یابد.
- استقلال از دیتابیس: انتخاب دیتابیس نباید منطق را تحت تأثیر قرار دهد.
- استقلال از اجزای خارجی: منطق باید مستقل از اجزای زیرساختی باشد.
ساختار معماری 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 منجر به کدی تمیز، منعطف و قابل توسعه خواهد شد.