世界を動かす技術を、日本語で。

D2: ダイアグラムスクリプト言語

概要

D2 はテキストからダイアグラムを生成する 宣言型スクリプト言語 CLIを使って 簡単に画像化 ファイル作成からコマンド実行まで の流れ ウォッチモードチートシート の活用 Playground でスニペットを直接編集可能

D2とは何か

  • D2Declarative Diagramming の略称
  • テキストで 図を宣言的に記述、自動でダイアグラム画像を生成
  • 「何を描きたいか」を 記述するだけ でOK

基本的な使い方

  • CLI(コマンドラインインターフェース) をダウンロード
  • 任意の名前(例: input.d2)で ファイルを作成
  • ダイアグラム記述例を コピーペースト
    • 例:
      NETWORKUSERAPI SERVERLOGSCELL TOWERONLINE PORTALDATA PROCESSORSATELLITESTRANSMITTERUISTORAGE
      SENDSENDSENDPHONE LOGSMAKE CALL ACCESSDISPLAYPERSIST
      
  • コマンドを実行して 画像を生成
  • ウォッチモード でリアルタイムプレビューが可能

学習サポート

  • 5-10分 のツアーで基本機能を体験
  • 2分 で完了するGetting Startedガイド
  • チートシート をダウンロードして参照

Playgroundの活用

  • 各D2スニペットに マウスオーバー でPlaygroundを開くリンク
  • Playgroundで 直接編集・確認 が可能
    • 一部例外(importを使うスニペットなど)

まとめ

  • D2 は宣言的な記述のみで 即座にダイアグラム生成
  • CLIとPlayground で初心者にも扱いやすい設計
  • 学習コストが低く、短時間で基本操作をマスター可能

Hackerたちの意見

D2は結構前からあって(ここにも前に投稿されたことあるけど)、それでも意外と知られてないよね。マーメイドより全然いいから、この投稿でみんなに知ってもらいたいな!

D2の方がマーメイドより好きだけど、マーメイドは色んなところでネイティブにサポートされてるから、実用的な選択肢になってるよね。

D2については知らなかったな。mermaidより優れた機能があれば教えてくれない?

D2に関する最近の投稿(73コメント): [1] D2(テキストから図を作るツール)がASCIIレンダリングをサポートしたよ! https://news.ycombinator.com/item?id=44954524

D2やペンローズみたいなものを見て、Pythonでラップしてデータに基づいた図を作るのをもうちょっと楽にしようと考えてるんだ。問題を解決していくうちに、Haskellみたいなものでやった方が良さそうだなって思うけど、これらのツールで図を描くのが簡単になればなるほど、プログラム的な図作成を使ってデバッグや説明を手助けする人が増えると思う。D2やdot、マーメイドみたいな宣言型ツールの最大の問題は、「宣言してから調整する」ワークフローをあまり提供してないことだよね。もちろんSVGを生成してからInkscapeで調整することはできるけど、時にはレイアウト後にちょっとだけ動かしたいだけの時もあるんだよね。ペンローズはそれを簡単にしてくれるけど、代わりに…他の部分が変わっててランダムになるって感じかな。

D2は独自のレイアウトエンジンでカスタムレイアウトの調整を許可してるよ。残念ながら、オープンソースのものではできないけどね。 https://docs.d2studio.ai/tour/freehand

スケッチモードも入ってるよ! https://d2lang.com/tour/sketch/ ツールチップやリンクもあるしね: https://d2lang.com/tour/interactive/ この2つは私にとって大きな違いをもたらしてる。

D2の共同著者だよ。最近、アニメーション機能を拡張するアイデアを考えてるんだ。ここでちょっと考えをつぶやいてみるけど、もし意見があったら聞かせてほしいな: https://github.com/terrastruct/d2/discussions/2677

あのアニメーションの目的って何なの?プレゼンで図をクリックしながら追加していって、その接続がアニメーションで強調されるならいいけど、リンク先の例みたいにテキストが変わるたびに図全体が飛び跳ねるのはちょっとイライラしそう。だから、すべてをレンダリングして、アクティベートされるまで隠しておく必要があるのかな?それと、ちゃんとしたスイムレーン図が欲しいな。フローチャートでネストできる能力はあるから、スイムレーンのボックスを強制的に整列させたり、レーン自体を整列させたりするだけでいいと思う(多分、裏でやることはもっとあるだろうけど)。

レベル4 - ドラマティックモード ;) https://blog.viraptor.info/dramatic-svg/index.html

最初の「クールなスロップ」の例にはちょっと驚いた。もっと具体的な(アニメーションを使った)データフローの可視化の方が役立つと思ってたんだけど。動的じゃないから(ライブデータとかに基づいてないから)、余計なものになっちゃうのかな?

こんにちは、アリクサンダー!D2を使い始めたのは数ヶ月前で、仕事で初めてシステムを設計することになったんだ。すごく満足してるよ。簡単に使えるのに驚いた。正直、こういう派手なアニメーションは必要ないと思う。図の中で特定のボックスや矢印に注目させたいなら、動かすより赤くする方がいいな。

まずはD2の開発に感謝!個人的には一番クールだと思ってる。アニメーションは絶対に使うよ。管理職はキラキラしたものが好きだから、彼らが喜んでくれれば給料も上がるしね。最近、D2を使ってAWSアカウントのネットワークレイアウトを動的にコーディングするソリューションを作ったんだ。D2だけが、たくさんのオブジェクトをレンダリングするのに、エンジンと戦わずに済む方法を提供してくれた。唯一の不満は、sdk/d2libのドキュメントがすごく不足してたこと。最初は地図としてテキストを生成するところから始めたけど、ほとんど使われてないもっと良い方法があることに気づくまで時間がかかった。難しい部分をライブラリで使う方法を理解するのにちょっと時間がかかったよ。

これは私のプロジェクトにめっちゃ役立ちそう!

これ、大きなリクエストだって分かってるけど、最近LLMを使ってアーキテクチャの決定をさくっとドラフトして見せることが多いんだ。主にmermaidに戻るけど、d2の方がもっと柔軟なのかな?結局、drawioで可視化することが多いし。LLMと一緒にもっとユーザーフレンドリーなインターフェース(mcpとかツール呼び出し機能)を作る計画があるのか気になるな。

この構文を見てると、「普通の」プログラミング言語でどれくらい近づけるか気になるな。x -> y: hello worldは、xとyという2つの形の間に「hello world」というラベルで接続を宣言してる。これを読んでると、頭の中にこのPythonの行が浮かぶんだ:connect('x', 'y', 'hello world') もちろん、こっちの方が長いけどね。D2は関数よりも演算子を使うことが多いみたいだから、別のアプローチとしては'x' * 'y' + 'hello world'ってのも考えられる。これは、strクラスの__add__と__mul__関数のオーバーロードをサポートしてる言語なら実装可能だね。でもPythonはそれをサポートしてないから、少なくともカスタムクラスのインスタンスを1つ混ぜる必要があるかな。例えば'scene'を使えば、次の行で上記を実現できるかもしれない:scene + 'x' * 'y' + 'hello world' つまり、「xとyの間に'hello world'というラベルの接続をsceneに入れる」ってこと。うーん…これもD2の構文にはあまり近くないね。だから、図のためのDSLが必要だと思うな。

Scalaでは、自分のオペレーターを定義できるから、できるんだよね(オペレーターはメソッド名に過ぎないし)。自分がコントロールしていない型を拡張することもできるし。ただ、オペレーターの優先順位のルールに少し制約されるけど、だいたいは問題ないよ。DSLを乱造するのは良くないけど、必要な時にはできるよね。例えば、ここでは「x」 --> 「y」 | 「hello world」みたいにできる。

すべての「普通の言語」(あるいは「動的スクリプト言語」)が同じように作られているわけじゃないよね。Rubyの内部DSLでd2の文法全体に相当するものを目指すつもりはないけど、オプションのラベル付きのエッジを作りたいなら、シンプルに「裸」のエッジをx >> y、ラベル付きのエッジをx >> yみたいにできるよ。こんな感じで書ける:

class Diagram
  def initialize
    @nodes = Hash.new { |h, k| h[k] = Node.new(self, k) }
    @edges = {}
  end

  def node(name)
    @nodes[name]
  end

  def add_edge(edge)
    @edges[edge.from_node] ||= {}
    @edges[edge.from_node][edge.to_node] = edge
  end

  def all_edges
    @edges.values.flat_map(&:values)
  end

  def interpret(&block)
    interpreter = D2.new(self)
    interpreter.instance_eval(&block)
    self
  end

  def to_s
    all_edges.map(&:to_s)
  end

  def inspect
    to_s
  end
end

class D2
  def initialize(diagram = nil)
    @diagram = diagram || Diagram.new
  end

  def method_missing(name, *args)
    @diagram.node(name)
  end
end

class Node
  def initialize(diagram, name)
    @diagram = diagram
    @name = name
  end

  def >>(other_node)
    Edge.new(self, other_node).tap do |edge|
      @diagram.add_edge(edge)
    end
  end

  def to_s
    @name
  end

  def inspect
    "Node(#{to_s})"
  end
end

class Edge
  def initialize(from_node, to_node, label = nil)
    @from_node = from_node
    @to_node = to_node
    @label = label
  end

  def to_s
    "#{@from_node.to_s} -> #{@to_node.to_s}" + (@label ? ":#@label" : "")
  end

  def inspect
    "Edge(#{to_s})"
  end
end

こんな風に使えるよ:

irb(main):090:0> d = Diagram.new
=> []
irb(main):091:1* d.interpret { irb(main):092:1* x >> y > z }
=> ["x -> y:hello, world!", "y -> z:goodbye, cruel world!"]

もちろん、これは機能のほんの一部しかサポートしてなくて、元のd2の文法に近いテキスト形式にしか「レンダリング」しないけど、DiagramクラスからDSLのオブジェクトモデルを作ることはできるよ。

エッジが左から右ではなく、右から左に行くのが大丈夫なら、Pythonではこんな風に書けるよ:

def main():
    a, b, c = Node("a"), Node("b"), Node("c")
    edges = [a

こういう風に動くよ:'-'記号は単項マイナスとして解釈されて、そのまま無視される。'<'記号はNodeクラスの'lt'オーバーロードで処理される。'|'オペレーターはPythonでは'<'よりも優先順位が高いから、エッジのラベルは右側のノードに保存される。とはいえ、これを実際にプロダクションで使ったら、追いかけるからね。

d2大好き!何年も使ってるよ。誰かにビジュアライゼーションを作ってって言われたら、必ず使うし、社内でもd2のことをみんなに勧めてる(笑)でも、エンタープライズ版は高すぎるよね。どこでもネイティブにレンダリングできないし、個人利用に限られちゃう。TALAのライセンスが年間3000ドルってのは…ちょっと納得できないな。d2スタジオの追加料金も気になるし…。TALAを試してみたいけど、120ドルの個人ライセンスでもちょっと高いよね。ヘルムチャートやシステムの説明をLLMに渡して、完璧な図を一発で描いてもらえるのは本当に画期的だよ。どこでもネイティブにレンダリングできないのは残念だけど、Confluence Cloudならできるみたい。ただ、アドオンは有料っぽいね。

TALAの出力が最悪だと思うのは私だけじゃないよね。ほとんどいつもELKを使ってる。

私はhttps://github.com/purpleidea/mgmt/の主な著者で、グラフをたくさん使ってるよ。(実際にはほとんどDAGだけど。)特にDAGを作ってからノードやエッジを追加したり、削除したりしてるんだけど、これらの変化を可視化できたらいいなと思ってる。今はgraphvizを使ってるけど、安定してないからスナップショット間で図がよく飛び跳ねるんだよね…もし(1)何らかの安定性を保証できて、(2)遷移をアニメーション化できるなら、可視化にはすごく役立つと思う。もし可能なら、ぜひ教えてほしいな!

d2ウォッチをファイルに置いて、スクリプトからステップバイステップでファイルを置き換えるって感じかな。ハックだけど、まあそれなりに使えるかも。

d2のデフォルトの図をもっと可愛くしたい。デフォルトテーマ(他のテーマも)は、技術的じゃない管理職がいる組織には受け入れられにくいんだ。Obsidianの図のテーマみたいなのがいいな。

D2が大好きなんだけど、ELKがデフォルトのレイアウトエンジンだったらいいな。DagreがELKより優れてることってめっちゃ稀だし、D2を使ってる時にレイアウトエンジンのプロパティに気づくまで結構時間がかかったよ。