[DDSP] 사용자 회원 도메인 리팩토링

이프·2024년 10월 2일

back-end

목록 보기
4/16

회원가입 기능을 조금 더 개선해보자.

우선 전체적인 패키지 구조도 바뀌었다.
해당 포스트에서는 회원 도메인에 대한 구조만 먼저 작성한다.
회원 도메인은 패키지 구조에 대해 변경된 부분은 없다.

이전 포스트를 확인해보면 Member와 Account라는 도메인을 바탕으로 작성했다.


리팩토링 배경

이전 구조에 대해 멘토님께 상담

Mento : Member와 Account로 나눈 이유가 있을까요?
Me : 분명 계정과 사용자는 하는 일이 다르기 때문에 나누었다.
Metno : 이정도 정보면 Member에 모두 다 포함해도 된다.

솔직히 와닿진 않았다.
왜냐하면, 비밀번호 변경의 주기를 관리하고 사용자 닉넴이과 같은 프로필 정보 변경의 주기를 관리하려면 구분되는게 옳다고 봤다.

상담에 대한 깨달음

개발을 진행하면서, 머리가 띵한 부분이 발생했다.
우리는 애자일 기반으로 유연하고 민첩하게 개발하는 것이 목표였다. 하지만, 내가 개발한 방식을 보면 water full에 가깝지 않을까? 라는 생각이 들었다. 무작정 개발을 진행하면서 나는 왜 이렇게 구조에 집착하지?, 정작 기능을 제작하는데는 시간이 얼마 걸리지 않으면서 어떻게 개발할 지를 정하는데에 많은 시간이 소요되지? 라는 생각이 들었다.

정리를 하자면, 내가 한 방식은 애자일이 아니라는 판단이 들었다.

  • 그럼 어떻게 진행했어야 했을까?

간단하다. 객체지향을 이해하고 객체지향에 걸맞은 설계 방법으로 개발하면 된다. 흔히 말하는 TDD, BDD, DDD-MDD 등이 있다. 이 부분을 깨달으면서 아! 멘토님께서 이것을 전달해주시려고 했나보다! 라는 생각을 하게 되었다.

그럼 우리는 어떻게 구조를 개선했을까?


회원 도메인 리팩토링

@Entity
@Getter
@EqualsAndHashCode(callSuper = false, of = {"id"})
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(
    uniqueConstraints = @UniqueConstraint(
        name = "uk_member_nickname",
        columnNames = {"nickname"}
    )
)
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@DynamicUpdate
public class Member extends BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Embedded
    private Email email;

    @Column(nullable = false, length = 100)
    private Password password;

    @Column(nullable = false, length = 50)
    @Enumerated(EnumType.STRING)
    private MemberRole role;

    @Column(nullable = false)
    private String imageUrl;

    @Column(length = 100, nullable = false)
    private String aboutMe;

    @Embedded
    private Nickname nickname;

    @Column(name = "lowerNickname", nullable = false, length = 20)
    private String lowerNickname;

    @Embedded
    private PhoneNumber phoneNumber;

    @Column(nullable = false, length = 100)
    private String githubAddr;

    @Column(nullable = false, length = 200)
    private String blogAddr;

    @Embedded
    private ActivityStats activityStats;

    @Enumerated(EnumType.STRING)
    @Column(nullable = false, columnDefinition = "varchar(50)")
    private MemberStatus status;

    @Column(nullable = false, columnDefinition = "varchar(50)")
    private MemberJob job;
    
}

결국, Member 도메인에 모든 정보가 다 포함된다.
이렇게 수정한 이유는 뭘까? 우리는 DDD를 적용하기엔 3-Layerd 방식을 채택했고, TDD로 하기엔 경험이 부족해서 테스트 코드를 작성하기에 너무 많은 시간이 소요 될 것이라고 판단했다.

그럼 객체지향 설계의 기본인 BDD(행위 주도 개발)을 적용해보자. 라는 결론이 나왔다. 현재, 우리 서비스에 대해 어떤 행위가 존재할까?

  • 회원가입, 로그인, pw 찾기, pw 변경, 프로필 수정, 내가 쓴 게시글 조회 등이 있다.

그럼 여기서 이어 생각할 수 있다. 우리는 pw 변경의 주기를 설정했는가? 정답은 x이다. 당장에 pw 변경의 필요성도 느끼지 못했고 pw 변경에 대해 기간을 설정할 이유가 없다는 것이다. 그래서, 추후에 필요하다면 account를 따로 분리하는게 맞겠다는 것이다. 이러한 이유로 회원 도메인을 재구성 해봤다.

물론, 해당 코드에서도 수정할 부분들은 있다. email, password 를 account라는 embed object로 작성한다면, account라는 도메인으로 분리하거나 계정과 관련된 수정 사항을 embed object에서 집중할 수 있다.


회고

개발할 때 멘토님의 도움과 자기주도적 학습을 통해 조금 더 객체지향에 가까워지는 경험이었다. 또,개발할 당시에는 acoount도 embed하는 부분까지는 생각하지 못했다. 지금 글을 작성하는 순간에도 내가 성장하고 있음을 느낀다.

profile
if (이런 시나리오는 어떨까?) then(테스트로 검증하고 해결) else(다음 시나리오 고민)

0개의 댓글