Tech Blog

Facebook Icon Twitter Icon Linkedin Icon

AnyMind Group

Facebook Icon Twitter Icon Linkedin Icon

[Tech Blog] How to deal with complex business requirements on AnyTag / AnyCreator platforms?

By Dat Nguyen | Tech Lead, AnyTag Team

In this blog, we are going to explore the approach which we have been using to build AnyTag & AnyCreator platforms.

There are several possible approaches to architecture design, it becomes difficult to select the right one. However in order to solve complexity on business level, we have chosen Domain-Driven Design (or DDD in short).

Let’s first understand why we have selected DDD.

Firstly, DDD primarily concentrates on business problem and how to organize the logic that solves it. It’s a good candidate to deal with highly complicated domain or constantly evolving model.

Secondly, we found out that the first version of our system was hard to maintain and test, it was also hard to read from a functional perspective and hard to add more complex requirements. That was a reason why we decided to use Domain-Driven Design for the next step of our platform.

Next, let check some basic concept of DDD.

Layered Architecture

User Interface

This layer presents the information to the client and interprets their actions.

Application layer

This layer doesn’t contain business logic, its purpose only is to organize and delegate domain objects to do their job.

Domain layer

This is where concepts of the business, information about the business situation, and business rules are representing.

Infrastructure Layer

It implements all the technical functionalities the application needs to support the higher layers, persistence for the, messaging, communication between layers.

Note that not all layers are required in every system, but the existence of the Domain Layer is a prerequisite in DDD.

DDD Layered Architecture

Other terms in Domain-Driven Design

Entities

An Entity is an object defined primarily by its identity, it’s also a combination of data and behavior.

# Entity example
class Advertiser:
    id: AdvertiserId
    name: str

    def update(self, name: str) -> 'Advertiser':
        return replace(self, name = name)

Domain services

The domain service is an additional layer that also contains domain logic. It’s a part of the domain model, just like entities.

# Domain services example
def delete_advertiser(adv_repo: AdvertiserRepository, id: AdvertiserId) -> None:
    # do service stuff
    return

Repositories

Repositories provide an interface that the Domain Layer can use to retrieve and persist objects.

# Repository interface example
class AdvertiserRepository(ABC):
    
    @abstractmethod
    def update(self, advertiser: Advertiser) -> None:
        pass

    @abstractmethod
    def find_by_id(self, id: AdvertiserId) -> Optional[Advertiser]:
        pass
# Repository implementation example
class AdvertiserRepositoryImpl(AdvertiserRepository):

    def update(self, advertiser: Advertiser) -> None:
        # implementation

    def find_by_id(self, id: AdvertiserId) -> Optional[Advertiser]:
        # implementation

Note that Repository interfaces are declared in the Domain Layer, but the repositories themselves are implemented in the Infrastructure Layer. This makes it easy to switch between different implementations of a repository without impacting any business code.

Lastly, although the domain-driven approach is able to solve the complexity challenge of software development, it has some disadvantages we need to think about before starting using it:

  • – Requires Domain Experts
  • – Requires additional efforts
  • – Only Suitable for Complex Applications

Latest News