undo/redo command model
이번에는 undo/redo입니다.
에디터에서 Cmd+Z가 이상하면 사용자는 바로 불안해집니다. 방금 한 작업을 믿고 되돌릴 수 있어야 과감하게 편집할 수 있습니다.
undo/redo는 과거 화면으로 돌아가는 버튼이 아니라, 편집 명령의 시간 순서를 관리하는 모델입니다.
command stack
undoStack.push(command)
undo: command.undo(model)
redo: command.do(model)
drag command = startState -> finalState
명령은 do와 undo를 가질 수 있습니다. 또는 before/after 상태를 저장할 수도 있습니다. 어떤 방식이든 중요한 건 사용자가 기대하는 단위로 history가 쌓이는 것입니다.
드래그는 하나의 명령이다
드래그 중에는 pointermove가 수십 번 발생합니다. 이걸 전부 undo stack에 넣으면 Cmd+Z를 수십 번 눌러야 원래 위치로 돌아갑니다. 사용자가 손목 운동하러 온 건 아닙니다.
그래서 preview state와 committed command를 분리합니다.
dragging: preview only
pointerup: commit one command
연속 방향키 이동은 시간 창 안에서 merge할 수 있습니다. 반대로 import/export처럼 큰 변경은 snapshot command가 더 단순할 수 있습니다.
데모에서 볼 것
데모에서는 드래그 중간 위치가 아니라 최종 위치 하나만 undo stack에 남도록 동작을 설계합니다.
오늘의 핵심은 history가 개발자 이벤트 단위가 아니라 사용자 의도 단위로 쌓여야 한다는 점입니다. 좋은 undo는 조용하지만, 없으면 바로 티가 납니다.