Back to Skills

model-patterns

verified

Expert model design decisions for iOS/tvOS: when DTO separation adds value vs overkill, validation strategy selection, immutability trade-offs, and custom Codable decoder design. Use when designing data models, implementing API contracts, or debugging decoding failures. Trigger keywords: Codable, DTO, domain model, CodingKeys, custom decoder, validation, immutable, struct, mapping, JSON decoding

View on GitHub

Marketplace

manifest-marketplace

Kaakati/rails-enterprise-dev

Plugin

reactree-ios-dev

development

Repository

Kaakati/rails-enterprise-dev
2stars

plugins/reactree-ios-dev/skills/model-patterns/SKILL.md

Last Verified

January 25, 2026

Install Skill

Select agents to install to:

Scope:
npx add-skill https://github.com/Kaakati/rails-enterprise-dev/blob/main/plugins/reactree-ios-dev/skills/model-patterns/SKILL.md -a claude-code --skill model-patterns

Installation paths:

Claude
.claude/skills/model-patterns/
Powered by add-skill CLI

Instructions

# Model Patterns — Expert Decisions

Expert decision frameworks for model design choices. Claude knows Codable syntax — this skill provides judgment calls for when to separate DTOs, validation strategies, and immutability trade-offs.

---

## Decision Trees

### DTO vs Single Model

```
Does API response match your domain needs?
├─ YES (1:1 mapping)
│  └─ Is API contract stable?
│     ├─ YES → Single Codable model is fine
│     └─ NO → DTO protects against API changes
│
├─ NO (needs transformation)
│  └─ DTO + Domain model
│     DTO: matches API exactly
│     Domain: matches app needs
│
└─ Multiple APIs for same domain concept?
   └─ Separate DTOs per API
      Single domain model aggregates
```

**The trap**: DTO for everything. If your API matches your domain and is stable, a single Codable struct is simpler. Add DTO layer when it solves a real problem.

### Validation Strategy Selection

```
When should validation happen?
├─ External data (API, user input)
│  └─ Validate at boundary (init or factory)
│     Fail fast with clear errors
│
├─ Internal data (already validated)
│  └─ Trust it (no re-validation)
│     Validation at boundary is sufficient
│
└─ Critical invariants (money, permissions)
   └─ Type-level enforcement
      Email type, not String
      Money type, not Double
```

### Struct vs Class Decision

```
What are your requirements?
├─ Simple data container
│  └─ Struct (value semantics)
│     Passed by copy, immutable by default
│
├─ Shared mutable state needed?
│  └─ Really? Reconsider design
│     └─ If truly needed → Class with @Observable
│
├─ Identity matters (same instance)?
│  └─ Class (reference semantics)
│     But consider if ID equality suffices
│
└─ Inheritance needed?
   └─ Class (but prefer composition)
```

### Custom Decoder Complexity

```
How much custom decoding?
├─ Just key mapping (snake_case → camelCase)
│  └─ Use keyDecodingStrategy
│     decoder.keyDecodingStrategy = .convertFromSnakeCase
│
├─ Few fields need transformation
│  

Validation Details

Front Matter
Required Fields
Valid Name Format
Valid Description
Has Sections
Allowed Tools
Instruction Length:
10691 chars