From harness-claude
Designs microservice boundaries using DDD bounded contexts, functional cohesion, and strategies like subdomain decomposition, business capabilities, and Strangler Fig for monolith migrations.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Design service boundaries using bounded contexts, DDD, and functional cohesion principles.
Guides microservices architecture: decompose monoliths, design service boundaries, implement sagas/CQRS/event sourcing, circuit breakers, API gateways, eventual consistency, resilience patterns, observability.
Designs microservices architectures with service boundaries, event-driven communication, data management, and resilience patterns. For decomposing monoliths and building distributed systems.
Designs microservices architectures using patterns for service boundaries, synchronous/asynchronous communication, data management, and resilience. For decomposing monoliths and building distributed systems.
Share bugs, ideas, or general feedback.
Design service boundaries using bounded contexts, DDD, and functional cohesion principles.
Decomposition strategies — pick the right one:
1. Decompose by Subdomain (DDD approach — start here):
Run event storming → identify bounded contexts → each context is a service candidate
Example domains for an e-commerce platform:
- Order Management: place, cancel, track orders
- Inventory: stock levels, reservations, warehouses
- Catalog: products, prices, descriptions, search
- User Accounts: registration, auth, profile
- Payment: charge, refund, payment methods
- Shipping: carriers, tracking, delivery estimation
- Notifications: email, SMS, push dispatch
2. Decompose by Business Capability:
Map each service to a business capability that can be owned by one team:
Capability → Service → Team
"Process Orders" → OrderService → Order Team
"Manage Inventory" → InventoryService → Inventory Team
"Accept Payments" → PaymentService → Payments Team (often a separate subdomain too)
3. Strangler Fig (for monolith migration):
Don't decompose the monolith in one go — extract incrementally:
1. Identify the highest-value or most change-prone module
2. Put an API gateway/facade in front of the monolith
3. Extract one service at a time behind the facade
4. Redirect routes to the new service gradually
5. Delete the monolith code when the service handles all traffic
Service boundary heuristics:
// GOOD service boundary: high cohesion, low coupling
// OrderService owns everything about an order's lifecycle
class OrderService {
async placeOrder(data: PlaceOrderInput): Promise<Order> {
/* ... */
}
async cancelOrder(orderId: string, reason: string): Promise<void> {
/* ... */
}
async getOrder(orderId: string): Promise<Order> {
/* ... */
}
async listUserOrders(userId: string): Promise<Order[]> {
/* ... */
}
}
// BAD: service that spans multiple domains (too broad)
class BusinessService {
placeOrder() {
/* Order domain */
}
reserveStock() {
/* Inventory domain — should be separate */
}
chargeCard() {
/* Payment domain — should be separate */
}
}
// BAD: service that's too granular (chatty, high coupling)
class OrderStatusService {
// Only manages status — forces callers to compose with OrderService for everything
getStatus(orderId: string): Promise<OrderStatus> {
/* ... */
}
updateStatus(orderId: string, status: OrderStatus): Promise<void> {
/* ... */
}
}
Service communication patterns:
// Synchronous (REST/gRPC) — use for queries and commands needing immediate response
// Order → Payment (charge must succeed before order is confirmed)
const paymentResult = await paymentClient.charge({
orderId: order.id,
amount: order.total,
customerId: order.userId,
});
// Async (events) — use for notifications and eventual consistency
// Order publishes event → Inventory reacts independently
await eventBus.publish('order.placed', {
orderId: order.id,
items: order.items,
});
// Inventory service subscribes and reserves stock asynchronously
Service contract checklist:
interface ServiceContract {
// 1. Clear API boundary — REST, gRPC, or event schema
// 2. Versioned — breaking changes require a new version
// 3. Owned — one team is responsible for this service
// 4. Independent deploy — can deploy without coordinating with others
// 5. Own data — service has its own database, not shared
// 6. Failure-isolated — failure doesn't cascade to callers
}
Service size guidance:
Database per service: Each service must own its data. Never share a database table across services — it creates tight coupling at the data level. Integration happens via APIs and events, not JOINs.
Anti-patterns:
Migration path:
microservices.io/patterns/decomposition/