[한샘] Integrated Member Project 오픈 회고

uijin kim·2023년 6월 20일
0

프로젝트의 시작

이전 스타트업에서 근무할 당시 경영난을 못이기고 결국 권고사직을 받은 후
2023년 올해 2월 한샘으로 이직하게 되었다.
회원 도메인을 담당하는 팀으로 배치받게 되었고, 6개월동안 진행중이던 프로젝트에 바로 합류하게 되었다.

토스가 사일로(Silo)단위로 팀을 꾸려 프로젝트가 진행되듯, 한샘또한 도메인별로 하나의 팀을 이뤄 프로젝트를 진행하게 된다.
한샘에는 PI(아직도 무슨 약자인지 모르겠다.)라는 역할이 존재하여, 일반적으로 기획자가 프론트 전반에 대해 설계를 담당 한다면 PI는 백엔드 전반에 걸쳐 설계를 진행해주고 있었다.

기획자 1명, PI 1명, 백엔드 4명으로 이뤄진 팀으로 첫 프로젝트를 시작 하게 되었다.

생각보다 복잡한 회원 구조

한샘은 온라인을 중요시 여기지 않는 제조업 기반의 회사에서 IT 기반의 테크 회사로 변화를 모색하고 있었다.
이 시점 회원 구조는 쉽게 납득하기 어려운 레거시 구조를 가지고 있었는데, 오프라인, 온라인, 멤버십 회원이 각각의 DB에 존재하고 있었다.
서로가 관계를 맺고 있는것이 아닌 완전 독립된 하나의 시스템별로 동작하고 있었으며, 오프라인에서 한샘에 가입한 회원의 데이터를 온라인에서 사용할 수 없는 구조였다. 즉 내가 한샘의 온라인몰인 '한샘몰'에서 가입한 회원이라 할지라도 오프라인 한샘 매장에 가면 나는 완전 별도의 고객으로 취급되게 된다.
회원 데이터의 통합이 이루어지지 않고 있다보니, 마케팅과 회원정보를 통한 인사이트 도출 그리고 다양한 시스템과의 연계가 어렵거나 불가능한 상황이었다.

이런 상황을 해결하기 위해 온, 오프라인 그리고 멤버십 DB를 통합하는 프로젝트가 기획되었고 기존 온,오프라인 시스템을 통합하는 통합회원 API를 구축하여 공통 플랫폼으로 전사에 제공하는 프로젝트를 담당하게 되었다.

이 시점에서 나는 외부 연동 API, 즉 카카오, 네이버, 카카오 페이와 같이 다양한 채널을 통해 유입되는 회원의 가입 및 SNS 연동과 사업자 회원과 관련된 부분을 담당하게 되었다.

야근,야근 그리고 테스트 코드의 중요성

JPA Entity Save에 대한 느낀점

입사 초기 팀내에서는 Spring Data JPA를 사용하고 있었다.
지금 생각하면 조금 특이한 방식으로 JPA를 사용하고 있었는데, 일반적으로 부모 Entity의 연관관계로 있는 Entity를 저장 할 때 부모 Entity에
직접 set 해주어 부모 Entity가 저장되는 시점에 연관관계로 지정된 Entity가 한번에 Insert 되도록 처리하는 것으로 알고 있다.
다만 우리팀에서는 연관관계로 있는 Entity가 새로 생성된 시점에 부모 Entity에 Set 해주어 저장하는 방식은 가독성이 떨어진다는 이유로 각각의
Entity마다 Repository를 이용해 save 메서드로 저장하고 있었다. 물론 정석적인 방법이 있다고는 알고있었지만, 딱히 이 방법으로 연관관계를 저장했을 때 문제가 있을거라는 생각이 없어 나또한 그렇게 진행했다.

// 1. 부모 엔티티에 연관관계 엔티티를 세팅하여 저장하는 방법
MembEntity newMembEntity = memberRepository.saveAndFlush(MembEntity.forCreateByKkoPay(
	registerDto.getForeignerYn(), registerDto.getFavoriteId()));

newMembEntity.updateIndvMembDtlEntity(individualMemberDetailMapper
	.toEntity(registerDto, newMembEntity, REGULAR, registerDto.getReqSystemCd().getReqSysId(), "123"));
// 2. 각각의 엔티티를 저장 하는 방법
MembEntity newMembEntity = memberRepository.saveAndFlush(MembEntity.forCreateByKkoPay(
	registerDto.getForeignerYn(), registerDto.getFavoriteId()));

indvMembDtlRepository.save(individualMemberDetailMapper
	.toEntity(registerDto, newMembEntity, REGULAR, registerDto.getReqSystemCd().getReqSysId(), "123")
);

프로젝트를 진행하면서 이 방식에 문제점을 발견하게 되었는데 다음과 같다.

  1. JPA가 바라는 객체 <-> DB 관계의 정체성이 깨진다.
    JPA는 DB 스키마를 Java 객체로 관리하겠다는 정체성을 가지고 있다.
    부모 Entity에 연관관계를 세팅하는 형태로 저장하지 않고 각각의 엔티티 별로 save 메서드를 호출하게 되면 개발자가 원하는 DB의 형태는 부모 Entity에 연관관계가 연결되어 있어야 하지만 부모 Entity에 연관관계를 세팅한적이 없으니 코드에서 부모 Entity의 연관관계에 접근해도 해당 연관관계는 null로 나오게된다. (논리적으로는 연관관계 Entity는 DB에 저장되어 있음.)

  2. 다른 모듈로 전달된 부모 Entity에서 연관관계 Entity를 꺼내서 사용 불가능
    위의 문제로 인해, A 모듈에서 생성되어 저장된 부모 Entity가 다른 모듈의 파라미터로 전달되더라도 연관관계 세팅이 되어 있지 않으므로 사용이 불가능하게 된다. 결국 팀내에서는 이 문제를 해결하기 위해 Entity별로 save 메서드 호출후 다시 부모 Entity의 update 메서드를 만들어 세팅하여 사용하였다.

프로젝트 동안 JPA 사용에 대해 발견된 문제점은 프로젝트 이후 팀내 회고시간을 통해 건의 드렸고, 위의 첫번째 코드로 언급된 부모 엔티티에 연관관계를 직접 세팅하여 저장하는 형태로 변경되었다.

운영 서버 세팅

오픈이 한달 남짓한 시간, 나에게 운영 서버 세팅이 주어졌다.
DEV, QA 서버는 이미 세팅되어 동작하고 있었지만, 내가 세팅하지 않았다는 부분과 운영서버라는 부담감이 짓눌렀다.

팀의 인프라 구조는 L4 Switch에 3대의 API 서버를 물리도록 하였고, 이와 별도로 Batch 서버, Jenkins기반의 Build 서버와 Nexus를 활용한 Proxy Repository로 구성되었다.

API, Batch 서버에는 Nginx를 붙였고, 인프라팀에 요청하여 도메인 할당을 받았다.
고객 정보를 다루는 도메인이다 보니 폐쇄망에서 서버가 돌아가게 되고, 이런 정책으로 인해 gradle의 maven repository를 사용하지 못하게 되어 있었다. 이를 해결 하기 위해 Nexus Repository를 통해 우리팀에서 사용할 사설 repository를 구성하였고, Jenkins를 이용해 CI/CD 환경을 구축하였다.

글로 적으니 생각보다 간단하게 적혔지만, 처음 해보는 다양한 서버 세팅에 3주간 머리 많이 뽑았다.

대망의 오픈

6월 20일, 다사다난 했던 프로젝트가 드디어 오픈 했다.
기존 회원 관련 기능을 사용하는 커머스, 오프라인에 사이드 이펙트를 최소화 하기 위해 새벽 시간 배포를 진행했고 한샘몰에는 점검 공지가 걸렸다.
10시 출근후 오후 5시에 잠시 퇴근하여 집에 들린후 새벽 2시에 다시 회사로 향했다.

느낀점

나는 생각보다 꼼꼼하지 않은 사람 테스트 코드의 중요성
아직도 배울점이 많고 그 과정에서 즐거움을 느끼는 것 보니 나도..개발자의 피가 흐르기는 하나보다

profile
느리더라도, 꾸준하게

0개의 댓글