DB에서 상대적 위치 값을 활용해 드래그 앤 드롭으로 인한 순서 변경 처리하기
Dev

DB에서 상대적 위치 값을 활용해 드래그 앤 드롭으로 인한 순서 변경 처리하기

최근 나는 드래그 기반의 계획표 서비스인 'DRAG ME'를 개발하고 있다.

우리 서비스의 특징은, 이름에서도 알 수 있듯이 '드래그' 기능이 굉장히 많이 사용된다는 점이다.

특정 계획에 대한 시간을 설정할 때, 특정 계획을 다른 날짜로 이동할 때 모두 드래그 기능이 사용된다.

다양한 드래그 기능들 중, 로직을 구성하고 DB를 설계하는 데 가장 많은 고민을 들였던 부분 중 하나가 바로 '드래그 앤 드롭'으로 인한 순서 변경이었다.

오늘 글에서는 이 기능을 구현하는 과정에서 직면했던 문제를 소개하고, 이를 어떻게 구현했는지에 대해 소개하려고 한다.

 

 

아래 화면에서, 사용자는 표지판 모양의 계획블록을 통해 계획을 세우고 시간을 관리할 수 있다.

그리고 이 계획블록들은, '해당 영역' 내에서 순서 변경이 가능하다.

예를 들어, 왼쪽 이미지의 첫 번째 계획블록인 '드래그미 팀원 만나 팀플'을 7월 25일의 다른 계획블록들 사이나 아래로 옮길 수 있다는 뜻이다.

각 계획블록들은 날짜 변경, 미루기, 자주 사용하는 계획 등록 등의 기능을 통해, 각각 미룬 계획, 자주 사용하는 계획 영역으로 이동할 수 있었고, 각 영역 내에서 모두 순서 변경이 가능했다.

또, 하나의 계획블록 내부에 하위 계획블록을 생성 할 경우, '특정 상위 계획블록의 내부'가 또 다른 영역이 되어 하위 계획블록 내부의 순서가 생겼다.

각 영역 내에서 계획블록들의 순서는 '사용자의 우선순위'를 나타내는 중요한 지표였기 때문에, 이 순서의 관리와 변경이 매우 중요한 기능이었다.

드래그미 서비스의 일간 / 주간 계획 뷰

드래그 앤 드랍 방식의 순서 변경을 구현할 때 고려해야 했던 점은, 순서를 절대값으로 가지고 있을 시에 너무 많은 변경 소요가 든다는 점이었다.

예를 들어, 영역 내의 a, b, c, d, e라는 계획블록들이 각각 0, 1, 2, 3, 4의 절대값 인덱스를 가지고 있을 경우를 생각 해 보겠다.

이 때, a 블록을 맨 아래로 이동할 경우, 실제로 이동하는 블록은 a이지만, 5개의 계획블록들의 모든 인덱스를 모두 변경해줘야 한다.

즉, 변경 후의 a, b, c, d, e 계획블록의 인덱스는 4, 0, 1, 2, 3이 되어야 한다.

 

계획블록의 개수가 더 늘어나고, 다른 영역으로의 이동까지 고려한다면, 이처럼 절대값 인덱스를 가지는 방식은 분명 무리였다.

이 때문에 다양한 방법을 생각해 보았고, 연결 리스트 구조의 적용까지 생각하던 차에 좋은 레퍼런스를 발견할 수 있었다.

순서 변경 고민을 노션에 정리하면서 로직을 정했다.

 

How to Update the Database After a Drag-and-Drop Operation

I researched what happens in the database behind the scenes when drag & drop is done and what...

dev.to

 

이 방법을 적용하면, 각 계획블록들의 위치를 '상대적 인덱스'를 이용해 관리할 수 있었다.

아까와 같이 a, b, c, d, e 블록들이 존재할 경우, 각 블록들은 0, 1, 2, 3, 4의 연속적인 값이 아니라 적당한 간격을 가지는 규칙적인 값을 인덱스로 가진다.

해당 레퍼런스와 우리 프로젝트의 경우, 이 간격을 1024로 적용했다.

이 경우 a, b, c, d, e 블록들은 각각 1024, 2048, 3072, 4095, 5120을 각각 상대적 위치 인덱스로 가지게 된다.

 

만약 여기서  2048의 인덱스를 가지는 b 블록이 c와 d 사이로 이동해 블록의 순서가 a, c, b, d, e가 된다고 가정해보자.

이 경우, b 블록의 새로운 위치 인덱스는 c와 d 블록의 인덱스의 중간값으로 변경한다.

우리 예시에라면, b 블록의 인덱스는 3584로 변경될 것이다.

이후 계획블록들을 조회할 시 정렬 기준으로 이 상대적 인덱스를 적용했고, 원하는 결과를 얻을 수 있었다.

 

다만 두 가지 변수가 있었는데, 계획블록이 영역의 맨 위로 이동할 때와 맨 아래로 이동할 때였다.

나는 첫 번째 경우는 계획블록의 새로운 인덱스를 '기존 첫번째 계획블록의 인덱스 / 2'로 설정했고,

두 번째 경우는 새로운 인덱스를 '기존 마지막 계획블록의 인덱스 + 1024'로 설정해 해결했다.

 

드래그 앤 드롭을 통한 영역 내에서의 순서 변경은 다양한 영역 내부에서, 또 다른 영역으로 이동 시에 범용적으로 사용되기 때문에, 재사용성을 높이기 위해 이 새로운 인덱스를 계산하는 로직을 모듈화했다.

 

이 방법을 사용해 드래그미 서비스의 필수적이고 중요한 기능을 제대로 구현할 수 있었고, 하나의 기능을 위해 더 효율적인 방법에 대해 고민해보며 많이 성장할 수 있었다.

 

마지막으로, 우리 팀의 Github 저장소 링크를 공유하며 글을 마친다.

 

GitHub - Team-DragMe/DragMe-Server: 광기의 리드 개발자 효식과 위기 메이커 민재의 드래그미 서버 🤪

광기의 리드 개발자 효식과 위기 메이커 민재의 드래그미 서버 🤪. Contribute to Team-DragMe/DragMe-Server development by creating an account on GitHub.

github.com