[JAVA] Let's stop the god entity that expresses all stats in one class!

I wrote it only with momentum! As the title says!

Suddenly, when I listen to stories and watch twitter at study sessions, I feel that there are often entities that use the nouns they find as classes and throw all the data-like things around them into them. I also wrote when I was a beginner w

Code immediately

UserStatus.java


public enum UserStatus {
    Applying,    //Applying
    Using,       //in use
    Leaved,      //Withdrawn
    BlackListed, //blacklist
    Erased,      //Erase
}

(Only) ʻUser`, which has such a state, has been represented by one class!

I think it's common at the stage, "Because it's DDD, create a class called User and write the processing there." I'm sure it wasn't in good shape at first, but I understand that it ended up being a mess while doing analysis or service growth. Unun

User.java


public class User {
    private UserId userId;
    private UserCourse userCourse;
    private UserStatus userStatus;
    private ApplyDate applyDate;
    private Optional<UseStartDate> useStartDate;
    private Optional<LeaveDate> leaveDate;
    private Optional<EraseDate> eraseDate;

    public User apply(UserCourse userCourse) {
        return new User(
                new UserId(), userCourse, Applying, new ApplyDate(), Optional.empty(), Optional.empty(), Optional.empty()
        );
    }

    public User useStart() {
        if (userStatus != Applying)
            throw new RuntimeException("not applying");

        return new User(
                userId, userCourse, Using, applyDate, Optional.of(new UseStartDate()), leaveDate, eraseDate
        );
    }

    public User courseChange(UserCourse userCourse) {
        if (userStatus != Using)
            throw new RuntimeException("not using");

        return new User(
                userId, userCourse, userStatus, applyDate, useStartDate, leaveDate, eraseDate
        );
    }

    public User leave() {
        if (userStatus != Using)
            throw new RuntimeException("not using");

        return new User(
                userId, userCourse, Leaved, applyDate, useStartDate, Optional.of(new LeaveDate()), eraseDate
        );
    }

    public User blackListIn() {
        if (userStatus != Using)
            throw new RuntimeException("not using");

        return new User(
                userId, userCourse, BlackListed, applyDate, useStartDate, leaveDate, eraseDate
        );
    }

    public User blackListOut() {
        if (userStatus != BlackListed)
            throw new RuntimeException("not black listed");

        return new User(
                userId, userCourse, Using, applyDate, useStartDate, leaveDate, eraseDate
        );
    }

    public User erase() {
        if (userStatus != BlackListed)
            throw new RuntimeException("not black listed");

        return new User(
                userId, userCourse, Erased, applyDate, useStartDate, leaveDate, Optional.of(new EraseDate())
        );
    }
}

The code to use is like this

UserService.java


public class UserService {
    public void leave(UserId userId) {
        User usingUser = userRepository.find(userId);
        User leavedUser = usingUser.leave();

        userRepository.leave(leavedUser);
        
        billing.stop(leavedUser.getLeaveDate().get());

        ...
    }
}

Uhe ~ spicy ~

The code is long! Even if you compile it, you will get an execution exception! I mean, domain logic is Nani!

** This isn't almost a DTO ~? ** **

Let's divide the class according to the state!

I will omit the implementation, but let's divide the class according to the state.

image.png

There are two points!

The main benefits!

It's easy, but it's super effective, so give it a try!

Of course, it's not tech-first, it's modeling.

I used the state in the example, but it depends on the modeling. The use cases and the degree of business impact must be different.

And this split isn't "this is DDD!" But "just a starting point"! This way you can make the model smaller, analyze it, and sort out the logic!

For example, in this example, the billing stop (billing.stop (...)) is modeled starting with LeavedUser.

If you take a little care, even if you think you created an entity, it will be just a DTO, so be careful!

By the way, I wrote a similar article about two years ago, if you like it, please. [It feels good to prepare different classes even with the same table values # Case 2-Update the status of one class](https://qiita.com/suzuki-hoge/items/b8eb2fe9fbe551cfede4#%E3%82%B1% E3% 83% BC% E3% 82% B92-% EF% BC% 91% E3% 81% A4% E3% 81% AE% E3% 82% AF% E3% 83% A9% E3% 82% B9% E3 % 81% AE% E7% 8A% B6% E6% 85% 8B% E6% 9B% B4% E6% 96% B0% E3% 82% 92% E3% 81% 99% E3% 82% 8B)

Recommended Posts

Let's stop the god entity that expresses all stats in one class!
Let's stop writing the spec path in the code in the comments
Solved the problem that all the data in the table was displayed
eclipse all in one installation
[Gradle] The story that the class file did not exist in the jar file