go-create-service

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Go Create Service

创建Go服务

Generate service files for GO modular architechture conventions.
按照Go模块化架构规范生成服务文件。

Three-File Pattern

三文件模式

Every service requires up to three files:
  1. DTO structs (if needed):
    internal/modules/<module>/dto/<service_name>_dto.go
  2. Port interface:
    internal/modules/<module>/ports/<service_name>_service.go
  3. Service implementation:
    internal/modules/<module>/service/<service_name>_service.go
每个服务最多需要三个文件:
  1. DTO结构体(如有需要):
    internal/modules/<module>/dto/<service_name>_dto.go
  2. Port接口
    internal/modules/<module>/ports/<service_name>_service.go
  3. 服务实现
    internal/modules/<module>/service/<service_name>_service.go

DTO File Layout Order

DTO文件布局顺序

  1. Input/output structs
  1. 输入/输出结构体

Port File Layout Order

Port文件布局顺序

  1. Interface definition (
    XxxService
    — no suffix)
  1. 接口定义(
    XxxService
    — 无后缀)

Service File Layout Order

服务文件布局顺序

  1. Implementation struct (
    XxxService
    )
  2. Compile-time interface assertion
  3. Constructor (
    NewXxxService
    )
  4. Methods
  1. 实现结构体(
    XxxService
  2. 编译时接口断言
  3. 构造函数(
    NewXxxService
  4. 方法

DTO Structure

DTO结构

Location:
internal/modules/<module>/dto/<service_name>_dto.go
go
package dto

type DoSomethingInput struct {
	Field string
}
位置
internal/modules/<module>/dto/<service_name>_dto.go
go
package dto

type DoSomethingInput struct {
	Field string
}

Port Interface Structure

Port接口结构

Location:
internal/modules/<module>/ports/<service_name>_service.go
go
package ports

import (
	"context"

	"github.com/cristiano-pacheco/pingo/internal/modules/<module>/dto"
)

type DoSomethingService interface {
	Execute(ctx context.Context, input dto.DoSomethingInput) error
}
位置
internal/modules/<module>/ports/<service_name>_service.go
go
package ports

import (
	"context"

	"github.com/cristiano-pacheco/pingo/internal/modules/<module>/dto"
)

type DoSomethingService interface {
	Execute(ctx context.Context, input dto.DoSomethingInput) error
}

Service Implementation Structure

服务实现结构

Location:
internal/modules/<module>/service/<service_name>_service.go
go
package service

import (
	"context"

	"github.com/cristiano-pacheco/bricks/pkg/logger"
    "github.com/cristiano-pacheco/bricks/pkg/otel/trace"
	"github.com/cristiano-pacheco/pingo/internal/modules/<module>/dto"
	"github.com/cristiano-pacheco/pingo/internal/modules/<module>/ports"
)

type DoSomethingService struct {
	logger logger.Logger
	// other dependencies
}

var _ ports.DoSomethingService = (*DoSomethingService)(nil)

func NewDoSomethingService(
	logger logger.Logger,
) *DoSomethingService {
	return &DoSomethingService{
		logger: logger,
	}
}

func (s *DoSomethingService) Execute(ctx context.Context, input dto.DoSomethingInput) error {
	ctx, span := trace.Span(ctx, "DoSomethingService.Execute")
	defer span.End()

	// Business logic here

	return nil
}
位置
internal/modules/<module>/service/<service_name>_service.go
go
package service

import (
	"context"

	"github.com/cristiano-pacheco/bricks/pkg/logger"
    "github.com/cristiano-pacheco/bricks/pkg/otel/trace"
	"github.com/cristiano-pacheco/pingo/internal/modules/<module>/dto"
	"github.com/cristiano-pacheco/pingo/internal/modules/<module>/ports"
)

type DoSomethingService struct {
	logger logger.Logger
	// other dependencies
}

var _ ports.DoSomethingService = (*DoSomethingService)(nil)

func NewDoSomethingService(
	logger logger.Logger,
) *DoSomethingService {
	return &DoSomethingService{
		logger: logger,
	}
}

func (s *DoSomethingService) Execute(ctx context.Context, input dto.DoSomethingInput) error {
	ctx, span := trace.Span(ctx, "DoSomethingService.Execute")
	defer span.End()

	// Business logic here

	return nil
}

Service Variants

服务变体

Single-action service (Execute pattern)

单动作服务(Execute模式)

Use
Execute
method with a dedicated input struct when the service does one thing.
DTO (
dto/send_email_confirmation_dto.go
):
go
type SendEmailConfirmationInput struct {
	UserModel             model.UserModel
	ConfirmationTokenHash []byte
}
Port (
ports/send_email_confirmation_service.go
):
go
type SendEmailConfirmationService interface {
	Execute(ctx context.Context, input dto.SendEmailConfirmationInput) error
}
当服务仅执行单一操作时,使用带专属输入结构体的
Execute
方法。
DTO(
dto/send_email_confirmation_dto.go
):
go
type SendEmailConfirmationInput struct {
	UserModel             model.UserModel
	ConfirmationTokenHash []byte
}
Port(
ports/send_email_confirmation_service.go
):
go
type SendEmailConfirmationService interface {
	Execute(ctx context.Context, input dto.SendEmailConfirmationInput) error
}

Multi-method service (named methods)

多方法服务(命名方法)

Use descriptive method names when the service groups related operations.
Port (
ports/hash_service.go
):
go
type HashService interface {
	GenerateFromPassword(password []byte) ([]byte, error)
	CompareHashAndPassword(hashedPassword, password []byte) error
	GenerateRandomBytes() ([]byte, error)
}
当服务需要分组相关操作时,使用描述性方法名称。
Port(
ports/hash_service.go
):
go
type HashService interface {
	GenerateFromPassword(password []byte) ([]byte, error)
	CompareHashAndPassword(hashedPassword, password []byte) error
	GenerateRandomBytes() ([]byte, error)
}

Stateless service (no dependencies)

无状态服务(无依赖)

Omit logger and config when the service is a pure utility with no I/O.
go
type HashService struct{}

func NewHashService() *HashService {
	return &HashService{}
}
当服务是纯工具类且无I/O操作时,可省略日志和配置。
go
type HashService struct{}

func NewHashService() *HashService {
	return &HashService{}
}

Tracing

链路追踪

Services performing I/O MUST use
trace.Span
. Pure utilities (hashing, template compilation) skip tracing.
go
ctx, span := trace.Span(ctx, "ServiceName.MethodName")
defer span.End()
Span name format:
"StructName.MethodName"
undefined
执行I/O操作的服务必须使用
trace.Span
。纯工具类服务(如哈希、模板编译)可跳过链路追踪。
go
ctx, span := trace.Span(ctx, "ServiceName.MethodName")
defer span.End()
Span名称格式:
"StructName.MethodName"

Naming

命名规范

  • Port interface:
    XxxService
    (in
    ports
    package, no suffix)
  • Implementation struct:
    XxxService
    (in
    service
    package, same name — disambiguated by package)
  • Constructor:
    NewXxxService
    , returns a pointer of the struct implementation
  • Port接口:
    XxxService
    (位于
    ports
    包,无后缀)
  • 实现结构体:
    XxxService
    (位于
    service
    包,同名——通过包名区分)
  • 构造函数:
    NewXxxService
    ,返回结构体指针

Fx Wiring

Fx依赖注入配置

Add to
internal/modules/<module>/fx.go
:
go
fx.Provide(
	fx.Annotate(
		service.NewXxxService,
		fx.As(new(ports.XxxService)),
	),
),
添加至
internal/modules/<module>/fx.go
go
fx.Provide(
	fx.Annotate(
		service.NewXxxService,
		fx.As(new(ports.XxxService)),
	),
),

Dependencies

依赖规则

Services depend on interfaces only. Common dependencies:
  • logger.Logger
    — structured logging
  • Other
    ports.XxxService
    interfaces — compose services
  • ports.XxxRepository
    — data access
  • ports.XxxCache
    — caching layer
服务仅依赖接口。常见依赖包括:
  • logger.Logger
    — 结构化日志
  • 其他
    ports.XxxService
    接口 — 服务组合
  • ports.XxxRepository
    — 数据访问
  • ports.XxxCache
    — 缓存层

Critical Rules

核心规则

  1. Three files: DTOs in
    dto/
    , port interface in
    ports/
    , implementation in
    service/
  2. Interface in ports: Interface lives in
    ports/<name>_service.go
  3. DTOs in dto: Input/output structs live in
    dto/<name>_dto.go
  4. Interface assertion: Add
    var _ ports.XxxService = (*XxxService)(nil)
    below the struct
  5. Constructor: MUST return pointer
    *XxxService
  6. Tracing: Every I/O method MUST use
    trace.Span
    with
    defer span.End()
  7. Context: Methods performing I/O accept
    context.Context
    as first parameter
  8. No comments: Do not add redundant comments above methods
  9. Dependencies: Always depend on port interfaces, never concrete implementations
  1. 三文件结构:DTO存放于
    dto/
    目录,Port接口存放于
    ports/
    目录,实现代码存放于
    service/
    目录
  2. 接口位置:接口定义在
    ports/<name>_service.go
  3. DTO位置:输入/输出结构体存放于
    dto/<name>_dto.go
  4. 接口断言:在结构体定义下方添加
    var _ ports.XxxService = (*XxxService)(nil)
  5. 构造函数:必须返回指针
    *XxxService
  6. 链路追踪:每个I/O方法必须使用
    trace.Span
    并配合
    defer span.End()
  7. 上下文参数:执行I/O操作的方法必须将
    context.Context
    作为第一个参数
  8. 避免冗余注释:不要在方法上方添加冗余注释
  9. 依赖原则:始终依赖Port接口,而非具体实现

Workflow

工作流程

  1. Create DTO file in
    dto/<name>_dto.go
    (if input/output structs are needed)
  2. Create port interface in
    ports/<name>_service.go
  3. Create service implementation in
    service/<name>_service.go
  4. Add Fx wiring to module's
    module.go
    (or
    fx.go
    )
  5. Run
    make lint
    to verify
  6. Run
    make nilaway
    for static analysis
  1. dto/<name>_dto.go
    中创建DTO文件(如需输入/输出结构体)
  2. ports/<name>_service.go
    中创建Port接口
  3. service/<name>_service.go
    中创建服务实现
  4. 将Fx依赖注入配置添加至模块的
    module.go
    (或
    fx.go
  5. 运行
    make lint
    进行验证
  6. 运行
    make nilaway
    进行静态分析