架构设计与项目结构
项目概览
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
}
}特性:
- 可配置并发: 支持动态调整工作协程数量
- 速率限制: 内置速率限制器,避免资源过载
- 优雅关闭: 支持信号处理和优雅的系统关闭
- 错误隔离: 单个任务失败不影响整体处理
配置管理架构
多层配置源
配置优先级(从高到低):
- 命令行参数: 直接通过 CLI 参数传递
- 环境变量: 使用
LZ_STASH_前缀 - 配置文件: YAML 格式,支持多个位置
- 默认值: 代码中定义的合理默认值
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 原则
- 单一职责原则: 每个模块专注于单一功能领域
- 开闭原则: 对扩展开放,对修改关闭
- 里氏替换原则: 接口实现可以安全替换
- 接口隔离原则: 客户端不依赖不需要的接口
- 依赖倒置原则: 依赖抽象而非具体实现
领域驱动设计
- 领域模型: 以业务领域为核心的模型设计
- 限界上下文: 清晰的模块边界和职责划分
- 聚合根: 确保数据一致性的聚合设计
- 领域服务: 不属于特定实体的业务逻辑
12-Factor App
- 配置: 配置存储在环境中
- 依赖: 显式声明和隔离依赖
- 日志: 将日志作为事件流处理
- 进程: 应用作为无状态进程执行
🚀 部署架构
容器化支持
Docker 镜像:
- 多阶段构建: 优化镜像大小和安全性
- 最小基础镜像: 使用 scratch 或 distroless 镜像
- 健康检查: 内置健康检查和就绪探针
CI/CD 流水线
自动化构建:
- 多平台编译: 支持 Linux、macOS、Windows
- 自动版本: 基于 Git 标签的语义化版本
- 制品发布: 自动发布到 GitHub Releases
质量保证:
- 代码检查: 使用 golangci-lint 进行代码质量检查
- 安全扫描: 依赖安全漏洞扫描
- 测试覆盖: 自动生成测试覆盖率报告
本文档描述了 lz-stash 的整体架构设计,为学习者提供系统的技术理解和实践指南。