Mermaid 상태 다이어그램 편집기
상태 다이어그램은 하나의 대상이 가질 수 있는 상태와, 그 사이를 옮기는 사건을 보여줍니다. 대상이 생애주기를 가질 때 적합합니다. 주문, 구독, 검토 중인 문서 같은 것들입니다. 알아보는 방법은 간단합니다. 레이블이 동작이 아니라 상태를 나타내는 말이면 상태 다이어그램입니다. 결제 대기, 배송됨, 취소됨.
취소가 종착인 주문 생애주기
상태는 주문이 「무엇인가」이고, 화살표의 레이블은 주문에 「무슨 일이 일어났는가」입니다. 취소됨에는 세 상태에서 도달하지만 거기서는 아무 데도 가지 않는다는 점을 보세요. 이런 비대칭이야말로 상태 다이어그램이 한눈에 보여주고 순서도가 감추는 것입니다.
stateDiagram-v2
state "결제 대기" as 결제대기
[*] --> 결제대기: 주문 접수
결제대기 --> 결제완료: 결제 승인
결제대기 --> 취소됨: 고객이 취소
결제완료 --> 출고준비: 창고에서 피킹
결제완료 --> 환불됨: 결제 취소
출고준비 --> 배송중: 택배사 인수
출고준비 --> 취소됨: 재고 부족
배송중 --> 배송완료: 수령 확인
배송중 --> 분실됨: 14일간 스캔 없음
배송완료 --> [*]
환불됨 --> [*]
취소됨 --> [*]
분실됨 --> 환불됨: 보상 승인예제로 익히기
1. 가장 작은 상태 기계
`[*]`는 시작이기도 하고 끝이기도 합니다. 어느 쪽을 뜻하는지는 화살표의 어느 편에 있느냐로 정해집니다.
stateDiagram-v2
[*] --> 초안
초안 --> 게시됨: 게시하기
게시됨 --> [*]2. 띄어쓰기가 들어간 상태 이름 붙이기
상태 ID에는 공백을 쓸 수 없지만, `state "표시 이름" as ID`로 쓰면 안전한 ID를 유지하면서 읽기 좋은 레이블을 붙일 수 있습니다. 한국어에서는 이 방식이 사실상 필수입니다. 자연스러운 상태 이름은 대부분 두 어절 이상이기 때문입니다.
stateDiagram-v2
state "검토 대기" as 검토
state "수정 요청됨" as 수정
[*] --> 검토
검토 --> 수정: 검토자가 반려
수정 --> 검토: 작성자가 수정
검토 --> [*]: 승인됨3. 복합 상태
상태는 그 안에 자신만의 상태 기계를 가질 수 있습니다. 어떤 단계에 의미 있는 내부 절차가 있고, 그것을 최상위에 늘어놓으면 지저분해질 때 씁니다. 여기서는 처리중 안에서 일어나는 일을 묶었습니다.
stateDiagram-v2
[*] --> 대기열
대기열 --> 처리중: 워커가 가져감
state 처리중 {
[*] --> 검증
검증 --> 변환: 스키마 일치
변환 --> 기록
기록 --> [*]
}
처리중 --> 성공: 오류 없음
처리중 --> 실패: 예외 발생
실패 --> 대기열: 재시도
성공 --> [*]4. 조건 분기 (choice)
`<<choice>>`는 사건이 아니라 조건으로 갈리는 분기입니다. 판단을 그림 위에 남기면서도, 그것이 대상이 머무는 상태인 것처럼 꾸미지 않아도 됩니다.
stateDiagram-v2
state 심사 <<choice>>
[*] --> 신청접수
신청접수 --> 심사: 리스크 점수 계산
심사 --> 자동승인: 점수 40 미만
심사 --> 수동심사: 점수 40 이상
수동심사 --> 자동승인: 심사자가 승인
수동심사 --> 거절됨: 심사자가 거절
자동승인 --> [*]
거절됨 --> [*]5. 병렬 영역
복합 상태 안에 하이픈 두 개만 있는 줄을 넣으면 동시에 유효한 영역으로 갈립니다. 순서도가 정말로 흉내 낼 수 없는, 상태 다이어그램만의 표현입니다.
stateDiagram-v2
[*] --> 가입절차
state 가입절차 {
[*] --> 메일미인증
메일미인증 --> 메일인증됨: 링크 클릭
--
[*] --> 프로필미작성
프로필미작성 --> 프로필완료: 폼 제출
}
가입절차 --> 활성: 둘 다 완료
활성 --> [*]상태 다이어그램 문법 요약
`stateDiagram`이 아니라 `stateDiagram-v2`를 쓰세요. 둘 다 그려지지만, v2가 지금도 개발이 이어지는 배치 엔진이고 복합 상태와 병렬 상태를 훨씬 잘 다룹니다.
| 문법 | 뜻 |
|---|---|
| stateDiagram-v2 | 다이어그램을 시작합니다. `stateDiagram`도 동작하지만 예전 배치입니다. |
| [*] --> A | 초기 상태 — 진입점. |
| A --> [*] | 종료 상태. |
| A --> B | 계기를 적지 않은 전이. |
| A --> B: 사건 | 그 전이를 일으키는 사건을 레이블로. |
| state "표시 이름" as id | 공백 없는 ID와 읽기 좋은 표시 이름. |
| state A { ... } | 내부에 상태 기계를 가진 복합 상태. |
| -- | 복합 상태 안에서 병렬 영역으로 나눕니다. 하이픈은 정확히 두 개. |
| state x <<choice>> | 조건에 따른 분기점. |
| state f <<fork>> / <<join>> | 병렬 전이로 갈라졌다가 합류. |
| note right of A: 글자 | 메모를 붙입니다. `note left of`도 있습니다. |
| direction LR | 위아래가 아니라 좌우로 배치합니다. |
상태 다이어그램을 깨뜨리는 여섯 가지 오류
Mermaid 11.12.2에서 재현한 것입니다. 앞의 네 개는 그리기가 멈춥니다. 뒤의 두 개는 더 고약합니다. 아무 일 없이 그려진 다음, 적은 것과 다른 그림을 돌려줍니다.
보이는 증상
그려지기는 하는데 상태 하나가 여러 개의 상자로 늘어나 있다
원인
상태 ID 안에 띄어쓰기가 들어갔습니다. 한국어에서 가장 자주 밟는 함정입니다. 중국어나 일본어는 단어를 띄어 쓰지 않아 이 문제가 아예 생기지 않지만, 한국어는 띄어 쓰고 자연스러운 상태 이름은 대개 두 어절입니다. Mermaid는 이것을 거부하지도 않고, 나머지를 설명으로 읽지도 않습니다. 어절마다 별개의 상자를 만듭니다. 출력된 state ID를 직접 읽어 측정했습니다. `[*] --> 결제 대기`는 「결제」와 「대기」 두 상태를 만들고, 화살표 끝에 걸리는 것은 앞의 것뿐이며 나머지는 아무 데도 연결되지 않은 채 남습니다. 세 어절이면 상자가 세 개가 되고, 그림은 아무 말 없이 옆으로 넓어집니다. 설명 기능은 실제로 있지만 콜론이 필요합니다. `대기: 입금을 기다리는 중`처럼 쓰는 것이며, 이 실수는 바로 그것과 혼동된 결과입니다.
해결
`state "표시 이름" as ID`로 선언하고, 이후로는 ID로만 참조합니다.
stateDiagram-v2
[*] --> 결제 대기
결제 대기 --> 종료stateDiagram-v2
state "결제 대기" as 결제대기
[*] --> 결제대기
결제대기 --> 종료보이는 증상
Parse error, 끝부분: got 'INVALID'
원인
상태 ID에 하이픈이 들어갔습니다. `in-progress` 같은 케밥 케이스는 손에 익어서 자꾸 나오는데, 하이픈은 전이 화살표의 시작으로 읽힙니다.
해결
ID는 한 덩어리나 밑줄로 잇고, 읽을 글자는 따옴표 표시 이름에 넣습니다.
stateDiagram-v2
[*] --> in-progress
in-progress --> 종료stateDiagram-v2
state "진행 중" as 진행중
[*] --> 진행중
진행중 --> 종료보이는 증상
복합 상태 안에서 Parse error
원인
`{`로 연 복합 상태가 닫히지 않았습니다. 닫는 중괄호는 단독 행에 두어야 합니다.
해결
블록을 닫습니다.
stateDiagram-v2
[*] --> 바깥
state 바깥 {
[*] --> 안쪽stateDiagram-v2
[*] --> 바깥
state 바깥 {
[*] --> 안쪽
}보이는 증상
Lexical error on line N. Unrecognized text.
원인
병렬 영역 구분선의 하이픈 개수가 틀렸습니다. 복합 상태 안에서, 단독 행에, 정확히 두 개입니다. 세 개는 완전히 다른 토큰입니다.
해결
`--`를 씁니다.
stateDiagram-v2
state 둘다 {
[*] --> A
---
[*] --> B
}stateDiagram-v2
state 둘다 {
[*] --> A
--
[*] --> B
}보이는 증상
Parse error on line 1, 끝부분: got 'ID'
원인
존재하지 않는 버전 접미사입니다. `stateDiagram`과 `stateDiagram-v2` 두 개뿐이고, `-v3`은 첫 줄에서 떨어집니다.
해결
`stateDiagram-v2`를 씁니다.
stateDiagram-v3
[*] --> 초안stateDiagram-v2
[*] --> 초안보이는 증상
그려지기는 하는데 분기점이 평범한 상태로 그려진다
원인
`<<choice>>` 선언을 그것을 쓰는 전이보다 뒤에 적었습니다. Mermaid는 이름이 처음 나온 시점에 그 상태를 만들기 때문에, 나중에 붙인 스테레오타입은 이미 만들어진 것을 바꾸지 않습니다.
해결
의사 상태는 그것을 참조하는 전이보다 먼저 선언합니다.
stateDiagram-v2
[*] --> 심사
심사 --> 자동승인
심사 --> 수동심사
state 심사 <<choice>>stateDiagram-v2
state 심사 <<choice>>
[*] --> 심사
심사 --> 자동승인
심사 --> 수동심사렌더링에 관한 메모
모두 이 사이트가 쓰는 Mermaid 11.12.2에서 실측한 것입니다.
한국어가 중국어·일본어와 갈라지는 지점이 바로 여기입니다
세 언어를 한 묶음으로 생각하기 쉽지만, 이 오류에서는 정반대로 갈립니다. 중국어와 일본어는 단어 사이를 띄우지 않으므로 상태 ID에 공백이 섞일 일이 구조적으로 없습니다. 한국어는 띄어 쓰고, 게다가 자연스러운 상태 이름이 거의 다 두 어절 이상입니다. 실측으로 확인한 것은 순서도와 상태 다이어그램의 처리가 다르다는 점입니다. 순서도에서는 노드 ID의 공백이 Parse error로 즉시 걸리지만, 상태 다이어그램에서는 아무 경고 없이 그려지고, 상태가 어절 수만큼의 상자로 늘어납니다. 알려주는 오류와 알려주지 않는 오류의 차이이고, 여기서는 스스로 알아채는 수밖에 없습니다.
높이는 상태당 약 114픽셀 늘어납니다
실측하면 상태 3개일 때 viewBox가 대략 91×348, 40개에서 100×4566이었습니다. 상태 하나당 약 114픽셀입니다. 순서도와 마찬가지로 폭은 거의 움직이지 않고 상태 기계는 아래로만 자랍니다. 생애주기가 길고 가지가 얕을 때는 다이어그램 안에 `direction LR`을 적는 것이 정석입니다.
stateDiagram도 stateDiagram-v2도 그려집니다 — 이것이 함정
「`stateDiagram-v2`를 쓰지 않으면 아무것도 안 그려진다」는 설명을 자주 보지만 11.12.2에서는 맞지 않습니다. 두 키워드 모두 오류 없이 그려집니다. 다른 것은 배치 품질, 특히 복합 상태와 병렬 상태의 처리이고, 옛것을 써도 경고가 나오지 않습니다. 복합 상태가 답답해 보이거나 화살표가 이상하게 돌아간다면, 다이어그램을 고쳐 쓰기 전에 어느 키워드로 열었는지부터 확인하세요.
레이블이 HTML이라 PNG 내보내기는 다시 그립니다
순서도·클래스 다이어그램·ER 다이어그램과 마찬가지로, 상태의 레이블은 SVG의 `<foreignObject>` 안에 그려집니다. 브라우저가 이것을 캔버스에 래스터화하기를 거부하므로, 이 사이트의 PNG 내보내기는 먼저 순수 SVG 텍스트 레이블로 다시 그린 뒤 출력합니다. PNG는 원래 크기로 올바르게 나오지만 글자 배치가 화면과 아주 조금 다릅니다.
테마는 색만 바꾸고 배치는 바꾸지 않습니다
같은 소스를 밝은 테마와 어두운 테마로 그리면 viewBox가 완전히 같습니다. 테마를 바꿨다고 상태 기계가 다시 짜이는 일은 없습니다.
다른 다이어그램이 나은 경우
레이블이 동사라면 — 검증한다, 전송한다, 재시도한다 — 그것은 생애주기가 아니라 절차를 적고 있는 것이고, 정직한 선택은 순서도입니다. 가장 분명한 신호는 「이 상태에 있는 것이 무엇입니까」라는 물음에 답할 수 없다는 점입니다.
여러 구성 요소가 각자의 생애주기를 갖고 있고 흥미로운 쪽이 그 상호작용이라면, 구성 요소마다 상태 다이어그램을 하나씩 그리고 주고받는 부분은 시퀀스 다이어그램에 맡기는 편이 거대한 상태 기계 한 장보다 확실히 잘 전달됩니다.
그리고 모든 상태가 모든 상태와 이어져 있다면 어떻게 그려도 실뭉치가 됩니다. 그것은 대개 상태라고 늘어놓은 것이 실은 자유롭게 조합되는 플래그라는 뜻입니다. 그럴 때는 유효한 조합의 표가 그림보다 훨씬 많은 것을 말해줍니다.
다른 다이어그램 종류
작성 Dominik Malsch · 마지막 업데이트: