Golang新手求助 - 应用结构设计问题求指导

Golang新手求助 - 应用结构设计问题求指导 你好

我写Go代码有一段时间了,但还没有完全靠自己从零开始编写过生产级的应用程序。

我写了一个基础结构,包含一些基础代码,需要有人帮我审查一下,看看我做得对不对,以及大家通常是怎么做的。

我把Git链接放在这里

GitHub

avinash92c/appbase

我的旧版基于Golang的微服务基础代码。通过在GitHub上创建账户,为avinash92c/appbase的开发做出贡献。


更多关于Golang新手求助 - 应用结构设计问题求指导的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang新手求助 - 应用结构设计问题求指导的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


看了你的代码库,整体结构清晰,但有几个地方可以优化。以下是我的具体分析和改进建议:

1. 配置管理优化

当前使用全局变量存储配置,建议改为依赖注入方式:

// config/config.go
type Config struct {
    Server   ServerConfig
    Database DatabaseConfig
    Redis    RedisConfig
}

func Load() (*Config, error) {
    // 从环境变量或配置文件加载
    var cfg Config
    // ... 加载逻辑
    return &cfg, nil
}

2. 数据库层改进

当前直接暴露*sql.DB,建议添加Repository模式:

// internal/repository/user_repository.go
type UserRepository interface {
    Create(ctx context.Context, user *User) error
    FindByID(ctx context.Context, id int64) (*User, error)
}

type userRepository struct {
    db *sql.DB
}

func NewUserRepository(db *sql.DB) UserRepository {
    return &userRepository{db: db}
}

3. 服务层添加

建议在handler和repository之间添加服务层:

// internal/service/user_service.go
type UserService struct {
    repo repository.UserRepository
    // 可以注入其他依赖如logger, cache等
}

func (s *UserService) CreateUser(ctx context.Context, req CreateUserRequest) error {
    // 业务逻辑验证
    if req.Name == "" {
        return errors.New("name is required")
    }
    
    // 调用repository
    user := &User{Name: req.Name}
    return s.repo.Create(ctx, user)
}

4. 依赖注入优化

使用wire或手动依赖注入:

// cmd/api/main.go
func main() {
    cfg := config.Load()
    
    db := database.New(cfg.Database)
    defer db.Close()
    
    userRepo := repository.NewUserRepository(db)
    userService := service.NewUserService(userRepo)
    
    handler := handler.NewUserHandler(userService)
    
    router := chi.NewRouter()
    router.Post("/users", handler.CreateUser)
    
    http.ListenAndServe(":8080", router)
}

5. 错误处理改进

定义应用级错误类型:

// internal/errors/app_error.go
type AppError struct {
    Code    string
    Message string
    Err     error
}

func (e *AppError) Error() string {
    if e.Err != nil {
        return fmt.Sprintf("%s: %v", e.Message, e.Err)
    }
    return e.Message
}

var (
    ErrNotFound     = &AppError{Code: "NOT_FOUND", Message: "resource not found"}
    ErrInvalidInput = &AppError{Code: "INVALID_INPUT", Message: "invalid input"}
)

6. 中间件优化

当前中间件可以更模块化:

// internal/middleware/logging.go
func Logging(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        
        // 使用response writer wrapper记录状态码
        rw := &responseWriter{ResponseWriter: w}
        next.ServeHTTP(rw, r)
        
        log.Printf("%s %s %d %v", 
            r.Method, 
            r.URL.Path, 
            rw.status, 
            time.Since(start))
    })
}

7. 测试结构

添加测试示例:

// internal/service/user_service_test.go
func TestUserService_CreateUser(t *testing.T) {
    mockRepo := &mockUserRepository{}
    service := NewUserService(mockRepo)
    
    err := service.CreateUser(context.Background(), CreateUserRequest{
        Name: "John Doe",
    })
    
    assert.NoError(t, err)
    assert.True(t, mockRepo.createCalled)
}

你的基础结构已经不错,主要是需要更清晰的分层和依赖管理。建议参考标准项目布局(Standard Go Project Layout),保持代码的可测试性和可维护性。

回到顶部