Skip to content

架构设计与项目结构

项目概览

lz-stash 是一个个人学习项目,采用标准的 Go 项目布局和清晰的分层架构设计,用于学习和实践账本管理和终端 UI 开发技术。

📁 项目结构

lz-stash/
├── main.go                    # 应用程序入口点
├── go.mod                     # Go 模块依赖管理
├── cmd/                       # CLI 命令定义
│   ├── root.go               # 根命令和全局配置
│   ├── example.go            # 示例命令容器
│   ├── example/              # 示例子命令
│   │   ├── bubble/           # Bubble Tea 基础示例
│   │   └── tea/              # Tea 高级示例
│   ├── ledger.go             # 账本命令容器
│   └── ledger/               # 账本管理命令
│       ├── init.go           # 系统初始化命令
│       └── server.go         # gRPC 服务启动命令
├── proto/                    # Protocol Buffers 定义
│   └── ledger/v1/           # 账本管理 API 契约
├── gen/                      # 自动生成的代码
│   └── ledger/v1/           # gRPC Go 客户端代码
├── internal/                 # 内部包(不对外暴露)
│   ├── app/                  # 应用层业务逻辑
│   │   └── ledger/          # 账本管理核心模块
│   └── pkg/                  # 内部共享包
│       ├── config/          # 配置管理
│       └── database/        # 数据库连接
├── pkg/                      # 可复用公共库
│   ├── bubble/              # Bubble Tea UI 组件
│   ├── errors/              # 错误处理
│   ├── id/                  # ID 生成器
│   ├── money/               # 货币处理
│   ├── utils/               # 工具函数
│   └── validation/          # 数据验证
├── sdk/                      # 多语言 SDK
│   ├── nodejs/              # Node.js/TypeScript SDK
│   ├── php/                 # PHP SDK
│   ├── python/              # Python SDK
│   └── go/                  # Go SDK
├── docs/                     # 项目文档
├── .github/                  # GitHub Actions 工作流
└── testing/                  # 性能测试和基准测试

🏗️ 架构设计

分层架构模式

项目采用经典的分层架构,实现关注点分离和模块解耦:

核心模块设计

1. CLI 命令系统

命令注册架构

  • 自动注册: 通过空白导入(_ "package")触发命令注册
  • 分层组织: 支持命令组和子命令的嵌套结构
  • 参数绑定: 统一的参数解析和验证机制

命令类型

  • 容器命令: 组织和分类子命令的父命令
  • 执行命令: 包含具体业务逻辑的叶子命令
go
// 命令注册示例
func init() {
    // 注册子命令到父命令
    rootCmd.AddCommand(ledgerCmd)
    ledgerCmd.AddCommand(initCmd)
    ledgerCmd.AddCommand(serverCmd)
}

2. 账本管理系统

Clean Architecture 设计

核心实体

  • Ledger: 账本实体,管理财务记录的容器
  • Transaction: 交易记录,包含收入和支出信息
  • Budget: 预算管理,支持周期性预算设置
  • Tag: 标签系统,用于交易分类和统计

3. 终端 UI 框架

Bubble Tea 组件架构

go
// 进度条组件接口
type ProgressModel interface {
    tea.Model
    SetProgress(current, total int)
    SetMessage(msg string)
    IsComplete() bool
}

// 组件工厂模式
func NewProgressBar(opts ...Option) ProgressModel {
    // 创建可配置的进度条组件
}

特性

  • 模块化组件: 可复用的 UI 组件库
  • 并发安全: 支持多协程的进度更新
  • 内存优化: 智能的显示模式和历史记录管理
  • 主题支持: 可配置的颜色主题和样式

数据管理架构

数据库设计

连接管理

  • 单例模式: 确保全局唯一的数据库连接实例
  • 连接池: 复用数据库连接,提升性能
  • 事务支持: 确保数据一致性和原子性操作

迁移策略

  • 自动迁移: 应用启动时自动创建/更新表结构
  • 版本管理: 支持数据库结构的版本控制
  • 数据种子: 自动创建默认数据和示例记录

API 接口设计

gRPC 服务定义

protobuf
service LedgerService {
  // 账本管理
  rpc CreateLedger(CreateLedgerRequest) returns (Ledger);
  rpc GetLedger(GetLedgerRequest) returns (Ledger);
  rpc ListLedgers(ListLedgersRequest) returns (ListLedgersResponse);
  
  // 交易管理
  rpc CreateTransaction(CreateTransactionRequest) returns (Transaction);
  rpc ListTransactions(ListTransactionsRequest) returns (ListTransactionsResponse);
  rpc GetTransactionStatistics(GetStatisticsRequest) returns (StatisticsResponse);
  
  // 预算管理
  rpc CreateBudget(CreateBudgetRequest) returns (Budget);
  rpc GetBudgetUsage(GetBudgetUsageRequest) returns (BudgetUsageResponse);
}

多语言 SDK

  • 自动生成: 基于 Protocol Buffers 自动生成客户端代码
  • 语言支持: Go, Node.js, Python, PHP
  • 文档同步: SDK 文档与 API 定义保持同步

并发处理架构

工作池模式

go
type WorkerPool struct {
    tasks       chan Task
    results     chan Result
    workers     int
    rateLimiter *rate.Limiter
    wg          sync.WaitGroup
}

func (p *WorkerPool) Start() {
    for i := 0; i < p.workers; i++ {
        go p.worker()
    }
}

func (p *WorkerPool) worker() {
    defer p.wg.Done()
    for task := range p.tasks {
        p.rateLimiter.Wait(context.Background())
        result := p.processTask(task)
        p.results <- result
    }
}

特性

  • 可配置并发: 支持动态调整工作协程数量
  • 速率限制: 内置速率限制器,避免资源过载
  • 优雅关闭: 支持信号处理和优雅的系统关闭
  • 错误隔离: 单个任务失败不影响整体处理

配置管理架构

多层配置源

配置优先级(从高到低):

  1. 命令行参数: 直接通过 CLI 参数传递
  2. 环境变量: 使用 LZ_STASH_ 前缀
  3. 配置文件: YAML 格式,支持多个位置
  4. 默认值: 代码中定义的合理默认值
go
// 配置管理器接口
type Manager interface {
    Load(configFile string) error
    GetString(key string) string
    GetInt(key string) int
    GetDuration(key string) time.Duration
    Validate() error
}

配置验证

验证策略

  • 延迟验证: 配置在实际使用时进行验证
  • 模块化验证: 不同模块独立验证各自的配置
  • 友好错误: 提供清晰的配置错误信息和修复建议

错误处理架构

错误分类系统

go
// 应用错误类型
type LedgerError struct {
    Code    string
    Message string
    Details []ErrorDetail
    Cause   error
}

// 错误分类
const (
    ErrorCodeNotFound      = "NOT_FOUND"
    ErrorCodeAlreadyExists = "ALREADY_EXISTS"
    ErrorCodeValidation    = "VALIDATION_ERROR"
    ErrorCodeInternal      = "INTERNAL_ERROR"
)

错误处理原则

  • 层级传播: 错误在层级间正确传播和包装
  • 上下文保留: 保留错误的完整上下文信息
  • 用户友好: 对用户显示清晰易懂的错误消息
  • 可观测性: 详细的错误日志用于问题诊断

测试架构

测试策略

单元测试

  • pkg/ 包强制测试: 所有公共包必须有单元测试
  • Mock 接口: 使用接口和 Mock 进行依赖隔离
  • 表驱动测试: 使用表驱动模式确保测试覆盖

集成测试

  • 内存数据库: 使用 SQLite 内存数据库进行测试
  • gRPC 测试: 完整的 gRPC 服务端到端测试
  • CLI 测试: 命令行接口的集成测试

性能测试

  • 基准测试: 关键路径的性能基准测试
  • 压力测试: 使用 Vegeta 进行 HTTP/gRPC 压力测试
  • 内存分析: 内存使用模式和泄漏检测

🎯 设计原则

SOLID 原则

  1. 单一职责原则: 每个模块专注于单一功能领域
  2. 开闭原则: 对扩展开放,对修改关闭
  3. 里氏替换原则: 接口实现可以安全替换
  4. 接口隔离原则: 客户端不依赖不需要的接口
  5. 依赖倒置原则: 依赖抽象而非具体实现

领域驱动设计

  • 领域模型: 以业务领域为核心的模型设计
  • 限界上下文: 清晰的模块边界和职责划分
  • 聚合根: 确保数据一致性的聚合设计
  • 领域服务: 不属于特定实体的业务逻辑

12-Factor App

  • 配置: 配置存储在环境中
  • 依赖: 显式声明和隔离依赖
  • 日志: 将日志作为事件流处理
  • 进程: 应用作为无状态进程执行

🚀 部署架构

容器化支持

Docker 镜像

  • 多阶段构建: 优化镜像大小和安全性
  • 最小基础镜像: 使用 scratch 或 distroless 镜像
  • 健康检查: 内置健康检查和就绪探针

CI/CD 流水线

自动化构建

  • 多平台编译: 支持 Linux、macOS、Windows
  • 自动版本: 基于 Git 标签的语义化版本
  • 制品发布: 自动发布到 GitHub Releases

质量保证

  • 代码检查: 使用 golangci-lint 进行代码质量检查
  • 安全扫描: 依赖安全漏洞扫描
  • 测试覆盖: 自动生成测试覆盖率报告

本文档描述了 lz-stash 的整体架构设计,为学习者提供系统的技术理解和实践指南。

基于 MIT 许可证发布