Ayden's journal

D2 Diagram Language

D2 Diagram Language는 간결하고 직관적인 다이어그램을 생성할 수 있는 도메인 특화 언어다. D2는 특히 텍스트 기반으로 다이어그램을 그릴 수 있는 기능을 제공하여, 복잡한 그래픽 툴 없이 코드처럼 간단하게 다이어그램을 정의하고, 이를 자동으로 시각화할 수 있다.

주로 시스템 아키텍처, 플로우 차트, 클래스 다이어그램 등 다양한 다이어그램을 생성하는 데 사용되며, 코드와 같은 방식으로 다이어그램을 관리할 수 있어 버전 관리가 용이하다. 또한, D2는 매우 간결한 문법을 제공하여, 복잡한 시각적 요소를 쉽게 표현할 수 있도록 돕고, 개발자와 협업하는 데 유리한 도구이다.

아래의 명령줄을 입력하여 설치할 수 있으며, VS Code에서는 [ D2 ] 익스텐션을 사용하여 즉각적인 시각적 피드백을 받을 수 있다.

curl -fsSL https://d2lang.com/install.sh | sh -s --

 

변수

D2에서 변수는 노드, 엣지, 텍스트 등을 정의하는 데 사용될 수 있으며, 다이어그램을 구성하는 요소들의 값을 설정하는 방식으로 활용된다.

a
b
a -> b

 

변수에 콜론을 사용해 별칭을 붙여줄 수 있다

a: front end server
b: back end server
a -> b

 

 

변수 내에 shape 프로퍼티를 사용하여 상자의 모양을 지정해줄 수 있고, 변수 내에 변수를 선언하여 포함 관계를 구현할 수 있다.

a: front end server {
  shape: cloud

  nodejs {
    shape: page
  }
}
b: back end server

a.nodejs -> b

 

이런 식으로 코드 상자와 마크다운 상자를 구현할 수도 있다. 다만, 이 경우 shape 프로퍼티 등은 적용할 수 없는 듯하다.

code: |ts
  const a: number = 1
|

explanation: |md
  # I can do headers
  - lists
  - lists

  And other normal markdown stuff
|

 

연결

D2는 네 가지 방식의 변수 연결을 지원한다. 이 연결 관계 또한 일종의 변수로 취급할 수 있다. 이 연결에서 앞에 오는 게 source이고 뒤에 오는 게 target이다.

  • --
  • ->
  • <-
  • <->
a: front end server
b: back end server

a -> b: modifies {
  style.stroke-dash: 5

  source-arrowhead: * ... 1
  target-arrowhead: 1 {
    shape: diamond
    style.filled: true
  }
}

 

SQL 테이블

D2에서 shape을 sql_table로 설정한다면 계체-관계 다이어그램(ERD)을 쉽게 나타낼 수 있다.

User: {
  shape: sql_table
  width: 500
  
  id: String {constraint: [primary_key; unique;]}
  role: Role           
  email: String {constraint: unique}
  password: String 
  nickname: String {constraint: unique}
  profileImage: String?
  bio: String?
  createdAt: DateTime       
  updatedAt: DateTime       
  report: Array<Report> {constraint: foreign_key}
  reportLikes: Array<ReportLike> {constraint: foreign_key}
  receivedNotification: Array<Notification> {constraint: foreign_key}
  sentNotification: Array<Notification> {constraint: foreign_key}
  comments: Array<Comment> {constraint: foreign_key}
}

Report: {
  shape: sql_table
  width: 500
  
  id: String {constraint: [primary_key; unique;]}
  title: String
  content: String
  tags: Array<String>
  createdAt: DateTime 
  updatedAt: DateTime 
  userId: String
  isbn13: String?
  user: User {constraint: foreign_key}
  userLiked: Array<ReportLike> {constraint: foreign_key}
  book: Book? {constraint: foreign_key}
  editorsPick: EditorsPick? {constraint: foreign_key}
  comments: Array<Comment> {constraint: foreign_key}
  Notification: Array<Notification> {constraint: foreign_key}
}

User.report -> Report.id

 

UML 클래스

D2에서 shape을 class로 설정한다면 UML 클래스 다이어그램을 쉽게 나타낼 수 있다.

Ihandler: <<interface>>\nIHandler {
  shape: class;
  handle(props HandleMethodProps\<T\>): string | null
}

RequiredHandler {
  shape: class;
  handle(props HandleMethodProps\<T\>): string | null
}

MinLengthHandler {
  shape: class;
  handle(props HandleMethodProps\<T\>): string | null
}

MaxLengthHandler {
  shape: class;
  handle(props HandleMethodProps\<T\>): string | null
}

Ihandler <- RequiredHandler {
  style.stroke-dash: 5
}
Ihandler <- MinLengthHandler {
  style.stroke-dash: 5
}
Ihandler <- MaxLengthHandler {
  style.stroke-dash: 5
}

HandlerChain: HandlerChain<T extends InitState> {
  shape: class;

  -handlers: Array<IHandler<T>>
  -handlerMap: Map<ValidateKey, IHandler<T>>
  -setError: (action: Partial<T>) => void
  addHandler(handlerKey ValidateKey): void;
  doHandle(props HandleMethodProps\<T\>): void;
}

HandlerChain -> Ihandler {
  style.stroke-dash: 5

  target-arrowhead {
    shape: arrow
  }
}

블로그의 정보

Ayden's journal

Beard Weard Ayden

활동하기