TIL 2021.04.13 [구현/문제해결] ⭐️

Kyu·2021년 4월 13일
0

TIL

목록 보기
93/322

어제에 이어서 카드들 사이에 옮기거나 했을 때 순서를 어떻게 만들것인가에 대한 고민을 쭉 코코와 같이 했다.

어떤 방법들이 있나?

첫번째 방법

첫번째로 생각했던것은 일단 position 이라는 컬럼을 만들고 모든 Card에 포지션이 바뀔때마다 포지션을 업데이트 해주는 방식이지만, 하나 바뀔때마다 전부 업데이트 해줘야한다는건 비효율적이라고 생각했다.

두번째 방법

두번째로 생각했던것은 소수점을 이용하는 거다. 그냥 한 아이템을 추가할때는 마지막 포지션에 +1만 하면 되고 만약에 카드 사이에 집어넣으려고 한다면 소수점을 이용한다는 거다. 예를들어서 포지션이 1과 2인 카드가 있고 그 사이로 카드를 옮기면 1.5가 되는 방식이다.

두번째 방법의 문제점

이 방식의 문제점은 다음과 같다고 한다.

First, don't try to do anything clever with decimal numbers, because they'll spite you. REAL and DOUBLE PRECISION are inexact and may not properly represent what you put into them.

real and double precision 이 부정확해서 문제라고 하는데 아직 정확한 건 모르겠다. 일단 50명 이상이 upvote했으므로 꽤 믿을만한 것이라고 생각이 들기 때문에 어쨋든 간에 답변자의 말을 따르는 것이 좋을것으로 보인다.

이것 외에도 우려되는 문제점은 계속 1과 2사이에 카드를 넣는다고 생각해본다면, 소수점 아래로 카드 하나당 하계속해서 자릿수가 하나씩 늘어나게된다. 이게 문제인 이유는 데이터베이스에 double 타입에 최대,최소값이 존재할 것이고 그 최대,최소값이 계속해서 자릿수가 하나씩 늘어나는 거에 비해서 범위가 그리 크지 않을거라는 것이다.

나름 타당해보이는 방법

질문자가 언급한 거처럼 내 생각에도 보통 투두앱이라면 기껏해봤자 몇십개 혹은 100개정도의 아이템이 등록되지 않을까? 그래서 크게 고민할 것없이 내 생각에는 List를 사용해도 괜찮을 것 같다. 그러니까 처음에 생각한 방법 말이다.

그래도 완벽한 방법을 찾고 싶은 건 어쩔수가 없는 것 같다.

결국에 계속 코코와 토의하면서 그 방법을 찾아내긴 찾아냈다. 코드로 구현하는 것이 굉장히 어려웠긴 하지만 말이다.

처음에 그 힌트를 얻은 것은 링크의 답변들 중에서 Alexander Bird가 납긴 답변이다. 그는 세가지 방법을 소개했는데, 마지막 3번에서 큰 힌트를 얻었다.

완벽한 방법은 없을까?

검색 중에 이 고민을 특히 https://softwareengineering.stackexchange.com/questions/195308/storing-a-re-orderable-list-in-a-database 여기에 질문한 사람이 너무 우리와 똑같아서 놀랬다. 이 링크에서 많은 도움을 얻었고 한번 정리해보고자 한다.

1번 방법

1번 방법은 index가 1과 2인 아이템 사이에 넣으려면 인덱스 2부터 5까지 모두 인덱스를 증가시켜야한다. 즉, 아까 첨에 생각했던 모두 업데이트시키기. 이건 패스.

2번 방법

2번 방법은 꽤 괜찮다. 아이템이 하나 생길때마다 100씩 증가시키고 100과 200사이인 아이템에 넣을때는 그 사이값을 넣는거다. 아마 넣는다고 생각해보면, 101이나 199가 아니라 그 중간값인 150이 되어야 할것 같다. 101이나 199를 넣는다면 바로 앞,뒤에 있는 카드에 또 다른 카드를 넣으려고 할때 바로 문제가 생길 것이다. 그러므로 사이에 넣을때 계속 그 중간값을 넣어야할것같다.

3번 방법

마지막 3번에서 큰 힌트를 얻었다. Jira라고 하는 데이터베이스에서 lexorank라는 개념?방법?을 이렇게 쓴다고 한다. 이걸 보고 비슷하게 구현하면 좋겠다 라고 생각했는데 일단 이게 어떤식으로 작동하는지 분석하는데에 시간을 많이썼다.

3번 방법 파헤치기

아이템을 맨위 혹은 맨아래로 움직이거나 아니면 다른 컬럼으로 옮기거나 할때 position(3번 방법에서는 jira_rank)을 수정해줘야하므로 3가지 경우의 수를 따져봐야한다.

만약에 3번 예시에 나와있는대로 아이템들이 저렇게 있다면 맨위나 맨아래로 옮겼을 경우의 postion은 어떻게 만들어줘야할까?

내가 생각했던 것은 맨위로 옮겼을 땐 맨위로 옮긴 아이템의 포지션은 0|hzztxk:보다 우선순위가 한단계 더 높은 0|hzztxj:가 될것이라고 생각했다. 또 그 위로 다른 카드가 올라가면 그 카드의 포지션은 마지막 알파벳 j보다 1 작은 i가 되어서 0|hzztxi:가 될것이다. 그러다가 마지막 알파벳이 a가 되면 그 앞에 있는 알파벳이 바뀌는 것이다. 그럼 x를 바꿔야한다. x는 당연히 y가 된다.

아이템을 맨아래로 넣을때는 위에 했던것과 정반대로 해주면된다. 즉, 0|hzztzz:0|hzzuaa:가 될 것이다.

그럼 답변자는 왜 마지막에 0|hzztzz:i 0|hzztzz:r 이런식으로 해줬을까? 나는 이걸 3가지의 경우의 수 중에서 3번째 경우의수인 카드 사이에 집어넣을때 이것을 활용해야하겠다고 생각했다.

위에 3번예제를 간소화시켜서 아래 예시로 만들어보았다.

item | position
----------------
1    | aaa
2    | aab
3    | aac
...
...

여기 1번아이템과 2번아이템 사이에 카드를 넣어야 한다고 생각해보자. 이건 처음에 소개했던 index가 1과 2인 아이템 사이에 넣는 방식이랑 똑같다. 그렇기때문에 별다른 뾰족한 수가 없다.

처음엔 aaaa를 넣어보자고 생각했다. 그럼 일단 정렬했을때 aaaa가 두번째 순서로 들어가긴 한다. 그런데 aaaaaaa사이에 집어 넣으려면? 여기선 전혀 방법이 없기 때문에 계속 고민을 하다가, 아까 그 답변자가 다른 곳에서 그에 대한 해결책을 알려준 것을 발견했다.

그가 제시한 해결책은 1번 아이템과 2번아이템 사이에 aaaa라고 넣는 대신에, aaaai을 넣으면 해결된다고 했다. 이것을 보기좋게 나누기위해서 :을 사용하여 aaa:ai라고 하겠다.

item | position
----------------
1    | aaa
???  | aaa:ai
2    | aab
3    | aac
...
...

이렇게 되면 aaaaaa:ai사이에 뭔가 아이템이 옮겨진다면 자연스럽게 aaa:ah, aaa:ag, ..., aaa:aa이런 식으로 나아갈수있다. 아까 말한거처럼 물론 aaa:aa를 넣을 차례라면 그 대신에 aaa:aai가 들어갈것이다. 이해가 안갈땐 직접 데이터베이스에 넣어보고 정렬해보면 바로 이해가간다.

반대로, aaa:aiaab 사이에 넣으면? aaa:aj, aaa:ak, ..., aaa:az 대신에 aaa:azi 이렇게 된다.

여기서 드는 의문은 그렇다면 aaa위에 아이템을 옮기면 어떻게 처리할것이라는거냐이다. 아까 말한대로하면 a보다 1작은 알파벳을 넣어줘야하는데 첫번째,두번째,세번째 모두가 a이기 때문에 여기서도 다른 수가 안생긴다.

그렇기 때문에 애초에 처음 아이템을 생성할때 hzztxk이런식으로 중간정도되는 값을 줘서 해결하는 것이라고 생각한다.

코드로 구현하기

오늘 이걸 코드로 구현해보려고 해봤으나 일단 시간상 내일로 미루어봐야겠다. 이걸 어떻게 구현할 수 있을지 아니면 아직 이정도까진 무리일지..잘 되면 좋겠다.

느낀점

해결될듯 안될듯한 어떤 문제를 가지고 그것을 어떻게 구현할지 집중해서 토의했던 것이 정말 즐거웠다. 실제로 코드로 옮길 수 있을지 아직은 미지수이지만 그것과 관계없이 머리맞대고 토의하는 행위 자체들이 즐거웠다.

profile
TIL 남기는 공간입니다

0개의 댓글