📚

自作パッケージの依存関係ちゃんと管理してる?静的解析とGraphvizで実現した自作パッケージ依存関係可視化ツール"prelviz"

2023/12/23に公開

はじめまして、株式会社アプリボットでバックエンドエンジニアをしている@_kz_devです。普段はスマホゲームのバックエンド開発をしています。

この記事はGo Advent Calender 2023Applibot Advent Calenderの 23日目の記事です。

この記事は、

  • "プロダクトのパッケージの依存関係ちゃんと見たいなあ~",
  • "このパッケージ修正するときに、どのパッケージに影響しそうかな~?"
  • "依存関係的にアーキテクチャ違反しているパッケージないよね、ちょっと気になるな~?"

などなどの、私が抱いていた気持ちや疑問を解消するために開発した、自作パッケージの依存関係の可視化ツールprelvizについての紹介記事です。
※全てのケースでうまく動作するとは限りませんのでご注意ください!

紹介するツールのリポジトリを以下に載せておきます。
https://github.com/kazdevl/prelviz

概要

prelvizgoプロジェクトに対して実行し、Graphvizで画像変換すると以下のような結果を得られます。

長方形がパッケージを表し、長方形間の線がリレーションを表現しています。
線上の"dep"は矢印の向きに存在するパッケージへの依存数を指します。(依存数は、依存先パッケージの構造体や関数の利用種類数です。)

また、設定ファイルを調整すると、それぞれ以下のような結果を得られます。

デフォルト設定時の結果 NGな依存関係を設定時の結果
デフォルト設定時の結果 グルーピングするパッケージを設定時の結果
デフォルト設定時の結果 除外するパッケージを設定時の結果
"app/util"・"app/domain/entity"を除外している
デフォルト設定時の結果 NGな依存関係とグルーピングするパッケージを設定時の結果
デフォルト設定時の結果 グルーピングするパッケージと除外するパッケージを設定時の結果
"app/util"・"app/domain/entity"を除外している

使い方

1.prelvizをinstallする

go install github.com/kazdevl/prelviz/cmd/prelviz@v1.0.1

2.実行時に引数を指定する

標準実行

prelviz -i {{対象Goプロジェクトのルートパスを指定する}}

DOT言語が標準出力されます

出力ファイルの指定

prelviz -i {{対象Goプロジェクトのルートパスを指定する}} -o {{出力ファイルを指定する}}

"-o"を指定することで、指定したファイルに結果が出力されます。

レイアウトの変更

prelviz -i {{対象Goプロジェクトのルートパスを指定する}} -l {{利用するレイアウトを指定する}}

"-l"を指定することで、Graphvizで利用するレイアウトが変更されます。
※ レイアウトの種類は、以下を参考にしてください。
https://graphviz.org/docs/layouts/

画像変換

prelviz -i {{対象Goプロジェクトのルートパスを指定する}} | dot -Tpng -o sample.png

dotコマンドを利用することで、画像に変換できます。
※ dotコマンドのオプションは以下を参考にしてください。
https://graphviz.org/doc/info/command.html

3.".prelviz.config.json"を設定する(推奨)

prelvizでは、".prelviz.config.json"を対象プロジェクトのルートパスに設定することで、以下の設定を適用できます。

  • NGな依存関係
    • "ng_relation"に値を設定する
    • "from"と"to"でNGな依存関係を設定する
    • NGな依存関係はパッケージ間の線を赤色に表示します。
  • パッケージをグルーピングするディレクトリの指定
    • "grouping_directory_path"に値を設定する
    • 設定したディレクトリ配下に存在するパッケージは一つにまとめられる
    • まとめられたパッケージは緑色で表示される
  • 除外するパッケージ
    • "exclude_package"に値を設定する
    • 設定したパッケージに関する情報が省かれる

以下に"prelviz.config.json"の設定例を示します。

{
  "ng_relation": [
    {
      "from": "github.com/kazdevl/sample_project/app/usecase",
      "to": ["github.com/kazdevl/sample_project/app/domain"]
    }
  ],
  "grouping_directory_path": ["app/domain"], 
  "exclude_package": [
    "github.com/kazdevl/sample_project/app/util",
    "github.com/kazdevl/sample_project/app/domain/entity"
  ]
}

その他、prelvizの詳細な説明は以下のREADME.mdをお読み下さい!
https://github.com/kazdevl/prelviz/tree/v1.0.1

要素技術

静的解析

prelvizでは、各パッケージが依存しているパッケージ一覧や依存数を可視化しています。それらを取得するために、対象パッケージのファイルのASTに存在する、*ast.ImportSpec*ast.SelectorExprを利用します。

prelvizでの、AST走査処理が気になる方は、以下のコードを参照してください。
https://github.com/kazdevl/prelviz/blob/5c71999c9a38c1e19b6ceacccf6e3b38affcf260/package.go#L45-L90

Graphviz

パッケージや依存関係の図や線などを、よしなに配置して画像に書き起こすために、Graphvizを採用しました。Graphvizで図や線を作成するには、DOT言語を利用します。

prelvizで、読み込んだパッケージやその依存関係などをDOT言語に書き起こすために、以下のライブラリを利用しました。
https://github.com/awalterschulze/gographviz

prelvizでの、上記のライブラリを利用した実装が気になる方は、以下のコードを参照してください。
https://github.com/kazdevl/prelviz/blob/5c71999c9a38c1e19b6ceacccf6e3b38affcf260/prelviz.go#L64-L159

終わりに

本記事では、独自パッケージの依存関係情報を可視化するprelvizについて紹介しました!

今後、読者様がGoのプロダクトで、自作パッケージの依存関係をしっかりと管理したい!という時に、本ツールが助けになれば幸いです。

prelvizは作り始めたばかりであり、考慮できていないところもたくさんあると思います。バグ報告や機能改善要望などは是非GitHubで気軽にissueを投げてください。starも頂ければ大きな活力になります。

Go Advent Calender 2023の24日目はさんの@mylifewithviolinさんの記事です。そして、Applibot Advent Calenderの 24日目は @Sigsiguma
さんの記事です。
お楽しみに!

Discussion