coding-standards

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Coding Standards Skill

Coding Standards Skill

觸發時機

触发时机

  • 編寫新代碼時
  • 代碼審查階段
  • 生成 Application Service / Use Case 時
  • 被 Sub-agent (command/query/reactor) 呼叫時
  • 编写新代码时
  • 代码审查阶段
  • 生成Application Service / Use Case时
  • 被Sub-agent (command/query/reactor)调用时

核心任務

核心任务

強制執行統一的編碼規範,確保 AI 生成的代碼風格高度一致,降低人類審閱成本。
强制执行统一的编码规范,确保AI生成的代码风格高度一致,降低人工审阅成本。

多語言支援

多语言支持

根據專案語言選擇對應的規範:
語言參考文件說明
Java本文件Spring Boot / Jakarta EE
Javareferences/JAVA_CLEAN_ARCH.mdClean Architecture 詳細結構
TypeScriptreferences/TYPESCRIPT.mdNode.js / Deno / Bun
Goreferences/GOLANG.mdStandard Go Project Layout
Rustreferences/RUST.mdCargo / Tokio async runtime
根据项目语言选择对应的规范:
语言参考文件说明
Java本文档Spring Boot / Jakarta EE
Javareferences/JAVA_CLEAN_ARCH.mdClean Architecture详细结构
TypeScriptreferences/TYPESCRIPT.mdNode.js / Deno / Bun
Goreferences/GOLANG.mdStandard Go Project Layout
Rustreferences/RUST.mdCargo / Tokio async runtime

Claude Code Sub-agent 整合

Claude Code Sub-agent 整合

當被其他 Sub-agent 呼叫時,本 Skill 提供語言特定的編碼規範:
command-sub-agent 呼叫 → 提供 Use Case / Command Handler 的編碼規範
query-sub-agent 呼叫 → 提供 Query Handler / Read Model 的編碼規範
reactor-sub-agent 呼叫 → 提供 Event Handler 的編碼規範

当被其他Sub-agent调用时,本Skill提供语言特定的编码规范:
command-sub-agent 调用 → 提供 Use Case / Command Handler 的编码规范
query-sub-agent 调用 → 提供 Query Handler / Read Model 的编码规范
reactor-sub-agent 调用 → 提供 Event Handler 的编码规范

規範 1:Input/Output Inner Class 模式

规范1:Input/Output内部类模式

目的

目的

  • 明確定義方法的輸入輸出契約
  • 提高代碼可讀性和可維護性
  • 便於單元測試
  • 明确定义方法的输入输出契约
  • 提高代码可读性和可维护性
  • 便于单元测试

標準模式

标准模式

java
public class CreateOrderUseCase {
    
    // ✅ Input 定義為靜態內部類別
    public static class Input {
        private final CustomerId customerId;
        private final List<OrderItemRequest> items;
        private final ShippingAddress address;
        
        public Input(CustomerId customerId, 
                     List<OrderItemRequest> items,
                     ShippingAddress address) {
            // 可在此進行基本驗證
            Objects.requireNonNull(customerId, "customerId must not be null");
            Objects.requireNonNull(items, "items must not be null");
            if (items.isEmpty()) {
                throw new IllegalArgumentException("items must not be empty");
            }
            this.customerId = customerId;
            this.items = List.copyOf(items);
            this.address = address;
        }
        
        // Getters
        public CustomerId getCustomerId() { return customerId; }
        public List<OrderItemRequest> getItems() { return items; }
        public ShippingAddress getAddress() { return address; }
    }
    
    // ✅ Output 定義為靜態內部類別
    public static class Output {
        private final OrderId orderId;
        private final OrderStatus status;
        private final LocalDateTime createdAt;
        
        public Output(OrderId orderId, OrderStatus status, LocalDateTime createdAt) {
            this.orderId = orderId;
            this.status = status;
            this.createdAt = createdAt;
        }
        
        // Getters
        public OrderId getOrderId() { return orderId; }
        public OrderStatus getStatus() { return status; }
        public LocalDateTime getCreatedAt() { return createdAt; }
    }
    
    // ✅ 主要執行方法,接收 Input,回傳 Output
    public Output execute(Input input) {
        // 業務邏輯
    }
}
java
public class CreateOrderUseCase {
    
    // ✅ Input 定义为静态内部类
    public static class Input {
        private final CustomerId customerId;
        private final List<OrderItemRequest> items;
        private final ShippingAddress address;
        
        public Input(CustomerId customerId, 
                     List<OrderItemRequest> items,
                     ShippingAddress address) {
            // 可在此进行基本验证
            Objects.requireNonNull(customerId, "customerId must not be null");
            Objects.requireNonNull(items, "items must not be null");
            if (items.isEmpty()) {
                throw new IllegalArgumentException("items must not be empty");
            }
            this.customerId = customerId;
            this.items = List.copyOf(items);
            this.address = address;
        }
        
        // Getters
        public CustomerId getCustomerId() { return customerId; }
        public List<OrderItemRequest> getItems() { return items; }
        public ShippingAddress getAddress() { return address; }
    }
    
    // ✅ Output 定义为静态内部类
    public static class Output {
        private final OrderId orderId;
        private final OrderStatus status;
        private final LocalDateTime createdAt;
        
        public Output(OrderId orderId, OrderStatus status, LocalDateTime createdAt) {
            this.orderId = orderId;
            this.status = status;
            this.createdAt = createdAt;
        }
        
        // Getters
        public OrderId getOrderId() { return orderId; }
        public OrderStatus getStatus() { return status; }
        public LocalDateTime getCreatedAt() { return createdAt; }
    }
    
    // ✅ 主要执行方法,接收Input,返回Output
    public Output execute(Input input) {
        // 业务逻辑
    }
}

禁止模式

禁止模式

java
// ❌ 禁止:直接使用多個參數
public OrderResult createOrder(String customerId, List<Item> items, String address) {
    // 這樣做會讓介面難以維護
}

// ❌ 禁止:使用 Map 作為輸入輸出
public Map<String, Object> createOrder(Map<String, Object> params) {
    // 這樣做會失去型別安全
}
java
// ❌ 禁止:直接使用多个参数
public OrderResult createOrder(String customerId, List<Item> items, String address) {
    // 这样做会让接口难以维护
}

// ❌ 禁止:使用Map作为输入输出
public Map<String, Object> createOrder(Map<String, Object> params) {
    // 这样做会失去类型安全
}

規範 2:@Bean not @Component

规范2:使用@Bean而非@Component

目的

目的

  • 集中管理依賴注入配置
  • 明確的依賴關係可視化
  • 便於測試時替換實作
  • 集中管理依赖注入配置
  • 明确的依赖关系可视化
  • 便于测试时替换实现

標準模式

标准模式

java
// ✅ 正確:使用 @Configuration + @Bean
@Configuration
public class UseCaseConfiguration {
    
    @Bean
    public CreateOrderUseCase createOrderUseCase(
            OrderRepository orderRepository,
            InventoryService inventoryService,
            EventPublisher eventPublisher) {
        return new CreateOrderUseCase(
            orderRepository, 
            inventoryService, 
            eventPublisher
        );
    }
    
    @Bean
    public CancelOrderUseCase cancelOrderUseCase(
            OrderRepository orderRepository,
            PaymentGateway paymentGateway) {
        return new CancelOrderUseCase(orderRepository, paymentGateway);
    }
}

// ✅ Use Case 類別保持純淨,無 Spring 註解
public class CreateOrderUseCase {
    private final OrderRepository orderRepository;
    private final InventoryService inventoryService;
    private final EventPublisher eventPublisher;
    
    // 建構子注入
    public CreateOrderUseCase(
            OrderRepository orderRepository,
            InventoryService inventoryService,
            EventPublisher eventPublisher) {
        this.orderRepository = orderRepository;
        this.inventoryService = inventoryService;
        this.eventPublisher = eventPublisher;
    }
}
java
// ✅ 正确:使用 @Configuration + @Bean
@Configuration
public class UseCaseConfiguration {
    
    @Bean
    public CreateOrderUseCase createOrderUseCase(
            OrderRepository orderRepository,
            InventoryService inventoryService,
            EventPublisher eventPublisher) {
        return new CreateOrderUseCase(
            orderRepository, 
            inventoryService, 
            eventPublisher
        );
    }
    
    @Bean
    public CancelOrderUseCase cancelOrderUseCase(
            OrderRepository orderRepository,
            PaymentGateway paymentGateway) {
        return new CancelOrderUseCase(orderRepository, paymentGateway);
    }
}

// ✅ Use Case 类保持纯净,无Spring注解
public class CreateOrderUseCase {
    private final OrderRepository orderRepository;
    private final InventoryService inventoryService;
    private final EventPublisher eventPublisher;
    
    // 构造函数注入
    public CreateOrderUseCase(
            OrderRepository orderRepository,
            InventoryService inventoryService,
            EventPublisher eventPublisher) {
        this.orderRepository = orderRepository;
        this.inventoryService = inventoryService;
        this.eventPublisher = eventPublisher;
    }
}

禁止模式

禁止模式

java
// ❌ 禁止:在 Use Case 上使用 @Component/@Service
@Service  // ❌ 不要這樣做
public class CreateOrderUseCase {
    
    @Autowired  // ❌ 不要這樣做
    private OrderRepository orderRepository;
}
java
// ❌ 禁止:在Use Case上使用@Component/@Service
@Service  // ❌ 不要这样做
public class CreateOrderUseCase {
    
    @Autowired  // ❌ 不要这样做
    private OrderRepository orderRepository;
}

例外情況

例外情况

以下情況可使用 @Component 系列註解:
類型允許使用說明
Controller@RestController展示層入口點
Repository 實作@RepositoryInfrastructure 層
Event Listener@Component技術性元件
Scheduled Task@Component技術性元件
以下情况可使用@Component系列注解:
类型允许使用说明
Controller@RestController展示层入口点
Repository实现@RepositoryInfrastructure层
Event Listener@Component技术性组件
Scheduled Task@Component技术性组件

規範 3:命名規範

规范3:命名规范

Use Case / Command Handler 命名

Use Case / Command Handler 命名

java
// ✅ 動詞 + 名詞 + UseCase
CreateOrderUseCase
CancelOrderUseCase
UpdateCustomerProfileUseCase

// ✅ CQRS Command Handler
CreateOrderCommandHandler
CancelOrderCommandHandler

// ✅ CQRS Query Handler
GetOrderByIdQueryHandler
ListOrdersByCustomerQueryHandler
java
// ✅ 动词 + 名词 + UseCase
CreateOrderUseCase
CancelOrderUseCase
UpdateCustomerProfileUseCase

// ✅ CQRS Command Handler
CreateOrderCommandHandler
CancelOrderCommandHandler

// ✅ CQRS Query Handler
GetOrderByIdQueryHandler
ListOrdersByCustomerQueryHandler

方法命名

方法命名

java
// ✅ Use Case 統一使用 execute()
public Output execute(Input input)

// ✅ Command Handler 統一使用 handle()
public void handle(CreateOrderCommand command)

// ✅ Query Handler 統一使用 handle()
public OrderDto handle(GetOrderByIdQuery query)
java
// ✅ Use Case 统一使用 execute()
public Output execute(Input input)

// ✅ Command Handler 统一使用 handle()
public void handle(CreateOrderCommand command)

// ✅ Query Handler 统一使用 handle()
public OrderDto handle(GetOrderByIdQuery query)

規範 4:不可變物件 (Immutable Objects)

规范4:不可变对象(Immutable Objects)

Input/Output 必須是不可變的

Input/Output必须是不可变的

java
public static class Input {
    private final CustomerId customerId;  // ✅ final
    private final List<OrderItemRequest> items;
    
    public Input(CustomerId customerId, List<OrderItemRequest> items) {
        this.customerId = customerId;
        this.items = List.copyOf(items);  // ✅ 防禦性複製
    }
    
    // ✅ 只有 Getter,沒有 Setter
    public CustomerId getCustomerId() { return customerId; }
    public List<OrderItemRequest> getItems() { 
        return items;  // 已經是不可變的
    }
}
java
public static class Input {
    private final CustomerId customerId;  // ✅ final
    private final List<OrderItemRequest> items;
    
    public Input(CustomerId customerId, List<OrderItemRequest> items) {
        this.customerId = customerId;
        this.items = List.copyOf(items);  // ✅ 防御性复制
    }
    
    // ✅ 只有Getter,没有Setter
    public CustomerId getCustomerId() { return customerId; }
    public List<OrderItemRequest> getItems() { 
        return items;  // 已经是不可变的
    }
}

規範 5:例外處理模式

规范5:异常处理模式

使用 Domain Exception

使用领域异常(Domain Exception)

java
// ✅ 定義領域特定例外
public class OrderNotFoundException extends DomainException {
    public OrderNotFoundException(OrderId orderId) {
        super("Order not found: " + orderId.getValue());
    }
}

public class InsufficientInventoryException extends DomainException {
    public InsufficientInventoryException(ProductId productId, int requested, int available) {
        super(String.format(
            "Insufficient inventory for product %s: requested %d, available %d",
            productId.getValue(), requested, available
        ));
    }
}
java
// ✅ 定义领域特定异常
public class OrderNotFoundException extends DomainException {
    public OrderNotFoundException(OrderId orderId) {
        super("Order not found: " + orderId.getValue());
    }
}

public class InsufficientInventoryException extends DomainException {
    public InsufficientInventoryException(ProductId productId, int requested, int available) {
        super(String.format(
            "Insufficient inventory for product %s: requested %d, available %d",
            productId.getValue(), requested, available
        ));
    }
}

檢查清單

检查清单

新增 Use Case 時

新增Use Case时

  • 是否定義了 Input 內部類別?
  • 是否定義了 Output 內部類別?
  • Input/Output 是否為不可變?
  • 是否使用 @Bean 而非 @Component?
  • 命名是否遵循規範?
  • 是否定义了Input内部类?
  • 是否定义了Output内部类?
  • Input/Output是否为不可变?
  • 是否使用@Bean而非@Component?
  • 命名是否遵循规范?

代碼審查時

代码审查时

  • 有無 @Autowired 欄位注入?(應改用建構子注入)
  • Use Case 類別是否有框架依賴?
  • 例外是否使用 Domain Exception?
  • 有无@Autowired字段注入?(应改用构造函数注入)
  • Use Case类是否有框架依赖?
  • 异常是否使用Domain Exception?

自動檢查規則 (供 Linter 使用)

自动检查规则(供Linter使用)

yaml
rules:
  - id: no-component-on-usecase
    pattern: "@(Component|Service).*class.*UseCase"
    message: "Use @Bean configuration instead of @Component on UseCase classes"
    severity: error
    
  - id: no-autowired-field
    pattern: "@Autowired\\s+private"
    message: "Use constructor injection instead of field injection"
    severity: error
    
  - id: require-input-output-class
    pattern: "class.*UseCase.*execute\\((?!Input)"
    message: "UseCase.execute() should accept Input inner class"
    severity: warning
yaml
rules:
  - id: no-component-on-usecase
    pattern: "@(Component|Service).*class.*UseCase"
    message: "Use @Bean configuration instead of @Component on UseCase classes"
    severity: error
    
  - id: no-autowired-field
    pattern: "@Autowired\\s+private"
    message: "Use constructor injection instead of field injection"
    severity: error
    
  - id: require-input-output-class
    pattern: "class.*UseCase.*execute\\((?!Input)"
    message: "UseCase.execute() should accept Input inner class"
    severity: warning