아마 누구나 이런 말을 들으면, 에이 설마 싶을꺼다.
언제는 되고, 언제는 안되고...
이런류의 문제는 복잡할 것이 분명하기 때문에 보고 싶지도 않다.
하지만 재현되는 걸 보면 어쩌겠어.. 봐야지..
페이지에 들어있는 첫번째 아이템 삭제시 문제 발생undefined로 인해 동작이 멈춤을 확인undefined가 나올 수 없는 부분인데?새로운 페이지가 생성된 뒤, 그 페이지에 아이템을 2개 만들 경우
②번은 삭제가 되지만, ①은 삭제가 안됨.
그런데 앱을 다시 실행한 뒤
다시 삭제를 시도하면 삭제된다!
interface IChat {
id: number; //this is created at.
userId: number;
content: string;
d: boolean; //is having date
p: number; //page
}
undefinded 가 되버린 변수 생성 로직을 검토
로직 자체의 이상은 없음.
그랬다면 삭제 자체가 불가능 했어야 함.
생성에 필요한 변수 검토
로직 앞 뒤로 생성에 필요한 모든 변수를 출력해 확인
p값이 예상과 다름1이여야 한다면0이고1이다id랑 다른 값들은 모두 정상인데, p만 다르다.잘못 생성했기 때문에 잘못된 데이터가 들어오겠지(추측)
대상 아이템은 redux의 add() 리듀서에서 저장이 된다.
그런데 생성된 원본 데이터는 1로, 잘 생성이 된다.
생성하고 저장하는 부분은 문제가 없으므로, add() 함수는 잘못이 없는 것 같다.🤔
그렇다면 중간에 누군가 데이터를 변형하는가?
그렇다면 remove() 리듀서가 문제일 것이다.
그러나 실패 후에 다시 삭제를 요청했는데 성공했다는 것은
원본 item은 바뀌지는 않는다는 것이다.
그러면 뭐가 문제지?? p값이 이상한 데이터가 요청되는건 확실한데?
원본 데이터와, 요청할 때 값이 다르다고?🤔
remove() 리듀서가 아닌, item 자체가 문제인가?
(이 부분을 생각하기까지 상당히 시간이 걸렸다.)
그러면 remove() 함수를 호출하는 곳에서 로그를 찍어보자.
호출 직전 p 값에 원래 문제가 있었다.
호출을 하는 부분은 View 컴포넌트다.
아!
item이 2개였다.
- redux가 들고있는 원본 item
- 그리고 이번에 문제가 된 사용자가 보고있는 View에 노출된 item
사용자가 보고있는 item이 문제인가?
원래 사용자가 보는 item도 add() reducer를 통해 생성이 된다.
즉 p값은 add()함수 내에서 결정지어진다는 것.
그리고 문제의 원인을 발견했다.
add() 리듀서에서
p값을 보정한 뒤 저장하는데,
View가 사용해야 할item을 지정해준다.
이때p값이 보정이 안된, 생성 과정 중에 생긴 item을 보내준 것.
View를 닫을 때 잘못된 값을 가진 item은 사라지고
다시 열릴 때 정상 item으로 채워지므로 버그 현상이 들쑥날쑥 했었던 것이다.
결국 문제를 해결했다.
2차 분석시 처음부터 생성 이 문제일 것으로 예측했음에도, 첫 분석에서 바로 잡아내지 못하고 시간을 소모했다.
잡지 못한 이유는 이 부분이다
생성하고 저장하는 부분은 문제가 없으므로, add() 함수는 잘못이 없는 것 같다.🤔
저 생각은 add() 생성/저장 부분까지만 봤기 때문에 한 생각이지만
add() 리듀서가 하는 역할은 마치 트랜젝션 같았다.
하는일이 너무 많다보니, 저기서 4번째 저장부분 까지만 보고,
마지막 부분인 따로 저장하는 부분에서 실수를 했던 것을 놓쳤던 것.
그래도 놓칠 수 밖에 없었다.
View가 호출하는 아이템이 원본과 다르며,
문제 있을 것이라고는 이때까진 생각하지 못했기 때문.
버그 분석시, 추론보다 데이터 확인을 먼저 하자
초반에 문제의 범위를 잘못된 추론으로 문제의 원인을 찾기 어려웠다.
또 View에서 사용중인 ①임시 Item과 ②원본 Item을 혼동해 분석에 시간이 더 걸렸다.
이 부분은 View와 Data를 따로 관리하는 모든 경우에 혼동될 수 있으므로,
항상 Data를 저장하는 주인이 누구인지 먼저 명확히 하고 문제범위를 줄인다면,
버그 확인에 시간을 줄일 수 있을 것이다.
하나의 함수는 하나의 역할을 수행해야 한다
할 수 없다면 분리할 수 있는 역할이라도 분리해야 한다
현재 각 리듀서가 함수의 역할보다 트랜젝션의 역할을 수행하게 된 것은 근본적으로
Saga 패턴 혹은 Redux-Saga 라이브러리를 쓰지 않아서
Saga가 있었다면 각 리듀서를 몇개로 구분하고,
그 역할을 모은 작업을 할 수 있었을 것이다.