Claude
Skills
Sign in
Back

deno-ddd

Included with Lifetime
$97 forever

Domain-Driven Design patterns and architecture for Deno TypeScript applications. Use when building complex business logic, implementing bounded contexts, or structuring large-scale Deno applications with clear separation of concerns.

Design

What this skill does


# Domain-Driven Design in Deno

## When to Use This Skill

Use this skill when:
- Building applications with complex business logic
- Implementing hexagonal/clean architecture in Deno
- Structuring large-scale Deno applications
- Separating domain logic from infrastructure
- Working with bounded contexts and aggregates
- Need clear separation between layers

**Prerequisites:** Always read `deno-core.md` first for essential Deno configuration.

---

## Project Philosophy

> **Clean, Modern TypeScript**: Embrace Deno's vision of secure, modern JavaScript/TypeScript development without the baggage of Node.js legacy patterns.

> **Domain-Driven Design**: Follow DDD principles with clear separation between domain logic, application services, and infrastructure concerns.

> **TypeScript-First**: Leverage TypeScript's type system for safety and developer experience. No `any` types in production code.

---

## Core DDD Principles

### Ubiquitous Language
- Use domain terminology consistently in code, docs, and conversations
- Type names, method names, and variables should match business concepts
- Avoid technical jargon in domain layer

### Bounded Contexts
- Each context has its own models and language
- Clear boundaries between contexts
- Explicit translation between contexts

### Layered Architecture
1. **Domain Layer** - Pure business logic, no dependencies
2. **Application Layer** - Use cases, orchestration
3. **Infrastructure Layer** - External services, databases, APIs
4. **API Layer** - HTTP handlers, CLI, GraphQL resolvers

---

## Project Structure

### Recommended Directory Layout

```
src/
├── domain/                    # Domain layer - core business logic
│   ├── entities/              # Domain entities (Memory, User, Order)
│   │   ├── user.ts
│   │   └── order.ts
│   ├── value-objects/         # Immutable values (Email, Money, Status)
│   │   ├── email.ts
│   │   ├── money.ts
│   │   └── order-status.ts
│   ├── aggregates/            # Consistency boundaries
│   │   └── order-aggregate.ts
│   ├── repositories/          # Repository interfaces (ports)
│   │   ├── user-repository.ts
│   │   └── order-repository.ts
│   ├── services/              # Domain services
│   │   └── pricing-service.ts
│   ├── events/                # Domain events
│   │   └── order-created.ts
│   └── errors/                # Domain-specific errors
│       ├── validation-error.ts
│       └── business-rule-error.ts
│
├── application/               # Application layer - use cases
│   ├── use-cases/             # Use case implementations
│   │   ├── create-order.ts
│   │   ├── update-user.ts
│   │   └── process-payment.ts
│   ├── services/              # Application services
│   ├── dto/                   # Data transfer objects
│   │   ├── create-order-dto.ts
│   │   └── user-response-dto.ts
│   └── errors/                # Application-specific errors
│       ├── not-found-error.ts
│       └── unauthorized-error.ts
│
├── infrastructure/            # Infrastructure layer - technical details
│   ├── persistence/           # Database implementations
│   │   ├── postgres/
│   │   │   ├── user-repository-impl.ts
│   │   │   └── order-repository-impl.ts
│   │   └── migrations/
│   ├── external/              # External service integrations
│   │   ├── payment-gateway.ts
│   │   └── email-service.ts
│   ├── logging/               # Structured logging
│   │   └── logger.ts
│   ├── config/                # Configuration
│   │   └── database.ts
│   └── errors/                # Infrastructure errors
│       ├── database-error.ts
│       └── external-api-error.ts
│
├── web/                       # Web/API layer - HTTP entry points
│   ├── controllers/           # Request handlers
│   │   ├── user-controller.ts
│   │   └── order-controller.ts
│   ├── middleware/            # HTTP middleware
│   │   ├── auth.ts
│   │   ├── validation.ts
│   │   ├── error-handler.ts
│   │   └── logging.ts
│   ├── routes/                # Route definitions
│   │   ├── user-routes.ts
│   │   └── order-routes.ts
│   └── server.ts              # HTTP server setup
│
└── shared/                    # Shared kernel
    ├── types/
    │   └── result.ts
    └── utils/
        └── validation.ts

tests/
├── domain/                    # Domain tests (unit)
│   ├── entities/
│   │   └── user.test.ts
│   └── value-objects/
│       └── email.test.ts
├── application/               # Application tests (integration)
│   └── use-cases/
│       └── create-order.test.ts
└── e2e/                       # End-to-end tests
    └── order-workflow.test.ts
```

### Import Map Configuration

Configure `deno.json` for clean imports across all layers:

```json
{
  "imports": {
    "@/": "./src/",
    "@/domain/": "./src/domain/",
    "@/application/": "./src/application/",
    "@/infrastructure/": "./src/infrastructure/",
    "@/web/": "./src/web/",
    "@/shared/": "./src/shared/"
  }
}
```

---

## Layer Dependencies

Understanding and enforcing layer dependencies is critical for maintaining a clean DDD architecture.

### Allowed Dependencies

- **`domain`** → (no external dependencies - pure business logic)
- **`application`** → `domain`
- **`infrastructure`** → `domain` + `application`
- **`web`** (or `api`) → `domain` + `application` + `infrastructure`

### Forbidden Dependencies

**NEVER allow these dependencies:**
- **`domain`** → `application`, `infrastructure`, `web`
- **`application`** → `infrastructure`, `web`
- **`infrastructure`** → `web`

### Dependency Flow Visualization

```
    ┌─────────────┐
    │     web     │  (HTTP handlers, routes, middleware)
    └──────┬──────┘
           │
    ┌──────▼──────┐
    │infrastructure│  (Database, external APIs)
    └──────┬──────┘
           │
    ┌──────▼──────┐
    │ application │  (Use cases, orchestration)
    └──────┬──────┘
           │
    ┌──────▼──────┐
    │   domain    │  (Entities, value objects, business rules)
    └─────────────┘
```

**Key Principle:** Dependencies flow inward. Inner layers have no knowledge of outer layers.

---

## Domain Layer

### Entities

Entities have identity and lifecycle. Use classes with private constructors.

```typescript
// src/domain/entities/user.ts
import type { Email } from "@/domain/value-objects/email.ts";
import type { UserId } from "@/domain/value-objects/user-id.ts";

export class User {
  private constructor(
    private readonly id: UserId,
    private name: string,
    private email: Email,
    private readonly createdAt: Date,
  ) {}

  // Factory method - ensures valid construction
  static create(name: string, email: Email): User {
    if (name.trim().length === 0) {
      throw new Error("User name cannot be empty");
    }
    return new User(
      UserId.generate(),
      name,
      email,
      new Date(),
    );
  }

  // Reconstruct from persistence
  static reconstitute(
    id: UserId,
    name: string,
    email: Email,
    createdAt: Date,
  ): User {
    return new User(id, name, email, createdAt);
  }

  // Business logic methods
  changeName(newName: string): void {
    if (newName.trim().length === 0) {
      throw new Error("User name cannot be empty");
    }
    this.name = newName;
  }

  // Getters
  getId(): UserId { return this.id; }
  getName(): string { return this.name; }
  getEmail(): Email { return this.email; }
  getCreatedAt(): Date { return this.createdAt; }
}
```

### Value Objects

Value objects have no identity, compared by value.

```typescript
// src/domain/value-objects/email.ts
export class Email {
  private constructor(private readonly value: string) {}

  static create(value: string): Email {
    if (!Email.isValid(value)) {
      throw new Error(`Invalid email: ${value}`);
    }
    return new Email(value.toLowerCase());
  }

  private static isValid(value: string): boolean {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(value);
  }

  getValue(): string { return this.value; }
  equals(other: Email): boolean { return this.value === other.value; }
  
Files: 1
Size: 18.3 KB
Complexity: 22/100
Category: Design

Related in Design