Skip to main content
← 블로그

X 상황이 오면 Y 라고 적어두기

VauDium ·

Gollwitzer가 30년 전에 보여준 if-then plan을 태스크 옆에 끼워 넣으면서 정리한 결정들 — 태스크 단위에 두는 이유, 카드의 구조, Rich Text를 쓴 이유.

X 상황이 오면 Y 라고 적어두기

오늘 태스크 화면에 작은 진입 버튼 하나를 추가했습니다. “작전” (description) 섹션 바로 아래에 가로로 깔린 버튼, “대응 지침”. 누르면 모달이 열리고, 카드 형태로 규칙들이 줄지어 있습니다. 각 카드는 두 줄짜리 구조 — 위는 상황(situation), 아래는 대응(response).

[1] 만약 어제 운동을 못 했다면
    오늘 30분만이라도 가볍게 걷는다.

이건 1999년 Peter Gollwitzer가 정리한 Implementation Intentions의 거의 그대로의 모양입니다.

Gollwitzer가 보여준 것

목표를 정한다고 행동이 따라오지는 않습니다. “운동을 더 하자” 라는 *목표 의도(goal intention)*는 의지에 비해 실행률이 낮습니다. 30년에 걸친 메타분석(94개 연구, n>8000)에서 효과 크기는 약 0.65 정도 — 단순한 목표 설정에 비해 의미 있는 개선이지만, 압도적이진 않습니다.

Gollwitzer가 보여준 것은 그 사이에 있는 작은 다리였습니다. 목표를 상황 → 행동 의 결합으로 미리 적어두는 것. “만약 X 상황이 오면 Y라는 행동을 한다” 라는 문장 하나로 바꾸는 순간, 행동의 실행률이 의미 있게 올라갑니다.

이유는 신경학적으로도 단순합니다. 상황을 외부에서 들어오는 신호로 인코딩해 두면, 그 신호가 실제로 발생했을 때 의지를 거치지 않고 자동으로 행동이 트리거됩니다. 의지력은 비싼 자원이라, 의지력을 적게 쓰는 구조가 결국 더 멀리 갑니다.

Fecit의 쓰기 공간 한 층 더

Fecit이 다른 태스크 매니저와 의도적으로 다르게 두는 부분 중 하나는, 태스크당 쓰기 공간이 유난히 많다는 점입니다. 제목, 작전(description), 의도(intention), 현재 상태(target), 기대(expectation), 난관(obstacle), 결과(result), 회고(retrospect). 각각이 다른 질문을 사용자에게 던집니다. 어떤 일을 깊이 들여다보고 싶을 때 사용자가 펼칠 수 있는 층이 많습니다 (그리고 평소엔 다 접혀 있습니다 — minimal to maximal).

대응 지침은 그 층의 위에 하나 더 얹는 셈입니다. “이 일을 진행할 때 이런 상황이 오면 이렇게 한다” 를 미리 적어두는 자리. 작전이 전반적인 어떻게 라면, 대응 지침은 예상 가능한 분기를 미리 결정해 두는 곳입니다.

태스크 단위에 두기로 했다

처음 고민은, 이걸 글로벌 차원에 둘지 (예: “아침에 일어나면 물 한 잔” 같은 일상 규칙들), 태스크 단위에 둘지였습니다.

글로벌은 일상 습관 정착에 어울립니다. 어떤 상황어떤 행동이 항상 연결되어 있어야 하는 경우.

태스크 단위는 더 좁고 정확합니다. 이 일의 맥락 안에서만 유효한 if-then. 예를 들어 “발표 자료 작성” 태스크에 “만약 헤더 잡는 게 30분 넘으면 일단 본문부터 쓴다” 라는 규칙. 이 규칙은 그 태스크 바깥에서는 의미가 없습니다.

Fecit의 다른 쓰기 공간들 — intention, target, expectation, obstacle — 이 다 태스크 단위인 결과 입니다. 같은 결을 따라가는 게 자연스러웠습니다. 글로벌 if-then 은 (만약 필요하다면) 나중에 별도의 면을 가질 수 있습니다.

태스크 단위에 두니 자연스럽게 따라오는 것: template 에 적어두면 record 가 생성될 때 함께 따라간다. 매번 같은 일을 만들 때 같은 규칙을 다시 쓰지 않아도 됩니다.

한 태스크에 여러 규칙, 순서 있음

처음엔 한 태스크에 규칙 하나만 두는 단순한 모양으로 시작할까 했지만, 사용성을 생각해 보면 약합니다. 실제 일들엔 분기가 여러 개 있습니다.

[1] 만약 자료 모으는 게 30분 넘으면 → 일단 헤더만 잡고 본문으로
[2] 만약 헤더가 안 잡히면 → 작년 발표 파일 한 번 열어보기
[3] 만약 본문 다 쓰고도 영감이 없으면 → 산책 15분 후 다시

여러 개를 둘 수 있게, 그리고 순서를 사용자가 조절할 수 있게 했습니다. 카드 단위로 드래그-앤-드롭으로 reorder. 순서는 우선순위보다는 체크리스트의 흐름 같은 의미입니다 — 일을 시작할 때 위에서부터 한 번 훑어보면 그 일에서 마주칠 분기들이 떠오르는, 그런 용도.

Rich Text 쓰기로 했다

처음엔 단순 textarea로 시작했습니다. plain text 두 줄 짜리. 만들기 쉽고, 모바일에서도 데스크탑에서도 익숙한 입력.

그런데 사용자가 실제로 적어 보니까 — 핵심 단어를 강조하고 싶어지더군요. “만약 30분 넘으면” 같이. plain text로는 그 강조가 안 됩니다.

RichDescriptionEditor 로 바꿨습니다(Fecit의 다른 description 입력들과 같은 컴포넌트). HTML로 저장되니, 기존에 plain text로 저장된 데이터와 섞일 위험은 있었습니다. 카드 미리보기에서는 stripHtml 로 plain 텍스트로 떨궈서 표시 — HTML 콘텐츠는 태그가 벗겨지고, 기존 plain 콘텐츠는 그대로 흘러갑니다. 양쪽 다 자연스럽게 처리됩니다.

화면을 셋으로 쪼갰다

처음엔 단일 모달 안에서 다 했습니다. 리스트 보기 + 카드 클릭하면 그 자리에서 인라인 편집. 빠르긴 했지만, 편집 중에 다른 카드를 잘못 누르면 unsaved 상태로 이동하거나 하는 micro-friction이 있었습니다.

세 화면으로 분리했습니다.

  • List — 카드 목록 + 드래그 reorder + + 버튼
  • Create — 새 규칙 작성
  • Browse — 기존 규칙 편집 + 삭제

데스크탑은 세 화면이 다 모달, 모바일은 세 화면이 다 routing 되는 화면. 헤더는 py-2로 단순하게 (타이틀은 빼고 버튼만), 카드는 14px 글자에 10/12 padding으로 정돈했습니다. 처음엔 padding이 14/12로 컸는데, “한 화면에 몇 줄이 보이느냐”가 더 중요한 화면이라 줄였습니다.

카운트 표시는 chevron 옆에 붙여서

진입 버튼은 task detail의 작전 섹션 바로 아래에 있는, 한 줄짜리 가로 띠입니다. 왼쪽에 아이콘 + “대응 지침” 라벨, 오른쪽에 > chevron. 그 사이에 개수를 표시합니다.

처음엔 라벨 바로 옆에 개수가 붙어 있었습니다 — “대응 지침 3 →” 같이. 그런데 라벨이랑 너무 바짝 붙어서 라벨의 일부처럼 읽혔습니다. textAlign을 우측으로 바꿔서 chevron 바로 왼쪽으로 보냈습니다 — “대응 지침 … 3 →”. 라벨은 라벨대로, 개수는 chevron 옆에 붙어서 카드 안으로 들어간다는 시각적 힌트가 됩니다.

count = 0 일 때는 “아직 등록된 대응 지침이 없습니다.” 라는 verbose한 empty state를 적어두고 있었는데, 다른 entry 필드들이 빈 값에 빈 영역으로 두는 패턴을 따라 그냥 비웠습니다. chevron이 알아서 “탭하면 들어간다”의 의미를 전달합니다.

의식적 행동을 의식하지 않게 한다

대응 지침이 잘 작동하는 순간은 사실 그 카드를 다시 안 보는 순간입니다. 한 번 적어두고 일을 시작했을 때, 30분이 지나서 자료가 안 모이고 있을 때, 머리속에서 자동으로 “본문부터 잡기”가 떠오르면 — 그 규칙은 이미 자기 일을 한 겁니다. 의식적인 결정이 의식 없이 일어나도록 미리 옮겨둔 거죠.


행동을 결정하는 건 결심의 강도가 아니라 결정을 미리 끝낸 정도 입니다. 의지력은 비싼 자원이고, 그걸 매번 쓰면 결국 바닥납니다. if-then 한 줄로 미래의 결정을 지금 끝내 두면, 미래의 자기 자신은 그 결정을 다시 안 해도 됩니다.

“내가 어떤 사람인가”는 “내가 어떤 상황에서 무엇을 하는가”의 누적입니다. 그래서 그 두 줄을 적어두는 자리가 도구에 있어야 한다고 생각합니다.