AnyMind Group
Published in

AnyMind Group

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

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.

Other terms in Domain-Driven Design


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 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

Originally published at



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store