@ruyfranca/myskills 1.0.27 → 1.0.29
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.
- package/.agent/skills/cqrs-implementation/SKILL.md +107 -0
- package/.agent/skills/ddd-strategic-design/SKILL.md +70 -0
- package/.agent/skills/ddd-tactical-patterns/SKILL.md +70 -0
- package/.agent/skills/elixir-pro/SKILL.md +89 -0
- package/.agent/skills/event-sourcing-architect/SKILL.md +66 -0
- package/.agent/skills/golang-pro/SKILL.md +121 -0
- package/.agent/skills/kotlin-coroutines-expert/SKILL.md +99 -0
- package/.agent/skills/modern-javascript-patterns/SKILL.md +131 -0
- package/.agent/skills/monorepo-architect/SKILL.md +91 -0
- package/.agent/skills/nextjs-react-expert/SKILL.md +94 -247
- package/.agent/skills/react-patterns/SKILL.md +200 -0
- package/.agent/skills/react-state-management/SKILL.md +147 -0
- package/.agent/skills/ruby-pro/SKILL.md +105 -0
- package/.agent/skills/zod-validation-expert/SKILL.md +132 -0
- package/README.md +41 -20
- package/package.json +1 -1
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cqrs-implementation
|
|
3
|
+
description: "Implement Command Query Responsibility Segregation for scalable architectures. Use when separating read and write models, optimizing query performance, or building event-sourced systems."
|
|
4
|
+
risk: unknown
|
|
5
|
+
source: community
|
|
6
|
+
date_added: "2026-02-27"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# CQRS Implementation
|
|
10
|
+
|
|
11
|
+
Comprehensive guide to implementing CQRS (Command Query Responsibility Segregation) patterns.
|
|
12
|
+
|
|
13
|
+
## Use this skill when
|
|
14
|
+
|
|
15
|
+
- Separating read and write concerns
|
|
16
|
+
- Scaling reads independently from writes
|
|
17
|
+
- Building event-sourced systems
|
|
18
|
+
- Optimizing complex query scenarios
|
|
19
|
+
- Different read/write data models are needed
|
|
20
|
+
- High-performance reporting is required
|
|
21
|
+
|
|
22
|
+
## Do not use this skill when
|
|
23
|
+
|
|
24
|
+
- The domain is simple and CRUD is sufficient
|
|
25
|
+
- You cannot operate separate read/write models
|
|
26
|
+
- Strong immediate consistency is required everywhere
|
|
27
|
+
|
|
28
|
+
## Instructions
|
|
29
|
+
|
|
30
|
+
- Identify read/write workloads and consistency needs.
|
|
31
|
+
- Define command and query models with clear boundaries.
|
|
32
|
+
- Implement read model projections and synchronization.
|
|
33
|
+
- Validate performance, recovery, and failure modes.
|
|
34
|
+
|
|
35
|
+
## Core Concepts
|
|
36
|
+
|
|
37
|
+
### Commands (Write Side)
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
// Command — intent to change state
|
|
41
|
+
interface SubmitOrderCommand {
|
|
42
|
+
orderId: string;
|
|
43
|
+
items: OrderItem[];
|
|
44
|
+
customerId: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Command Handler
|
|
48
|
+
class SubmitOrderHandler {
|
|
49
|
+
async handle(cmd: SubmitOrderCommand): Promise<void> {
|
|
50
|
+
const order = await this.orderRepo.findById(cmd.orderId);
|
|
51
|
+
order.submit(cmd.items);
|
|
52
|
+
await this.orderRepo.save(order);
|
|
53
|
+
await this.eventBus.publish(order.domainEvents);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Queries (Read Side)
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
// Read model — optimized for queries
|
|
62
|
+
interface OrderSummaryView {
|
|
63
|
+
orderId: string;
|
|
64
|
+
customerName: string;
|
|
65
|
+
totalAmount: number;
|
|
66
|
+
status: string;
|
|
67
|
+
createdAt: Date;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Query Handler
|
|
71
|
+
class GetOrderSummaryHandler {
|
|
72
|
+
async handle(orderId: string): Promise<OrderSummaryView> {
|
|
73
|
+
return this.readDb.query(
|
|
74
|
+
'SELECT * FROM order_summaries WHERE order_id = $1',
|
|
75
|
+
[orderId]
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Projection Building
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
// Project events to read model
|
|
85
|
+
class OrderProjection {
|
|
86
|
+
async on(event: OrderSubmitted): Promise<void> {
|
|
87
|
+
await this.readDb.upsert('order_summaries', {
|
|
88
|
+
order_id: event.orderId,
|
|
89
|
+
status: 'submitted',
|
|
90
|
+
submitted_at: event.occurredAt,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Synchronization Strategies
|
|
97
|
+
|
|
98
|
+
| Strategy | Consistency | Complexity |
|
|
99
|
+
|----------|-------------|------------|
|
|
100
|
+
| Synchronous | Strong | High |
|
|
101
|
+
| Async via events | Eventual | Medium |
|
|
102
|
+
| Change Data Capture | Near-real-time | Medium |
|
|
103
|
+
| Scheduled rebuild | Eventual | Low |
|
|
104
|
+
|
|
105
|
+
## Related Skills
|
|
106
|
+
|
|
107
|
+
Works well with: `event-sourcing-architect`, `ddd-tactical-patterns`
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ddd-strategic-design
|
|
3
|
+
description: "Design DDD strategic artifacts including subdomains, bounded contexts, and ubiquitous language for complex business domains."
|
|
4
|
+
risk: safe
|
|
5
|
+
source: self
|
|
6
|
+
tags: "[ddd, strategic-design, bounded-context, ubiquitous-language]"
|
|
7
|
+
date_added: "2026-02-27"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# DDD Strategic Design
|
|
11
|
+
|
|
12
|
+
## Use this skill when
|
|
13
|
+
|
|
14
|
+
- Defining core, supporting, and generic subdomains.
|
|
15
|
+
- Splitting a monolith or service landscape by domain boundaries.
|
|
16
|
+
- Aligning teams and ownership with bounded contexts.
|
|
17
|
+
- Building a shared ubiquitous language with domain experts.
|
|
18
|
+
|
|
19
|
+
## Do not use this skill when
|
|
20
|
+
|
|
21
|
+
- The domain model is stable and already well bounded.
|
|
22
|
+
- You need tactical code patterns only.
|
|
23
|
+
- The task is purely infrastructure or UI oriented.
|
|
24
|
+
|
|
25
|
+
## Instructions
|
|
26
|
+
|
|
27
|
+
1. Extract domain capabilities and classify subdomains.
|
|
28
|
+
2. Define bounded contexts around consistency and ownership.
|
|
29
|
+
3. Establish a ubiquitous language glossary and anti-terms.
|
|
30
|
+
4. Capture context boundaries in ADRs before implementation.
|
|
31
|
+
|
|
32
|
+
## Required artifacts
|
|
33
|
+
|
|
34
|
+
- Subdomain classification table
|
|
35
|
+
- Bounded context catalog
|
|
36
|
+
- Glossary with canonical terms
|
|
37
|
+
- Boundary decisions with rationale
|
|
38
|
+
|
|
39
|
+
## Subdomain Classification
|
|
40
|
+
|
|
41
|
+
| Type | Description | Example |
|
|
42
|
+
|------|-------------|---------|
|
|
43
|
+
| **Core** | Competitive advantage, high complexity | Order management |
|
|
44
|
+
| **Supporting** | Needed but not differentiating | Notifications |
|
|
45
|
+
| **Generic** | Commodity, buy or use SaaS | Authentication |
|
|
46
|
+
|
|
47
|
+
## Bounded Context Patterns
|
|
48
|
+
|
|
49
|
+
### Context Map Relationships
|
|
50
|
+
|
|
51
|
+
| Pattern | When to Use |
|
|
52
|
+
|---------|------------|
|
|
53
|
+
| **Partnership** | Teams must cooperate closely |
|
|
54
|
+
| **Shared Kernel** | Small shared model owned jointly |
|
|
55
|
+
| **Customer-Supplier** | One team depends on the other |
|
|
56
|
+
| **Anti-Corruption Layer** | Protect from legacy/external models |
|
|
57
|
+
| **Published Language** | Well-documented integration protocol |
|
|
58
|
+
|
|
59
|
+
## Examples
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
Use @ddd-strategic-design to map our commerce domain into bounded contexts,
|
|
63
|
+
classify subdomains, and propose team ownership.
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Limitations
|
|
67
|
+
|
|
68
|
+
- This skill does not produce executable code.
|
|
69
|
+
- It cannot infer business truth without stakeholder input.
|
|
70
|
+
- It should be followed by tactical design before implementation.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ddd-tactical-patterns
|
|
3
|
+
description: "Apply DDD tactical patterns in code using entities, value objects, aggregates, repositories, and domain events with explicit invariants."
|
|
4
|
+
risk: safe
|
|
5
|
+
source: self
|
|
6
|
+
tags: "[ddd, tactical, aggregates, value-objects, domain-events]"
|
|
7
|
+
date_added: "2026-02-27"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# DDD Tactical Patterns
|
|
11
|
+
|
|
12
|
+
## Use this skill when
|
|
13
|
+
|
|
14
|
+
- Translating domain rules into code structures.
|
|
15
|
+
- Designing aggregate boundaries and invariants.
|
|
16
|
+
- Refactoring an anemic model into behavior-rich domain objects.
|
|
17
|
+
- Defining repository contracts and domain event boundaries.
|
|
18
|
+
|
|
19
|
+
## Do not use this skill when
|
|
20
|
+
|
|
21
|
+
- You are still defining strategic boundaries.
|
|
22
|
+
- The task is only API documentation or UI layout.
|
|
23
|
+
- Full DDD complexity is not justified.
|
|
24
|
+
|
|
25
|
+
## Instructions
|
|
26
|
+
|
|
27
|
+
1. Identify invariants first and design aggregates around them.
|
|
28
|
+
2. Model immutable value objects for validated concepts.
|
|
29
|
+
3. Keep domain behavior in domain objects, not controllers.
|
|
30
|
+
4. Emit domain events for meaningful state transitions.
|
|
31
|
+
5. Keep repositories at aggregate root boundaries.
|
|
32
|
+
|
|
33
|
+
## Core Building Blocks
|
|
34
|
+
|
|
35
|
+
| Building Block | Description | Key Rule |
|
|
36
|
+
|----------------|-------------|----------|
|
|
37
|
+
| **Entity** | Has identity, mutable | ID never changes |
|
|
38
|
+
| **Value Object** | No identity, immutable | Equality by value |
|
|
39
|
+
| **Aggregate** | Transaction boundary | Only root is public |
|
|
40
|
+
| **Repository** | Collection abstraction | One per aggregate root |
|
|
41
|
+
| **Domain Event** | Fact that happened | Immutable, past tense name |
|
|
42
|
+
| **Domain Service** | Stateless behavior | For cross-aggregate logic |
|
|
43
|
+
|
|
44
|
+
## Example
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
class Order {
|
|
48
|
+
private status: "draft" | "submitted" = "draft";
|
|
49
|
+
|
|
50
|
+
submit(itemsCount: number): void {
|
|
51
|
+
if (itemsCount === 0) throw new Error("Order cannot be submitted empty");
|
|
52
|
+
if (this.status !== "draft") throw new Error("Order already submitted");
|
|
53
|
+
this.status = "submitted";
|
|
54
|
+
this.addEvent(new OrderSubmitted(this.id));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Aggregate Design Rules
|
|
60
|
+
|
|
61
|
+
- Keep aggregates small — focus on invariants
|
|
62
|
+
- Reference other aggregates by ID only
|
|
63
|
+
- Design for eventual consistency between aggregates
|
|
64
|
+
- One transaction = one aggregate
|
|
65
|
+
|
|
66
|
+
## Limitations
|
|
67
|
+
|
|
68
|
+
- This skill does not define deployment architecture.
|
|
69
|
+
- It does not choose databases or transport protocols.
|
|
70
|
+
- It should be paired with testing patterns for invariant coverage.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: elixir-pro
|
|
3
|
+
description: Write idiomatic Elixir code with OTP patterns, supervision trees, and Phoenix LiveView. Masters concurrency, fault tolerance, and distributed systems.
|
|
4
|
+
risk: unknown
|
|
5
|
+
source: community
|
|
6
|
+
date_added: "2026-02-27"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Elixir Pro
|
|
10
|
+
|
|
11
|
+
You are an Elixir expert specializing in concurrent, fault-tolerant, and distributed systems.
|
|
12
|
+
|
|
13
|
+
## Use this skill when
|
|
14
|
+
|
|
15
|
+
- Building concurrent, fault-tolerant Elixir applications
|
|
16
|
+
- Working with OTP patterns (GenServer, Supervisor, Application)
|
|
17
|
+
- Developing Phoenix applications and LiveView real-time features
|
|
18
|
+
- Designing distributed systems with Elixir
|
|
19
|
+
|
|
20
|
+
## Do not use this skill when
|
|
21
|
+
|
|
22
|
+
- The task is unrelated to Elixir/OTP/Phoenix
|
|
23
|
+
- You need a different language or runtime
|
|
24
|
+
|
|
25
|
+
## Focus Areas
|
|
26
|
+
|
|
27
|
+
- OTP patterns (GenServer, Supervisor, Application)
|
|
28
|
+
- Phoenix framework and LiveView real-time features
|
|
29
|
+
- Ecto for database interactions and changesets
|
|
30
|
+
- Pattern matching and guard clauses
|
|
31
|
+
- Concurrent programming with processes and Tasks
|
|
32
|
+
- Distributed systems with nodes and clustering
|
|
33
|
+
- Performance optimization on the BEAM VM
|
|
34
|
+
|
|
35
|
+
## Core Patterns
|
|
36
|
+
|
|
37
|
+
```elixir
|
|
38
|
+
# GenServer example
|
|
39
|
+
defmodule MyWorker do
|
|
40
|
+
use GenServer
|
|
41
|
+
|
|
42
|
+
def start_link(opts), do: GenServer.start_link(__MODULE__, opts, name: __MODULE__)
|
|
43
|
+
def init(state), do: {:ok, state}
|
|
44
|
+
|
|
45
|
+
def handle_call(:get_state, _from, state) do
|
|
46
|
+
{:reply, state, state}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def handle_cast({:update, new_val}, state) do
|
|
50
|
+
{:noreply, Map.put(state, :value, new_val)}
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Supervision tree
|
|
55
|
+
defmodule MyApp.Supervisor do
|
|
56
|
+
use Supervisor
|
|
57
|
+
|
|
58
|
+
def start_link(opts), do: Supervisor.start_link(__MODULE__, opts, name: __MODULE__)
|
|
59
|
+
|
|
60
|
+
def init(_opts) do
|
|
61
|
+
children = [
|
|
62
|
+
MyWorker,
|
|
63
|
+
{Task.Supervisor, name: MyApp.TaskSupervisor}
|
|
64
|
+
]
|
|
65
|
+
Supervisor.init(children, strategy: :one_for_one)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Approach
|
|
71
|
+
|
|
72
|
+
1. Embrace "let it crash" philosophy with proper supervision
|
|
73
|
+
2. Use pattern matching over conditional logic
|
|
74
|
+
3. Design with processes for isolation and concurrency
|
|
75
|
+
4. Leverage immutability for predictable state
|
|
76
|
+
5. Test with ExUnit, focusing on property-based testing
|
|
77
|
+
6. Profile with :observer and :recon for bottlenecks
|
|
78
|
+
|
|
79
|
+
## Output
|
|
80
|
+
|
|
81
|
+
- Idiomatic Elixir following community style guide
|
|
82
|
+
- OTP applications with proper supervision trees
|
|
83
|
+
- Phoenix apps with contexts and clean boundaries
|
|
84
|
+
- ExUnit tests with doctests and async where possible
|
|
85
|
+
- Dialyzer specs for type safety
|
|
86
|
+
- Performance benchmarks with Benchee
|
|
87
|
+
- Telemetry instrumentation for observability
|
|
88
|
+
|
|
89
|
+
Follow Elixir conventions. Design for fault tolerance and horizontal scaling.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: event-sourcing-architect
|
|
3
|
+
description: "Expert in event sourcing, CQRS, and event-driven architecture patterns. Masters event store design, projection building, saga orchestration, and eventual consistency patterns."
|
|
4
|
+
risk: unknown
|
|
5
|
+
source: community
|
|
6
|
+
date_added: "2026-02-27"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Event Sourcing Architect
|
|
10
|
+
|
|
11
|
+
Expert in event sourcing, CQRS, and event-driven architecture patterns. Masters event store design, projection building, saga orchestration, and eventual consistency patterns. Use PROACTIVELY for event-sourced systems, audit trail requirements, or complex domain modeling with temporal queries.
|
|
12
|
+
|
|
13
|
+
## Capabilities
|
|
14
|
+
|
|
15
|
+
- Event store design and implementation
|
|
16
|
+
- CQRS (Command Query Responsibility Segregation) patterns
|
|
17
|
+
- Projection building and read model optimization
|
|
18
|
+
- Saga and process manager orchestration
|
|
19
|
+
- Event versioning and schema evolution
|
|
20
|
+
- Snapshotting strategies for performance
|
|
21
|
+
- Eventual consistency handling
|
|
22
|
+
|
|
23
|
+
## Use this skill when
|
|
24
|
+
|
|
25
|
+
- Building systems requiring complete audit trails
|
|
26
|
+
- Implementing complex business workflows with compensating actions
|
|
27
|
+
- Designing systems needing temporal queries ("what was state at time X")
|
|
28
|
+
- Separating read and write models for performance
|
|
29
|
+
- Building event-driven microservices architectures
|
|
30
|
+
- Implementing undo/redo or time-travel debugging
|
|
31
|
+
|
|
32
|
+
## Do not use this skill when
|
|
33
|
+
|
|
34
|
+
- The domain is simple and CRUD is sufficient
|
|
35
|
+
- You cannot support event store operations or projections
|
|
36
|
+
- Strong immediate consistency is required everywhere
|
|
37
|
+
|
|
38
|
+
## Instructions
|
|
39
|
+
|
|
40
|
+
1. Identify aggregate boundaries and event streams
|
|
41
|
+
2. Design events as immutable facts
|
|
42
|
+
3. Implement command handlers and event application
|
|
43
|
+
4. Build projections for query requirements
|
|
44
|
+
5. Design saga/process managers for cross-aggregate workflows
|
|
45
|
+
6. Implement snapshotting for long-lived aggregates
|
|
46
|
+
7. Set up event versioning strategy
|
|
47
|
+
|
|
48
|
+
## Safety
|
|
49
|
+
|
|
50
|
+
- Never mutate or delete committed events in production.
|
|
51
|
+
- Rebuild projections in staging before running in production.
|
|
52
|
+
|
|
53
|
+
## Best Practices
|
|
54
|
+
|
|
55
|
+
- Events are facts - never delete or modify them
|
|
56
|
+
- Keep events small and focused
|
|
57
|
+
- Version events from day one
|
|
58
|
+
- Design for eventual consistency
|
|
59
|
+
- Use correlation IDs for tracing
|
|
60
|
+
- Implement idempotent event handlers
|
|
61
|
+
- Plan for projection rebuilding
|
|
62
|
+
- Use durable execution for process managers and sagas
|
|
63
|
+
|
|
64
|
+
## Related Skills
|
|
65
|
+
|
|
66
|
+
Works well with: `cqrs-implementation`, `ddd-tactical-patterns`, `saga-orchestration`
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: golang-pro
|
|
3
|
+
description: Master Go 1.21+ with modern patterns, advanced concurrency, performance optimization, and production-ready microservices.
|
|
4
|
+
risk: unknown
|
|
5
|
+
source: community
|
|
6
|
+
date_added: "2026-02-27"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Go Pro
|
|
10
|
+
|
|
11
|
+
You are a Go expert specializing in modern Go 1.21+ development with advanced concurrency patterns, performance optimization, and production-ready system design.
|
|
12
|
+
|
|
13
|
+
## Use this skill when
|
|
14
|
+
|
|
15
|
+
- Building Go services, CLIs, or microservices
|
|
16
|
+
- Designing concurrency patterns and performance optimizations
|
|
17
|
+
- Reviewing Go architecture and production readiness
|
|
18
|
+
|
|
19
|
+
## Do not use this skill when
|
|
20
|
+
|
|
21
|
+
- You need another language or runtime
|
|
22
|
+
- You only need basic Go syntax explanations
|
|
23
|
+
- You cannot change Go tooling or build configuration
|
|
24
|
+
|
|
25
|
+
## Instructions
|
|
26
|
+
|
|
27
|
+
1. Confirm Go version, tooling, and runtime constraints.
|
|
28
|
+
2. Choose concurrency and architecture patterns.
|
|
29
|
+
3. Implement with testing and profiling.
|
|
30
|
+
4. Optimize for latency, memory, and reliability.
|
|
31
|
+
|
|
32
|
+
## Key Capabilities
|
|
33
|
+
|
|
34
|
+
### Concurrency & Parallelism
|
|
35
|
+
|
|
36
|
+
```go
|
|
37
|
+
// Worker pool pattern
|
|
38
|
+
func workerPool(ctx context.Context, jobs <-chan Job, numWorkers int) <-chan Result {
|
|
39
|
+
results := make(chan Result, numWorkers)
|
|
40
|
+
var wg sync.WaitGroup
|
|
41
|
+
|
|
42
|
+
for i := 0; i < numWorkers; i++ {
|
|
43
|
+
wg.Add(1)
|
|
44
|
+
go func() {
|
|
45
|
+
defer wg.Done()
|
|
46
|
+
for job := range jobs {
|
|
47
|
+
select {
|
|
48
|
+
case results <- processJob(ctx, job):
|
|
49
|
+
case <-ctx.Done():
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
go func() {
|
|
57
|
+
wg.Wait()
|
|
58
|
+
close(results)
|
|
59
|
+
}()
|
|
60
|
+
|
|
61
|
+
return results
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Error Handling
|
|
66
|
+
|
|
67
|
+
```go
|
|
68
|
+
// Wrap errors with context
|
|
69
|
+
if err := store.Save(user); err != nil {
|
|
70
|
+
return fmt.Errorf("saving user %s: %w", user.ID, err)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Sentinel errors
|
|
74
|
+
var ErrNotFound = errors.New("not found")
|
|
75
|
+
|
|
76
|
+
// Check wrapped errors
|
|
77
|
+
if errors.Is(err, ErrNotFound) {
|
|
78
|
+
// handle not found
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Testing
|
|
83
|
+
|
|
84
|
+
```go
|
|
85
|
+
func TestCalculate(t *testing.T) {
|
|
86
|
+
cases := []struct {
|
|
87
|
+
name string
|
|
88
|
+
input int
|
|
89
|
+
want int
|
|
90
|
+
}{
|
|
91
|
+
{"positive", 5, 25},
|
|
92
|
+
{"zero", 0, 0},
|
|
93
|
+
{"negative", -3, 9},
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
for _, tc := range cases {
|
|
97
|
+
t.Run(tc.name, func(t *testing.T) {
|
|
98
|
+
got := Calculate(tc.input)
|
|
99
|
+
if got != tc.want {
|
|
100
|
+
t.Errorf("Calculate(%d) = %d, want %d", tc.input, got, tc.want)
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Modern Go Features (1.21+)
|
|
108
|
+
|
|
109
|
+
- Structured logging with `slog` (built-in)
|
|
110
|
+
- Improved type inference for generics
|
|
111
|
+
- `slices` and `maps` packages for common operations
|
|
112
|
+
- `min`, `max`, `clear` built-in functions
|
|
113
|
+
- `errors.Join` for combining errors
|
|
114
|
+
|
|
115
|
+
## Best Practices
|
|
116
|
+
|
|
117
|
+
- Prefer composition over inheritance (embed interfaces)
|
|
118
|
+
- Accept interfaces, return structs
|
|
119
|
+
- Use context for cancellation and deadlines
|
|
120
|
+
- Profile before optimizing (pprof)
|
|
121
|
+
- Use `golangci-lint` with strict config in CI
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: kotlin-coroutines-expert
|
|
3
|
+
description: "Expert patterns for Kotlin Coroutines and Flow, covering structured concurrency, error handling, and testing."
|
|
4
|
+
risk: safe
|
|
5
|
+
source: community
|
|
6
|
+
date_added: "2026-02-27"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Kotlin Coroutines Expert
|
|
10
|
+
|
|
11
|
+
## Overview
|
|
12
|
+
|
|
13
|
+
A guide to mastering asynchronous programming with Kotlin Coroutines. Covers advanced topics like structured concurrency, `Flow` transformations, exception handling, and testing strategies.
|
|
14
|
+
|
|
15
|
+
## When to Use This Skill
|
|
16
|
+
|
|
17
|
+
- Use when implementing asynchronous operations in Kotlin.
|
|
18
|
+
- Use when designing reactive data streams with `Flow`.
|
|
19
|
+
- Use when debugging coroutine cancellations or exceptions.
|
|
20
|
+
- Use when writing unit tests for suspending functions or Flows.
|
|
21
|
+
|
|
22
|
+
## Step-by-Step Guide
|
|
23
|
+
|
|
24
|
+
### 1. Structured Concurrency
|
|
25
|
+
|
|
26
|
+
Always launch coroutines within a defined `CoroutineScope`. Use `coroutineScope` or `supervisorScope` to group concurrent tasks.
|
|
27
|
+
|
|
28
|
+
```kotlin
|
|
29
|
+
suspend fun loadDashboardData(): DashboardData = coroutineScope {
|
|
30
|
+
val userDeferred = async { userRepo.getUser() }
|
|
31
|
+
val settingsDeferred = async { settingsRepo.getSettings() }
|
|
32
|
+
|
|
33
|
+
DashboardData(
|
|
34
|
+
user = userDeferred.await(),
|
|
35
|
+
settings = settingsDeferred.await()
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 2. Exception Handling
|
|
41
|
+
|
|
42
|
+
Use `CoroutineExceptionHandler` for top-level scopes, but rely on `try-catch` within suspending functions for granular control.
|
|
43
|
+
|
|
44
|
+
```kotlin
|
|
45
|
+
val handler = CoroutineExceptionHandler { _, exception ->
|
|
46
|
+
println("Caught $exception")
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
viewModelScope.launch(handler) {
|
|
50
|
+
try {
|
|
51
|
+
riskyOperation()
|
|
52
|
+
} catch (e: IOException) {
|
|
53
|
+
// Handle network error specifically
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### 3. Reactive Streams with Flow
|
|
59
|
+
|
|
60
|
+
Use `StateFlow` for state that needs to be retained, and `SharedFlow` for events.
|
|
61
|
+
|
|
62
|
+
```kotlin
|
|
63
|
+
// Cold Flow (Lazy)
|
|
64
|
+
val searchResults: Flow<List<Item>> = searchQuery
|
|
65
|
+
.debounce(300)
|
|
66
|
+
.flatMapLatest { query -> searchRepo.search(query) }
|
|
67
|
+
.flowOn(Dispatchers.IO)
|
|
68
|
+
|
|
69
|
+
// Hot Flow (State)
|
|
70
|
+
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 4. Parallel Execution with Error Handling
|
|
74
|
+
|
|
75
|
+
```kotlin
|
|
76
|
+
suspend fun fetchDataWithErrorHandling() = supervisorScope {
|
|
77
|
+
val task1 = async {
|
|
78
|
+
try { api.fetchA() } catch (e: Exception) { null }
|
|
79
|
+
}
|
|
80
|
+
val task2 = async { api.fetchB() }
|
|
81
|
+
|
|
82
|
+
// If task2 fails, task1 is NOT cancelled because of supervisorScope
|
|
83
|
+
val result1 = task1.await()
|
|
84
|
+
val result2 = task2.await() // May throw
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Best Practices
|
|
89
|
+
|
|
90
|
+
- ✅ **Do:** Use `Dispatchers.IO` for blocking I/O operations.
|
|
91
|
+
- ✅ **Do:** Cancel scopes when they are no longer needed (e.g., `ViewModel.onCleared`).
|
|
92
|
+
- ✅ **Do:** Use `TestScope` and `runTest` for unit testing coroutines.
|
|
93
|
+
- ❌ **Don't:** Use `GlobalScope`. It breaks structured concurrency and can lead to leaks.
|
|
94
|
+
- ❌ **Don't:** Catch `CancellationException` unless you rethrow it.
|
|
95
|
+
|
|
96
|
+
## Troubleshooting
|
|
97
|
+
|
|
98
|
+
**Problem:** Coroutine test hangs or fails unpredictably.
|
|
99
|
+
**Solution:** Ensure you are using `runTest` and injecting `TestDispatcher` into your classes so you can control virtual time.
|