데브코스에서 진행하는 마지막 최종 프로젝트가 시작되었다.
프로젝트를 진행하며 느꼈던 배웠던 부분들에 대해서 정리해보려고 한다.
사용자의 중심 위치를 바탕으로 반경 이내의 학원 목록을 보여줘야 하는 기능을 담당하게 되었다.
이를 위해서 각 학원의 위도, 경도를 가지고 공간 데이터 형태인 Point로 바꿔줘야 했다.
또한 하버사인 공식을 이용해서 동그란 지구의 길이를 반영할 수 있도록 하여 반경 2km 이내의 대각선을 구했다.
이 대각선을 포함하는 사각형 내부에 포함된 학원 목록을 반환하는 방향으로 구현하게 되었다.
그런데 주변 학원들이 많게는 3~400개가 되었고 총 데이터의 양이 20만개가 되다 보니
아무래도 쿼리 성능에 대해서 고민하게 되었다.
사용자가 지도를 움직이며 학원 조회에 대해 서비스 이용이 빈번할 것이라고 생각했기 때문이다.
그래서 이 공간 데이터에 대한 인덱스가 필요하다고 생각했고
저번에 RealMySQL 책을 통해서 접했던 r-index를 적용해 보기로 했다.
사실 이 기능에 대해서는 이전 프로젝트에서 구현해보지 못해서
다음 프로젝트에서는 중심 위치 기반 주변 목록을 보여주는 기능을 구현해보고 싶었다.
기존 방식에서 생각해보지 못했던 r-index나 하버사인 공식을 이용한 방식, 공간 데이터를 활용하는 쿼리에 대해서 배울 수 있어서 좋은 시간이었다.
학부모들을 위한 학원 정보 제공 및 학원 스케줄 관리 플랫폼으로 주제가 정해지면서
교습소 공공 데이터를 활용하기로 했다.
먼저 데이터가 잘 확보된 경기도 교습소 데이터를 활용하기로 했다.
데이터를 꺼내서 열어보니 빈 값들이 존재했고 실제로 존재하지 않는 주소로 적혀 있어 네이버 reverse geocode에서 검색되지 않은 정보들이 존재했다.
따라서 이를 분리하는 작업을 진행했다.
그리고
최대한 python을 이용하지 않고 Java 코드만으로 돌아가게 하기 위해서 노력했다.
python을 이용하지 않은 이유는 Java 언어 하나만으로 서버가 돌아가기를 원했기 때문이었다.
DB 구조를 설계하면서 외래키의 존재에 대해서 생각하게 되었다.
만약에 대시보드라는 테이블이 학원 이름이 필요한데 학원 이름을 저장할 것인까 학원의 외래키를 저장할 것인가에 대한 고민하게 되었다.
그런데 추후에 학원 이름이 바뀌었을 때 이를 대시보드가 알아야하는데 외래키가 없기 때문에 이를 알지 못한다는 문제점을 발견하게 되었다. 따라서 이 정보의 주인이 누구인가? 누가 최신화를 책임질 것인가?를 기준으로 외래키를 결졍해야 한다는 것을 깨달았다.
또한 과거 데이터들에 대한 정합성을 생각하게 되었다.
기능 중에 학원 스케줄이 있다.
대시보드를 통해서 등록된 학원들을 바탕으로 스케줄을 생성할 수 있는데
이 학원 스케줄이 대시보드의 정보를 디폴트로 가지고 있어서 대시보드가 수정되는 순간, 수정한 날 이전에
만들어진 학원 스케줄 정보의 정합성이 사라지게 된다.
따라서 이를 해결해 주기 위해서 사용자가 느끼기에 대시보드의 수정이 실제로 DB에서는 생성으로 바뀌도록 해놓았고
과거의 스케줄은 수정되기 전의 대시보드를 향하도록 구현하게 되었다.
RealMySQL이라는 책을 읽을 때 like를 통해서 %검색어%을 하면 인덱스를 사용할 수 없으므로
fulltext index를 통해 인덱스를 사용하는 방법에 대해서 배웠다.
fulltext index 중에서 ngram parser가 한글에 더 잘 적용이 된다고 하여 적용하게 되었고
기본 토큰 사이즈가 2여서 1로 수정하게 되었다.
그런데도 검색어에 두글자로 검색했을 때만 결과가 나와 이유가 무엇인지 찾아보게 되었다.
찾으면서 여러 가지의 이유를 알게 되었다.
학원 스케줄 테이블은 날짜 데이터를 저장한다.
이 날짜 데이터의 형식을 무엇으로 할까 고민했었다.
TimeStamp로 할 것인가, DateTime으로 할 것인가
TimeStamp로 결정한 이유는 TimeZone을 제공하기 때문에 서비스 확장에 유연하다고 생각했다.
또한 제공하는 날짜의 범위가 1970~2038까지여서 우리의 서비스를 이용하는데 문제가 없다고 판단했다.
그렇기 때문에 차지하는 byte 수도 DateTime에 비해서 절감할 수 있었다.
한 가지 문제는 38년도가 넘어가는 순간 오버플로우가 발생하여 다시 1970년도로 돌아간다는 문제가 있었다.
그러나 MySQL에서 이 문제를 해결해서 이제는 괜찮다는 글을 접하게 되었다.
근데 현재 테이블에서 필요한 것은 시간 데이터를 뺀 날짜 데이터만 필요해서 결국 Date 타입의 자료형을 사용하게 되었다.
커스텀 어노테이션을 만들어 요청값에 대한 검증을 진행했다.
최대한 도메인을 지켜 검증되지 않은 데이터들이 DB에 쌓이지 않도록 노력했다.
어떤 서비스를 제공해야 사람들에게 정말 유의미한 정보를 제공할 수 있을까?
사람들이 정말로 필요로 할까?
일회성에서 그치지 않고 계속해서 사용해야 하는 서비스는 무엇이 있을까?
유저가 확보되지 않은 상황에서도 사용자에게 유의미한 정보를 제공하기 위해서 어떤 공공API를 사용할 수 있을까?
주된 타켓층을 정리할 수 있을까?
생각한 주제들만 10개가 넘어갔고 위 질문들을 모두 충족하는 하나의 주제를 정하게 되었다.
그래서 정한 주제는 "여러 개의 학원을 다니는 자녀를 둔 학부모가 아이들의 학원을 쉽게 관리 할 수 있도록 도와주는 서비스"
였다.
우리 모두 학부모가 아니기 때문에
학부모의 입장에서 어떤 서비스가 필요한 지 유저 리서치를 진행하며 정해진 기능들을 모아 서비스를 구현해보기로 결정하게 되었다.


주된 서비스는 아래와 같이 정리되었다.
마지막으로 학원 정보에 대한 필터링 검색이 필요했고
이 학원 데이터에 대해서 어떻게 필터링 되도록 카테고리를 분리해야 할까에 대한 물음이 아직 남아있다.
또한 현재 원본 데이터를 코드로 가공해서 DB에 쌓아서 바로 비즈니스에 사용하는 데이터로 만들어 놓았다.
그런데 이러한 방식에 세가지 문제점이 존재했다.
첫 번째, 추후에 분기마다 업데이트 될 데이터에 대해서 스냅샵을 찍을 수 없다는 단점이 존재하고
두 번째, 쿼리문을 통해서 실제로 어떤 데이터를 가지고 있는지 조회하기에 어려움이 존재했다.
세 번째, 어떠한 가공으로 인해서 데이터의 구조가 바뀌는 경우 이전 학원 DB를 삭제하고 다시 몇 만개의 데이터를 쌓아햐 한다는 많은 시간적 비용이 발생하는 문제가 있었다.
따라서 원본 데이터 자체를 DB에 쌓고 이 쌓여진 데이터를 바탕으로 여러 쿼리문을 작성해보며 데이터를 파악해서
가공하는 작업이 필요하다고 느꼈다.
그리고 이 데이터가 분기마다 업데이트 되다 보니까 어떤 데이터가 기존에 존재했고 어떤 데이트가 업데이트 되었는지 비교하는 작업이 필요했다. 그런데 우리가 어떻게 어떤 데이터는 같고 다름을 증명할 수 있는지에 대한 기준을 정해놓지 않았기 때문에 이를 해결할 방법이 필요했다.
그러나 학원 데이터가 많기 때문에 fulltext index ngram parser를 이용하는 것보다
아무래도 Elastic search를 이용하는 것이 좋은 방향이 아닐까
하지만 아직 성능 테스트나 이에 대한 정당성을 느껴보지 않았기 때문에
생각해보고 적용해볼 생각이다.
나에게 있어서 "마지막"이라는 단어는 스스로를 조급하게 만들었다.
프로젝트를 시작하기에 앞 서 나를 제외한 팀원분들이 다른 교육 프로그램과 병행을 하고 계셨고
이 부분이 마음에 걸렸었다.
그래서 프로젝트를 시작하기 전에 이 부분에 대해서 팀원분들과 정리할 필요가 있다고 생각했다.
어떻게 일을 나눠야할 지 실제로 본인이 할 수 있는 일의 분량이 어느정도인 지를 서로 알고 있어야 겠다고 생각했다.
그리고 한 켠으로는 한마음 한뜻으로 으쌰으쌰해서 나아갈 수 없어 서운한 감정들도 있었다.
팀원분들과 시간을 잡아 이 부분에 대해서 이야기를 나눴다.
스케줄이 어떻게 될 지 어떻게 일을 분배해야 할 지 그리고 내 감정에 대해서도 공유드렸다.
팀원들은 같이 앞으로 나아갈 수 있음을 말해주셨고 나의 불안한 감정들을 이해하며 공감해주셨다.
지금 생각하면 그 때의 나는 팀원들을 믿지 못했었던 같다.
우리 모두 좋은 개발자가 되기 위해 모였고 같은 곳을 바라보며 나아가고 있다는 생각을 잠시 잊었던 거 같다.
프로젝트를 하며 팀원들과 자주 대화를 나누고 서로에 대한 믿음을 가지는 자세가 중요하다고 생각했다.
그리고 우리 모두 이 프로젝트가 성공하기를 바라는 똑같은 마음을 가지고 있다는 생각을 잊어서는 안된다고 생각했다.
의사소통은 언제나 조심스럽다.
나는 내 의견이 맞다고 생각하기 때문에 상대방의 의견을 들으면서 답답한 감정들을 느낄 때가 있었다.
그러나 이내 이 자세가 회의를 할 때 많은 비용을 발생시켰다.
잘못된 자세였고 나의 고집이었다.
나는 이 자세를 고치려고 노력했다.
내 의견은 맞은 것이 아니고 정당한 이유가 하나 정도는 있다는 것
그리고 상대방의 의견도 다른 정당한 이유가 있을테고 나는 열린 자세를 가지고 상대방의 정당성을 귀기울여야 겠다고 생각했다.