아마 누구나 이런 말을 들으면, 에이 설마 싶을꺼다.
언제는 되고, 언제는 안되고...
이런류의 문제는 복잡할 것이 분명하기 때문에 보고 싶지도 않다.
하지만 재현되는 걸 보면 어쩌겠어.. 봐야지..
페이지
에 들어있는 첫번째 아이템
삭제시 문제 발생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가 있었다면 각 리듀서를 몇개로 구분하고,
그 역할을 모은 작업을 할 수 있었을 것이다.