agentic-team-templates 0.13.2 → 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,348 @@
1
+ # TypeScript Deep Dive
2
+
3
+ Advanced type system mastery. Conditional types, mapped types, type-level programming, and runtime boundary validation.
4
+
5
+ This builds on the type safety foundations in overview.md. That file covers discriminated unions, branded types, and const assertions. This file goes deeper.
6
+
7
+ ## Generics — Beyond the Basics
8
+
9
+ ```typescript
10
+ // Constrained generics
11
+ function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
12
+ return obj[key];
13
+ }
14
+
15
+ // Generic with defaults
16
+ type Result<T, E = Error> =
17
+ | { ok: true; value: T }
18
+ | { ok: false; error: E };
19
+
20
+ // Multiple constraints
21
+ function merge<T extends object, U extends object>(a: T, b: U): T & U {
22
+ return { ...a, ...b };
23
+ }
24
+
25
+ // Generic factory functions
26
+ function createStore<T>(initial: T) {
27
+ let state = initial;
28
+ return {
29
+ get: (): T => state,
30
+ set: (next: T): void => { state = next; },
31
+ update: (fn: (current: T) => T): void => { state = fn(state); },
32
+ };
33
+ }
34
+ // Type is inferred from usage — no annotation needed at call site
35
+ const counter = createStore(0); // Store<number>
36
+ const users = createStore<User[]>([]); // Explicit when needed
37
+ ```
38
+
39
+ ## Conditional Types
40
+
41
+ ```typescript
42
+ // Basic conditional
43
+ type IsString<T> = T extends string ? true : false;
44
+
45
+ // Extract and Exclude (built-in, but understand how they work)
46
+ type Extract<T, U> = T extends U ? T : never;
47
+ type Exclude<T, U> = T extends U ? never : T;
48
+
49
+ // Practical: extract function return types from a module
50
+ type ApiMethods = {
51
+ getUser: (id: string) => Promise<User>;
52
+ createUser: (data: CreateUserInput) => Promise<User>;
53
+ deleteUser: (id: string) => Promise<void>;
54
+ };
55
+
56
+ type ApiReturnTypes = {
57
+ [K in keyof ApiMethods]: ApiMethods[K] extends (...args: any[]) => infer R ? R : never;
58
+ };
59
+ // { getUser: Promise<User>; createUser: Promise<User>; deleteUser: Promise<void> }
60
+
61
+ // Unwrap Promise
62
+ type Awaited<T> = T extends Promise<infer U> ? Awaited<U> : T;
63
+ type UserResult = Awaited<Promise<Promise<User>>>; // User
64
+
65
+ // Distributive conditional types — union members are distributed
66
+ type ToArray<T> = T extends unknown ? T[] : never;
67
+ type Result = ToArray<string | number>; // string[] | number[]
68
+
69
+ // Prevent distribution with tuple wrapping
70
+ type ToArrayNonDist<T> = [T] extends [unknown] ? T[] : never;
71
+ type Result2 = ToArrayNonDist<string | number>; // (string | number)[]
72
+ ```
73
+
74
+ ## Mapped Types
75
+
76
+ ```typescript
77
+ // Transform all properties
78
+ type Readonly<T> = { readonly [K in keyof T]: T[K] };
79
+ type Partial<T> = { [K in keyof T]?: T[K] };
80
+ type Nullable<T> = { [K in keyof T]: T[K] | null };
81
+
82
+ // Key remapping (TypeScript 4.1+)
83
+ type Getters<T> = {
84
+ [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
85
+ };
86
+
87
+ type UserGetters = Getters<{ name: string; age: number }>;
88
+ // { getName: () => string; getAge: () => number }
89
+
90
+ // Filter keys by value type
91
+ type PickByType<T, V> = {
92
+ [K in keyof T as T[K] extends V ? K : never]: T[K];
93
+ };
94
+
95
+ type StringFields = PickByType<User, string>;
96
+ // Only string-typed fields from User
97
+
98
+ // Deep mapped types
99
+ type DeepReadonly<T> = {
100
+ readonly [K in keyof T]: T[K] extends object
101
+ ? T[K] extends Function
102
+ ? T[K]
103
+ : DeepReadonly<T[K]>
104
+ : T[K];
105
+ };
106
+
107
+ type DeepPartial<T> = {
108
+ [K in keyof T]?: T[K] extends object
109
+ ? T[K] extends Function
110
+ ? T[K]
111
+ : DeepPartial<T[K]>
112
+ : T[K];
113
+ };
114
+ ```
115
+
116
+ ## Template Literal Types
117
+
118
+ ```typescript
119
+ // Type-safe string manipulation
120
+ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
121
+ type ApiPath = `/api/v1/${string}`;
122
+ type Route = `${HttpMethod} ${ApiPath}`;
123
+
124
+ // Extract route parameters
125
+ type ExtractParams<T extends string> =
126
+ T extends `${string}:${infer Param}/${infer Rest}`
127
+ ? Param | ExtractParams<`/${Rest}`>
128
+ : T extends `${string}:${infer Param}`
129
+ ? Param
130
+ : never;
131
+
132
+ type Params = ExtractParams<'/users/:userId/posts/:postId'>;
133
+ // "userId" | "postId"
134
+
135
+ // Type-safe event emitter
136
+ type EventHandler<T extends string> = `on${Capitalize<T>}`;
137
+ type ClickHandler = EventHandler<'click'>; // "onClick"
138
+
139
+ // Dot-notation paths for nested objects
140
+ type DotPath<T, Prefix extends string = ''> = T extends object
141
+ ? {
142
+ [K in keyof T & string]: T[K] extends object
143
+ ? `${Prefix}${K}` | DotPath<T[K], `${Prefix}${K}.`>
144
+ : `${Prefix}${K}`;
145
+ }[keyof T & string]
146
+ : never;
147
+
148
+ type UserPaths = DotPath<{ name: string; address: { city: string; zip: string } }>;
149
+ // "name" | "address" | "address.city" | "address.zip"
150
+ ```
151
+
152
+ ## Type Predicates and Assertion Functions
153
+
154
+ ```typescript
155
+ // Type predicates — custom narrowing functions
156
+ function isUser(value: unknown): value is User {
157
+ return (
158
+ typeof value === 'object' &&
159
+ value !== null &&
160
+ 'id' in value &&
161
+ typeof (value as Record<string, unknown>).id === 'string' &&
162
+ 'email' in value &&
163
+ typeof (value as Record<string, unknown>).email === 'string'
164
+ );
165
+ }
166
+
167
+ // Works in filter — TypeScript narrows the array type
168
+ const users: User[] = mixedArray.filter(isUser);
169
+
170
+ // Assertion functions — throw or narrow
171
+ function assertUser(value: unknown): asserts value is User {
172
+ if (!isUser(value)) {
173
+ throw new TypeError('Expected User');
174
+ }
175
+ }
176
+
177
+ // After calling assertUser, TypeScript knows value is User
178
+ assertUser(data);
179
+ data.email; // OK — narrowed to User
180
+
181
+ // Type predicate for discriminated unions
182
+ function isSuccess<T>(result: Result<T>): result is { ok: true; value: T } {
183
+ return result.ok;
184
+ }
185
+ ```
186
+
187
+ ## satisfies Operator
188
+
189
+ ```typescript
190
+ // Validate a type without widening — the best of both worlds
191
+ const palette = {
192
+ red: [255, 0, 0],
193
+ green: '#00ff00',
194
+ blue: [0, 0, 255],
195
+ } satisfies Record<string, string | readonly number[]>;
196
+
197
+ // palette.red is number[] (not string | number[])
198
+ // palette.green is string (not string | number[])
199
+ // But TypeScript verified it matches Record<string, string | number[]>
200
+
201
+ // Route config example
202
+ const routes = {
203
+ home: { path: '/', component: HomePage },
204
+ about: { path: '/about', component: AboutPage },
205
+ user: { path: '/users/:id', component: UserPage },
206
+ } satisfies Record<string, { path: string; component: React.ComponentType }>;
207
+
208
+ // routes.home.path is the literal "/" — not widened to string
209
+ ```
210
+
211
+ ## Runtime Boundary Validation
212
+
213
+ ```typescript
214
+ // Types disappear at runtime. Validate at every I/O boundary.
215
+ import { z } from 'zod';
216
+
217
+ // Schema is the single source of truth — infer the type from it
218
+ const UserSchema = z.object({
219
+ id: z.string().uuid(),
220
+ name: z.string().min(1).max(200),
221
+ email: z.string().email(),
222
+ role: z.enum(['admin', 'user', 'viewer']),
223
+ createdAt: z.string().datetime(),
224
+ });
225
+
226
+ type User = z.infer<typeof UserSchema>;
227
+
228
+ // Validate at boundaries
229
+ async function handleCreateUser(req: Request): Promise<Response> {
230
+ const body = await req.json();
231
+ const parsed = UserSchema.safeParse(body);
232
+ if (!parsed.success) {
233
+ return Response.json(
234
+ { errors: parsed.error.flatten().fieldErrors },
235
+ { status: 400 },
236
+ );
237
+ }
238
+ // parsed.data is fully typed User
239
+ const user = await db.users.create(parsed.data);
240
+ return Response.json(user, { status: 201 });
241
+ }
242
+
243
+ // Validate environment variables at startup — fail fast
244
+ const EnvSchema = z.object({
245
+ DATABASE_URL: z.string().url(),
246
+ JWT_SECRET: z.string().min(32),
247
+ PORT: z.coerce.number().int().positive().default(3000),
248
+ });
249
+ export const env = EnvSchema.parse(process.env);
250
+
251
+ // Validate external API responses — don't trust the network
252
+ const ExternalUserSchema = z.object({
253
+ id: z.number(),
254
+ login: z.string(),
255
+ avatar_url: z.string().url(),
256
+ });
257
+
258
+ async function fetchGitHubUser(username: string) {
259
+ const response = await fetch(`https://api.github.com/users/${username}`);
260
+ const data = await response.json();
261
+ return ExternalUserSchema.parse(data); // Throws if shape is wrong
262
+ }
263
+ ```
264
+
265
+ ## Declaration Files and Library Types
266
+
267
+ ```typescript
268
+ // Augment third-party types
269
+ declare module 'express' {
270
+ interface Request {
271
+ user?: AuthenticatedUser;
272
+ requestId: string;
273
+ }
274
+ }
275
+
276
+ // Augment global types
277
+ declare global {
278
+ interface Window {
279
+ __APP_CONFIG__: AppConfig;
280
+ }
281
+ }
282
+
283
+ // Type-only imports (tree-shakeable, explicit intent)
284
+ import type { User } from './types.js';
285
+
286
+ // For library authors: ensure .d.ts files are generated
287
+ // tsconfig.json: "declaration": true, "declarationMap": true
288
+ // package.json: "types": "./dist/index.d.ts"
289
+ ```
290
+
291
+ ## Utility Patterns
292
+
293
+ ```typescript
294
+ // Make specific keys required
295
+ type WithRequired<T, K extends keyof T> = T & Required<Pick<T, K>>;
296
+ type UserWithEmail = WithRequired<Partial<User>, 'email'>;
297
+
298
+ // Make specific keys optional
299
+ type WithOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
300
+ type UpdateUser = WithOptional<User, 'id' | 'createdAt'>;
301
+
302
+ // Strict extract for exhaustive checking
303
+ type StrictExtract<T, U extends T> = Extract<T, U>;
304
+
305
+ // Non-empty array type
306
+ type NonEmptyArray<T> = [T, ...T[]];
307
+ function first<T>(arr: NonEmptyArray<T>): T {
308
+ return arr[0]; // No undefined — guaranteed at least one element
309
+ }
310
+
311
+ // Exact types (prevent excess properties in specific contexts)
312
+ type Exact<T, Shape> = T extends Shape
313
+ ? Exclude<keyof T, keyof Shape> extends never
314
+ ? T
315
+ : never
316
+ : never;
317
+ ```
318
+
319
+ ## Anti-Patterns
320
+
321
+ ```typescript
322
+ // Never: any
323
+ function process(data: any) { } // Type checker disabled entirely
324
+ // Use: unknown, then narrow with type guards or Zod
325
+
326
+ // Never: as for silencing errors
327
+ const user = data as User; // What if data is garbage?
328
+ // Use: runtime validation, then the type follows
329
+
330
+ // Never: enums (they generate runtime code and have surprising behavior)
331
+ enum Status { Active, Inactive } // 0, 1 — not "Active", "Inactive"
332
+ // Use: string literal unions
333
+ type Status = 'active' | 'inactive';
334
+
335
+ // Never: non-null assertion (!) without proof
336
+ user!.email; // Runtime NPE waiting to happen
337
+ // Use: if (user) { user.email }
338
+
339
+ // Never: @ts-ignore without explanation
340
+ // @ts-ignore
341
+ brokenCode();
342
+ // Use: @ts-expect-error — explanation of why this is necessary
343
+ // At minimum, @ts-expect-error will fail if the error is fixed (unlike @ts-ignore)
344
+
345
+ // Never: interface for unions or mapped types (use type alias)
346
+ // Interfaces are for object shapes that may be extended/implemented
347
+ // Type aliases are for unions, intersections, mapped types, conditional types
348
+ ```
@@ -1,6 +1,8 @@
1
- # JavaScript Expert Development Guide
1
+ # JavaScript & TypeScript Expert Development Guide
2
2
 
3
- Comprehensive guidelines for principal-level JavaScript engineering across all runtimes, frameworks, and paradigms.
3
+ Comprehensive guidelines for principal-level JavaScript and TypeScript engineering across all runtimes, frameworks, and paradigms.
4
+
5
+ **This template covers both JavaScript and TypeScript.** TypeScript is the default — all code is written in strict TypeScript. Advanced type system patterns (conditional types, mapped types, generics, runtime validation) are included.
4
6
 
5
7
  ---
6
8
 
@@ -10,7 +12,7 @@ This guide applies to:
10
12
  - Node.js services, CLIs, and tooling
11
13
  - React, Vue, Angular, Svelte, and other UI frameworks
12
14
  - Vanilla JavaScript and Web APIs
13
- - TypeScript (strict mode, always)
15
+ - TypeScript (strict mode, always) — including advanced type system patterns
14
16
  - Build tools, bundlers, and transpilers
15
17
  - Testing at every level (unit, integration, E2E, performance)
16
18
 
@@ -76,6 +78,35 @@ const EVENTS = ['click', 'keydown', 'submit'] as const;
76
78
  type EventName = (typeof EVENTS)[number];
77
79
  ```
78
80
 
81
+ ### TypeScript Deep Dive
82
+
83
+ Advanced type system patterns beyond the basics:
84
+
85
+ ```typescript
86
+ // Conditional types
87
+ type Awaited<T> = T extends Promise<infer U> ? Awaited<U> : T;
88
+
89
+ // Mapped types with key remapping
90
+ type Getters<T> = {
91
+ [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
92
+ };
93
+
94
+ // Template literal type extraction
95
+ type ExtractParams<T extends string> =
96
+ T extends `${string}:${infer Param}/${infer Rest}`
97
+ ? Param | ExtractParams<`/${Rest}`>
98
+ : T extends `${string}:${infer Param}` ? Param : never;
99
+
100
+ // satisfies — validate without widening
101
+ const config = { port: 3000, host: 'localhost' } satisfies Record<string, string | number>;
102
+ // config.port is still number, not string | number
103
+
104
+ // Runtime boundary validation with Zod
105
+ const UserSchema = z.object({ id: z.string().uuid(), email: z.string().email() });
106
+ type User = z.infer<typeof UserSchema>;
107
+ // Types disappear at runtime — validate at every I/O boundary
108
+ ```
109
+
79
110
  ### Functional Patterns
80
111
 
81
112
  ```typescript
@@ -0,0 +1,237 @@
1
+ # Kotlin Coroutines
2
+
3
+ Structured concurrency is the law. Every coroutine has a scope. Every scope has a lifecycle.
4
+
5
+ ## Fundamentals
6
+
7
+ ```kotlin
8
+ // Coroutines are lightweight — thousands are cheap
9
+ suspend fun fetchUser(id: UserId): User {
10
+ return userRepository.findById(id)
11
+ ?: throw NotFoundException("User", id.value)
12
+ }
13
+
14
+ // suspend functions can only be called from coroutines or other suspend functions
15
+ // They mark suspension points — where the function may pause and resume
16
+ ```
17
+
18
+ ## Structured Concurrency
19
+
20
+ ```kotlin
21
+ // Every coroutine lives in a scope — when the scope cancels, all children cancel
22
+ class UserService(
23
+ private val userRepo: UserRepository,
24
+ private val emailService: EmailService,
25
+ ) {
26
+ // CoroutineScope tied to service lifecycle
27
+ suspend fun register(request: CreateUserRequest): User {
28
+ val user = userRepo.create(request)
29
+ // This child coroutine is tied to the caller's scope
30
+ emailService.sendWelcome(user.email)
31
+ return user
32
+ }
33
+ }
34
+
35
+ // Parallel decomposition with coroutineScope
36
+ suspend fun loadDashboard(userId: UserId): Dashboard = coroutineScope {
37
+ val userDeferred = async { userService.findById(userId) }
38
+ val ordersDeferred = async { orderService.findRecent(userId) }
39
+ val statsDeferred = async { statsService.forUser(userId) }
40
+
41
+ Dashboard(
42
+ user = userDeferred.await(),
43
+ orders = ordersDeferred.await(),
44
+ stats = statsDeferred.await()
45
+ )
46
+ }
47
+ // If any async fails, ALL are cancelled — no orphaned work
48
+ ```
49
+
50
+ ## Dispatchers
51
+
52
+ ```kotlin
53
+ // Dispatchers.IO — blocking I/O (database, file, network)
54
+ withContext(Dispatchers.IO) {
55
+ database.query(sql)
56
+ }
57
+
58
+ // Dispatchers.Default — CPU-intensive computation
59
+ withContext(Dispatchers.Default) {
60
+ data.map { expensiveTransform(it) }
61
+ }
62
+
63
+ // Dispatchers.Main — UI thread (Android)
64
+ withContext(Dispatchers.Main) {
65
+ updateUI(result)
66
+ }
67
+
68
+ // Never create custom thread pools unless you have a specific reason
69
+ // The built-in dispatchers are well-tuned
70
+ ```
71
+
72
+ ## Flow
73
+
74
+ ```kotlin
75
+ // Cold asynchronous stream — values emitted on demand
76
+ fun observeUsers(): Flow<List<User>> = flow {
77
+ while (true) {
78
+ emit(userRepository.findAll())
79
+ delay(5.seconds)
80
+ }
81
+ }
82
+
83
+ // Operators
84
+ val activeUserNames: Flow<String> = observeUsers()
85
+ .map { users -> users.filter { it.isActive } }
86
+ .flatMapConcat { users -> users.asFlow() }
87
+ .map { it.name }
88
+ .distinctUntilChanged()
89
+
90
+ // StateFlow — hot observable with current value (replaces LiveData)
91
+ class UserViewModel : ViewModel() {
92
+ private val _state = MutableStateFlow<UiState>(UiState.Loading)
93
+ val state: StateFlow<UiState> = _state.asStateFlow()
94
+
95
+ fun loadUser(id: UserId) {
96
+ viewModelScope.launch {
97
+ _state.value = UiState.Loading
98
+ try {
99
+ val user = userService.findById(id)
100
+ _state.value = UiState.Success(user)
101
+ } catch (e: Exception) {
102
+ _state.value = UiState.Error(e.message ?: "Unknown error")
103
+ }
104
+ }
105
+ }
106
+ }
107
+
108
+ // SharedFlow — hot stream for events (no replay by default)
109
+ class EventBus {
110
+ private val _events = MutableSharedFlow<AppEvent>()
111
+ val events: SharedFlow<AppEvent> = _events.asSharedFlow()
112
+
113
+ suspend fun emit(event: AppEvent) = _events.emit(event)
114
+ }
115
+
116
+ // Collecting flows
117
+ lifecycleScope.launch {
118
+ viewModel.state.collect { state ->
119
+ when (state) {
120
+ is UiState.Loading -> showLoading()
121
+ is UiState.Success -> showUser(state.user)
122
+ is UiState.Error -> showError(state.message)
123
+ }
124
+ }
125
+ }
126
+ ```
127
+
128
+ ## Cancellation
129
+
130
+ ```kotlin
131
+ // Cooperative cancellation — coroutines must check for cancellation
132
+ suspend fun processItems(items: List<Item>) {
133
+ for (item in items) {
134
+ ensureActive() // Throws CancellationException if cancelled
135
+ process(item)
136
+ }
137
+ }
138
+
139
+ // All suspend functions in kotlinx.coroutines are cancellable
140
+ // delay(), yield(), withContext(), etc. check for cancellation
141
+
142
+ // CancellationException is special — it doesn't propagate as failure
143
+ // Use it for normal cancellation, not for errors
144
+
145
+ // Timeout
146
+ val result = withTimeout(5.seconds) {
147
+ fetchDataFromNetwork()
148
+ }
149
+
150
+ // Timeout with null instead of exception
151
+ val result = withTimeoutOrNull(5.seconds) {
152
+ fetchDataFromNetwork()
153
+ }
154
+ ```
155
+
156
+ ## Exception Handling
157
+
158
+ ```kotlin
159
+ // CoroutineExceptionHandler — last resort for uncaught exceptions
160
+ val handler = CoroutineExceptionHandler { _, exception ->
161
+ logger.error("Uncaught coroutine exception", exception)
162
+ }
163
+
164
+ // supervisorScope — child failure doesn't cancel siblings
165
+ suspend fun fetchAllData(): DashboardData = supervisorScope {
166
+ val user = async { fetchUser() }
167
+ val orders = async { fetchOrders() } // If this fails...
168
+ val stats = async { fetchStats() } // ...this continues
169
+
170
+ DashboardData(
171
+ user = user.await(),
172
+ orders = runCatching { orders.await() }.getOrDefault(emptyList()),
173
+ stats = runCatching { stats.await() }.getOrNull()
174
+ )
175
+ }
176
+
177
+ // try-catch in coroutines
178
+ launch {
179
+ try {
180
+ riskyOperation()
181
+ } catch (e: Exception) {
182
+ if (e is CancellationException) throw e // Never catch cancellation
183
+ logger.error("Operation failed", e)
184
+ }
185
+ }
186
+ ```
187
+
188
+ ## Channels
189
+
190
+ ```kotlin
191
+ // Producer-consumer with bounded channel
192
+ val channel = Channel<Event>(capacity = Channel.BUFFERED)
193
+
194
+ // Producer
195
+ launch {
196
+ for (event in events) {
197
+ channel.send(event) // Suspends if buffer is full
198
+ }
199
+ channel.close()
200
+ }
201
+
202
+ // Consumer
203
+ launch {
204
+ for (event in channel) { // Iterates until channel is closed
205
+ process(event)
206
+ }
207
+ }
208
+
209
+ // Fan-out: multiple consumers from one channel
210
+ repeat(workerCount) {
211
+ launch { for (event in channel) process(event) }
212
+ }
213
+ ```
214
+
215
+ ## Anti-Patterns
216
+
217
+ ```kotlin
218
+ // Never: GlobalScope
219
+ GlobalScope.launch { } // No lifecycle, no cancellation, leaks coroutines
220
+ // Use: viewModelScope, lifecycleScope, or a custom CoroutineScope
221
+
222
+ // Never: runBlocking in production code (except main() or tests)
223
+ runBlocking { fetchData() } // Blocks the thread, defeats the purpose
224
+ // Use: suspend functions all the way up
225
+
226
+ // Never: catching CancellationException without rethrowing
227
+ catch (e: Exception) { log(e) } // Swallows cancellation!
228
+ // Use: catch (e: Exception) { if (e is CancellationException) throw e; log(e) }
229
+
230
+ // Never: launch without error handling
231
+ launch { riskyWork() } // Exception silently crashes
232
+ // Use: launch with try-catch or CoroutineExceptionHandler
233
+
234
+ // Never: Thread.sleep() in coroutines
235
+ Thread.sleep(1000) // Blocks the thread
236
+ // Use: delay(1000) // Suspends without blocking
237
+ ```