golang使用六边形架构编写可维护代码指南插件库Hex Monscape的使用
Golang使用六边形架构编写可维护代码指南 - Hex Monscape插件库使用
Hex Monscape是一个基于Golang和Vue 3开发的回合制游戏项目,它展示了如何应用六边形架构(Hexagonal Architecture)来编写可维护的代码。
项目概述
Hex Monscape是Haraj Solutions团队用于新成员入职培训的有趣项目。通过这个游戏项目,团队展示了他们如何在生产代码中使用六边形架构,即使团队规模很小也能维护好服务数百万用户的系统。
六边形架构优势
六边形架构的主要优势在于:
- 加快服务开发速度
- 使代码可以被整个团队维护
- 容易替换基础设施代码(如存储层)
游戏设计
在游戏中,玩家扮演一个10岁的怪物猎人,与怪物伙伴一起旅行,寻找并击败3只强大的野生怪物。
游戏流程如下:
战斗流程如下:
如何使用Hex Monscape
在线体验
你可以直接访问在线版本: https://hex-monscape.haraj.app
本地运行
要本地运行游戏,需要先安装:
- Docker v20.10.23或更高版本(包含Docker Compose v2.15.1)
- make工具
然后运行:
make run
等待看到如下消息后,访问 http://localhost:8161 即可:
rest-memory-client-1 | yarn run v1.22.19
rest-memory-client-1 | $ vite --host --port 8161
rest-memory-client-1 |
rest-memory-client-1 | vite v2.8.4 dev server running at:
rest-memory-client-1 |
rest-memory-client-1 | > Local: http://localhost:8161/
rest-memory-client-1 | > Network: http://172.31.0.3:8161/
rest-memory-client-1 |
rest-memory-client-1 | ready in 151ms.
服务器变体
项目提供了3种不同的服务器实现,展示如何轻松替换基础设施:
- 使用内存存储:
make run-rest-memory
- 使用DynamoDB存储:
make run-rest-dynamodb
- 使用MySQL存储:
make run-rest-mysql
示例代码
以下是使用六边形架构的核心代码示例:
// 领域层 - 定义核心业务逻辑
package battle
// Battle是领域模型,代表一场战斗
type Battle struct {
ID string
Player *Monster
Enemy *Monster
Turn int
Status Status
CreatedAt time.Time
FinishedAt *time.Time
}
// 领域服务接口
type Service interface {
StartBattle(playerID, enemyID string) (*Battle, error)
Attack(battleID string) (*Battle, error)
GetBattle(battleID string) (*Battle, error)
}
// 基础设施层 - 实现存储接口
package storage
// BattleRepository定义了持久化接口
type BattleRepository interface {
Save(battle *battle.Battle) error
FindByID(id string) (*battle.Battle, error)
}
// 内存存储实现
type BattleMemoryStorage struct {
battles map[string]*battle.Battle
mu sync.Mutex
}
func (s *BattleMemoryStorage) Save(b *battle.Battle) error {
s.mu.Lock()
defer s.mu.Unlock()
s.battles[b.ID] = b
return nil
}
// 应用层 - 连接领域和基础设施
package app
type BattleApp struct {
battleSvc battle.Service
}
func NewBattleApp(repo storage.BattleRepository) *BattleApp {
return &BattleApp{
battleSvc: battle.NewService(repo),
}
}
func (a *BattleApp) StartBattle(playerID, enemyID string) (*battle.Battle, error) {
return a.battleSvc.StartBattle(playerID, enemyID)
}
核心维护者
如有问题可以联系:
- Riandy Rahman Nugraha (@riandyrn)
- Muhammad Iskandar Dzulqornain (@isdzulqor)
- Muhammad Izzuddin al Fikri (@knightazura)
- Alfat Saputra Harun (@harunalfat)
- Ilham Syahid Syamsudin (@ilhamsyahids)
许可证
MIT
更多关于golang使用六边形架构编写可维护代码指南插件库Hex Monscape的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang使用六边形架构编写可维护代码指南插件库Hex Monscape的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
使用六边形架构编写可维护Go代码:Hex Monscape指南
六边形架构(Hexagonal Architecture)是一种将业务逻辑与外部依赖分离的设计模式,使应用程序更易于维护和测试。Hex Monscape是一个Go语言的插件库,帮助开发者实现六边形架构。
六边形架构核心概念
六边形架构的核心是将应用程序分为:
- 内部核心:包含业务逻辑和领域模型
- 外部适配器:处理与外部系统的交互(数据库、API、UI等)
Hex Monscape基本使用
安装
go get github.com/hexdigest/gowrap
基础示例
package main
import (
"github.com/hexdigest/gowrap/hex"
)
// 定义核心业务接口
type UserService interface {
CreateUser(name string, email string) (User, error)
GetUser(id string) (User, error)
}
// 领域模型
type User struct {
ID string
Name string
Email string
}
// 实现核心业务逻辑
type userServiceImpl struct{}
func (s *userServiceImpl) CreateUser(name string, email string) (User, error) {
// 业务逻辑实现
return User{
ID: "123",
Name: name,
Email: email,
}, nil
}
func (s *userServiceImpl) GetUser(id string) (User, error) {
// 业务逻辑实现
return User{
ID: id,
Name: "John Doe",
Email: "john@example.com",
}, nil
}
func main() {
// 创建核心服务
coreService := &userServiceImpl{}
// 使用Hex Monscape包装核心服务
hexService := hex.NewServiceWrapper(coreService)
// 添加适配器
httpAdapter := hex.NewHTTPAdapter(hexService)
httpAdapter.Start(":8080")
}
高级用法
自定义适配器
package adapters
import (
"encoding/json"
"net/http"
"github.com/hexdigest/gowrap/hex"
)
type JSONHTTPAdapter struct {
service hex.Service
}
func NewJSONHTTPAdapter(service hex.Service) *JSONHTTPAdapter {
return &JSONHTTPAdapter{service: service}
}
func (a *JSONHTTPAdapter) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/users":
if r.Method == "POST" {
var req struct {
Name string `json:"name"`
Email string `json:"email"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
user, err := a.service.(UserService).CreateUser(req.Name, req.Email)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
json.NewEncoder(w).Encode(user)
}
default:
http.NotFound(w, r)
}
}
依赖注入
package main
import (
"github.com/hexdigest/gowrap/hex"
"yourproject/adapters"
"yourproject/core"
)
func main() {
// 初始化核心服务
userService := core.NewUserService()
// 初始化存储库适配器
userRepo := adapters.NewPostgresUserRepository()
// 将适配器注入核心服务
userService.SetRepository(userRepo)
// 包装核心服务
hexService := hex.NewServiceWrapper(userService)
// 启动HTTP适配器
httpAdapter := adapters.NewJSONHTTPAdapter(hexService)
http.ListenAndServe(":8080", httpAdapter)
}
最佳实践
- 明确边界:严格区分核心业务逻辑和适配器代码
- 依赖倒置:适配器应该实现核心定义的接口,而不是反过来
- 单一职责:每个适配器只处理一种外部交互
- 测试策略:
- 核心逻辑使用单元测试
- 适配器使用集成测试
测试示例
package core_test
import (
"testing"
"github.com/hexdigest/gowrap/hex"
"yourproject/core"
"yourproject/core/mocks"
)
func TestUserService(t *testing.T) {
// 创建mock存储库
mockRepo := new(mocks.UserRepository)
mockRepo.On("Save", mock.Anything).Return(nil)
// 创建服务实例
service := core.NewUserService()
service.SetRepository(mockRepo)
// 包装服务
hexService := hex.NewServiceWrapper(service)
// 测试
user, err := hexService.(core.UserService).CreateUser("test", "test@example.com")
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if user.Name != "test" {
t.Errorf("Expected user name 'test', got '%s'", user.Name)
}
mockRepo.AssertExpectations(t)
}
Hex Monscape通过提供标准化的包装器和适配器接口,简化了六边形架构的实现过程。遵循这些模式可以显著提高Go应用程序的可维护性和可测试性。