architecture-patterns:把後端分層架構講成可執行的樣板

前言

後端代碼寫久了最常見的問題不是性能,而是分層退化:domain 裏直接 import 了 ORM,use case 裏塞滿了 HTTP 狀態碼,測試必須連數據庫才能跑。架構規則寫在文檔裏沒人看,寫在代碼裏又沒人維護。下面介紹的 architecture-patterns 是一個提示詞型 Skill,作用是把這些規則帶進對話流程,讓模型在設計或重構時按同一套分層約束產出代碼。

這是什麼

architecture-patterns 是一個通用 SKILL.md 格式的後端架構模式 Skill,座標 @clawhub_wpank/architecture-patterns,版本 1.0.0,發佈者 wpank,來源 clawhub,分類 dev-programming。它覆蓋清潔架構(Clean Architecture)、六邊形架構(Hexagonal / Ports & Adapters)與領域驅動設計(DDD),用於構建可維護、可測試、可擴展的系統,並給出清晰的分層結構和依賴方向約束。

在 SkillHub 上的頁面標註爲「Architecture Patterns」,屬於 dev-programming 分類。

核心功能

下面介紹的都是 SKILL.md 中實際寫明的能力。

1、一個選型決策表,按場景推薦模式。簡單 CRUD 應用建議不加架構(避免過度設計),中等複雜度且需要團隊統一標準時用清潔架構,外部集成多且變化頻繁時用六邊形架構,業務規則複雜的領域用 DDD,多團隊的大規模系統用 DDD + 限界上下文。

2、清潔架構的分層圖與依賴規則。四層分別是 Entities、Use Cases、Interface Adapters、Frameworks & Drivers,依賴只能由外向內,內層不得 import 外層。

3、六邊形架構的 Port 與 Adapter 圖示,端口定義領域需要什麼,適配器是可替換的實現,測試時可換掉。

4、一套目錄結構約定,app/domain 放實體與業務規則(內層),use_cases 放應用邏輯,adapters 放接口實現(倉儲、控制器),infrastructure 放框架與外部關注點。

5、可直接參考的代碼骨架,包括實體定義、抽象端口(IUserRepository)、用例編排(CreateUserUseCase)、Postgres 適配器、領域服務與適配器替換示例、不可變值對象(Email、Money)、聚合根與不變量校驗。

6、要點標註:實體內不寫框架依賴,業務規則放在實體和聚合裏,端口定義契約而不給實現,適配器可互換以便測試。

安裝與啓用

安裝命令來自官方頁面:

$ openclaw skills install @wpank/architecture-patterns

頁面同時給出另一種途徑,用 npx 通過 skills CLI:

npx skills

安裝後在對話中觸發即可,觸發條件寫得很明確:從零設計後端系統、爲可維護性重構單體、爲團隊建立架構標準、創建可測試可 mock 的代碼庫、規劃微服務拆分。

當前資料裏沒有列出 Cursor / Codex CLI / Claude Code 的差異化安裝方式,這裏不做推測。

典型用法

下面的例子都來自 SKILL.md,可直接對照。

先看目錄結構,把分層落到文件上:

app/
├── domain/            # 實體與業務規則(最內層)
│   ├── entities/
│   │   └── user.py
│   ├── value_objects/
│   │   └── email.py
│   └── interfaces/    # 端口
│       └── user_repository.py
├── use_cases/         # 應用業務規則
│   └── create_user.py
├── adapters/          # 接口實現
│   ├── repositories/
│   │   └── postgres_user_repository.py
│   └── controllers/
│       └── user_controller.py
└── infrastructure/    # 框架與外部關注點
    ├── database.py
    └── config.py

實體層不引入框架,業務規則寫在實體方法裏:

from dataclasses import dataclass
from datetime import datetime

@dataclass
class User:
    """Core entity - NO framework dependencies."""
    id: str
    email: str
    name: str
    created_at: datetime
    is_active: bool = True

    def deactivate(self):
        """Business rule in entity."""
        self.is_active = False

    def can_place_order(self) -> bool:
        return self.is_active

端口只定義契約,不給實現:

from abc import ABC, abstractmethod
from typing import Optional

class IUserRepository(ABC):
    """Port: defines contract, no implementation."""

    @abstractmethod
    async def find_by_id(self, user_id: str) -> Optional[User]:
        pass

    @abstractmethod
    async def save(self, user: User) -> User:
        pass

用例負責編排,依賴通過構造函數注入:

@dataclass
class CreateUserRequest:
    email: str
    name: str

@dataclass
class CreateUserResponse:
    user: Optional[User]
    success: bool
    error: Optional[str] = None

class CreateUserUseCase:
    """Use case: orchestrates business logic."""

    def __init__(self, user_repository: IUserRepository):
        self.user_repository = user_repository  # Injected dependency

    async def execute(self, request: CreateUserRequest) -> CreateUserResponse:
        existing = await self.user_repository.find_by_email(request.email)
        if existing:
            return CreateUserResponse(user=None, success=False, error="Email exists")

        user = User(
            id=str(uuid.uuid4()),
            email=request.email,
            name=request.name,
            created_at=datetime.now()
        )

        saved = await self.user_repository.save(user)
        return CreateUserResponse(user=saved, success=True)

適配器實現端口,可以換成 Postgres、內存實現或其他:

class PostgresUserRepository(IUserRepository):
    """Adapter: PostgreSQL implementation of the port."""

    def __init__(self, pool: asyncpg.Pool):
        self.pool = pool

    async def find_by_id(self, user_id: str) -> Optional[User]:
        async with self.pool.acquire() as conn:
            row = await conn.fetchrow(
                "SELECT * FROM users WHERE id = $1", user_id
            )
        return self._to_entity(row) if row else None

    async def save(self, user: User) -> User:
        async with self.pool.acquire() as conn:
            await conn.execute(
                """INSERT INTO users (id, email, name, created_at, is_active)
                   VALUES ($1, $2, $3, $4, $5)
                   ON CONFLICT (id) DO UPDATE SET email=$2, name=$3, is_active=$5""",
                user.id, user.email, user.name, user.created_at, user.is_active
            )
        return user

六邊形架構的用法是給領域服務注入多個端口,測試時替換爲 mock 適配器:

class OrderService:
    def __init__(
        self,
        order_repo: OrderRepositoryPort,   # Port
        payment: PaymentGatewayPort,      # Port
        notifications: NotificationPort   # Port
    ):
        self.orders = order_repo
        self.payments = payment
        self.notifications = notifications

    async def place_order(self, order: Order) -> OrderResult:
        if not order.is_valid():
            return OrderResult(success=False, error="Invalid order")

        payment = await self.payments.charge(order.total, order.customer_id)
        if not payment.success:
            return OrderResult(success=False, error="Payment failed")

        order.mark_as_paid()
        saved = await self.orders.save(order)
        await self.notifications.send(order.customer_email, "Order confirmed")

        return OrderResult(success=True, order=saved)

class StripePaymentAdapter(PaymentGatewayPort):
    async def charge(self, amount: Money, customer: str) -> PaymentResult:
        # Real Stripe implementation
        ...

class MockPaymentAdapter(PaymentGatewayPort):
    async def charge(self, amount: Money, customer: str) -> PaymentResult:
        return PaymentResult(success=True, transaction_id="mock-123")

DDD 部分給出不可變值對象與聚合根。值對象用 frozen=True 保證不可變,在 __post_init__ 裏校驗:

@dataclass(frozen=True)
class Email:
    """Value object: validated, immutable."""
    value: str

    def __post_init__(self):
        if "@" not in self.value:
            raise ValueError("Invalid email")

@dataclass(frozen=True)
class Money:
    amount: int  # cents
    currency: str

    def add(self, other: "Money") -> "Money":
        if self.currency != other.currency:
            raise ValueError("Currency mismatch")
        return Money(self.amount + other.amount, self.currency)

聚合根承擔一致性邊界,在方法裏強制不變量:

class Order:
    """Aggregate root: enforces invariants."""

    def __init__(self, id: str, customer: Customer):
        self.id = id
        self.customer = customer
        self.items: List[OrderItem] = []
        self.status = OrderStatus.PENDING
        self._events: List[DomainEvent] = []

    def add_item(self, product: Product, quantity: int):
        """Business logic in aggregate."""
        if quantity > product.max_quantity:
            raise ValueError(f"Max {product.max_quantity} allowed")

        item = OrderItem(product, quantity)
        self.items.append(item)
        self._events.append(ItemAddedEvent(self.id, item))

    def submit(self):
        """State transition with invariant enforcement."""
        if not self.items:
            raise ValueError("Cannot submit empty order")
        if self.status != OrderStatus.PENDING:
            raise ValueError("Order already submitted")

        self.status = OrderStatus.SUBMITTED
        self._events.append(OrderSubmittedEvent(self.id))

單元測試部分,資料中的要點是:領域層與用例層只依賴端口,測試時注入內存適配器(in-memory adapter)即可,不需要真實數據庫。上面 MockPaymentAdapter 的寫法就是同一思路。

適用場景與注意

適合這些情況:新後端服務要定分層標準,單體要按限界上下文拆,外部集成多且可能更換供應商,業務規則複雜需要落在聚合與值對象裏,或者正在排查應用層之間的循環依賴。

要注意幾點。第一,SKILL.md 明確寫了簡單 CRUD 應用不需要上這些模式,強行套用屬於過度設計,選型表裏這是第一行。第二,這套內容是架構約束與代碼骨架,不包含運行時框架,落地時需要自己選語言對應的 ORM、HTTP 庫和測試框架,示例代碼是 Python 風格(async、asyncpg、dataclass),直接抄到別的語言需要改寫。第三,示例中的 find_by_email 只出現在 CreateUserUseCase 裏,端口定義中並沒有聲明,按示例跑之前先確認端口補全,否則會運行期報錯。第四,資料中未給出運行時的調用示例或配置項,接入方式只有安裝命令和觸發條件。

結尾

architecture-patterns 的價值在於把「分層」和「依賴方向」從口頭約定變成對話裏可執行的約束,同時給出目錄結構、端口寫法和測試替換方式,適合在設計期和重構期使用。它不做框架集成,也不生成項目腳手架,需要與具體技術棧配合。

官方地址:https://api.skillhub.cn/user_692c63a9/architecture-patterns
上游倉庫:https://clawhub.ai/wpank/architecture-patterns
SkillHub 頁面:https://www.skillhub.cn/skills/clawhub_wpank/architecture-patterns

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜