[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CD2EPF7CG3YZKNQNFV5C3C":3,"skill-same:01M6CD2EPF7CG3YZKNQNFV5C3C":80},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":28,"publishedAt":48,"linkOnly":49,"markdownContent":50,"markdownBody":51,"frontMatter":52,"refName":54,"commitSha":55,"skillDirectory":56,"forksCount":57,"repositoryHtmlUrl":58,"repositoryHomepageUrl":6,"ownerHtmlUrl":59,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":60,"install":61,"resources":73},"01M6CD2EPF7CG3YZKNQNFV5C3C","python-design-patterns",null,"Python design patterns including KISS, Separation of Concerns, Single Responsibility, and composition over inheritance. Use when making architecture decisions, refactoring code structure, or evaluating when abstractions are appropriate.","cercova-studios\u002F10x-swe","cercova-studios","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F217108198?v=4","01M6CCYGHXTH80N3BXRW6KESTE","Cercova Studios","01M6CCYGPADH5MJDR0VNNR775C",1,"MIT","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fpython-design-patterns\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47],"python","design","python design patterns","design patterns","patterns","separation","kiss","structure","when","code structure","inheritance","single","separation of concerns","architecture","code","decisions","use","refactoring","Composition","2026-11-10 10:12:30",false,"---\nname: python-design-patterns\ndescription: Python design patterns including KISS, Separation of Concerns, Single Responsibility, and composition over inheritance. Use when making architecture decisions, refactoring code structure, or evaluating when abstractions are appropriate.\ndisable-model-invocation: true\n---\n\n# Python Design Patterns\n\nWrite maintainable Python code using fundamental design principles. These patterns help you build systems that are easy to understand, test, and modify.\n\n## When to Use This Skill\n\n- Designing new components or services\n- Refactoring complex or tangled code\n- Deciding whether to create an abstraction\n- Choosing between inheritance and composition\n- Evaluating code complexity and coupling\n- Planning modular architectures\n\n## The Zen of Python\n\nThese aphorisms guide every design decision. When in doubt, refer back here.\n\n```\nBeautiful is better than ugly.\nExplicit is better than implicit.\nSimple is better than complex.\nComplex is better than complicated.\nFlat is better than nested.\nSparse is better than dense.\nReadability counts.\nSpecial cases aren't special enough to break the rules.\nAlthough practicality beats purity.\nErrors should never pass silently.\nUnless explicitly silenced.\nIn the face of ambiguity, refuse the temptation to guess.\nThere should be one-- and preferably only one --obvious way to do it.\nAlthough that way may not be obvious at first unless you're Dutch.\nNow is better than never.\nAlthough never is often better than *right* now.\nIf the implementation is hard to explain, it's a bad idea.\nIf the implementation is easy to explain, it may be a good idea.\nNamespaces are one honking great idea -- let's do more of those!\n```\n\nHow the Zen maps to the patterns in this skill:\n\n| Zen Principle | Pattern |\n|---|---|\n| Simple is better than complex | KISS |\n| Readability counts | Function size guidelines, explicit over clever |\n| Flat is better than nested | Separation of concerns, layered architecture |\n| Explicit is better than implicit | Dependency injection, avoiding anti-patterns |\n| There should be one obvious way | Single responsibility |\n| If the implementation is hard to explain, it's a bad idea | Rule of three, composition over inheritance |\n| Errors should never pass silently | Proper error handling at layer boundaries |\n| Practicality beats purity | Rule of three (duplication over wrong abstraction) |\n| Namespaces are one honking great idea | Separation of concerns, distinct layers |\n\n## Core Concepts\n\n### 1. KISS (Keep It Simple)\n\nChoose the simplest solution that works. Complexity must be justified by concrete requirements.\n\n### 2. Single Responsibility (SRP)\n\nEach unit should have one reason to change. Separate concerns into focused components.\n\n### 3. Composition Over Inheritance\n\nBuild behavior by combining objects, not extending classes.\n\n### 4. Rule of Three\n\nWait until you have three instances before abstracting. Duplication is often better than premature abstraction.\n\n## Quick Start\n\n```python\n# Simple beats clever\n# Instead of a factory\u002Fregistry pattern:\nFORMATTERS = {\"json\": JsonFormatter, \"csv\": CsvFormatter}\n\ndef get_formatter(name: str) -> Formatter:\n    return FORMATTERS[name]()\n```\n\n## Fundamental Patterns\n\n### Pattern 1: KISS - Keep It Simple\n\nBefore adding complexity, ask: does a simpler solution work?\n\n```python\n# Over-engineered: Factory with registration\nclass OutputFormatterFactory:\n    _formatters: dict[str, type[Formatter]] = {}\n\n    @classmethod\n    def register(cls, name: str):\n        def decorator(formatter_cls):\n            cls._formatters[name] = formatter_cls\n            return formatter_cls\n        return decorator\n\n    @classmethod\n    def create(cls, name: str) -> Formatter:\n        return cls._formatters[name]()\n\n@OutputFormatterFactory.register(\"json\")\nclass JsonFormatter(Formatter):\n    ...\n\n# Simple: Just use a dictionary\nFORMATTERS = {\n    \"json\": JsonFormatter,\n    \"csv\": CsvFormatter,\n    \"xml\": XmlFormatter,\n}\n\ndef get_formatter(name: str) -> Formatter:\n    \"\"\"Get formatter by name.\"\"\"\n    if name not in FORMATTERS:\n        raise ValueError(f\"Unknown format: {name}\")\n    return FORMATTERS[name]()\n```\n\nThe factory pattern adds code without adding value here. Save patterns for when they solve real problems.\n\n### Pattern 2: Single Responsibility Principle\n\nEach class or function should have one reason to change.\n\n```python\n# BAD: Handler does everything\nclass UserHandler:\n    async def create_user(self, request: Request) -> Response:\n        # HTTP parsing\n        data = await request.json()\n\n        # Validation\n        if not data.get(\"email\"):\n            return Response({\"error\": \"email required\"}, status=400)\n\n        # Database access\n        user = await db.execute(\n            \"INSERT INTO users (email, name) VALUES ($1, $2) RETURNING *\",\n            data[\"email\"], data[\"name\"]\n        )\n\n        # Response formatting\n        return Response({\"id\": user.id, \"email\": user.email}, status=201)\n\n# GOOD: Separated concerns\nclass UserService:\n    \"\"\"Business logic only.\"\"\"\n\n    def __init__(self, repo: UserRepository) -> None:\n        self._repo = repo\n\n    async def create_user(self, data: CreateUserInput) -> User:\n        # Only business rules here\n        user = User(email=data.email, name=data.name)\n        return await self._repo.save(user)\n\nclass UserHandler:\n    \"\"\"HTTP concerns only.\"\"\"\n\n    def __init__(self, service: UserService) -> None:\n        self._service = service\n\n    async def create_user(self, request: Request) -> Response:\n        data = CreateUserInput(**(await request.json()))\n        user = await self._service.create_user(data)\n        return Response(user.to_dict(), status=201)\n```\n\nNow HTTP changes don't affect business logic, and vice versa.\n\n### Pattern 3: Separation of Concerns\n\nOrganize code into distinct layers with clear responsibilities.\n\n```\n┌─────────────────────────────────────────────────────┐\n│  API Layer (handlers)                                │\n│  - Parse requests                                    │\n│  - Call services                                     │\n│  - Format responses                                  │\n└─────────────────────────────────────────────────────┘\n                        │\n                        ▼\n┌─────────────────────────────────────────────────────┐\n│  Service Layer (business logic)                      │\n│  - Domain rules and validation                       │\n│  - Orchestrate operations                            │\n│  - Pure functions where possible                     │\n└─────────────────────────────────────────────────────┘\n                        │\n                        ▼\n┌─────────────────────────────────────────────────────┐\n│  Repository Layer (data access)                      │\n│  - SQL queries                                       │\n│  - External API calls                                │\n│  - Cache operations                                  │\n└─────────────────────────────────────────────────────┘\n```\n\nEach layer depends only on layers below it:\n\n```python\n# Repository: Data access\nclass UserRepository:\n    async def get_by_id(self, user_id: str) -> User | None:\n        row = await self._db.fetchrow(\n            \"SELECT * FROM users WHERE id = $1\", user_id\n        )\n        return User(**row) if row else None\n\n# Service: Business logic\nclass UserService:\n    def __init__(self, repo: UserRepository) -> None:\n        self._repo = repo\n\n    async def get_user(self, user_id: str) -> User:\n        user = await self._repo.get_by_id(user_id)\n        if user is None:\n            raise UserNotFoundError(user_id)\n        return user\n\n# Handler: HTTP concerns\n@app.get(\"\u002Fusers\u002F{user_id}\")\nasync def get_user(user_id: str) -> UserResponse:\n    user = await user_service.get_user(user_id)\n    return UserResponse.from_user(user)\n```\n\n### Pattern 4: Composition Over Inheritance\n\nBuild behavior by combining objects rather than inheriting.\n\n```python\n# Inheritance: Rigid and hard to test\nclass EmailNotificationService(NotificationService):\n    def __init__(self):\n        super().__init__()\n        self._smtp = SmtpClient()  # Hard to mock\n\n    def notify(self, user: User, message: str) -> None:\n        self._smtp.send(user.email, message)\n\n# Composition: Flexible and testable\nclass NotificationService:\n    \"\"\"Send notifications via multiple channels.\"\"\"\n\n    def __init__(\n        self,\n        email_sender: EmailSender,\n        sms_sender: SmsSender | None = None,\n        push_sender: PushSender | None = None,\n    ) -> None:\n        self._email = email_sender\n        self._sms = sms_sender\n        self._push = push_sender\n\n    async def notify(\n        self,\n        user: User,\n        message: str,\n        channels: set[str] | None = None,\n    ) -> None:\n        channels = channels or {\"email\"}\n\n        if \"email\" in channels:\n            await self._email.send(user.email, message)\n\n        if \"sms\" in channels and self._sms and user.phone:\n            await self._sms.send(user.phone, message)\n\n        if \"push\" in channels and self._push and user.device_token:\n            await self._push.send(user.device_token, message)\n\n# Easy to test with fakes\nservice = NotificationService(\n    email_sender=FakeEmailSender(),\n    sms_sender=FakeSmsSender(),\n)\n```\n\n## Advanced Patterns\n\n### Pattern 5: Rule of Three\n\nWait until you have three instances before abstracting.\n\n```python\n# Two similar functions? Don't abstract yet\ndef process_orders(orders: list[Order]) -> list[Result]:\n    results = []\n    for order in orders:\n        validated = validate_order(order)\n        result = process_validated_order(validated)\n        results.append(result)\n    return results\n\ndef process_returns(returns: list[Return]) -> list[Result]:\n    results = []\n    for ret in returns:\n        validated = validate_return(ret)\n        result = process_validated_return(validated)\n        results.append(result)\n    return results\n\n# These look similar, but wait! Are they actually the same?\n# Different validation, different processing, different errors...\n# Duplication is often better than the wrong abstraction\n\n# Only after a third case, consider if there's a real pattern\n# But even then, sometimes explicit is better than abstract\n```\n\n### Pattern 6: Function Size Guidelines\n\nKeep functions focused. Extract when a function:\n\n- Exceeds 20-50 lines (varies by complexity)\n- Serves multiple distinct purposes\n- Has deeply nested logic (3+ levels)\n\n```python\n# Too long, multiple concerns mixed\ndef process_order(order: Order) -> Result:\n    # 50 lines of validation...\n    # 30 lines of inventory check...\n    # 40 lines of payment processing...\n    # 20 lines of notification...\n    pass\n\n# Better: Composed from focused functions\ndef process_order(order: Order) -> Result:\n    \"\"\"Process a customer order through the complete workflow.\"\"\"\n    validate_order(order)\n    reserve_inventory(order)\n    payment_result = charge_payment(order)\n    send_confirmation(order, payment_result)\n    return Result(success=True, order_id=order.id)\n```\n\n### Pattern 7: Dependency Injection\n\nPass dependencies through constructors for testability.\n\n```python\nfrom typing import Protocol\n\nclass Logger(Protocol):\n    def info(self, msg: str, **kwargs) -> None: ...\n    def error(self, msg: str, **kwargs) -> None: ...\n\nclass Cache(Protocol):\n    async def get(self, key: str) -> str | None: ...\n    async def set(self, key: str, value: str, ttl: int) -> None: ...\n\nclass UserService:\n    \"\"\"Service with injected dependencies.\"\"\"\n\n    def __init__(\n        self,\n        repository: UserRepository,\n        cache: Cache,\n        logger: Logger,\n    ) -> None:\n        self._repo = repository\n        self._cache = cache\n        self._logger = logger\n\n    async def get_user(self, user_id: str) -> User:\n        # Check cache first\n        cached = await self._cache.get(f\"user:{user_id}\")\n        if cached:\n            self._logger.info(\"Cache hit\", user_id=user_id)\n            return User.from_json(cached)\n\n        # Fetch from database\n        user = await self._repo.get_by_id(user_id)\n        if user:\n            await self._cache.set(f\"user:{user_id}\", user.to_json(), ttl=300)\n\n        return user\n\n# Production\nservice = UserService(\n    repository=PostgresUserRepository(db),\n    cache=RedisCache(redis),\n    logger=StructlogLogger(),\n)\n\n# Testing\nservice = UserService(\n    repository=InMemoryUserRepository(),\n    cache=FakeCache(),\n    logger=NullLogger(),\n)\n```\n\n### Pattern 8: Avoiding Common Anti-Patterns\n\n**Don't expose internal types:**\n\n```python\n# BAD: Leaking ORM model to API\n@app.get(\"\u002Fusers\u002F{id}\")\ndef get_user(id: str) -> UserModel:  # SQLAlchemy model\n    return db.query(UserModel).get(id)\n\n# GOOD: Use response schemas\n@app.get(\"\u002Fusers\u002F{id}\")\ndef get_user(id: str) -> UserResponse:\n    user = db.query(UserModel).get(id)\n    return UserResponse.from_orm(user)\n```\n\n**Don't mix I\u002FO with business logic:**\n\n```python\n# BAD: SQL embedded in business logic\ndef calculate_discount(user_id: str) -> float:\n    user = db.query(\"SELECT * FROM users WHERE id = ?\", user_id)\n    orders = db.query(\"SELECT * FROM orders WHERE user_id = ?\", user_id)\n    # Business logic mixed with data access\n\n# GOOD: Repository pattern\ndef calculate_discount(user: User, order_history: list[Order]) -> float:\n    # Pure business logic, easily testable\n    if len(order_history) > 10:\n        return 0.15\n    return 0.0\n```\n\n## Best Practices Summary\n\n1. **Keep it simple** - Choose the simplest solution that works\n2. **Single responsibility** - Each unit has one reason to change\n3. **Separate concerns** - Distinct layers with clear purposes\n4. **Compose, don't inherit** - Combine objects for flexibility\n5. **Rule of three** - Wait before abstracting\n6. **Keep functions small** - 20-50 lines (varies by complexity), one purpose\n7. **Inject dependencies** - Constructor injection for testability\n8. **Delete before abstracting** - Remove dead code, then consider patterns\n9. **Test each layer** - Isolated tests for each concern\n10. **Explicit over clever** - Readable code beats elegant code\n","# Python Design Patterns\n\nWrite maintainable Python code using fundamental design principles. These patterns help you build systems that are easy to understand, test, and modify.\n\n## When to Use This Skill\n\n- Designing new components or services\n- Refactoring complex or tangled code\n- Deciding whether to create an abstraction\n- Choosing between inheritance and composition\n- Evaluating code complexity and coupling\n- Planning modular architectures\n\n## The Zen of Python\n\nThese aphorisms guide every design decision. When in doubt, refer back here.\n\n```\nBeautiful is better than ugly.\nExplicit is better than implicit.\nSimple is better than complex.\nComplex is better than complicated.\nFlat is better than nested.\nSparse is better than dense.\nReadability counts.\nSpecial cases aren't special enough to break the rules.\nAlthough practicality beats purity.\nErrors should never pass silently.\nUnless explicitly silenced.\nIn the face of ambiguity, refuse the temptation to guess.\nThere should be one-- and preferably only one --obvious way to do it.\nAlthough that way may not be obvious at first unless you're Dutch.\nNow is better than never.\nAlthough never is often better than *right* now.\nIf the implementation is hard to explain, it's a bad idea.\nIf the implementation is easy to explain, it may be a good idea.\nNamespaces are one honking great idea -- let's do more of those!\n```\n\nHow the Zen maps to the patterns in this skill:\n\n| Zen Principle | Pattern |\n|---|---|\n| Simple is better than complex | KISS |\n| Readability counts | Function size guidelines, explicit over clever |\n| Flat is better than nested | Separation of concerns, layered architecture |\n| Explicit is better than implicit | Dependency injection, avoiding anti-patterns |\n| There should be one obvious way | Single responsibility |\n| If the implementation is hard to explain, it's a bad idea | Rule of three, composition over inheritance |\n| Errors should never pass silently | Proper error handling at layer boundaries |\n| Practicality beats purity | Rule of three (duplication over wrong abstraction) |\n| Namespaces are one honking great idea | Separation of concerns, distinct layers |\n\n## Core Concepts\n\n### 1. KISS (Keep It Simple)\n\nChoose the simplest solution that works. Complexity must be justified by concrete requirements.\n\n### 2. Single Responsibility (SRP)\n\nEach unit should have one reason to change. Separate concerns into focused components.\n\n### 3. Composition Over Inheritance\n\nBuild behavior by combining objects, not extending classes.\n\n### 4. Rule of Three\n\nWait until you have three instances before abstracting. Duplication is often better than premature abstraction.\n\n## Quick Start\n\n```python\n# Simple beats clever\n# Instead of a factory\u002Fregistry pattern:\nFORMATTERS = {\"json\": JsonFormatter, \"csv\": CsvFormatter}\n\ndef get_formatter(name: str) -> Formatter:\n    return FORMATTERS[name]()\n```\n\n## Fundamental Patterns\n\n### Pattern 1: KISS - Keep It Simple\n\nBefore adding complexity, ask: does a simpler solution work?\n\n```python\n# Over-engineered: Factory with registration\nclass OutputFormatterFactory:\n    _formatters: dict[str, type[Formatter]] = {}\n\n    @classmethod\n    def register(cls, name: str):\n        def decorator(formatter_cls):\n            cls._formatters[name] = formatter_cls\n            return formatter_cls\n        return decorator\n\n    @classmethod\n    def create(cls, name: str) -> Formatter:\n        return cls._formatters[name]()\n\n@OutputFormatterFactory.register(\"json\")\nclass JsonFormatter(Formatter):\n    ...\n\n# Simple: Just use a dictionary\nFORMATTERS = {\n    \"json\": JsonFormatter,\n    \"csv\": CsvFormatter,\n    \"xml\": XmlFormatter,\n}\n\ndef get_formatter(name: str) -> Formatter:\n    \"\"\"Get formatter by name.\"\"\"\n    if name not in FORMATTERS:\n        raise ValueError(f\"Unknown format: {name}\")\n    return FORMATTERS[name]()\n```\n\nThe factory pattern adds code without adding value here. Save patterns for when they solve real problems.\n\n### Pattern 2: Single Responsibility Principle\n\nEach class or function should have one reason to change.\n\n```python\n# BAD: Handler does everything\nclass UserHandler:\n    async def create_user(self, request: Request) -> Response:\n        # HTTP parsing\n        data = await request.json()\n\n        # Validation\n        if not data.get(\"email\"):\n            return Response({\"error\": \"email required\"}, status=400)\n\n        # Database access\n        user = await db.execute(\n            \"INSERT INTO users (email, name) VALUES ($1, $2) RETURNING *\",\n            data[\"email\"], data[\"name\"]\n        )\n\n        # Response formatting\n        return Response({\"id\": user.id, \"email\": user.email}, status=201)\n\n# GOOD: Separated concerns\nclass UserService:\n    \"\"\"Business logic only.\"\"\"\n\n    def __init__(self, repo: UserRepository) -> None:\n        self._repo = repo\n\n    async def create_user(self, data: CreateUserInput) -> User:\n        # Only business rules here\n        user = User(email=data.email, name=data.name)\n        return await self._repo.save(user)\n\nclass UserHandler:\n    \"\"\"HTTP concerns only.\"\"\"\n\n    def __init__(self, service: UserService) -> None:\n        self._service = service\n\n    async def create_user(self, request: Request) -> Response:\n        data = CreateUserInput(**(await request.json()))\n        user = await self._service.create_user(data)\n        return Response(user.to_dict(), status=201)\n```\n\nNow HTTP changes don't affect business logic, and vice versa.\n\n### Pattern 3: Separation of Concerns\n\nOrganize code into distinct layers with clear responsibilities.\n\n```\n┌─────────────────────────────────────────────────────┐\n│  API Layer (handlers)                                │\n│  - Parse requests                                    │\n│  - Call services                                     │\n│  - Format responses                                  │\n└─────────────────────────────────────────────────────┘\n                        │\n                        ▼\n┌─────────────────────────────────────────────────────┐\n│  Service Layer (business logic)                      │\n│  - Domain rules and validation                       │\n│  - Orchestrate operations                            │\n│  - Pure functions where possible                     │\n└─────────────────────────────────────────────────────┘\n                        │\n                        ▼\n┌─────────────────────────────────────────────────────┐\n│  Repository Layer (data access)                      │\n│  - SQL queries                                       │\n│  - External API calls                                │\n│  - Cache operations                                  │\n└─────────────────────────────────────────────────────┘\n```\n\nEach layer depends only on layers below it:\n\n```python\n# Repository: Data access\nclass UserRepository:\n    async def get_by_id(self, user_id: str) -> User | None:\n        row = await self._db.fetchrow(\n            \"SELECT * FROM users WHERE id = $1\", user_id\n        )\n        return User(**row) if row else None\n\n# Service: Business logic\nclass UserService:\n    def __init__(self, repo: UserRepository) -> None:\n        self._repo = repo\n\n    async def get_user(self, user_id: str) -> User:\n        user = await self._repo.get_by_id(user_id)\n        if user is None:\n            raise UserNotFoundError(user_id)\n        return user\n\n# Handler: HTTP concerns\n@app.get(\"\u002Fusers\u002F{user_id}\")\nasync def get_user(user_id: str) -> UserResponse:\n    user = await user_service.get_user(user_id)\n    return UserResponse.from_user(user)\n```\n\n### Pattern 4: Composition Over Inheritance\n\nBuild behavior by combining objects rather than inheriting.\n\n```python\n# Inheritance: Rigid and hard to test\nclass EmailNotificationService(NotificationService):\n    def __init__(self):\n        super().__init__()\n        self._smtp = SmtpClient()  # Hard to mock\n\n    def notify(self, user: User, message: str) -> None:\n        self._smtp.send(user.email, message)\n\n# Composition: Flexible and testable\nclass NotificationService:\n    \"\"\"Send notifications via multiple channels.\"\"\"\n\n    def __init__(\n        self,\n        email_sender: EmailSender,\n        sms_sender: SmsSender | None = None,\n        push_sender: PushSender | None = None,\n    ) -> None:\n        self._email = email_sender\n        self._sms = sms_sender\n        self._push = push_sender\n\n    async def notify(\n        self,\n        user: User,\n        message: str,\n        channels: set[str] | None = None,\n    ) -> None:\n        channels = channels or {\"email\"}\n\n        if \"email\" in channels:\n            await self._email.send(user.email, message)\n\n        if \"sms\" in channels and self._sms and user.phone:\n            await self._sms.send(user.phone, message)\n\n        if \"push\" in channels and self._push and user.device_token:\n            await self._push.send(user.device_token, message)\n\n# Easy to test with fakes\nservice = NotificationService(\n    email_sender=FakeEmailSender(),\n    sms_sender=FakeSmsSender(),\n)\n```\n\n## Advanced Patterns\n\n### Pattern 5: Rule of Three\n\nWait until you have three instances before abstracting.\n\n```python\n# Two similar functions? Don't abstract yet\ndef process_orders(orders: list[Order]) -> list[Result]:\n    results = []\n    for order in orders:\n        validated = validate_order(order)\n        result = process_validated_order(validated)\n        results.append(result)\n    return results\n\ndef process_returns(returns: list[Return]) -> list[Result]:\n    results = []\n    for ret in returns:\n        validated = validate_return(ret)\n        result = process_validated_return(validated)\n        results.append(result)\n    return results\n\n# These look similar, but wait! Are they actually the same?\n# Different validation, different processing, different errors...\n# Duplication is often better than the wrong abstraction\n\n# Only after a third case, consider if there's a real pattern\n# But even then, sometimes explicit is better than abstract\n```\n\n### Pattern 6: Function Size Guidelines\n\nKeep functions focused. Extract when a function:\n\n- Exceeds 20-50 lines (varies by complexity)\n- Serves multiple distinct purposes\n- Has deeply nested logic (3+ levels)\n\n```python\n# Too long, multiple concerns mixed\ndef process_order(order: Order) -> Result:\n    # 50 lines of validation...\n    # 30 lines of inventory check...\n    # 40 lines of payment processing...\n    # 20 lines of notification...\n    pass\n\n# Better: Composed from focused functions\ndef process_order(order: Order) -> Result:\n    \"\"\"Process a customer order through the complete workflow.\"\"\"\n    validate_order(order)\n    reserve_inventory(order)\n    payment_result = charge_payment(order)\n    send_confirmation(order, payment_result)\n    return Result(success=True, order_id=order.id)\n```\n\n### Pattern 7: Dependency Injection\n\nPass dependencies through constructors for testability.\n\n```python\nfrom typing import Protocol\n\nclass Logger(Protocol):\n    def info(self, msg: str, **kwargs) -> None: ...\n    def error(self, msg: str, **kwargs) -> None: ...\n\nclass Cache(Protocol):\n    async def get(self, key: str) -> str | None: ...\n    async def set(self, key: str, value: str, ttl: int) -> None: ...\n\nclass UserService:\n    \"\"\"Service with injected dependencies.\"\"\"\n\n    def __init__(\n        self,\n        repository: UserRepository,\n        cache: Cache,\n        logger: Logger,\n    ) -> None:\n        self._repo = repository\n        self._cache = cache\n        self._logger = logger\n\n    async def get_user(self, user_id: str) -> User:\n        # Check cache first\n        cached = await self._cache.get(f\"user:{user_id}\")\n        if cached:\n            self._logger.info(\"Cache hit\", user_id=user_id)\n            return User.from_json(cached)\n\n        # Fetch from database\n        user = await self._repo.get_by_id(user_id)\n        if user:\n            await self._cache.set(f\"user:{user_id}\", user.to_json(), ttl=300)\n\n        return user\n\n# Production\nservice = UserService(\n    repository=PostgresUserRepository(db),\n    cache=RedisCache(redis),\n    logger=StructlogLogger(),\n)\n\n# Testing\nservice = UserService(\n    repository=InMemoryUserRepository(),\n    cache=FakeCache(),\n    logger=NullLogger(),\n)\n```\n\n### Pattern 8: Avoiding Common Anti-Patterns\n\n**Don't expose internal types:**\n\n```python\n# BAD: Leaking ORM model to API\n@app.get(\"\u002Fusers\u002F{id}\")\ndef get_user(id: str) -> UserModel:  # SQLAlchemy model\n    return db.query(UserModel).get(id)\n\n# GOOD: Use response schemas\n@app.get(\"\u002Fusers\u002F{id}\")\ndef get_user(id: str) -> UserResponse:\n    user = db.query(UserModel).get(id)\n    return UserResponse.from_orm(user)\n```\n\n**Don't mix I\u002FO with business logic:**\n\n```python\n# BAD: SQL embedded in business logic\ndef calculate_discount(user_id: str) -> float:\n    user = db.query(\"SELECT * FROM users WHERE id = ?\", user_id)\n    orders = db.query(\"SELECT * FROM orders WHERE user_id = ?\", user_id)\n    # Business logic mixed with data access\n\n# GOOD: Repository pattern\ndef calculate_discount(user: User, order_history: list[Order]) -> float:\n    # Pure business logic, easily testable\n    if len(order_history) > 10:\n        return 0.15\n    return 0.0\n```\n\n## Best Practices Summary\n\n1. **Keep it simple** - Choose the simplest solution that works\n2. **Single responsibility** - Each unit has one reason to change\n3. **Separate concerns** - Distinct layers with clear purposes\n4. **Compose, don't inherit** - Combine objects for flexibility\n5. **Rule of three** - Wait before abstracting\n6. **Keep functions small** - 20-50 lines (varies by complexity), one purpose\n7. **Inject dependencies** - Constructor injection for testability\n8. **Delete before abstracting** - Remove dead code, then consider patterns\n9. **Test each layer** - Isolated tests for each concern\n10. **Explicit over clever** - Readable code beats elegant code\n",{"name":5,"description":7,"disable-model-invocation":53},true,"main","224d7699a283a75bd3f75d4d8b03b15aca0ae309","plugins\u002F10x-swe\u002Fskills\u002Fpython-design-patterns",0,"https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe","https:\u002F\u002Fgithub.com\u002Fcercova-studios","2026-11-12 07:39:44",{"source":8,"skillName":5,"commands":62,"prompt":72,"zipAvailable":53},[63,66,69],{"tool":64,"command":65},"npx","npx skills add cercova-studios\u002F10x-swe --skill python-design-patterns",{"tool":67,"command":68},"bunx","bunx skills add cercova-studios\u002F10x-swe --skill python-design-patterns",{"tool":70,"command":71},"pnpm","pnpm dlx skills add cercova-studios\u002F10x-swe --skill python-design-patterns","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fpython-design-patterns\u002FSKILL.md",[74],{"path":75,"resourceType":76,"resourceTypeDesc":77,"sizeBytes":78,"sourceHtmlUrl":79},"agents\u002Fopenai.yaml","REFERENCE","参考文档",43,"https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fpython-design-patterns\u002Fagents\u002Fopenai.yaml",[81,119,148,168,187,199],{"skillNo":82,"name":83,"nameZh":6,"description":84,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":85,"licenseFileUrl":86,"sourceHtmlUrl":87,"categories":88,"keywords":92,"publishedAt":48},"01M6CD3T6EQ9N5KPNXCM6ABHVA","turnstile-spin","Set up Cloudflare Turnstile end-to-end in a project. Scan the codebase, create the widget via the Cloudflare API, embed it where user requests need bot verification (form submissions, SPA actions, API endpoints, download links, comment or vote submissions, etc.), wire canonical server-side siteverify in the customer's existing backend, validate, and persist the skill. Load this when a user asks to add Turnstile, set up CAPTCHA, protect a form or endpoint from bots, or fix a Turnstile integration. Uses Cloudflare's documented Turnstile contract.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fturnstile-spin\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Fturnstile-spin\u002FSKILL.md",[89],{"categoryNo":90,"categoryName":91,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口",[93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,37],"turnstile spin","SET","nextjs","actions","up","fix","cloudflare","bot","api","permissions","create","astro","server","verification","plugin","endpoints","customer","backend","sveltekit","integration","app","bots","spa","project","end","SWE",{"skillNo":120,"name":121,"nameZh":6,"description":122,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":85,"licenseFileUrl":123,"sourceHtmlUrl":124,"categories":125,"keywords":131,"publishedAt":48},"01M6CD0BJYRNV610HYYPX933RE","frontend-design","Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Ffrontend-design\u002FLICENSE.txt","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002F10x-swe\u002Fskills\u002Ffrontend-design\u002FSKILL.md",[126,129,130],{"categoryNo":127,"categoryName":128,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000009","前端开发",{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},[132,133,30,103,134,135,136,137,138,139,45,43,140,141,142,143,144,37,145,146,147],"frontend design","frontend","web","quality","applications","creative","web components","Production","components","user","generic","aesthetics","pages","with","high","build",{"skillNo":149,"name":150,"nameZh":6,"description":151,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":152,"categories":153,"keywords":154,"publishedAt":48},"01M6CD4QX8C4DST98AY21HEYCM","source-insights","Prepare inspected source evidence, preserve exact citations, and publish reviewed insights into an explicit local library.","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002Fknowledge\u002Fskills\u002Fsource-insights\u002FSKILL.md",[],[155,156,157,158,159,160,161,162,163,164,165,166,167],"source insights","insights","source","publish","Citations","evidence","library","workflows","prepare","session","global","local","preserve",{"skillNo":169,"name":170,"nameZh":6,"description":171,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":172,"categories":173,"keywords":177,"publishedAt":48},"01M6CD4N1HVNC1EXPEBZT7YS31","skill-graph","Discover skills and workflows through independent lexical search, relationship paths and a terminal graph.","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002Fknowledge\u002Fskills\u002Fskill-graph\u002FSKILL.md",[174],{"categoryNo":175,"categoryName":176,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[178,179,107,162,180,181,182,165,183,184,185,118,186],"graph","skill graph","terminal","10x","search","discover skills","discover","paths","relationship",{"skillNo":188,"name":189,"nameZh":6,"description":190,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":191,"categories":192,"keywords":193,"publishedAt":48},"01M6CD4HQKXNZ57YEGD8QVK6Z6","session-search","Recall public session turns with exact provenance, bounded excerpts and independent piped exports.","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002Fknowledge\u002Fskills\u002Fsession-search\u002FSKILL.md",[],[182,164,194,195,162,196,197,165,145,156,157,198],"session search","public","provenance","recall","bounded",{"skillNo":200,"name":201,"nameZh":6,"description":202,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":203,"categories":204,"keywords":211,"publishedAt":48},"01M6CD4ET7DVNBYPDAMAYMSK2T","newsletter","Produce a private local AI newsletter from bounded public research, with cited deep dives, HTML\u002FMarkdown output, Dagu scheduling and seven-day retention.","https:\u002F\u002Fgithub.com\u002Fcercova-studios\u002F10x-swe\u002Fblob\u002Fmain\u002Fplugins\u002Fknowledge\u002Fskills\u002Fnewsletter\u002FSKILL.md",[205,208],{"categoryNo":206,"categoryName":207,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000005","邮件与沟通",{"categoryNo":209,"categoryName":210,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000021","资料检索与研究",[201,212,213,214,215,195,162,216,217,218,219,165,145,220,221,166,198,222],"local ai","dagu","produce","research","markdown","scheduling","html","daily","deep","retention","output"]