agentic-team-templates 0.13.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +6 -1
  2. package/package.json +1 -1
  3. package/src/index.js +22 -2
  4. package/src/index.test.js +5 -0
  5. package/templates/cpp-expert/.cursorrules/concurrency.md +211 -0
  6. package/templates/cpp-expert/.cursorrules/error-handling.md +170 -0
  7. package/templates/cpp-expert/.cursorrules/memory-and-ownership.md +220 -0
  8. package/templates/cpp-expert/.cursorrules/modern-cpp.md +211 -0
  9. package/templates/cpp-expert/.cursorrules/overview.md +87 -0
  10. package/templates/cpp-expert/.cursorrules/performance.md +223 -0
  11. package/templates/cpp-expert/.cursorrules/testing.md +230 -0
  12. package/templates/cpp-expert/.cursorrules/tooling.md +312 -0
  13. package/templates/cpp-expert/CLAUDE.md +242 -0
  14. package/templates/csharp-expert/.cursorrules/aspnet-core.md +311 -0
  15. package/templates/csharp-expert/.cursorrules/async-patterns.md +206 -0
  16. package/templates/csharp-expert/.cursorrules/dependency-injection.md +206 -0
  17. package/templates/csharp-expert/.cursorrules/error-handling.md +235 -0
  18. package/templates/csharp-expert/.cursorrules/language-features.md +204 -0
  19. package/templates/csharp-expert/.cursorrules/overview.md +92 -0
  20. package/templates/csharp-expert/.cursorrules/performance.md +251 -0
  21. package/templates/csharp-expert/.cursorrules/testing.md +282 -0
  22. package/templates/csharp-expert/.cursorrules/tooling.md +254 -0
  23. package/templates/csharp-expert/CLAUDE.md +360 -0
  24. package/templates/java-expert/.cursorrules/concurrency.md +209 -0
  25. package/templates/java-expert/.cursorrules/error-handling.md +205 -0
  26. package/templates/java-expert/.cursorrules/modern-java.md +216 -0
  27. package/templates/java-expert/.cursorrules/overview.md +81 -0
  28. package/templates/java-expert/.cursorrules/performance.md +239 -0
  29. package/templates/java-expert/.cursorrules/persistence.md +262 -0
  30. package/templates/java-expert/.cursorrules/spring-boot.md +262 -0
  31. package/templates/java-expert/.cursorrules/testing.md +272 -0
  32. package/templates/java-expert/.cursorrules/tooling.md +301 -0
  33. package/templates/java-expert/CLAUDE.md +325 -0
  34. package/templates/javascript-expert/.cursorrules/overview.md +5 -3
  35. package/templates/javascript-expert/.cursorrules/typescript-deep-dive.md +348 -0
  36. package/templates/javascript-expert/CLAUDE.md +34 -3
  37. package/templates/kotlin-expert/.cursorrules/coroutines.md +237 -0
  38. package/templates/kotlin-expert/.cursorrules/error-handling.md +149 -0
  39. package/templates/kotlin-expert/.cursorrules/frameworks.md +227 -0
  40. package/templates/kotlin-expert/.cursorrules/language-features.md +231 -0
  41. package/templates/kotlin-expert/.cursorrules/overview.md +77 -0
  42. package/templates/kotlin-expert/.cursorrules/performance.md +185 -0
  43. package/templates/kotlin-expert/.cursorrules/testing.md +213 -0
  44. package/templates/kotlin-expert/.cursorrules/tooling.md +258 -0
  45. package/templates/kotlin-expert/CLAUDE.md +276 -0
  46. package/templates/swift-expert/.cursorrules/concurrency.md +230 -0
  47. package/templates/swift-expert/.cursorrules/error-handling.md +213 -0
  48. package/templates/swift-expert/.cursorrules/language-features.md +246 -0
  49. package/templates/swift-expert/.cursorrules/overview.md +88 -0
  50. package/templates/swift-expert/.cursorrules/performance.md +260 -0
  51. package/templates/swift-expert/.cursorrules/swiftui.md +260 -0
  52. package/templates/swift-expert/.cursorrules/testing.md +286 -0
  53. package/templates/swift-expert/.cursorrules/tooling.md +285 -0
  54. package/templates/swift-expert/CLAUDE.md +275 -0
@@ -0,0 +1,276 @@
1
+ # Kotlin Expert Development Guide
2
+
3
+ Principal-level guidelines for Kotlin engineering. Deep language mastery, coroutines, multiplatform, and idiomatic patterns.
4
+
5
+ ---
6
+
7
+ ## Overview
8
+
9
+ This guide applies to:
10
+ - Backend services (Ktor, Spring Boot, Quarkus)
11
+ - Android applications (Jetpack Compose, Architecture Components)
12
+ - Kotlin Multiplatform (KMP) — shared code across platforms
13
+ - CLI tools and scripting
14
+ - Libraries and Maven/Gradle artifacts
15
+ - Data processing and streaming
16
+
17
+ ### Core Philosophy
18
+
19
+ Kotlin is a pragmatic language. It gives you safety, expressiveness, and interoperability — use all three.
20
+
21
+ - **Null safety is the foundation.** The type system distinguishes nullable from non-nullable. No `!!` without proof.
22
+ - **Immutability by default.** `val` over `var`, immutable collections, data classes.
23
+ - **Conciseness without cleverness.** Less code doesn't mean unreadable code.
24
+ - **Coroutines are structured.** Every coroutine has a scope, every scope has a lifecycle.
25
+ - **Interop is a feature.** Use Java libraries freely, but write Kotlin idiomatically.
26
+ - **If you don't know, say so.** Admitting uncertainty is professional.
27
+
28
+ ### Key Principles
29
+
30
+ 1. **Null Safety Is Non-Negotiable** — No `!!` without justification. Safe calls, elvis, smart casts
31
+ 2. **Immutability by Default** — `val`, `List` (not `MutableList`), data classes, `copy()`
32
+ 3. **Structured Concurrency** — Every coroutine in a scope. No `GlobalScope`
33
+ 4. **Extension Functions Over Utility Classes** — Extend types at the call site
34
+ 5. **Sealed Types for State Modeling** — Exhaustive `when`, impossible states are compile errors
35
+
36
+ ### Project Structure
37
+
38
+ ```
39
+ project/
40
+ ├── src/main/kotlin/com/example/myapp/
41
+ │ ├── Application.kt
42
+ │ ├── config/
43
+ │ ├── domain/
44
+ │ │ ├── model/
45
+ │ │ ├── service/
46
+ │ │ └── event/
47
+ │ ├── application/
48
+ │ ├── infrastructure/
49
+ │ └── api/
50
+ ├── src/test/kotlin/
51
+ ├── build.gradle.kts
52
+ └── Dockerfile
53
+ ```
54
+
55
+ ---
56
+
57
+ ## Language Features
58
+
59
+ ### Null Safety
60
+
61
+ ```kotlin
62
+ val displayName = user?.name ?: "Anonymous"
63
+ val userId = request.userId ?: throw IllegalArgumentException("userId required")
64
+ // Never: user!!.name — use requireNotNull() with a message
65
+ ```
66
+
67
+ ### Data Classes and Value Classes
68
+
69
+ ```kotlin
70
+ data class Order(val id: OrderId, val items: List<OrderItem>, val status: OrderStatus)
71
+ val updated = order.copy(status = OrderStatus.SHIPPED)
72
+
73
+ @JvmInline
74
+ value class UserId(val value: String) // Zero-overhead type safety
75
+ ```
76
+
77
+ ### Sealed Types
78
+
79
+ ```kotlin
80
+ sealed interface Result<out T> {
81
+ data class Success<T>(val value: T) : Result<T>
82
+ data class Failure(val error: AppError) : Result<Nothing>
83
+ }
84
+
85
+ fun describe(result: Result<User>): String = when (result) {
86
+ is Result.Success -> "User: ${result.value.name}"
87
+ is Result.Failure -> "Error: ${result.error}"
88
+ // Exhaustive — compiler enforces all cases
89
+ }
90
+ ```
91
+
92
+ ### Extension Functions and Scope Functions
93
+
94
+ ```kotlin
95
+ fun String.toSlug(): String = lowercase().replace(Regex("[^a-z0-9\\s-]"), "").replace(Regex("\\s+"), "-")
96
+
97
+ val connection = HttpClient().apply { timeout = 30.seconds; retries = 3 }
98
+ val user = createUser(request).also { logger.info("Created: ${it.id}") }
99
+ ```
100
+
101
+ ---
102
+
103
+ ## Coroutines
104
+
105
+ ### Structured Concurrency
106
+
107
+ ```kotlin
108
+ suspend fun loadDashboard(userId: UserId): Dashboard = coroutineScope {
109
+ val user = async { userService.findById(userId) }
110
+ val orders = async { orderService.findRecent(userId) }
111
+ Dashboard(user = user.await(), orders = orders.await())
112
+ }
113
+ // If any async fails, ALL are cancelled
114
+ ```
115
+
116
+ ### Flow
117
+
118
+ ```kotlin
119
+ val state: StateFlow<UiState> = _state.asStateFlow()
120
+
121
+ fun observeUsers(): Flow<List<User>> = flow {
122
+ while (true) {
123
+ emit(userRepository.findAll())
124
+ delay(5.seconds)
125
+ }
126
+ }
127
+ ```
128
+
129
+ ### Rules
130
+
131
+ - No `GlobalScope` — use lifecycle-bound scopes
132
+ - No `runBlocking` in production (except `main()` and tests)
133
+ - No `Thread.sleep()` — use `delay()`
134
+ - Always rethrow `CancellationException`
135
+ - Use `supervisorScope` when child failures should be independent
136
+
137
+ ---
138
+
139
+ ## Error Handling
140
+
141
+ ### Sealed Result Types
142
+
143
+ ```kotlin
144
+ when (val result = userService.register(request)) {
145
+ is Result.Success -> call.respond(HttpStatusCode.Created, result.value)
146
+ is Result.Failure -> when (result.error) {
147
+ is AppError.Validation -> call.respond(HttpStatusCode.BadRequest, result.error)
148
+ is AppError.Conflict -> call.respond(HttpStatusCode.Conflict, result.error)
149
+ is AppError.NotFound -> call.respond(HttpStatusCode.NotFound, result.error)
150
+ }
151
+ }
152
+ ```
153
+
154
+ ### Validation
155
+
156
+ ```kotlin
157
+ require(customerId.isNotBlank()) { "customerId must not be blank" }
158
+ check(order.status == OrderStatus.PAID) { "Can only ship paid orders" }
159
+ val user = requireNotNull(userRepo.findById(id)) { "User $id must exist" }
160
+ ```
161
+
162
+ ---
163
+
164
+ ## Frameworks
165
+
166
+ ### Ktor
167
+
168
+ ```kotlin
169
+ fun Route.userRoutes() {
170
+ route("/users") {
171
+ get("/{id}") {
172
+ val id = UserId(call.parameters["id"] ?: return@get call.respond(HttpStatusCode.BadRequest))
173
+ // ...
174
+ }
175
+ post { val request = call.receive<CreateUserRequest>(); /* ... */ }
176
+ }
177
+ }
178
+ ```
179
+
180
+ ### Spring Boot
181
+
182
+ ```kotlin
183
+ @RestController
184
+ @RequestMapping("/api/v1/orders")
185
+ class OrderController(private val orderService: OrderService) {
186
+ @GetMapping("/{id}")
187
+ suspend fun getById(@PathVariable id: UUID): ResponseEntity<OrderResponse> { /* ... */ }
188
+ }
189
+ ```
190
+
191
+ ### Exposed (SQL)
192
+
193
+ ```kotlin
194
+ object Users : Table("users") {
195
+ val id = uuid("id").autoGenerate()
196
+ val name = varchar("name", 200)
197
+ val email = varchar("email", 255).uniqueIndex()
198
+ }
199
+ ```
200
+
201
+ ---
202
+
203
+ ## Testing
204
+
205
+ ### Framework Stack
206
+
207
+ | Tool | Purpose |
208
+ |------|---------|
209
+ | JUnit 5 / Kotest | Test framework |
210
+ | MockK | Kotlin-native mocking |
211
+ | kotlinx-coroutines-test | Coroutine testing |
212
+ | Testcontainers | Real databases/services |
213
+ | Ktor Test | HTTP endpoint testing |
214
+
215
+ ### Test Structure
216
+
217
+ ```kotlin
218
+ @Test
219
+ fun `create with valid items returns success`() = runTest {
220
+ coEvery { inventoryClient.checkAvailability("SKU-001", 2) } returns true
221
+ val result = sut.create(request)
222
+ assertThat(result).isInstanceOf(Result.Success::class.java)
223
+ }
224
+ ```
225
+
226
+ ---
227
+
228
+ ## Performance
229
+
230
+ ### Key Patterns
231
+
232
+ - `inline` functions for higher-order function hot paths
233
+ - `value class` for zero-overhead type wrappers
234
+ - Sequences for large collection chains (lazy evaluation)
235
+ - Pre-size collections with `HashMap(expectedSize)`
236
+ - `buildList`/`buildString` for single-allocation construction
237
+ - Buffered channels for coroutine throughput
238
+
239
+ ---
240
+
241
+ ## Tooling
242
+
243
+ ### Essential Stack
244
+
245
+ | Tool | Purpose |
246
+ |------|---------|
247
+ | Gradle (Kotlin DSL) | Build system |
248
+ | Detekt | Static analysis |
249
+ | ktlint | Code formatting |
250
+ | kotlinx.serialization | Compile-time serialization |
251
+ | kotlin-logging | Structured logging |
252
+ | Koin | Dependency injection |
253
+
254
+ ### CI Essentials
255
+
256
+ ```bash
257
+ ./gradlew check # Build + test + analysis
258
+ ./gradlew detekt # Static analysis
259
+ ```
260
+
261
+ ---
262
+
263
+ ## Definition of Done
264
+
265
+ A Kotlin feature is complete when:
266
+
267
+ - [ ] Compiles with zero warnings (`allWarningsAsErrors = true`)
268
+ - [ ] All tests pass
269
+ - [ ] No `!!` without documented justification
270
+ - [ ] No `var` where `val` suffices
271
+ - [ ] No `MutableList`/`MutableMap` exposed in public APIs
272
+ - [ ] Coroutines use structured concurrency (no `GlobalScope`)
273
+ - [ ] Nullable types handled explicitly
274
+ - [ ] Detekt reports zero findings
275
+ - [ ] No `TODO` without an associated issue
276
+ - [ ] Code reviewed and approved
@@ -0,0 +1,230 @@
1
+ # Swift Concurrency
2
+
3
+ Structured concurrency with async/await, actors, and task groups. No more callback pyramids.
4
+
5
+ ## async/await
6
+
7
+ ```swift
8
+ // Async functions
9
+ func fetchUser(id: UUID) async throws -> User {
10
+ let (data, response) = try await urlSession.data(from: userURL(id))
11
+ guard let httpResponse = response as? HTTPURLResponse,
12
+ httpResponse.statusCode == 200 else {
13
+ throw APIError.invalidResponse
14
+ }
15
+ return try JSONDecoder().decode(User.self, from: data)
16
+ }
17
+
18
+ // Calling async code
19
+ let user = try await fetchUser(id: userId)
20
+
21
+ // Async let — parallel execution
22
+ async let user = fetchUser(id: userId)
23
+ async let orders = fetchOrders(userId: userId)
24
+ async let preferences = fetchPreferences(userId: userId)
25
+
26
+ let dashboard = try await Dashboard(
27
+ user: user,
28
+ orders: orders,
29
+ preferences: preferences
30
+ )
31
+ // All three requests run concurrently
32
+ ```
33
+
34
+ ## Task and TaskGroup
35
+
36
+ ```swift
37
+ // Unstructured task (use sparingly)
38
+ Task {
39
+ do {
40
+ let result = try await processData()
41
+ await MainActor.run { updateUI(with: result) }
42
+ } catch {
43
+ await MainActor.run { showError(error) }
44
+ }
45
+ }
46
+
47
+ // Task group — dynamic parallelism
48
+ func fetchAllUsers(ids: [UUID]) async throws -> [User] {
49
+ try await withThrowingTaskGroup(of: User.self) { group in
50
+ for id in ids {
51
+ group.addTask {
52
+ try await fetchUser(id: id)
53
+ }
54
+ }
55
+
56
+ var users: [User] = []
57
+ for try await user in group {
58
+ users.append(user)
59
+ }
60
+ return users
61
+ }
62
+ }
63
+
64
+ // Task cancellation
65
+ func longRunningProcess() async throws {
66
+ for item in items {
67
+ try Task.checkCancellation() // Throws if cancelled
68
+ await process(item)
69
+ }
70
+ }
71
+
72
+ // Cooperative cancellation
73
+ Task {
74
+ let result = try await longRunningProcess()
75
+ }
76
+ // Later:
77
+ task.cancel() // Cooperative — task must check
78
+ ```
79
+
80
+ ## Actors
81
+
82
+ ```swift
83
+ // Actor — thread-safe mutable state
84
+ actor ImageCache {
85
+ private var cache: [URL: UIImage] = [:]
86
+
87
+ func image(for url: URL) -> UIImage? {
88
+ cache[url]
89
+ }
90
+
91
+ func store(_ image: UIImage, for url: URL) {
92
+ cache[url] = image
93
+ }
94
+
95
+ func clear() {
96
+ cache.removeAll()
97
+ }
98
+ }
99
+
100
+ // Using actors
101
+ let cache = ImageCache()
102
+ let image = await cache.image(for: url) // await required for actor isolation
103
+
104
+ // nonisolated — opt out for non-mutable access
105
+ actor UserStore {
106
+ let id: UUID // Immutable, safe without isolation
107
+
108
+ nonisolated var description: String {
109
+ "UserStore(\(id))"
110
+ }
111
+ }
112
+ ```
113
+
114
+ ## MainActor
115
+
116
+ ```swift
117
+ // MainActor — UI thread safety
118
+ @MainActor
119
+ class UserViewModel: ObservableObject {
120
+ @Published var users: [User] = []
121
+ @Published var isLoading = false
122
+ @Published var error: AppError?
123
+
124
+ func loadUsers() async {
125
+ isLoading = true
126
+ defer { isLoading = false }
127
+
128
+ do {
129
+ users = try await userService.fetchAll()
130
+ } catch {
131
+ self.error = AppError(error)
132
+ }
133
+ }
134
+ }
135
+
136
+ // MainActor.run for one-off UI updates
137
+ func processInBackground() async {
138
+ let result = await heavyComputation()
139
+ await MainActor.run {
140
+ self.displayResult = result
141
+ }
142
+ }
143
+ ```
144
+
145
+ ## Sendable
146
+
147
+ ```swift
148
+ // Sendable — safe to pass across concurrency domains
149
+ struct UserDTO: Sendable {
150
+ let id: UUID
151
+ let name: String
152
+ let email: String
153
+ }
154
+
155
+ // @Sendable closures
156
+ func performAsync(_ work: @Sendable @escaping () async -> Void) {
157
+ Task { await work() }
158
+ }
159
+
160
+ // @unchecked Sendable — manual safety guarantee
161
+ final class ThreadSafeCache: @unchecked Sendable {
162
+ private let lock = NSLock()
163
+ private var storage: [String: Any] = [:]
164
+
165
+ func get(_ key: String) -> Any? {
166
+ lock.lock()
167
+ defer { lock.unlock() }
168
+ return storage[key]
169
+ }
170
+ }
171
+ ```
172
+
173
+ ## AsyncSequence and AsyncStream
174
+
175
+ ```swift
176
+ // AsyncStream for bridging callback APIs
177
+ func notifications(named name: Notification.Name) -> AsyncStream<Notification> {
178
+ AsyncStream { continuation in
179
+ let observer = NotificationCenter.default.addObserver(
180
+ forName: name, object: nil, queue: nil
181
+ ) { notification in
182
+ continuation.yield(notification)
183
+ }
184
+ continuation.onTermination = { _ in
185
+ NotificationCenter.default.removeObserver(observer)
186
+ }
187
+ }
188
+ }
189
+
190
+ // Consuming async sequences
191
+ for await notification in notifications(named: .userDidLogin) {
192
+ handleLogin(notification)
193
+ }
194
+
195
+ // AsyncSequence transformations
196
+ let validUsers = userStream
197
+ .filter { $0.isActive }
198
+ .map { UserViewModel(user: $0) }
199
+ .prefix(10)
200
+ ```
201
+
202
+ ## Rules
203
+
204
+ - No `DispatchQueue.main.async` in new code — use `@MainActor` or `MainActor.run`
205
+ - No completion handlers in new code — use `async`/`await`
206
+ - No `DispatchGroup` — use `TaskGroup`
207
+ - Always check `Task.isCancelled` or call `Task.checkCancellation()` in loops
208
+ - Mark types as `Sendable` when passed across concurrency domains
209
+ - Use actors for shared mutable state, not locks (in new code)
210
+ - `Task {}` is unstructured — prefer structured concurrency (`async let`, `TaskGroup`)
211
+
212
+ ## Anti-Patterns
213
+
214
+ ```swift
215
+ // Never: fire-and-forget tasks without error handling
216
+ Task { try await riskyOperation() } // Errors silently swallowed
217
+ // Use: Task with do/catch
218
+
219
+ // Never: blocking the main thread
220
+ DispatchQueue.main.sync { /* ... */ } // Deadlock risk
221
+ // Use: @MainActor or MainActor.run
222
+
223
+ // Never: capturing self strongly in long-lived tasks
224
+ Task { [self] in await self.process() } // Potential retain cycle
225
+ // Use: Task { [weak self] in await self?.process() }
226
+
227
+ // Never: using GCD for new concurrent code
228
+ DispatchQueue.global().async { /* ... */ }
229
+ // Use: Task { /* ... */ } with async/await
230
+ ```
@@ -0,0 +1,213 @@
1
+ # Swift Error Handling
2
+
3
+ Typed errors, Result, and defensive validation. Make failure states explicit.
4
+
5
+ ## Error Types
6
+
7
+ ```swift
8
+ // Domain-specific errors with associated values
9
+ enum APIError: Error, LocalizedError {
10
+ case networkUnavailable
11
+ case unauthorized
12
+ case notFound(resource: String, id: String)
13
+ case serverError(statusCode: Int, message: String)
14
+ case decodingFailed(type: String, underlying: Error)
15
+ case rateLimited(retryAfter: TimeInterval)
16
+
17
+ var errorDescription: String? {
18
+ switch self {
19
+ case .networkUnavailable:
20
+ "Network connection is unavailable"
21
+ case .unauthorized:
22
+ "Authentication required"
23
+ case .notFound(let resource, let id):
24
+ "\(resource) with ID '\(id)' not found"
25
+ case .serverError(let code, let message):
26
+ "Server error \(code): \(message)"
27
+ case .decodingFailed(let type, let error):
28
+ "Failed to decode \(type): \(error.localizedDescription)"
29
+ case .rateLimited(let retryAfter):
30
+ "Rate limited. Retry after \(retryAfter)s"
31
+ }
32
+ }
33
+ }
34
+ ```
35
+
36
+ ## do/catch
37
+
38
+ ```swift
39
+ // Specific error handling
40
+ func loadUser(id: UUID) async {
41
+ do {
42
+ let user = try await userService.fetch(id: id)
43
+ self.user = user
44
+ } catch let error as APIError {
45
+ switch error {
46
+ case .notFound:
47
+ self.state = .notFound
48
+ case .unauthorized:
49
+ self.state = .needsLogin
50
+ case .networkUnavailable:
51
+ self.state = .offline
52
+ default:
53
+ self.state = .error(error)
54
+ }
55
+ } catch {
56
+ // Catch-all for unexpected errors
57
+ self.state = .error(AppError.unexpected(error))
58
+ }
59
+ }
60
+
61
+ // try? — convert to optional (use when failure is acceptable)
62
+ let cachedImage = try? imageCache.load(key: url.absoluteString)
63
+
64
+ // try! — only when failure is a programmer error
65
+ let regex = try! NSRegularExpression(pattern: "^[a-z]+$")
66
+ ```
67
+
68
+ ## Result Type
69
+
70
+ ```swift
71
+ // Result for synchronous operations
72
+ func validate(email: String) -> Result<Email, ValidationError> {
73
+ guard !email.isEmpty else {
74
+ return .failure(.empty("email"))
75
+ }
76
+ guard email.contains("@") else {
77
+ return .failure(.invalidFormat("email"))
78
+ }
79
+ return .success(Email(rawValue: email))
80
+ }
81
+
82
+ // Pattern matching on Result
83
+ switch validate(email: input) {
84
+ case .success(let email):
85
+ createAccount(email: email)
86
+ case .failure(let error):
87
+ showValidationError(error)
88
+ }
89
+
90
+ // Result with map/flatMap
91
+ let userName = fetchUser(id: userId)
92
+ .map { $0.name }
93
+ .mapError { AppError.network($0) }
94
+ ```
95
+
96
+ ## Guard and Preconditions
97
+
98
+ ```swift
99
+ // Guard — early exit for invalid state
100
+ func processOrder(_ order: Order) throws {
101
+ guard order.items.isEmpty == false else {
102
+ throw OrderError.emptyOrder
103
+ }
104
+ guard order.status == .confirmed else {
105
+ throw OrderError.invalidStatus(order.status)
106
+ }
107
+ guard let paymentMethod = order.paymentMethod else {
108
+ throw OrderError.noPaymentMethod
109
+ }
110
+ // Happy path continues here, all values available
111
+ charge(paymentMethod, for: order)
112
+ }
113
+
114
+ // precondition — programmer errors (removed in -Ounchecked)
115
+ func element(at index: Int) -> Element {
116
+ precondition(index >= 0 && index < count, "Index \(index) out of bounds")
117
+ return storage[index]
118
+ }
119
+
120
+ // assert — debug-only checks
121
+ func configure(retryCount: Int) {
122
+ assert(retryCount > 0, "retryCount must be positive")
123
+ self.maxRetries = retryCount
124
+ }
125
+
126
+ // fatalError — truly impossible states
127
+ func handle(_ state: AppState) {
128
+ switch state {
129
+ case .ready: start()
130
+ case .running: continue_()
131
+ // If new states are added, this will force handling them
132
+ @unknown default:
133
+ fatalError("Unhandled state: \(state)")
134
+ }
135
+ }
136
+ ```
137
+
138
+ ## Typed Throws (Swift 6+)
139
+
140
+ ```swift
141
+ // Typed throws — callers know exact error type
142
+ func parse(json: Data) throws(ParseError) -> Config {
143
+ guard let dict = try? JSONSerialization.jsonObject(with: json) as? [String: Any] else {
144
+ throw .invalidJSON
145
+ }
146
+ guard let name = dict["name"] as? String else {
147
+ throw .missingField("name")
148
+ }
149
+ return Config(name: name)
150
+ }
151
+
152
+ // Caller gets typed error without casting
153
+ do {
154
+ let config = try parse(json: data)
155
+ } catch {
156
+ // error is ParseError, not any Error
157
+ switch error {
158
+ case .invalidJSON: handleInvalidJSON()
159
+ case .missingField(let name): handleMissingField(name)
160
+ }
161
+ }
162
+ ```
163
+
164
+ ## Error Recovery Patterns
165
+
166
+ ```swift
167
+ // Retry with exponential backoff
168
+ func fetchWithRetry<T>(
169
+ maxAttempts: Int = 3,
170
+ operation: () async throws -> T
171
+ ) async throws -> T {
172
+ var lastError: Error?
173
+ for attempt in 0..<maxAttempts {
174
+ do {
175
+ return try await operation()
176
+ } catch {
177
+ lastError = error
178
+ if attempt < maxAttempts - 1 {
179
+ let delay = pow(2.0, Double(attempt))
180
+ try await Task.sleep(for: .seconds(delay))
181
+ }
182
+ }
183
+ }
184
+ throw lastError!
185
+ }
186
+
187
+ // Fallback chain
188
+ func loadAvatar(for user: User) async -> UIImage {
189
+ if let cached = avatarCache[user.id] { return cached }
190
+ if let downloaded = try? await downloadAvatar(user.avatarURL) { return downloaded }
191
+ return UIImage(systemName: "person.circle")!
192
+ }
193
+ ```
194
+
195
+ ## Anti-Patterns
196
+
197
+ ```swift
198
+ // Never: catching and ignoring errors
199
+ do { try operation() } catch { } // Silent failure
200
+ // Use: at minimum, log the error
201
+
202
+ // Never: using try! on fallible operations
203
+ let data = try! Data(contentsOf: fileURL) // Crash on missing file
204
+ // Use: do/try/catch or try? with fallback
205
+
206
+ // Never: throwing generic Error
207
+ throw NSError(domain: "", code: 0) // No context
208
+ // Use: domain-specific error types
209
+
210
+ // Never: error types without context
211
+ enum AppError: Error { case failed } // Useless for debugging
212
+ // Use: associated values with context
213
+ ```