
한화시스템 BEYOND SW 캠프의 첫 번째 프로젝트인 기반기술 프로젝트가 끝났다. beebuddy (bee + be buddy) 팀에서는 협업 기반 여행 계획 서비스 trip buddy의 데이터베이스를 설계하였다. 주요 기능은 다음과 같다.
이어서 프로젝트에 본인이 기여한 점, 프로젝트 진행 과정에서 본인이 배우고 느낀 점을 소개할 것이다. 그 전에, 모를 수 있는 용어에 대해 짚고 넘어가보겠다.
개발자를 준비하며 공부하는 과정에서 지겹도록 많이 들었겠지만, 혹시 독자 중에 아직 못 들어본 분이 계실 수 있으니 소개한다. 어떤 문제를 해결하는 여러 가지 방법에는 각각의 장단점이 존재한다. 이 상황을 trade off라 하며, 의사결정 과정에서 그 장단점을 잘 비교하여 더 좋은 쪽을 취하는 것이 요구된다. 예를 들어, java에서 추상화하여 무언가를 상속받는 구조를 만들고 싶다면 추상클래스를 이용할 수도 있고 인터페이스를 이용할 수도 있다. 이 중 현재 나에게 주어진 상황에서 어떤 것이 더 좋은 지 잘 판단하는 것이 trade off를 잘하는 것이라고 할 수 있겠다.
흔히 좋은 개발자가 갖춰야 할 능력으로 요구되는 것에는 다음의 2가지가 포함되는 것 같다.
1. trade off 능력: 단순히 기능을 구현하기만 할 줄 아는 것이 아니라 여러 가지 방법으로 구현할 수 있고, 그 중 어떤 방법이 더 좋은 지에 대한 철학을 가지고 있음
2. 협업 능력: 이렇게 서로 다른 철학을 가진 개발자가 만나 무엇이 좋은 방법인지 논의하고 하나로 합의할 수 있음
프로젝트를 진행하면서도 느꼈지만 개발은 trade off와 합의의 연속이라고 할 수 있다. 이런 합의의 과정을 즐길 줄 아는 사람이 좋은 개발자가 될 수 있다고 생각한다.
같은 기능을 하는 코드는 정말 수도 없이 많다. 완전히 동일한 코드라도 공백, 개행 등을 달리할 수 있으며, 특히 SQL의 명령어와 객체 이름 등은 대체로 대소문자를 구분하지 않는다. 몇 가지 예시를 들어보겠다.
SELECT
emp_id
, emp_name
, manager_id
FROM employee;
SELECT EMP_ID, EMP_NAME, MANAGER_ID
FROM EMPLOYEE;
select emp_id, emp_name, manager_id
from employee;
이렇게 개인마다 코드 스타일이 다를 수 있기에 효율적인 협업 관리를 위해 팀마다 코드 스타일을 맞추는 작업을 하는데, 이를 코딩 컨벤션이라 한다.
프로젝트 기획, 회의 등 팀원들과 함께 한 부분을 제외하고 본인이 프로젝트에 기여한 내용을 정리해본다.
이전 2주차 회고에서도 언급한 내용인데, 부트캠프 기존 프로젝트의 저장소를 정리한 엑셀 파일을 공유하였다. 사실 링크를 따놓고 하나하나 자세히 살펴보지는 못했는데, 팅원 한 분께서 이 엑셀 파일을 바탕으로 다른 팀 저장소 여러 곳을 살펴보며 어떤 팀의 프로젝트가 어떤 점에서 인상깊었는지를 공유해주셨다. 덕분에 프로젝트의 진행에 많은 도움이 되었다.

기존 프로젝트를 참고하여 협업 일정 관리를 위해 WBS(Work Breakdown Structure)를 작성하였는데, 노트북 환경에서 작업하기에는 행도 많고 옆으로도 꽤 길어지는 구조였다. 수작업으로 모두 채우기에는 귀찮다는 생각이 들었다.

따라서 스프레드시트의 조건부 서식 기능을 활용하여, 시작일과 종료일만 입력하면 자동으로 색칠되는 시스템을 구현하였다.

본인은 자동화를 중요하게 생각하기에 시스템을 구축하느라 수작업으로 5분이면 끝날 일에 30분-1시간 정도를 사용하기도 한다. 하지만 이게 손해는 아니라고 생각하는 게, 이런 시스템을 구축해둔다면 이후에 참고 자료로 평생 써먹을 수 있기 때문이다. 1시간 걸려서 구축한 시스템으로 5분 걸리는 일을 12번 이상 수행한다면, 자동화를 통해 이득을 보았다고 할 수 있다.
이 외에도 전 직장에서 스프레드시트를 많이 활용하여 어느 정도 익숙하였기에 행 고정을 걸어두거나 드롭다운 목록을 생성하는 등, 시트 관리의 편의를 위한 기능을 적용하고 시트 정리에 도움을 주었다.

UML, ERD 등을 작성하는 과정에서 팀원과 회의하는 과정에서 대댓글 기능은 셀프 조인으로 구현할 수 있다는 말을 들으며, 개념으로 알고 있던게 실제로는 이렇게 적용되는구나 하고 깨달았다. 그 전까지는 댓글이라는 것을 테이블 관점으로 볼 생각을 하지 못했었다. 본인은 투표 부분 ERD 작성을 담당했기에 투표 테이블을 어떻게 구성할 수 있을 지 고민해보았고, 다음의 3개의 테이블을 생각해보았다.
나중에 chatGPT와 대화하다가 우연히 투표 테이블의 구조에 대한 답을 얻게 되었는데, 본인이 작성한 테이블 구조와 일치하였다. 아래 사진은 팀원에게 테이블 구조를 설명했던 종이를 찍은 것이다.

이렇게 투표 테이블 구조를 작성하였는데, 팀원으로부터 집계함수 COUNT로 인한 성능 저하 우려로 카운트 변수를 도입하고 테이블 2개로 구현하는 방법을 제안받았다. "이런 방법도 있구나" 싶으면서도 어딘가 마음 한 구석이 불편했는데, 바로 데이터 정합성 문제였다. 만약 데이터가 오염되어 실제 득표수와 카운트 변수 사이의 불일치가 발생한다면 이를 수습하기가 쉽지 않으며, 다음과 같이 심각한 버그가 발생할 우려도 있다는 생각이 들었다.
실제로 2개의 득표를 받은 항목의 카운터 변수가 0이 되어버렸고, 한 명이 투표를 취소한다고 가정해보자.
CHECK (cnt >= 0)과 같은 제약조건이 걸린 경우이에 대해 알아보니 정합성을 위해 3개의 테이블로 구현하는 것이 바람직하며, 만약 성능 문제로 카운트 변수를 도입하더라도 실제 데이터(득표 수)를 별도로 관리하되 트리거 등을 이용해 실제 값을 반영해주어야 한다는 결론을 얻었다. 그래서 3개의 테이블을 유지하는 방향으로 잘 trade off하여 합의할 수 있었다.
git 컨벤션 및 코딩 컨벤션에 관한 논의를 제안하고 이를 문서화하였다.
feat과 같은 키워드를 몇 가지 정하여 사용하는 것은 많이들 알고 있을텐데, 이는 CHANGELOG를 자동 생성하는 데에도 도움이 된다고 한다. 메시지의 작성을 주로 git commit -m "커밋 메시지"와 같은 형태로 하는 경우가 많아 한 줄로만 남기는 것에 익숙한데, 아래와 같은 방법을 제안하였다.
feat: 그룹 아이디 선택 구현 완료 # 제목
# 한 줄 공백 (이 부분이 있어야 제목과 본문으로 구분)
세부 내용 (예시: 그룹 아이디 선택을 구현)
closes #2 #연결된 GitHub 이슈 자동 close
이렇게 작성하면 하나의 commit으로 구성된 PR에서 제목과 본문으로 자동으로 나눠주기도 한다.

또한 앞서 언급한 코딩 컨벤션에 대한 논의를 제안하였다. 아무래도 각자의 스타일이 다 다르다보니 짧은 기간 안에 합의하기가 어려웠는데, 팀원 한 분께서 HeidiSQL에 formatter가 있으니 각자 편한대로 작성한 뒤 그것을 사용할 것을 제안해주셨다. 이후 본인이 해당 기능 단축키가 Ctrl+F8임을 확인하여 팀원에게 공유하였고 논의된 내용을 정리할 수 있도록 문서화 하였다.

원활한 테스트를 위해서 테이블에 입력해두는 초기 데이터가 필요하여, 다른 팀원 한 분께서 이 작업을 주로 맡아주셨다. 회원 테이블에 200명을 추가하는 등 많은 데이터를 생성하가 위해 AI를 활용하시다가 FK 제약조건으로 인해 정상적인 데이터 생성에 어려움이 있어 파이썬 코드를 활용하셨다. 할 일이 워낙 많으시다보니 pseudo code와 import할 패키지를 알려주며 본인에게 여행방 데이터 생성에 대한 도움을 요청하셨다. 약 30분-1시간 정도 소요하여 코드를 완성할 수 있었다. 코드 작성 과정에서 약간 당황스러웠던 점은 리스트 안에 따옴표가 없어 정상적인 문자열로 인식할 수 없었다는 점이었다. 아마 노션 코드 블럭에 옮기는 과정에서 일부가 사라진 게 아닐까 싶다. 실제로는 길이 68에 항목별 길이도 매우 긴 리스트였으나, 가독성을 위해 3개로 줄여 작성한다.
import random
import datetime
trip_name = [노을 속 감성 드라이브, 감각적인 도시 산책, 시간 여행자의 길]
다행히도 이전 직장에서 비슷한 테크닉을 써본 적이 있기에 빠르게 수습할 수 있었다.
import random
import datetime
trip_name = "노을 속 감성 드라이브, 감각적인 도시 산책, 시간 여행자의 길".split(", ")
작성한 코드는 구현에만 충실한 쓰레기같은 코드였는데, 해당 코드는 리팩토링을 거쳐 전후 코드를 올려볼 생각이다. 모 부트캠프에서는 "돌아가는 쓰레기를 만들어라"라고 가르친다고 하는데, 정말 맞는 말이라고 생각한다. 일단 빠르게 구현할 줄 아는 능력도 중요하니 돌아가는 코드부터 만들어보고, 이후 여유가 있을 때 리팩토링 해보며 좋은 코드가 무엇인지 고민해보는 것이 좋은 공부법이라고 생각한다. 이렇게 경험을 쌓으면서 좋은 코드에 대한 철학이 정리되면, 처음부터 좋은 코드를 작성할 수 있는 능력이 길러진다고 믿는다.
기능 구현에서는 그룹, 그룹 캘린더, 여행방 관리 부분을 맡았다. 기능 구현을 위해 DDL을 수정하기도 했는데, 그룹 권한은 "그룹장", "그룹원" 뿐이지만 유지보수성을 고려하여 테이블을 만들었다. (추후 "부그룹장" 등 권한이 추가될 것을 생각) 그룹 권한 관리에는 다음과 같은 방법이 가능하다.
1. ENUM 활용
ENUM('그룹장', '그룹원')으로 지정하면 편하지만 권한이 추가될 때마다 자료형을 수정해야하며, 순서를 관리하기 어렵다는 단점이 있다.
2. 테이블에 순서를 관리
| id | 권한명 | 순서 |
|---|---|---|
| 1 | '그룹장' | 1 |
| 2 | '그룹원' | 2 |
이후 부그룹장이 추가되면 먼저 그룹원의 순서를 3으로 변경하고 테이블에 (3, '부그룹장', 2)를 입력해주면 되는 방식이다. 권한 안에서도 카테고리가 존재한다면 사용할 수 없지만, 순서가 있는 선형 권한만을 관리한다면 좋은 방법이 될 수 있다.
3. 계층형으로 관리
| id | 권한명 | 상위권한id |
|---|---|---|
| 1 | '그룹장' | <null> |
| 2 | '그룹원' | 1 |
권한 안에서도 카테고리가 있는 경우까지 포괄하는 가장 유지보수하기 좋은 방법이지만, 순서 관리를 위해서는 계층형 질의의 사용을 요구한다. 이번 프로젝트에서는 2번의 방법을 선택하였다.
기능 구현 시에는 다음과 같은 비즈니스 규칙이 적용되기에 코드 작성에 어려움이 있었다.
1. 각 회원은 최대 100개의 그룹에만 속할 수 있다.
2. 각 그룹의 구성원 수는 최대 100명으로 제한한다.
3. 각 그룹 내 여행방의 개수는 최대 100개로 제한한다.
또한, 유효한 권한을 가진 회원인지 체크하기 위해 테이블 3-4개 정도를 조인해야 하는 경우가 많았다. 이와 같은 비즈니스 규칙 및 권한 체크를 위해 프로시저를 만들기도 하고 기능 구현에 필요한 코드를 작성하였는데, 이 중 일부를 완성하지 못한 채로 프로젝트가 끝나게 되어 아쉬움이 남는다.
이번 DB 프로젝트에서 중요했던 것은 논리 모델링, 물리 모델링이었다고 생각한다.
복잡한 관계 개선

기존에 설계한 그룹장 정보를 그룹 테이블에 관리하는 방식에서는 회원, 그룹원, 그룹 3개의 테이블이 모두 연관되는 복잡한 상황이었는데, 팀원과의 의논 덕분에 연관 관계 하나를 제거하고 더 깔끔한 구조를 만들 수 있었다.
열 이름 명명 규칙
테이블의 열 이름 명명 규칙을 정할 때, 테이블 이름을 붙일 지 말 지에 관한 논의가 있었다. 즉, 회원 테이블의 ID 열 이름이 member_id일 지 id일 지였는데, 본인은 후자가 더 좋은 명명법이라고 생각했다. 백엔드에서는 테이블이 클래스, 열이 인스턴스 변수가 될 것인데, 자바에서는 일반적으로 Member.memberID보다는 Member.id를 더 좋다고 여기기 때문이다. 하지만 팀원 한 분께서 id라는 필드가 중복되므로 조인했을 때 헷갈릴 것이라고 말씀해주셔서 그 의견을 수용하였다. 실제로 알아보니 단일 테이블에 대한 select가 이루어질 때는 id가 더 좋은 명명법이지만, 조인이 많이 될 경우에는 member_id와 같이 테이블 이름을 포함하는 것이 더 좋은 명명법이라고 한다. 물리 모델링을 잘 한 덕분에 합의를 통해 좋은 명명법을 선택할 수 있었다.
단위 테스트, 통합 테스트라는 개념을 접했을 때 잘 와닿지 않았는데, 이번 프로젝트를 하면서 무슨 의미인지 알 수 있게 되었다. 테이블에 FK 제약조건이 걸려있다보니, 나의 기능만을 수행하는 데에는 문제 없이 돌아가던 코드가 다른 테이블도 추가되니 돌아가지 않는 경우가 발생하였다. 이렇게 통합 테스트의 중요성을 직접 체감해볼 수 있었다.
아직까지도 git 사용이 익숙하지 않다. merge conflict를 수습하는 과정에서 브랜치 관리를 잘못하는 바람에 작성한 코드 일부가 main 브랜치에 병합되지 않았다. 프로젝트 제출 마감일에 코드를 다시 작성하여 수습하였다. 프로젝트가 끝난 이후 찾아보니 merge conflict를 해결하기 위한 여러 명령어가 많던데, git 사용에 더 익숙해져야겠다.
VSCode, IntelliJ 등 좋은 IDE를 사용하고 있음에도 불구하고 각각 마크다운 편집기, 자바 편집기 등 제한적인 용도로만 사용하고 있다. 툴 사용법을 공부해서 적용하기에는 시간이 부족하다 느껴서 기존 방식을 고수하였는데, 창을 옮겨다니며 SQL 편집(HeidiSQL), git 관리(Sourcetree), pull request(GitHub 웹사이트)를 하려니 번거로웠다. 한 창에서 편하게 작업할 수 있도록 툴 사용법을 공부해야겠다.
팀원 한 분께서 프로젝트가 마무리될 때쯤 자신은 서둘러서 미리 작업을 많이 하는 것을 좋아한다고 하셨는데, 그게 정말 좋은 자세라고 생각한다. 본인은 물리 모델링이 완성되기 이전이었던 주말에 SQL 코드의 초안을 어느 정도 작성해 두었는데, 기능 구현을 서둘러야 하는 시점이 오니 급한 와중에 제대로 된 코드를 작성하는 것이 어려웠다. 주말에 초안을 작성해둔 것이 정말 다행이었다. 이 경험을 바탕으로 여유가 있을 때 많이 작업해둬야 한다는 것을 느꼈다.
제한된 시간과 환경에서 나름대로 열심히 했지만, 좀 더 열심히 해서 기능을 제대로 구현해볼걸 하는 아쉬움이 남는다. 이번 프로젝트에서 남은 아쉬움은 다음 프로젝트를 완벽히 수행하는 것으로 극복해 보려한다!
멋진 글 잘봤습니다 응원할게요!