무료 · 가입 불필요 · .mmd 파일 지원

Mermaid 클래스 다이어그램 편집기

클래스 다이어그램은 타입과 타입의 관계를 보여줍니다. 무엇이 무엇을 담고, 무엇이 무엇을 상속하며, 무엇이 무엇에 의존하는지. 코드의 형태 자체가 논점일 때 적합합니다. 도메인 모델, 확장 인터페이스, 상속 계층 같은 것들입니다. 타입이 어떻게 맞물리는지가 아니라 실행 중에 무슨 일이 일어나는지를 보이고 싶다면 시퀀스 다이어그램을 쓰세요.

결제 도메인 모델

한 장에 세 종류의 관계가 들어 있습니다. 전체보다 오래 살 수 없는 부분을 나타내는 합성, 결제수단 계층을 나타내는 상속, 그리고 다중도 레이블이 붙은 평범한 연관입니다. 여기서 의미를 나르는 것은 대부분 화살표 쪽이고, 클래스 상자는 곁들이에 가깝다는 점을 눈여겨보세요.

classDiagram
    class 주문 {
        +String 주문번호
        +주문상태 상태
        +금액 합계()
        +void 항목추가(상품 p, int 수량)
    }
    class 주문항목 {
        +상품 상품
        +int 수량
        +금액 소계()
    }
    class 결제수단 {
        <<abstract>>
        +승인(금액 액수) bool
    }
    class 신용카드 {
        +String 끝네자리
        +승인(금액 액수) bool
    }
    class 계좌이체 {
        +String 가상계좌번호
        +승인(금액 액수) bool
    }
    class 간편결제 {
        +String 연동토큰
        +승인(금액 액수) bool
    }

    주문 "1" *-- "1..*" 주문항목 : 항목을 가짐
    주문 --> 결제수단 : 결제
    결제수단 <|-- 신용카드
    결제수단 <|-- 계좌이체
    결제수단 <|-- 간편결제
편집기에서 열기
광고

예제로 익히기

1. 클래스 하나

`+`는 public, `-`는 private, `#`는 protected입니다. 반각 소괄호가 붙은 멤버는 메서드로, 붙지 않으면 필드로 그려집니다.

classDiagram
    class 회원 {
        +String 이메일
        -String 비밀번호해시
        +bool 검증(String 입력)
    }
편집기에서 열기

2. 상속과 인터페이스

`<|--`가 상속이고 「오른쪽이 왼쪽을 상속한다」로 읽습니다. `<<interface>>`는 동작이 아니라 표시일 뿐이지만, 다이어그램의 읽기 쉬움은 이것으로 결정됩니다.

classDiagram
    class 회원저장소 {
        <<interface>>
        +조회(String id) 회원
        +저장(회원 e) void
    }
    class Postgres회원저장소 {
        -Connection 연결
        +조회(String id) 회원
        +저장(회원 e) void
    }
    class 메모리회원저장소 {
        -Map 보관소
        +조회(String id) 회원
        +저장(회원 e) void
    }
    회원저장소 <|.. Postgres회원저장소
    회원저장소 <|.. 메모리회원저장소
편집기에서 열기

3. 합성과 집합

차이는 수명입니다. 채워진 마름모 `*--`는 전체가 사라지면 부분도 사라진다는 뜻입니다. 청구서를 지우면 명세도 없어집니다. 빈 마름모 `o--`는 부분이 독립적으로 계속 존재한다는 뜻입니다.

classDiagram
    class 청구서 {
        +String 청구번호
    }
    class 청구명세 {
        +String 품목
    }
    class 거래처 {
        +String 상호
    }
    청구서 "1" *-- "1..*" 청구명세 : 구성됨
    거래처 "1" o-- "0..*" 청구서 : 발행함
편집기에서 열기

4. 제네릭

물결표로 타입 인자를 씁니다. `저장소~회원~`처럼 한글 타입 이름도 그대로 쓸 수 있습니다. 중첩도 되지만, 된다는 것뿐이지 좋은 생각인 경우는 드뭅니다.

classDiagram
    class 저장소~T~ {
        +조회(String id) T
        +전체() List~T~
    }
    class 캐시~K, V~ {
        +가져오기(K 키) V
        +넣기(K 키, V 값) void
    }
    class 회원저장소 {
        +이메일로조회(String 이메일) 회원
    }
    저장소~회원~ <|-- 회원저장소
편집기에서 열기

5. 메모와 배치 방향

`direction LR`은 왼쪽에서 오른쪽으로 배치합니다. 상속 계층은 기본 상하보다 가로로 놓는 편이 대개 잘 들어맞습니다. 클래스 상자에 담기지 않는 제약은 메모에 적는 것이 정답입니다.

classDiagram
    direction LR
    class 이벤트저장소 {
        +추가(이벤트 e) void
        +재생(String 스트림id) List~이벤트~
    }
    class 스냅샷 {
        +int 버전
        +byte[] 내용
    }
    이벤트저장소 --> 스냅샷 : 100건마다 기록
    note for 이벤트저장소 "추가 전용. 이벤트는 수정도 삭제도 하지 않습니다."
편집기에서 열기

클래스 다이어그램 문법 요약

외울 값어치가 있는 것은 관계 화살표입니다. 이것이 클래스 다이어그램을 단순한 상자와 선 그림에서 구별해 주며, 오른쪽에서 왼쪽으로 읽는 탓에 오래도록 헷갈립니다.

문법
classDiagram다이어그램을 시작합니다. 대소문자를 구분합니다.
class 이름 { ... }멤버를 가진 클래스. 닫는 중괄호는 단독 행에.
+멤버public.
-멤버private.
#멤버protected.
+메서드(타입 인자) 반환타입메서드 — 반각 소괄호가 붙은 것이 메서드가 됩니다.
<<interface>> / <<abstract>>스테레오타입. 클래스 안의 첫 행에 적습니다.
A <|-- B상속: B가 A를 상속합니다.
A <|.. B실현: B가 인터페이스 A를 구현합니다.
A *-- B합성: B는 A보다 오래 살 수 없습니다.
A o-- B집합: B는 A 없이도 존재할 수 있습니다.
A --> B방향이 있는 연관.
A ..> B의존 — A가 B를 쓰지만 보유하지는 않습니다.
A "1" --> "0..*" B : 레이블양 끝의 다중도와 관계 레이블.
class 저장소~T~제네릭 타입 인자.
note for A "글자"클래스에 메모를 붙입니다.
direction LR배치 방향을 바꿉니다.
광고

클래스 다이어그램을 깨뜨리는 여섯 가지 오류

Mermaid 11.12.2에서 재현했습니다. 클래스 다이어그램은 여기서 다루는 여섯 종류 가운데 너그러운 편이라, 아래의 절반은 아무 일 없이 그려진 다음 의도와 다른 그림을 돌려줍니다.

보이는 증상

Parse error, 끝부분: got 'EOF_IN_STRUCT'

원인

`{`로 연 클래스 본체가 닫히지 않았습니다. 이 토큰 이름은 드물게 친절해서, 클래스 안에 있는 채로 파일이 끝났다는 뜻입니다.

해결

닫는 중괄호를 단독 행에 둡니다.

잘못된 예
classDiagram
    class 주문 {
        +String 주문번호
고친 예
classDiagram
    class 주문 {
        +String 주문번호
    }

보이는 증상

그려지기는 하는데 메서드가 필드로 그려진다

원인

소괄호가 전각입니다. 메서드인지 필드인지를 정하는 것은 반각 `()`뿐이고, 전각 `()`는 이름의 일부로 취급됩니다. 한글 입력 상태에서 괄호를 치면 자연스럽게 이렇게 되고, 화면에서 구별하기도 어렵습니다. 실측하면 차이가 분명합니다. 반각이면 `+합계() : 금액`으로 메서드 칸에 재배치되면서 반환 타입 서식이 붙지만, 전각이면 `+합계() 금액` 그대로 필드 칸에 남습니다.

해결

괄호는 반각으로 칩니다. 한글 입력 중에도 괄호만은 반각으로 바꾸는 습관을 들이면 안전합니다.

잘못된 예
classDiagram
    class 주문 {
        +합계() 금액
        +String 주문번호
    }
고친 예
classDiagram
    class 주문 {
        +합계() 금액
        +String 주문번호
    }

보이는 증상

Parse error, 끝부분: got 'ANNOTATION_END'

원인

시퀀스 다이어그램의 화살표를 클래스 다이어그램에서 썼습니다. `->>`는 여기서 아무 뜻도 없고, 파서가 중간까지 읽어 들이기 때문에 알아보기 어려운 토큰 이름이 나옵니다.

해결

클래스 다이어그램의 관계를 씁니다. 연관은 `-->`, 상속은 `<|--`, 합성은 `*--`입니다.

잘못된 예
classDiagram
    주문 ->> 고객
고친 예
classDiagram
    주문 --> 고객 : 속함

보이는 증상

No diagram type detected matching given configuration

원인

키워드의 대소문자가 다릅니다. `classdiagram`은 `classDiagram`이 아닙니다.

해결

D를 대문자로 합니다.

잘못된 예
classdiagram
    class 주문
고친 예
classDiagram
    class 주문

보이는 증상

화살표가 의도와 반대를 가리킨다

원인

클래스 다이어그램의 관계는 화살촉에서 거꾸로 읽습니다. `A <|-- B`는 「B가 A를 상속한다」이지 그 반대가 아닙니다. 거꾸로 써도 그려지기는 합니다. 다만 부모 클래스가 자기 자식 클래스를 상속한다고 주장하는 그림이 됩니다.

해결

「멀리 있는 쪽이 화살촉 쪽을 상속한다」로 읽습니다. `<|--`의 왼쪽에 부모를 두세요.

잘못된 예
classDiagram
    신용카드 <|-- 결제수단
고친 예
classDiagram
    결제수단 <|-- 신용카드

보이는 증상

합성과 집합이 얼핏 같아 보이는데 뜻은 정반대

원인

`*--`와 `o--`는 한 글자 차이지만, 부분이 전체보다 오래 살 수 있는지라는 실제 의미의 차이를 담습니다. 잘못 고르면 형식적으로는 옳고 도메인에 대해서는 틀린 그림이 나옵니다.

해결

부모를 지우면 자식도 지워지면 채워진 `*--`, 지워지지 않으면 빈 `o--`입니다.

잘못된 예
classDiagram
    주문 o-- 주문항목 : 항목을 가짐
고친 예
classDiagram
    주문 *-- 주문항목 : 항목을 가짐

렌더링에 관한 메모

모두 이 사이트가 쓰는 Mermaid 11.12.2에서 실측했습니다.

여기서 다루는 종류 가운데 세로로 가장 빨리 자랍니다

멤버를 두 개씩 가진 클래스를 상속으로 이어 실측하면, 3개일 때 viewBox가 대략 176×548, 40개에서 180×7726이었습니다. 클래스 하나당 약 194픽셀로, 여섯 종류 중 가장 가파른 증가입니다. 40클래스 그림은 7000픽셀을 넘어 한 장의 이미지로는 쓸 수 없습니다. `direction LR`이 도움이 되지만, 15클래스를 넘어서면 업무 경계로 그림을 나누는 것이 정직한 대처입니다.

멤버 개수는 폭에 거의 영향을 주지 않습니다

폭을 정하는 것은 가장 긴 멤버 한 줄이지 멤버가 몇 개인가가 아닙니다. 짧은 필드를 20개 가진 클래스는 3개짜리 클래스와 같은 폭입니다. 즉 멤버에는 후하고 클래스 수에는 인색해도 된다는 뜻이며, 대개의 직관과는 반대입니다.

한글 클래스명의 띄어쓰기는 조용히 붙습니다

`class 주문 항목`이라고 쓰면 결과는 `주문항목`이 됩니다. 오류도 경고도 없이 공백만 사라집니다. 상태 다이어그램에서는 같은 띄어쓰기가 상태를 둘로 쪼개 버리므로, 그림 종류에 따라 동작이 다르다는 점은 알아둘 값어치가 있습니다. 클래스 다이어그램에서는 대체로 무해하지만, 그만큼 알아채지 못한 채 남습니다.

제네릭은 물결표를 쓰고, 그에 따른 결과가 있습니다

`저장소~T~`가 이런 모양인 것은 꺾쇠가 레이블의 HTML과 충돌하기 때문입니다. 동시에 클래스나 멤버 이름 안의 물결표 한 글자가 타입 인자의 시작으로 읽힌다는 뜻이기도 합니다. 드물지만 일어나면 정말 헷갈립니다.

레이블이 HTML이라 PNG 내보내기는 다시 그립니다

클래스 레이블은 SVG의 `<foreignObject>` 안에 그려지고, 브라우저는 이것을 캔버스에 래스터화하기를 거부합니다. 이 사이트의 PNG 내보내기는 예전에 이 때문에 조용히 실패해 SVG 파일을 돌려주고 있었습니다. 지금은 순수 SVG 텍스트 레이블로 다시 그린 뒤 출력합니다. PNG는 원래 크기로 올바르게 나오지만 글자 배치가 화면과 아주 조금 다릅니다.

다른 다이어그램이 나은 경우

타입 체계가 아니라 데이터베이스를 설명하고 있다면 ER 다이어그램을 쓰세요. 이 구별에는 실질이 있습니다. 클래스 다이어그램은 동작과 상속을 표현할 수 있지만 테이블에는 그 둘이 없고, 반대로 ER 다이어그램은 키와 다중도를 제대로 표현하지만 클래스 다이어그램은 그 부분을 얼버무립니다.

그림이 거의 상자와 `-->`뿐이고 멤버가 적혀 있지 않다면, 그것은 클래스 다이어그램이 아니라 아키텍처 그림입니다. 서브그래프를 쓴 순서도가 보기에도 낫고 군더더기 주장도 하지 않습니다.

그리고 클래스 목록을 코드에서 생성하고 있다면, 그림도 생성해야 하는지 생각해 보세요. 매주 바뀌는 코드베이스의 클래스 다이어그램을 손으로 유지하면 한 달이면 거짓말이 됩니다. 틀린 그림은 그림이 없는 상태보다 비싸게 먹힙니다.

다른 다이어그램 종류

작성 Dominik Malsch · 마지막 업데이트:

편집기 열기 →