스택큐힙리스트

커맨드 vs 메멘토: 언제 어떤 패턴이 덜 아픈가 본문

개발

커맨드 vs 메멘토: 언제 어떤 패턴이 덜 아픈가

스택큐힙리스트 2025. 8. 8. 13:14
반응형

“되돌리기(Undo)”나 “기록/재실행(Redo·Macro)”가 필요할 때, 팀이 가장 많이 헷갈리는 두 패턴이 커맨드(Command)와 메멘토(Memento)죠. 결론부터 말할게요.

  • 작업 자체를 기록·재생하고 싶다면 → 커맨드
  • 객체 상태를 ‘그 순간’으로 즉시 되돌리고 싶다면 → 메멘토

두 패턴은 겹치는 영역이 있지만 목표가 다릅니다. 커맨드는 “행위(요청)”를 객체로 만들고 큐잉·지연·원격 실행·로그·매크로까지 다룹니다. 메멘토는 “상태 스냅샷”을 캡슐화해 내부 구현을 노출하지 않고 저장·복원합니다.


언제 커맨드가 맞나?

이럴 때 커맨드가 덜 아픕니다.

  • 행위 중심으로 생각해야 할 때: “이 버튼이 누르면 어떤 작업을 수행한다”를 깔끔히 객체화.
  • 큐·지연·원격 실행이 필요할 때(잡 큐, 워커, 재시도).
  • Audit/로그/매크로가 필요할 때: 기록을 그대로 재생 가능.
  • Undo/Redo를 “반대 연산”으로 처리할 수 있을 때(execute()와 unexecute() 쌍).

커맨드는 “요청을 객체로 변환”해서 호출자와 수신자를 느슨하게 분리하고, 실행 취소와 대기열 등을 자연스럽게 지원합니다. 

초소형 Kotlin 스케치

interface Command { fun execute(); fun undo() }
class Insert(private val buf: StringBuilder, private val s: String) : Command {
    override fun execute() { buf.append(s) }
    override fun undo() { buf.delete(buf.length - s.length, buf.length) }
}

언제 메멘토가 맞나?

이럴 때 메멘토가 덜 아픕니다.

  • 상태 중심으로 생각해야 할 때: “이전 상태 그대로 복구”가 목표.
  • 캡슐화를 지키며 내부 상태를 외부에 노출하고 싶지 않을 때.
  • Undo/Redo가 행위의 반대 연산 없이 “스냅샷 복원”만으로 충분할 때(복원 O(1), 심플).

메멘토는 “구현을 드러내지 않고” 객체의 이전 상태를 저장·복원하는 행동 패턴입니다.

초소형 Kotlin 스케치

data class EditorState(val text: String) // Memento
class Editor { var text = ""; fun save() = EditorState(text); fun restore(m: EditorState){ text = m.text } }

비용 구조 한눈에 (감으로 고르는 체크리스트)

  • 되돌리기 단위가 ‘행위’인가, ‘상태’인가?
    • 행위 단위(매크로, 원격 재생): 커맨드
    • 상태 단위(“딱 그 화면 그대로”): 메멘토
  • Redo가 ‘다시 실행’이어야 하나?커맨드가 유리(재생/대기열/로그).
  • 복원이 아주 자주·즉시 일어나나?메멘토가 단순(스냅샷 복원).
  • 상태가 큰가? 큰 스냅샷을 자주 찍으면 메모리 부담(메멘토)의 대가가 큽니다.
  • 반대 연산 정의가 어렵나? 반대 연산이 애매하면 커맨드의 undo()가 지옥이 됩니다 → 메멘토 고려.
  • 감사/리플레이가 필수인가?(업무 로그, 매크로) → 커맨드 쪽이 자연스러움.

하이브리드가 정답일 때가 많다

실무에선 둘을 섞는 게 제일 편합니다.
예를 들어, 커맨드로 기록과 재생을 담당하면서 주기적으로 메멘토 체크포인트를 찍어 빠른 복구와 메모리·성능 균형을 잡습니다. 국내 글들도 “둘 중 하나만 고집할 필요 없고 함께 쓰면 좋다”고 정리하죠.

  • 패턴: Command 히스토리를 유지하되, N번마다 Memento를 저장
  • 복구: 가장 가까운 스냅샷으로 점프 → 남은 커맨드만 재생(콜드 스타트 단축)
  • 모바일/안드로이드: 앱 백그라운드 전환 시 메멘토 저장, 전면 복귀 후엔 커맨드 재생으로 세부 동기화

실무 팁 6가지

  1. Undo/Redo UX 규칙: Undo 후 새로운 편집이 발생하면 Redo 스택은 폐기(편집기 표준). 커맨드든 메멘토든 동일.
  2. 깊은 복사 주의(메멘토): 참조 공유로 스냅샷이 오염되지 않게 불변 + 딥카피 전략.
  3. 메모리 관리(메멘토): 스냅샷 압축·델타 저장·기간 제한(예: 30일)로 용량 제어.
  4. 보상 트랜잭션(커맨드): 외부 API/결제처럼 역함수가 없는 작업은 “보상” 커맨드를 별도 설계.
  5. 대기열/재시도(커맨드): 실패 시 백오프·리트라이는 Invoker 수준에서 공통 처리.
  6. 테스트 전략:
    • 커맨드: execute()/undo()의 아이템포턴스, 순서 보장 테스트.
    • 메멘토: “N번 편집 → 스냅샷 → undo → redo” 경계값(0개/1개/많이) 시나리오.

간단 결론

  • 행위 추적·재생·로그가 핵심 → 커맨드
  • 상태의 즉시 복원이 핵심 → 메멘토
  • 현실은 하이브리드가 제일 덜 아프다(체크포인트 + 커맨드 히스토리).
반응형
Comments