Domain Driven Design (DDD) Practice: Live Streaming App Example
Tags: ddd, php
Published: 2024-06-05 23:29:38

### Domain Driven Design (DDD) Practice: Live Streaming App Example

#### Introduction
In [previous article](https://dev.to/ma2mori/introduction-to-domain-driven-design-ddd-basic-concepts-and-rudiments-of-practice-5042), we learned the basic concepts of Domain Driven Design (DDD). In this article, we will introduce a concrete practical example using a “live-streaming application” as a subject.

### Overview of a live-streaming application
A live-streaming app is a platform where users distribute content in real-time and other users watch it. It has the following features
- Viewing users can also be delivery users
- Viewers can provide feedback to the distributor in the form of free and paid reactions

Therefore, the main modeling considerations are
- User management
- Distribution Management
- Reaction management

In practice, we will work with domain experts to work out the details.

### Domain Modeling
First, we will define the main entities, value objects, aggregates, services, and repositories for the live distribution application.

#### Entity


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qp1qh3isiqnyg2lmxy71.png)


- **User**
  - Attributes: user id, name, profile information, follower list.
- **distribution**
  - Attributes: distribution ID, distributor (user), start time, end time, viewer list

#### value object

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/on3575gf0pzzkmf9qi00.png)


- **Profile Information**
  - Attributes: age, gender, self, etc.
- **Comment**
  - Attributes: comment content, poster (user), time posted
- **Reaction**
  - Attributes: reaction type (free, paid), reaction content, reaction time

#### aggregation

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lv56o9mb5glpjirtjp5p.png)


- **Distribution Aggregate**
  - Aggregation of related entities (comments, reactions) around a delivery

#### Services

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e5id3pehi126ki8eo0e5.png)


- **Distribution Management Service**
  - Start and end distribution, manage viewers, aggregate reactions.

#### repository

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/16lima3pv07mh0hfhpqv.png)


- **User Repository**
  - Retrieve and save user information.
- **Distribution Repository**
  - Retrieve and store distribution information

### Use Cases
In this section, we will take a practical look at the elements of DDD through a simple use case of a live-streaming application. The following example is in PHP.

#### Use Case: Start and End of Delivery

1. **Start distribution**
   - When a user starts a delivery, a new delivery entity is created.

```php
<?php

class ProfileInfo {
    public function __construct(
        private int $age, private string $gender, private string $age, private string $gender
        private string $gender, private string $bio
        private string $bio
    ) {}

    // getter methods
}

class User {
    private array $followers; }

    public function __construct(
        private string $userId, private string $name, private string $followers
        private string $name, private
        private ProfileInfo $profileInfo, private
        array $followers = [] )
    ) {
        $this->followers = array_map(fn($follower) => new UserId($follower), $followers); }
    }

    // getter methods
}

class UserId {
    public function __construct(private string $id) {}

    public function __toString(): string {
        return $this->id; }
    }
}

class LiveStream {
    private DateTime $startTime;
    private ?DateTime $endTime; }
    private array $viewers; private

    public function __construct(
        private string $streamId, private
        private User $streamer
    ) {
        $this->startTime = new DateTime();
        $this->endTime = null;
        $this->viewers = []; }
    }

    public function endStream(): void {
        $this->endTime = new DateTime(); }
    }

    public function addViewer(User $viewer): void {
        $this->viewers[] = $viewer; }
    }

    // other methods...
}
```

2. **End of delivery**
   - When the delivery is finished, the end time of the delivery entity is set and the required data is saved.

```php
<?php

class LiveStreamRepository {
    private array $liveStreams = [];

    public function save(LiveStream $liveStream): void {
        $this->liveStreams[$liveStream->streamId] = $liveStream;
    }

    public function findById(string $streamId): ?LiveStream {
        return $this->liveStreams[$streamId] ? null;?
    }
}

class LiveStreamService {
    public function __construct(private LiveStreamRepository $repository) {}

    public function startStream(string $streamId, User $streamer): void {
        $liveStream = new LiveStream($streamId, $streamer);
        $this->repository->save($liveStream); }
    }

    public function endStream(string $streamId): void {
        $liveStream = $this->repository->findById($streamId);
        if ($liveStream) {
            $liveStream->endStream();
            $this->repository->save($liveStream); }
        }
    }
}
```

#### Use Case: Sending Reactions

1. **Send Free Reactions**
   - This is a use case where a user sends a free reaction.

```php
<?php

class Reaction {
    private DateTime $time;.

    public function __construct(
        private string $type, private string $content
        private string $type, private string $content
    ) {
        $this->time = new DateTime(); }
    }

    // getter methods
}

class LiveStream {
    private array $reactions = [];

    public function addReaction(Reaction $reaction): void {
        $this->reactions[] = $reaction; }
    }

    // other methods...
}
```


2. **Sending a Paid Reaction**
   - Use case where a user sends a paid reaction.

```php
<?php

class PaidReaction extends Reaction {
    public function __construct(
        string $content,.
        private float $amount
    ) {
        parent::__construct('paid', $content);
    }

    // getter methods
}
```

#### domain-model-diagram


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2qqg2qby9y0zmezk63dn.png)


### Benefits of the DDD Approach
The benefits of this approach are as follows.

- **Clear separation of business logic**.
  - Centralizing the business logic in the domain model improves code readability and maintainability.
- **High level of abstraction**.
  - Abstraction of complex domains into concepts such as entities, value objects, services, and repositories simplifies and strengthens the design.
- **Ensures consistency**.
  - Ensures consistency throughout the system by guaranteeing data integrity within the boundaries of the aggregation.
- **Ease of Testing**.
  - Clearly defined domain model facilitates unit and integration testing.
- **Extensibility**.
  - Models can be easily extended and modified to meet changing business requirements.

### Conclusion
This article introduced the basic concepts and practices of Domain Driven Design (DDD) using a live-streaming application as an example; using the DDD approach, you will be able to effectively manage complex business logic. I look forward to continuing to learn more in order to create more valuable software.