How to Design in Clean Architecture Way

A look at a data-oriented design approach

Chuunting Wu
onion engineering

There are many articles and books about it but the focus is on the why and what, such as why the onion structure is used, what each layer represents, and what it is SOLID Principle.

However, developers actually want to pay more attention to how to write a good software architecture according to these design principles.

In this article, we try to solve a common architectural problem in a clean architectural way.

In many mobile games or cCommercial websites, in order to improve user retention, login task is designed. If you log in, you will get some rewards. When you log in continuously for a certain number of days, there will be more Gift boxes It can be unlocked, and you will get rewards after opening. Let’s try to meet this requirement together.

Users who log in constantly will get diamonds, as shown in the following table:

To simplify the problem, let’s have a fixed amount of 100 diamonds that the gift box is opened every time. For example, if the user logs in for four consecutive days, the user can get 30 gift boxes on the fifth day of login.

Each time the user enters the home page, they will see a login map, which tells the user how many consecutive logins have been completed in this cycle and how many rewards have been received.

There are two different approaches to design, data-oriented design and domain-driven design. We’ll start talking about data-oriented design and tell you why it’s not a mainstream design solution.

Data-oriented design means that when we see a problem, we first think about how to store the data, and then we deal with the specific data format to try to solve the original problem.

So, after getting the question, the first step is to think about what database to use, what schema it will include, and what format the data will be in.

Let’s take the login task as an example. Suppose we are designing on a small block, usually with a relational database, so we first define a table to realize our problem. Define a login schedule to store the time of each login, so you can see how many rewards you can get based on your previous login records.

From the above table, if today 2022-01-04then John can get 15 diamonds when logging in, and Mary will start a new course because she didn’t log in in a row and only got 10 diamonds.

The logic of the task would be to filter the login history of a specific user and sort it by date, then retrieve the most recent N records. By calculating the total days of consecutive logins, then you can find out what bonus you will get this time.

There is a problem with such a design. When the user login is not interrupted at all, that is, the number of consecutive login days is greater than N, the amount of data is not enough to determine the current reward. However, we do not want to expand N To avoid pulling a lot of data makes the database a bottleneck. Thus, we must try to make some changes to the original scheme, such as adding a new field, diamond.

For John, log in 2022-01-09 We will get 10 diamonds because we know it was the end of the previous round 2022-01-07.

The story is not over yet. When the number of users grows, the performance of the RDBMS will be difficult. Every time you enter the home page, you have to pull data from the database, perform a complex calculation, and finally see the result. This process is very inefficient.

In order to improve the efficiency of the homepage, most projects will provide a cache for recording the entire login state. However, how do you know that the cache is invalid? Or the cache isn’t actually invalid, but it’s garbled. I covered this issue in a previous Elastic Caching article. By adding integrity, we can distinguish whether the data is reliable. Once the data is corrupted, we will rebuild the data from the RDBMS.

From the above introduction, we found that even the cache has many aspects to consider, the entire data-oriented design is very complex, and the operation is very difficult.

Hence, field-driven design was born.

In the second part, we will start designing from the entity, cover the use cases, then implement unit tests like TDD, and finally complete our task. I will provide a better design process, and you can follow the steps to simplify the stories of every user you will encounter. Let’s call it today. Until next time

Leave a Comment