Search

PythonReactSEOPDF
GitHub Skill

system-boundaries

Defining clear boundaries between systems, services, and modules to manage complexity and enable independent evolution.

AmnadTaowsoam☆ 0 Repository stars0 Repository forks

Installation

Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.

View source ↗Guides

Skill instructions

System Boundaries

Overview

System Boundaries define where one system ends and another begins, establishing clear interfaces, ownership, and responsibilities. Well-defined boundaries reduce coupling and enable teams to work independently.

Core Principle: "Strong boundaries enable weak coupling. Define interfaces, not implementations."


1. Why System Boundaries Matter

  • Reduces Coupling: Systems can evolve independently
  • Enables Scaling: Teams can own and scale their systems
  • Clarifies Ownership: Clear who is responsible for what
  • Improves Testability: Easier to test in isolation
  • Facilitates Understanding: Simpler mental models

2. Types of Boundaries

Service Boundaries
┌─────────────────┐     ┌─────────────────┐
│  User Service   │────▶│  Order Service  │
│  (owns users)   │     │  (owns orders)  │
└─────────────────┘     └─────────────────┘
        │                        │
        ▼                        ▼
   Users Table              Orders Table
Module Boundaries (within monolith)
// src/modules/auth/
export interface AuthService {
  login(credentials: Credentials): Promise<Token>;
  verify(token: Token): Promise<User>;
}

// src/modules/orders/
import { AuthService } from '../auth';  // Uses interface, not implementation
Data Boundaries
Each service owns its own database:
- User Service → users_db
- Order Service → orders_db
- Payment Service → payments_db

No cross-database queries allowed!

3. Bounded Contexts (DDD)

## E-commerce System Boundaries

### Sales Context
- **Entities**: Product, Cart, Order
- **Language**: "Add to cart", "Checkout", "Purchase"
- **Owner**: Sales team

### Inventory Context
- **Entities**: Stock, Warehouse, SKU
- **Language**: "Restock", "Allocate", "Reserve"
- **Owner**: Operations team

### Shipping Context
- **Entities**: Shipment, Carrier, Tracking
- **Language**: "Ship", "Deliver", "Track"
- **Owner**: Logistics team

**Note**: "Product" means different things in each context!
- Sales: Product with price, description
- Inventory: Product with stock level, location
- Shipping: Product with weight, dimensions

4. Interface Definition

REST API Boundary
// Public API contract (boundary)
interface OrderAPI {
  POST /orders
  GET /orders/:id
  PUT /orders/:id/cancel
}

// Implementation details (hidden)
class OrderService {
  private database: Database;
  private paymentGateway: PaymentGateway;
  
  // Internal methods not exposed via API
  private validateInventory() { }
  private processPayment() { }
}
Event-Driven Boundary
// Published events (boundary)
interface OrderEvents {
  'order.created': { orderId: string; userId: string; total: number };
  'order.shipped': { orderId: string; trackingNumber: string };
}

// Other services subscribe to events, don't call directly

5. Ownership and Responsibilities

## Service Ownership Matrix

| Service | Team | Owns Data | Provides | Consumes |
|---------|------|-----------|----------|----------|
| User Service | Identity Team | Users, Profiles | User CRUD, Auth | - |
| Order Service | Commerce Team | Orders, Line Items | Order Management | User Service (user validation) |
| Payment Service | Finance Team | Transactions | Payment Processing | Order Service (order details) |
| Notification Service | Platform Team | - | Email/SMS | All services (events) |

6. Anti-Corruption Layer

// External API has different model than our domain
interface ExternalPaymentAPI {
  charge(amount_cents: number, card_token: string): ExternalResponse;
}

// Anti-corruption layer translates
class PaymentAdapter {
  constructor(private external: ExternalPaymentAPI) {}
  
  async processPayment(payment: Payment): Promise<PaymentResult> {
    // Translate our domain model to external API
    const response = await this.external.charge(
      payment.amount * 100,  // dollars to cents
      payment.cardToken
    );
    
    // Translate response back to our domain
    return {
      success: response.status === 'succeeded',
      transactionId: response.id
    };
  }
}

7. Boundary Crossing Patterns

Synchronous (API Call)
// Order Service calls User Service
const user = await userService.getUser(userId);
if (!user) throw new Error('User not found');
Asynchronous (Events)
// Order Service publishes event
eventBus.publish('order.created', { orderId, userId, total });

// Notification Service subscribes
eventBus.subscribe('order.created', async (event) => {
  await sendOrderConfirmationEmail(event.userId, event.orderId);
});
Shared Database (Anti-pattern)
// ❌ DON'T: Order Service directly queries users table
const user = await db.query('SELECT * FROM users WHERE id = ?', [userId]);

// ✅ DO: Call User Service API
const user = await userService.getUser(userId);

8. Boundary Violations

Common Violations
// ❌ Violation: Reaching into another service's database
await orderDb.query('SELECT * FROM users WHERE id = ?', [userId]);

// ❌ Violation: Exposing internal implementation
class OrderService {
  public database: Database;  // Leaking internals
}

// ❌ Violation: Tight coupling
class OrderService {
  constructor(private userService: UserServiceImpl) {}  // Depends on concrete class
}

// ✅ Correct: Use interface
class OrderService {
  constructor(private userService: IUserService) {}  // Depends on interface
}

9. Boundary Testing

// Test boundary with mocks
describe('OrderService', () => {
  it('validates user exists before creating order', async () => {
    const mockUserService = {
      getUser: jest.fn().mockResolvedValue(null)
    };
    
    const orderService = new OrderService(mockUserService);
    
    await expect(
      orderService.createOrder({ userId: '123', items: [] })
    ).rejects.toThrow('User not found');
    
    expect(mockUserService.getUser).toHaveBeenCalledWith('123');
  });
});

10. System Boundaries Checklist

  • Clear Ownership: Each boundary has an owner?
  • Well-Defined Interfaces: APIs/events documented?
  • No Shared Databases: Each service owns its data?
  • Bounded Contexts: Domain language consistent within boundary?
  • Anti-Corruption Layers: External systems isolated?
  • Testable: Can test each boundary independently?
  • Documented: Boundaries documented in architecture diagrams?
  • Enforced: Linting/architecture tests prevent violations?

Related Skills

  • 59-architecture-decision/adr-templates
  • 40-system-resilience/service-mesh
  • 51-contracts-governance/api-contracts

Examples

Read the usage examples in the source repository.

View source ↗

Source history

Indexed on
2026-01-20
Index updated
2026-01-26
Branch
main

Index and sync dates describe this directory. View the source repository for code history.

GitHub ↗

chat Comments (0)

chat_bubble_outline

No comments yet. Be the first to share your thoughts!