第 5 章: パッケージ管理と静的解析¶
5.1 はじめに¶
Scala 開発では、依存関係の管理とコード品質の維持を仕組み化することが重要です。
この章では、sbt によるパッケージ管理と scalafmt、WartRemover、コンパイラオプションによる品質管理を扱います。
5.2 sbt によるパッケージ管理¶
build.sbt の構成¶
apps/scala/build.sbt では、プロジェクトの基本情報と依存関係を定義します。
lazy val root = (project in file("."))
.settings(
name := "fizzbuzz",
version := "0.1.0",
scalaVersion := "3.3.4",
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % "3.2.18" % Test
)
)
name: プロジェクト名version: アプリケーションのバージョンscalaVersion: 使用する Scala バージョンlibraryDependencies: 利用ライブラリ
プラグインの追加(project/plugins.sbt)¶
sbt プラグインは apps/scala/project/plugins.sbt に追加します。
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.2")
addSbtPlugin("org.wartremover" % "sbt-wartremover" % "3.2.5")
依存関係の管理(% と %% の違い、Test スコープ)¶
%: Java など Scala バージョンに依存しない Artifact に使います。%%: Scala バージョン接尾辞(例:_3)を自動付与します。% Test: テスト時だけ必要な依存関係に付けます。
例:
"org.scalatest" %% "scalatest" % "3.2.18" % Test
この指定により、本番 Artifact には ScalaTest が含まれません。
5.3 scalafmt によるコードフォーマット¶
apps/scala/.scalafmt.conf は次の設定です。
version = 3.7.17
runner.dialect = scala3
maxColumn = 100
整形コマンド:
cd apps/scala
sbt scalafmt
sbt scalafmtCheck
sbt scalafmt: 自動整形sbt scalafmtCheck: 未整形コードを検出(CI 向け)
5.4 WartRemover による静的解析¶
WartRemover は危険な記述をコンパイル時に検出する静的解析ツールです。
build.sbt への設定追加¶
build.sbt に次のような設定を追加します。
wartremoverErrors ++= Seq(
Wart.Null,
Wart.Var,
Wart.Return
)
検出される問題の種類¶
Null:null利用によるNullPointerExceptionリスクVar: 可変変数による状態変化の複雑化Return: 早期 return による制御フローの可読性低下
警告と推奨事項¶
- まずは
Errorsを最小セットで導入します。 - 既存コードが多い場合は段階的にルールを増やします。
Option、不変val、式指向の記述に置き換えると改善しやすいです。
5.5 コード複雑度チェック¶
コードの循環複雑度(Cyclomatic Complexity)は、メソッド内の分岐数に基づいてコードの複雑さを数値化する指標です。複雑度が高いメソッドはテストが困難で、バグが混入しやすくなります。
循環複雑度の計算ルール¶
| ルール | 説明 |
|---|---|
| 基本複雑度 | 各メソッドの初期値は 1 |
if / else if |
条件分岐ごとに +1 |
match / case |
各 case 分岐ごとに +1(case class / case object 定義は除外) |
while / for |
ループごとに +1 |
&& / \|\| |
短絡評価の論理演算子ごとに +1 |
try / catch |
例外処理ごとに +1 |
一般的な目安として、1 メソッドあたり複雑度 10 以下 が推奨されます。
カスタム複雑度チェッカー¶
Scala には標準的な複雑度チェックツールがないため、scripts/complexity.sh にカスタムスクリプトを用意しています。
# 実行(デフォルト閾値: 7)
bash scripts/complexity.sh src
# 閾値を指定して実行
bash scripts/complexity.sh --threshold 10 src
実行結果の例:
=== Scala 循環複雑度チェック (閾値: 10) ===
OK generate (FizzBuzz.scala) 複雑度: 8
OK generateList (FizzBuzz.scala) 複雑度: 1
OK create (Type.scala) 複雑度: 5
関数数: 22, 違反: 0
OK すべての関数が複雑度閾値以内です。
Makefile への統合¶
Makefile の check タスクに複雑度チェックを組み込んでいます。
complexity:
bash scripts/complexity.sh --threshold 10 src
check: fmt-check lint complexity test
make check を実行すると、フォーマットチェック → コンパイル → 複雑度チェック → テスト の順に品質ゲートが走ります。
複雑度が高い場合の対処¶
複雑度が閾値を超えた場合は、以下のリファクタリングを検討します。
- メソッド分割: 長い
match式を小さなメソッドに分解 - ポリモーフィズムの活用: 条件分岐を
sealed trait+case objectのパターンマッチに置き換え - 高階関数の利用:
if/forをコレクション操作(map/filter)に置き換え - ガード条件の簡略化: 複雑な条件を別メソッドとして抽出
5.6 コンパイラオプション¶
apps/scala/build.sbt では次の scalacOptions を設定しています。
scalacOptions ++= Seq(
"-deprecation",
"-feature",
"-unchecked",
"-Xfatal-warnings"
)
-deprecation: 非推奨 API 使用時に警告-feature: 明示が必要な言語機能使用時に警告-unchecked: 型検査が不十分な箇所を警告-Xfatal-warnings: 警告をエラー扱いにして品質を強制
5.7 まとめ¶
この章では、Scala プロジェクトの品質基盤を整えました。
sbtで依存関係とプラグインを管理するscalafmtでフォーマットを統一するWartRemoverで危険な記述を早期検出する- カスタムスクリプトでコード複雑度をチェックする
scalacOptionsでコンパイル時の品質ゲートを強化する
次章では、これらを Makefile と GitHub Actions で自動実行する方法を扱います。