
리스트를 다루는 기능을 구현하면서
생성, 수정, 삭제 요청을 각각 나눠서 처리해야 하는 상황이 있었다.
처음에는 단순하게 생각했다.
요청을 하나씩 순서대로 보내는 것보다,
한 번에 묶어서 처리하면 더 깔끔하고 효율적일 것 같았다.
특히 생성, 수정, 삭제가 모두 비동기 요청이었기 때문에
이걸 병렬로 처리하면 속도도 더 빨라질 거라고 생각했다.
그래서 자연스럽게
여러 작업을 동시에 처리할 수 있는 방법을 찾게 되었고,
그 과정에서 Promise를 떠올리게 됐다.
예전에 한 번 간단하게 배워본 적은 있었지만,
실제 기능 구현에 제대로 써본 건 이번이 처음이었다.
그래서 이번 기회에 생각나서
생성, 수정, 삭제를 모두 Promise로 묶어서 처리했었고,
하면서 발생했던 일들과 함께
Promise를 다시 한 번 짚고 가려고 한다.
Promise는 비동기 작업의 결과를 다루기 위한 객체다.
지금 당장은 결과를 알 수 없지만,
나중에 완료될 작업의 상태를 가지고 있다고 보면 이해하기 편하다.
이 작업은 크게 세 가지 상태로 나뉜다.
이 상태에 따라 이후 실행 흐름이 결정된다.
그래서 Promise를 사용한다는 건 단순히
비동기 코드를 작성하는 게 아니라
작업이 끝난 이후 흐름을 어떻게 이어갈지를 정의하는 것에 가깝다.
여기까지는 기본적인 개념이고,
내가 Promise를 떠올리게 된 이유는 조금 달랐다.
나는 이걸 “비동기 처리”보다는
여러 요청을 한 번에 처리할 수 있는 방법으로 먼저 인식했다.
생성, 수정, 삭제 요청을 각각 분기해서 진행해야 하니까
한 번에 묶어서 처리하면 더 효율적일 것 같았고,
그 과정에서 자연스럽게 Promise를 사용하게 됐다.
즉, 처음에는 Promise를
병렬 처리를 위한 도구로 생각하고 접근했던 것이다.
Promise를 사용해서
생성, 수정, 삭제 요청을 한 번에 묶어서 처리했다.
처음에는 별생각 없었다.
코드도 깔끔히 설계했던 대로 분기해서 처리하고,
처리 속도도 병렬로 처리하니까
빨라졌을 것이다.
그런데 이상한 문제가 발생하기 시작했다.
분명 내가 입력한 순서대로 생성 요청을 보냈는데,
실제로 반영된 결과를 보면
생성 순서가 매번 뒤죽박죽으로 섞여 있었다.
처음에는 단순히 정렬 문제라고 생각했다.
그래서 데이터를 가져온 뒤에
sort를 적용해서 순서를 맞춰보기도 했고,
다른 방식으로 정렬 기준을 바꿔보기도 했다.
하지만 아무리 정렬을 바꿔봐도
근본적인 문제는 해결되지 않았다.
정렬의 문제가 아니라, 생성 자체가 꼬이고 있었던 것이다.
그렇게 거의 두 시간을 헤매면서,
이게 왜 안 되는지 정확한 원인을 잡지 못한 채
로그만 계속 찍어내고 있었다.
근데 코드를 좀 멀리서 보기 시작하면서 문제가 보였다.
세부적인 로직에서의 문제가 아닌
이걸 어떻게 처리를 하냐로 시야를 멀리 잡았을 때,
그때 문득 떠올랐던 게 Promise였다.
여러 요청을 Promise로 묶어서 실행하면
각 요청이 동시에 실행되고,
먼저 끝난 요청이 먼저 반영되는 구조가 된다.
즉, 내가 보낸 순서와는 상관없이
서버에서 처리되는 순서가 달라질 수 있다는 뜻이었다.
결국 문제는 여기였다.
나는 단순히 요청을 “같이 보냈다”고 생각했지만,
실제로는 각 요청이 독립적으로 경쟁하면서 처리되고 있었던 것이다.
그래서 확인을 위해
생성만 Promise에서 제외하고,
수정과 삭제만 Promise로 처리하도록 구조를 바꿔봤다.
그 결과는 바로 드러났다.
이전까지 계속 꼬이던 생성 순서가
정상적으로 유지되기 시작했다.
그제서야 확실하게 이해할 수 있었다.
생성은 순서가 중요한 작업이었고,
그걸 병렬로 처리하면서 문제가 발생했던 것이다.
생성만 Promise에서 제외하고 나서야
왜 문제가 발생했는지가 조금 더 명확하게 보이기 시작했다.
겉으로 보면 생성, 수정, 삭제 모두
같은 “비동기 요청”처럼 보였지만,
실제로는 성격이 완전히 다른 작업이었다.
먼저, 생성은 순서 자체가 의미를 가진다.
사용자가 입력한 순서대로 데이터가 쌓이길 기대하기 때문에
이 순서가 깨지면 결과가 어색해질 수밖에 없다.
반면 수정과 삭제는 다르다.
이미 존재하는 데이터를 대상으로
값을 바꾸거나 제거하는 작업이기 때문에
처리 순서가 크게 중요하지 않다.
즉,
생성은 순서가 중요하고,
수정과 삭제는 이미 순서가 정해져 있으니 크게 중요하지 않았다.
이 차이를 고려하지 않고
모든 요청을 동일하게 Promise로 묶어버린 것이 문제였다.
이번 경험을 통해 하나 분명해진 게 있다.
Promise는 병렬로 처리해준다고 사용할 도구가 아니라
작업의 성격을 고려해서 선택해야 하는 도구라는 점이다.
정리해보면 기준은 이렇게 나눌 수 있다.
순서가 중요한 작업은 순차적으로 처리하고
서로 독립적인 작업은 병렬로 처리한다.
그리고 가장 크게 느꼈던 건 이거였다.
사실 어떻게 보면 간단한 문제다.
그저 생성에서 순서까지는 미처 생각하지 못해
일어난 문제였다.
아무튼 이번에 나에게 있어 Promise는
코드를 병렬로 처리할 수 있도록 하는 도구가 아니라,
실행 흐름을 어떻게 설계할지 결정하는 도구였다.