[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6F1JF3WD1FCSET3SR46B0KV":3,"skill-same:01M6F1JF3WD1FCSET3SR46B0KV":78},{"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":44,"linkOnly":45,"markdownContent":46,"markdownBody":47,"frontMatter":48,"refName":49,"commitSha":50,"skillDirectory":51,"forksCount":52,"repositoryHtmlUrl":53,"repositoryHomepageUrl":54,"ownerHtmlUrl":55,"ownerBlogUrl":6,"ownerDescription":56,"updatedAt":57,"install":58,"resources":71},"01M6F1JF3WD1FCSET3SR46B0KV","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.","ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fwshobson\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],"design","python","design patterns","python design patterns","patterns","architecture","code","Composition","refactoring","decisions","use","structure","inheritance","separation of concerns","separation","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.\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## 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## 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},"main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002Faiskillstore\u002Fmarketplace\u002Fwshobson\u002Fpython-design-patterns",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":8,"skillName":5,"commands":59,"prompt":69,"zipAvailable":70},[60,63,66],{"tool":61,"command":62},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill python-design-patterns",{"tool":64,"command":65},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill python-design-patterns",{"tool":67,"command":68},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill python-design-patterns","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fwshobson\u002Fpython-design-patterns\u002FSKILL.md",true,[72],{"path":73,"resourceType":74,"resourceTypeDesc":75,"sizeBytes":76,"sourceHtmlUrl":77},"skill-report.json","REFERENCE","参考文档",8482,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fwshobson\u002Fpython-design-patterns\u002Fskill-report.json",[79,91,101,110,116,123],{"skillNo":80,"name":81,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":82,"categories":83,"keywords":87,"publishedAt":44},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[84],{"categoryNo":85,"categoryName":86,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[88,89,90],"model","model hierarchy","model hierarchy skill",{"skillNo":92,"name":93,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":94,"categories":95,"keywords":97,"publishedAt":44},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[96],{"categoryNo":85,"categoryName":86,"taxonomyType":21,"taxonomyTypeDesc":22},[98,99,100],"MCP","zoom","zoom mcp",{"skillNo":102,"name":103,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":104,"categories":105,"keywords":106,"publishedAt":44},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[107,108,109,99],"sdk","zoom apps sdk","apps",{"skillNo":111,"name":112,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":113,"categories":114,"keywords":115,"publishedAt":44},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[112],{"skillNo":117,"name":118,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":119,"categories":120,"keywords":122,"publishedAt":44},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[121],{"categoryNo":85,"categoryName":86,"taxonomyType":21,"taxonomyTypeDesc":22},[118],{"skillNo":124,"name":125,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":126,"categories":127,"keywords":128,"publishedAt":44},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[125]]