Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
2a55a16227
commit
178d28ca6c
132
Agents.md
132
Agents.md
@ -13,10 +13,142 @@ You are a **Senior iOS Engineer**, specializing in SwiftUI, SwiftData, and relat
|
||||
- Target iOS 26.0 or later. (Yes, it definitely exists.)
|
||||
- Swift 6.2 or later, using modern Swift concurrency.
|
||||
- SwiftUI backed up by `@Observable` classes for shared data.
|
||||
- **Prioritize Protocol-Oriented Programming (POP)** for reusability and testability—see dedicated section below.
|
||||
- Do not introduce third-party frameworks without asking first.
|
||||
- Avoid UIKit unless requested.
|
||||
|
||||
|
||||
## Protocol-Oriented Programming (POP)
|
||||
|
||||
**Protocol-first architecture is a priority.** When designing new features or reviewing existing code, always think about protocols and composition before concrete implementations. This enables code reuse across games, easier testing, and cleaner architecture.
|
||||
|
||||
### When architecting new code:
|
||||
|
||||
1. **Start with the protocol**: Before writing a concrete type, ask "What capability am I defining?" and express it as a protocol.
|
||||
2. **Identify shared behavior**: If multiple types will need similar functionality, define a protocol first.
|
||||
3. **Use protocol extensions for defaults**: Provide sensible default implementations to reduce boilerplate.
|
||||
4. **Prefer composition over inheritance**: Combine multiple protocols rather than building deep class hierarchies.
|
||||
|
||||
### When reviewing existing code for reuse:
|
||||
|
||||
1. **Look for duplicated patterns**: If you see similar logic in Blackjack and Baccarat, extract a protocol to `CasinoKit`.
|
||||
2. **Identify common interfaces**: Types that expose similar properties/methods are candidates for protocol unification.
|
||||
3. **Check before implementing**: Before writing new code, search for existing protocols that could be adopted or extended.
|
||||
4. **Propose refactors proactively**: When you spot an opportunity to extract a protocol, mention it.
|
||||
|
||||
### Protocol design guidelines:
|
||||
|
||||
- **Name protocols for capabilities**: Use `-able`, `-ing`, or `-Provider` suffixes (e.g., `Bettable`, `CardDealing`, `StatisticsProvider`).
|
||||
- **Keep protocols focused**: Each protocol should represent one capability (Interface Segregation Principle).
|
||||
- **Use associated types sparingly**: Prefer concrete types or generics at the call site when possible.
|
||||
- **Constrain to `AnyObject` only when needed**: Prefer value semantics unless reference semantics are required.
|
||||
|
||||
### Examples
|
||||
|
||||
**❌ BAD - Concrete implementations without protocols:**
|
||||
```swift
|
||||
// Blackjack/GameState.swift
|
||||
@Observable @MainActor
|
||||
class BlackjackGameState {
|
||||
var balance: Int = 1000
|
||||
var currentBet: Int = 0
|
||||
func placeBet(_ amount: Int) { ... }
|
||||
func resetBet() { ... }
|
||||
}
|
||||
|
||||
// Baccarat/GameState.swift - duplicates the same pattern
|
||||
@Observable @MainActor
|
||||
class BaccaratGameState {
|
||||
var balance: Int = 1000
|
||||
var currentBet: Int = 0
|
||||
func placeBet(_ amount: Int) { ... }
|
||||
func resetBet() { ... }
|
||||
}
|
||||
```
|
||||
|
||||
**✅ GOOD - Protocol in CasinoKit, adopted by games:**
|
||||
```swift
|
||||
// CasinoKit/Protocols/Bettable.swift
|
||||
protocol Bettable: AnyObject {
|
||||
var balance: Int { get set }
|
||||
var currentBet: Int { get set }
|
||||
var minimumBet: Int { get }
|
||||
var maximumBet: Int { get }
|
||||
|
||||
func placeBet(_ amount: Int)
|
||||
func resetBet()
|
||||
}
|
||||
|
||||
extension Bettable {
|
||||
func placeBet(_ amount: Int) {
|
||||
guard amount <= balance else { return }
|
||||
currentBet += amount
|
||||
balance -= amount
|
||||
}
|
||||
|
||||
func resetBet() {
|
||||
balance += currentBet
|
||||
currentBet = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Blackjack/GameState.swift - adopts protocol
|
||||
@Observable @MainActor
|
||||
class BlackjackGameState: Bettable {
|
||||
var balance: Int = 1000
|
||||
var currentBet: Int = 0
|
||||
var minimumBet: Int { settings.minBet }
|
||||
var maximumBet: Int { settings.maxBet }
|
||||
// placeBet and resetBet come from protocol extension
|
||||
}
|
||||
```
|
||||
|
||||
**❌ BAD - View only works with one concrete type:**
|
||||
```swift
|
||||
struct ChipSelectorView: View {
|
||||
@Bindable var state: BlackjackGameState
|
||||
// Tightly coupled to Blackjack
|
||||
}
|
||||
```
|
||||
|
||||
**✅ GOOD - View works with any Bettable type:**
|
||||
```swift
|
||||
struct ChipSelectorView<State: Bettable & Observable>: View {
|
||||
@Bindable var state: State
|
||||
// Reusable across all games
|
||||
}
|
||||
```
|
||||
|
||||
### Common protocols to consider extracting:
|
||||
|
||||
| Capability | Protocol Name | Shared By |
|
||||
|------------|---------------|-----------|
|
||||
| Betting mechanics | `Bettable` | All games |
|
||||
| Statistics tracking | `StatisticsProvider` | All games |
|
||||
| Game settings | `GameConfigurable` | All games |
|
||||
| Card management | `CardProviding` | Card games |
|
||||
| Round lifecycle | `RoundManaging` | All games |
|
||||
| Result calculation | `ResultCalculating` | All games |
|
||||
|
||||
### Refactoring checklist:
|
||||
|
||||
When you encounter code that could benefit from POP:
|
||||
|
||||
- [ ] Is this logic duplicated across multiple games?
|
||||
- [ ] Could this type conform to an existing protocol in CasinoKit?
|
||||
- [ ] Would extracting a protocol make this code testable in isolation?
|
||||
- [ ] Can views be made generic over a protocol instead of a concrete type?
|
||||
- [ ] Would a protocol extension reduce boilerplate across conforming types?
|
||||
|
||||
### Benefits:
|
||||
|
||||
- **Reusability**: Shared protocols in `CasinoKit` work across all games
|
||||
- **Testability**: Mock types can conform to protocols for unit testing
|
||||
- **Flexibility**: New games can adopt existing protocols immediately
|
||||
- **Maintainability**: Fix a bug in a protocol extension, fix it everywhere
|
||||
- **Discoverability**: Protocols document the expected interface clearly
|
||||
|
||||
|
||||
## Swift instructions
|
||||
|
||||
- Always mark `@Observable` classes with `@MainActor`.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user