“심화교육은 기본교육을 수강한 교육생만 신청할 수 있어야 해요.”

8월 신규 오픈을 준비중인아이돌봄 플랫폼 시터 심화교육 과정아이돌봄 플랫폼 시터 기본교육 과정을 수강해야만 신청할 수 있다는 조건이 달려있다. 이전까지는 각 교육의 신청-수강-수료증 발급까지 모든 단계에서 완전히 격리 되어 있었지만, 처음으로 신청 단계에서 교육끼리의 의존관계가 생겨나게 된 것이다.

단순히 심화교육 과정 신청 조건에 기본교육 과정을 추가할 수 있었지만 새로운 교육이 추가될 때마다 매번 개발자에게 요청을 하실 필요 없이 운영팀분들께서 직접 신청 조건을 관리하실 수 있는 방향이 좋을거 같았다. ‘교육 간의 의존관계를 어떻게 표현해야할까?’ 단순하게 시작한 고민이 ‘더 유연하게’, ‘더 이해하기 쉽게’, ‘더 유지보수하기 쉽게’ 까지 커져나가 일주일 가까이를 잡아먹었다.


🎓 식별 키값 부여

고민을 시작하는 단계에서 중요하다고 생각한 것은 각각의 교육을 식별해내는 방법이었다. 교육(education) 테이블은 PK를 AUTO_INCREMENT 한 정수 값을 사용하고 있었기 때문에, 특별히 교육을 식별해낼 수 있는 방법이 없었다. 만일 각 PK를 고정해서 사용하고자 한다해도 운영DB와 테스트DB간 PK 값이 달라질 가능성이 높아서 안전해보이지 못했다. 그렇다고 Enum 형태로 교육 데이터를 관리하자니 새로운 교육이 추가될 때마다 매번 서버 배포를 진행해야함이 마음에 들지 않았다. 그래서 처음 떠올린 방법이 각각의 교육에 10자리의 랜덤한 값을 부여하고, 그 값을 PK로 사용하는 것이었다.

image image

기존 AUTO_INCREMENT 한 PK를 10자리의 랜던함 값으로 변경

교육 데이터들이 고유한 식별값을 갖게 되면 환경별로 PK 값이 다를 문제도 없었고, 새로운 교육을 추가할 때마다 서버 배포를 진행할 필요도 없었다. 그러나 각각의 교육이 선후수 관계에 놓여있음을 판별하기 위해서 서버 코드가 수정되어야 하는 불편함이 여전히 존재했다.


🎓 자기 참조 테이블로 변경

image

다음에 중요하게 생각한 것은 교육끼리의 식별이 아니라 선후수 관계 표현이었다. 기가 막힌 교육코가 막힌 교육끼리의 선후수 관계를 저장해두면, 코가 막힌 교육을 신청할 때 기가 막힌 교육을 찾아내어 수강했는지 여부를 알아낼 수 있을 터였다.

image

이렇게 1:1로 표현되는 선후수 관계의 경우 별도로 연관관계 중간 테이블을 만들 필요 없이 자기참조테이블을 형성하면 될 것 같았다. 그러나 학교 수강신청을 해본 사람이라면 의문이 떠오를 것이다.

기가 막힌 교육아이돌봄 플랫폼 시터 기본교육을 모두 수강해야만 코가 막힌 교육을 신청할 수 있다면? 그런 과목이 하나쯤은 있지 않았나?”

image

테이블을 다 구성하고서야 머리 속에 질문이 떠올랐는데, 자기참조테이블 형태에서는 1:N 관계 표현이 불가능했다. 결국 선후수 관계에 대한 중간 테이블을 구성하는 것으로 1:N 관계 표현을 풀어내는 것으로 경로를 바꿨다.


🎓 선후수 관계 테이블 생성

image

선후수 연관관계 테이블을 분리하니 제법 마음에 드는 테이블 형태가 만들어졌다. 기존 교육 테이블의 형태를 바꿀 필요도 없었고, ‘교육’과 ‘선후수 교육’의 관심사도 완벽히 분리되었다.

관계 그래프를 그려보니 문뜩 학부생 때 지겹도록 보던 전공과목 선후수이수체계도와 비슷하다는 느낌이 들었다. 추억도 회상할 겸 선후수이수체계도를 검색해보다가 충격적인 사실을 발견했다.

image

‘모든 선수교육을 수강해야 신청 가능한 후수교육’ 말고도, ‘주어진 선수교육 중 하나만 수강하면 신청 가능한 후수교육’ 케이스도 존재한다는 것이다. 현재 선후수 관계 테이블은 1:N 관계만 표현하고 있기 때문에 둘 중 하나의 케이스만 커버가 가능했다. 결국 N:M 관계를 1:N, N:1 로 분리하기 위해 선수 관계, 후수 관계 테이블을 나누었다.


🎓 선수, 후수 관계 테이블 분리

image

최종적으로 타깃이 되는 교육과 선수관계에 있는 교육들을 표현하는 테이블, 타깃이 되는 교육과 후수관계에 있는 교육들을 표현하는 테이블 2개가 만들어졌다. 각 서비스에서 선수 수강 조건을 알아내야 하는 경우 선수 관계 테이블만, 후수로 신청 가능한 교육을 노출해야하는 경우 후수 관계 테이블만 조인하면 된다.

기존에 존재하는 교육 테이블에는 아무런 변경을 가하지 않고, 새로운 테이블만 추가하는 것으로 기능이 변경된 것이다!


🎓 후기 및 요약

의도한건 아니지만 엉겹결에라도 개방-폐쇄 원칙을 지켜본 경험이 너무 재밌었다! 먼저 선후수 관계 테이블을 별도로 분리했기 때문에, 추가로 기획을 변경할 때 선수 후수 테이블을 나누는 것도 어렵지 않았다. (자기 참조 테이블에서 분리하려면 꽤나 어려웠을 듯…) 특히나 설계 레벨로 개방-폐쇄 원칙을 지켰다는 경험이 색다른 것 같다. 어찌보면 기존 교육 테이블이 정말 필요한 정보만 갖고 있었기 때문에 이런 경험이 가능했던 것 같다. 앞으로도 가능한 적은 책임, 정말 필요한 정보만 갖게 설계해서 자주자주 경험하고 싶다.

사실 LMS(Learning Management Service)의 경우 이미 잘 알려지고, 잘 만들어진 도메인이라 검색을 통해 참고할 정보가 굉장히 많다. 연관 관계를 어떻게 표현할지 고민하기 전에 먼저 검색을 해보았다면 ‘자기 참조 테이블로 바꾸기’, ‘선후수 관계 테이블 만들기’ 같은 과정들이 생략됐을 것이다. (고민과 경험을 한다는 관점에서는 좋지만, 제품 개발에 주어진 시간이 무한하지 않다는 측면에서) 먼저 닦여진 길이 있는지 찾아보는 것도 중요할 것 같다.

  • 연관 관계는 별도 테이블로 풀어내는게 편하다.
    • 관계가 언제, 어떤 형태로 변할지 모른다.
    • 미리 분리해둬야 퓨어한 도메인이 영향을 받지 않는다.
    • ‘관계’ 그 자체만 생각하면 되기 때문에 개발자도 편하다.
  • 연관 관계를 별도 테이블로 풀어내기 편하려면 퓨어한 도메인이 최소한의 정보만 가져야 한다.
    • ‘단일책임 원칙’, ‘개방-폐쇄 원칙’이 이런 방면에서 존재하는게 아닐까…
  • Well-Known-Domain, Well-Made-Domain 인지 아닌지 알아보고 설계하자
    • 이미 잘 알려지고 잘 만들어진 도메인이라면 많은 시행착오를 스킵시켜줄 수 있다.

댓글남기기