coding-standards

代碼實作階段觸發。強制執行統一的編碼規範,支援 Java、TypeScript、Go 多語言。包含 Input/Output 模式、依賴注入、不可變物件等規範,確保代碼風格一致性。

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "coding-standards" with this command: npx skills add knowlet/skills/knowlet-skills-coding-standards

Coding Standards Skill

觸發時機

  • 編寫新代碼時
  • 代碼審查階段
  • 生成 Application Service / Use Case 時
  • 被 Sub-agent (command/query/reactor) 呼叫時

核心任務

強制執行統一的編碼規範,確保 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

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 的編碼規範

規範 1:Input/Output Inner Class 模式

目的

  • 明確定義方法的輸入輸出契約
  • 提高代碼可讀性和可維護性
  • 便於單元測試

標準模式

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) {
        // 業務邏輯
    }
}

禁止模式

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

// ❌ 禁止:使用 Map 作為輸入輸出
public Map<String, Object> createOrder(Map<String, Object> params) {
    // 這樣做會失去型別安全
}

規範 2:@Bean not @Component

目的

  • 集中管理依賴注入配置
  • 明確的依賴關係可視化
  • 便於測試時替換實作

標準模式

// ✅ 正確:使用 @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;
    }
}

禁止模式

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

例外情況

以下情況可使用 @Component 系列註解:

類型允許使用說明
Controller@RestController展示層入口點
Repository 實作@RepositoryInfrastructure 層
Event Listener@Component技術性元件
Scheduled Task@Component技術性元件

規範 3:命名規範

Use Case / Command Handler 命名

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

// ✅ CQRS Command Handler
CreateOrderCommandHandler
CancelOrderCommandHandler

// ✅ CQRS Query Handler
GetOrderByIdQueryHandler
ListOrdersByCustomerQueryHandler

方法命名

// ✅ 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)

Input/Output 必須是不可變的

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:例外處理模式

使用 Domain Exception

// ✅ 定義領域特定例外
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 時

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

代碼審查時

  • 有無 @Autowired 欄位注入?(應改用建構子注入)
  • Use Case 類別是否有框架依賴?
  • 例外是否使用 Domain Exception?

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

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

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

code-reviewer

No summary provided by upstream source.

Repository SourceNeeds Review
General

spec-compliance-validator

No summary provided by upstream source.

Repository SourceNeeds Review
General

enforce-contract

No summary provided by upstream source.

Repository SourceNeeds Review