Dive Into Domain-Driven Design with a Cozy Online Bookstore Example in TypeScript

Explore how to apply Domain-Driven Design (DDD) principles to build a scalable online bookstore using TypeScript. This guide covers key concepts, models, and a practical folder structure for optimal organization.

Dive Into Domain-Driven Design with a Cozy Online Bookstore Example in TypeScript
Photo by AltumCode / Unsplash

Hey there! Ever heard about Domain-Driven Design (DDD)? It’s a super handy method that helps you design your software to perfectly match the business you're dealing with. Today, we're going to take a friendly stroll through the world of DDD using a fun example—an online bookstore. Plus, we’ll code a bit in TypeScript to see how it all comes alive.

Getting Our Heads Around Domain-Driven Design

Imagine DDD as a tailor crafting a bespoke suit that fits your business just right. This approach gets you thinking deeply about the needs and complexities of the business domain you're working in. Here’s a quick peek at some key ideas:

  • Ubiquitous Language: This is like the secret handshake or lingo that everyone in your project understands, keeping everyone on the same page.
  • Entities and Value Objects: Entities are like your friends with names, you know them no matter where they are or what they're up to. Value Objects are more like your favorite snacks—important but not individually distinct.
  • Aggregates: These are clusters of objects that you treat as a cohesive whole.
  • Repositories: Think of these as special recipe books where you keep your secret sauces or code snippets to access data sources.
  • Domain Events: These are important moments worth celebrating or noting, like sending out an invite when a new book release drops.

Our Project: A Snug Little Online Bookstore

Let's put our DDD hats on and design a comfy little online bookstore. We'll manage books, customers, and their orders. Here’s how we can map it out:

Step 1: Craft Our Ubiquitous Language

  • Book: A book with a title, an author, an ISBN, and a price tag.
  • Customer: Someone who loves reading and has a unique ID, name, and email.
  • Order: A happy parcel of books a customer wants to buy.
  • Shopping Cart: A collection where our customers stash their soon-to-be treasures (books).

Step 2: Sketch Out Our Models in TypeScript

Let’s jump right into some TypeScript to see how we might model these ideas:

class Book {
    constructor(
        public ISBN: string,
        public title: string,
        public author: string,
        public price: number
    ) {}
}

class OrderItem {
    constructor(
        public book: Book,
        public quantity: number
    ) {
        if (quantity < 1) {
            throw new Error("Quantity must be at least 1.");
        }
    }

    get total() {
        return this.book.price * this.quantity;
    }
}

class Order {
    private items: OrderItem[] = [];

    constructor(
        public orderId: string,
        public customerId: string
    ) {}

    addItem(item: OrderItem) {
        this.items.push(item);
    }

    get totalPrice() {
        return this.items.reduce((total, item) => total + item.total, 0);
    }
}

Step 3: Imagine Our Data Repositories

Now, let’s set up our data repositories. They're like magical cupboards where we store and retrieve data.

interface IRepository<T> {
    findById(id: string): T | undefined;
    save(entity: T): void;
}

class OrderRepository implements IRepository<Order> {
    private orders: Order[] = [];

    findById(orderId: string): Order | undefined {
        return this.orders.find(order => order.orderId === orderId);
    }

    save(order: Order): void {
        this.orders.push(order);
    }
}

Bringing in the Folder Structure

Alright, let’s get our folders neat and tidy! A typical DDD folder structure for our bookstore might look something like this:

src/
|-- domain/
|   |-- entities/
|   |   |-- book.ts
|   |   |-- customer.ts
|   |-- value-objects/
|   |-- aggregates/
|   |   |-- order.ts
|-- infrastructure/
|   |-- repositories/
|   |   |-- orderRepository.ts
|-- application/
|   |-- services/
|   |-- handlers/
|-- interfaces/
|   |-- web/
|   |   |-- controllers/

Wrapping Up With a Smile

So there you have it! A peek into the world of Domain-Driven Design with a sprinkle of TypeScript. By organizing our code around the domain itself, we make our software a reflection of the business. Isn’t that neat? Now, go ahead and try modeling your own project using DDD. It’s not just about coding; it’s about understanding and solving real-world problems. Enjoy the journey!