このPHPがテンプレートエンジンのくせに慎重すぎる (前篇)

この記事では[Packagist]で公開可能な形式のPHPのライブラリ([Composerパッケージ][Composer])を公開するための道具立てを紹介します。あと、現代のPHPerはツールを組み合せてさくっと開発しているんだという自慢です。

タイトルは「[この TypeScript が Hello, world! のくせに慎重すぎる](https://qiita.com/matzkoh/items/90baab22ad489b78384b)」と「[この勇者が俺TUEEEくせに慎重すぎる](https://dic.pixiv.net/a/%E3%81%93%E3%81%AE%E5%8B%87%E8%80%85%E3%81%8C%E4%BF%BATUEEE%E3%81%8F%E3%81%9B%E3%81%AB%E6%85%8E%E9%87%8D%E3%81%99%E3%81%8E%E3%82%8B)」の*ぱくｒ*… パロディです。

テンプレートエンジンのくせに型安全なんてなまいきな。

[Packagist]: https://packagist.org/
[Composer]: https://getcomposer.org/

## この記事の読みかた

せっかくなので手を動かしながら自分でComposerパッケージを作成してみましょう。

今回の題材は「Hello worldを出力する」という革新的機能を提供する、**とても画期的な実用ライブラリ**です。

記事名通り「慎重すぎる」ので、細かく刻んでGitで経過を保存しながら作業を進めていましょう。なんかよくわからない状態になったら`git reset --hard`とかで吹っ飛ばしながらやればだいたいなんとかなります。適宜「コミットしましょう」と書いていますが、省略しているところもあるので、次の見出しに進む前に`git status`で差分があれば必ずコミットしておいてください。

*Composerがおかしなことになったら、だいたい`composer install`、それでも`composer require`が通らないことがあれば`rm composer.lock`とかすれば、きっとどうにかなります。 (無責任)*

## 名前を決めよう

Composerのパッケージ名は`vendor/name`(発行者/名前)という構成になっています。すべて小文字です。

また、[PSR-4](https://www.php-fig.org/psr/psr-4/)という仕様ではPHPのトップレベル名前空間にはベンダー名を付けることになっており、`\Vendor\SubNamespace\`をプレフィクスにする構成です。

私であればComposerのパッケージ名は`tadsan/hello`、PHPの名前空間`\Tadsan\Hello\`のような感じです。……が、私はvendor名としてしばしば`Bag2`を使っているので、今回は`Bag2\Hello\`でいきます。以下、記事にこの名前が出てきたら全部自分で決めた名前に置き換えて読んでください。

## Composerパッケージの初期化

現代的なのPHPパッケージは[Composer]を基本にしています。Composerは依存するパッケージなどの依存を管理し、それらをオートロード可能な状態にできます。(オートロードとは、個別のクラスファイルなどを`include`や`require`で明示的に読み込まなくても使えるということです)

重要な性質として、Composerは依存パッケージを局所的にインストールします。また、パッケージをインストールする対象(私たちがこれから作る新しいライブラリ)もComposerパッケージです。「いままでComposerパッケージなんか作ったことないよ」という皆さんも、実は`composer require`コマンドでパッケージをインストールしたり、`composer.json`を弄った時点で(一般公開していなかったとしても)**既にComposerパッケージを管理したことがある**ということになります。 `ΩΩΩ<な、なんだってー!?`

ということで、Composerパッケージを作りましょう。`composer`と`git`はコマンドとしてインストール済みである前提です。

そうそう、とりあえず今回はサンプルプロジェクトなので、`hello`という名前で作成していきます。

```sh
$ cd ~/your/code/dir
$ mkdir hello
$ cd hello
$ git init
$ composer init
$ git add -A
$ git commit -m "Init"
```

`~/your/code/dir`はあなたのコンピュータのお好きなソースコード置き場を指定してください。(私は`~/repo/php/$project`のようなディレクトリに置くのが気に入ってます)

ひとつひとつのコマンドの意味について解説することはしませんが、一連の流れを動画にしました。
(動画は`mkdir`, `cd`, `git init` の後から始まっています)

![composer-init.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/011f8370-1bfb-f867-39c6-e99905eaae59.gif)

忘れないうちに`LICENSE`ファイルも作っておきましょう。

動画では`Apache-2.0`(Apache License, Version 2)を指定しています。なぜApache Licenseなのかは[ApacheライセンスのソースコードをGitHubにあげるまで](https://qiita.com/tadsan/items/c16e443db39fcf13a0fa)に書きました。

Apache Licenseを採用する場合は以下のように作業を進めてください。

```sh
$ curl https://www.apache.org/licenses/LICENSE-2.0.txt > LICENSE
```

または

```sh
$ php -r 'copy("https://www.apache.org/licenses/LICENSE-2.0.txt", "LICENSE");'
```

好きな方を実行してください。起こる結果は同じです。この結果もコミットしておきましょう。

```sh
$ git add LICENSE
$ git commit -m "Add LICENSE"
```

ここで実行した結果は、もうGitHubにpushしておきましょう。

ということで、このリポジトリは https://github.com/bag2php/hello に置いてあります。

## `composer.lock`は抜く

ここまでうっかり忘れていましたが、`composer.lock`はコミットしたままでした。

`composer.lock`をGit管理に含めるかどうかは各自判断する必要があります。

 * `composer.lock`を含める利点
    * 固定したバージョンのパッケージを確実にインストールできる
    * `composer install`時に依存性の解決を省けるので高速
 * `composer.lock`を含める欠点
    * 依存パッケージのバージョンが固定されるので、環境によってインストールできない
    * 定期的にアップデートしないと依存バージョンがどんどん古びていく

インストールする対象のPHP環境が均一である場合は`composer.lock`を含めるのが有利です。

デプロイ対象の環境の均質度が高い業務アプリケーションやDockerなどのコンテナで動作させる前提のアプリケーションは`composer.lock`を含めておくべきでしょう。一方でライブラリは、あえて`composer.lock`を管理対象から除くことで、マイナーバージョンごとに`composer update`する手間を省けます。

ということで、今回は幅広い環境にインストールするパッケージを作りたいので`composer.lock`はGitの管理対象から消します。

```sh
$ git rm --cached composer.lock
$ echo "/composer.lock" >> .gitignore
$ git add -u
$ git commit -m "Remove composer.lock"
```

間違って`--cached`オプションを付け忘れて`git rm composer.lock`を実行してしまっても心配しないでください。`composer install`すれば戻ってきます。

## テスティングフレームワークのインストール

PHPのテスティングフレームワークの定番中の定番であるPHPUnitを入れていきましょう。

```sh
$ composer require --dev phpunit/phpunit
```

今回もまたバージョンは指定しません。この時点でまたコミットしておきましょう。

```sh
$ git add -u
$ git commit -m "composer require --dev phpunit/phpunit"
```

Composer経由でクラスをロードするために`composer.json`を編集して設定します。

```diff
diff --git a/composer.json b/composer.json
index 943af4f..d559d78 100644
--- a/composer.json
+++ b/composer.json
@@ -14,5 +14,15 @@
     ],
     "require-dev": {
         "phpunit/phpunit": "^8.5"
+    },
+    "autoload": {
+        "psr-4": {
+            "Bag2\\Hello\\": "src"
+        }
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "Bag2\\Hello\\": "tests"
+        }
     }
 }
```

ファイルの置き場に決まったルールはありませんが、ソースコードは`src`に、ユニットテストは`tests`に置くのが定番の構成です。ほかにも`lib`だったり名前空間と同じ名前だったり、ルートファイルに直接置く場合もあるので、好きな位置に置いて構いません。

`composer.json`に書く時は、名前空間の`\`を`\\`のように二重にすることを忘れないでください(これはJSONの制約です)。また、名前空間の最後にも`\\`を付けることをを忘れないでください。実装だけでなく`autoload-dev`も漏れなく設定するのは、後述するPHPStanで静的解析するためです。

`autoload-dev`に登録するユニットテストの名前空間を実装コードを同じにするか、`Bag2\Hello\Test\`のように空間を別にするかは個人の好みによります。これも決め手はありませんが、私は同じにしておいた方が`use`を減らせるので好きです。逆に、全ての実装クラスを明示的に`use`で列挙せざるを得ない構成にすることをメリットと捉えることもできます。

この設定の意味について詳しく知りたい人は[includeって書きたくない僕たちのためのオートローディングとComposer - Qiita](https://qiita.com/tadsan/items/a78c9160418200e2d47a)を読んでください。

せっかくなので、もうひとつ。依存関係が増える前にテキストエディタで`composer.json`を弄っておきましょう。

```diff
diff --git a/composer.json b/composer.json
index d559d78..56ca999 100644
--- a/composer.json
+++ b/composer.json
@@ -24,5 +24,8 @@
         "psr-4": {
             "spec\\Bag2\\Hello\\": "spec"
         }
+    },
+    "config": {
+        "sort-packages": true
     }
 }
```

この設定をすると、`composer require`で依存関係が増えたときにパッケージ名を勝手にソートしてくれるようになります。

手作業で`composer.json`を編集した後は、必ず`composer update php && composer validate`で検証してください。また、オートロード関連の設定をした後は`composer dump-autoload`を実行してください。

## PHPUnitを設定する

PHPUnitの設定の初期化は[3. XML 設定ファイル — PHPUnit latest Manual](https://phpunit.readthedocs.io/ja/latest/configuration.html)を読んで自分で設定しろ… ということになるのですが当然だるいので、これに関しては秘伝の`phpunit.xml.dist`があるので、これをそのまま使ってもいいです。

```xml:phpunit.xml.dist
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/8.5/phpunit.xsd"
    backupGlobals="false"
    backupStaticAttributes="false"
    bootstrap="tests/bootstrap.php"
    colors="true"
    verbose="false">
  <testsuites>
    <testsuite name="Hello">
      <directory>tests/</directory>
    </testsuite>
  </testsuites>
  <filter>
    <whitelist processUncoveredFilesFromWhitelist="true">
      <directory suffix=".php">src/</directory>
    </whitelist>
  </filter>

  <logging>
    <log type="coverage-clover" target="build/logs/clover.xml"/>
  </logging>
</phpunit>
```

この設定では `tests/bootstrap.php` というスクリプトを読み込むようにしています。

ここではComposerのオートロードスクリプトを読み込むだけにしておきます。

```php
<?php

require_once __DIR__ . '/../vendor/autoload.php';
```

最初の方で「`include`や`require`で明示的に読み込まなくても使える」と言いましたが、このファイルだけは例外です。PHPスクリプトを起動する起点となるファイルでこのファイルを読み込むだけです。何度読み込んでもエラーにはなりませんが、一度だけ読み込めば十分です。

さて、`./vendor/bin/phpunit`を実行してみましょう。

<img width="436" alt="スクリーンショット 2020-01-29 1.52.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/46018551-0d8a-a287-c7af-5dc5016adc16.png">

とりあえず`No tests executed!`と表示されていれば成功です

## 抽象テストケースを用意しておこう

はじめに、このプロジェクトでの共通のテストケースクラスを定義しておきます。

```tests/TestCase.php
<?php

namespace Bag2\Hello;

abstract class TestCase extends \PHPUnit\Framework\TestCase
{
}
```

このクラスは現在特に何の役割も持っていません。ただ、将来的にPHPUnitに後方互換性のない変更があった際の差分を吸収する層としての役割を期待することもできます。 ~~私は過去何度かPHPUnitの非互換変更に苦しめられてきましたが、この層の存在が薬に立っています。~~

さておき、外部のライブラリを使用する際はアプリケーションコードから直接利用するのではなく、委譲や継承としてラッパークラスを用意するというのは有用な戦術なので覚えておいてください。PHPUnitの制約としてテスト対象のクラスは`PHPUnit\Framework\TestCase`を継承しなければいけないので、PHPUnitに対しては委譲ではなく継承を用います。

## 実装とテストケースを追加しよう

空のテストケースと実装を用意するので、ここに足していきましょう。

```tests/HelloTest.php
<?php

namespace Bag2\Hello;

use Bag2\Hello\TestCase;

final class HelloTest extends TestCase
{
}
```

```src/Hello.php
<?php

namespace Bag2\Hello;

final class Hello
{
}
```

外側のクラスだけです。これでPHPUnitを実行すると以下のようになるはずです。

<img width="654" alt="スクリーンショット 2020-01-29 2.29.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/c0b9c213-ca90-4f89-18e7-c6fb4f9b9775.png">

WARNINGですが、今はこれで問題ありません。Gitでコミットして次に進みましょう。

### テストを先に書く

`tests/HelloTest.php`にテストと追加してみましょう。

さて、ユニットテストとは何のために書くのでしょう。動作を保証したいという目論見があるのはもちろんそうなのですが、「**Clean Code that works** (動作するきれいなコード）」という言葉があります。

つまり、そのクラスを使うためのシンプルなサンプルコードであって、それが実際に動くものだというのです。

ということで、難しいことは考えずに書いてみます。

```diff
diff --git a/tests/HelloTest.php b/tests/HelloTest.php
index 873d123..3c56906 100644
--- a/tests/HelloTest.php
+++ b/tests/HelloTest.php
@@ -6,4 +6,10 @@ use Bag2\Hello\TestCase;

 final class HelloTest extends TestCase
 {
+    public function test()
+    {
+        $subject = new Hello();
+
+        $this->assertSame('Hello, World!', $subject->to('World'));
+    }
 }
```

`Hello`クラスが`->to()`というメソッドを持ち、それは'Hello, World!'という文字列を返すものである、という仕様は**私がいま即興で考えました**。どのような呼び出しをすれば使いやすい実装になるかということを想像しながら「動作するサンプルコード」として、このテストケースを書きました。`->to()`というメソッド名がぴんとこなければ、各自好きな名前を付けましょう。所詮は私の思い付きなので。

`$this->assertSame($expected, $actual)`は期待する値と実際の値が同じであることを検証するメソッドです。順番を間違えないように気をつけてください。

この状態でPHPUnitを実行してみましょう。

<img width="651" alt="スクリーンショット 2020-01-29 2.43.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/f142c6e8-622b-6853-27ad-9f4851f02d05.png">

当然ですね。まだメソッドを実装してないからです。ただ、ここでわかる事実が一つあります。`new Hello`には成功しているのです。つまりいままでの作業で、オートロードの設定は成功しているのです。

もしどこかでクラス名の定義や呼び出しなどが間違っていると、以下のようなエラーが出ているはずです。(この例では`Hello`を間違って`Hallo`と書いている箇所があります)

また、ファイル名が間違っていて`HelloTast.php`のようなファイル名(ファイル名の末尾が`Test.php`になっていない)であれば、そもそもテストが実行できていないのです。

ここで私が言いたいのは「わざとテストを失敗させることでも得られる情報がある」ということです。失敗もしないテストというのはそもそもテストが動いていないので、私はどんな簡単なテストでもまず最初にテストを失敗させます。

<img width="653" alt="スクリーンショット 2020-01-29 2.52.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/e2f31e9f-2fae-6b68-dfed-59aaecf3176d.png">

`Error: Call to undefined method`が出ることが確認できたら、次に進みましょう。

## 実装→テスト→実装

`src/Hello.php`にテストが通るための最低限のコードを実装してみましょう。

```diff
diff --git a/src/Hello.php b/src/Hello.php
index 74e44fd..d03dbed 100644
--- a/src/Hello.php
+++ b/src/Hello.php
@@ -4,4 +4,8 @@ namespace Bag2\Hello;

 final class Hello
 {
+    public function to($name)
+    {
+        return 'Hello, World!';
+    }
 }
```

引数は受け取るのですが、ここではまず`return 'Hello, World!'`と書くだけでテストは通せます。

実行してみましょう。

<img width="650" alt="スクリーンショット 2020-01-29 3.01.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/1b467757-3a45-efc0-f265-9c4d697c44f9.png">

おめでとう！ コードが動きました。ここまで長かったですね。ではテストもどんどん増やしていきましょう。 (ここでまた`git commit`しておく)

次にテストケースをまた増やします。

```diff
diff --git a/tests/HelloTest.php b/tests/HelloTest.php
index 3c56906..a1e489f 100644
--- a/tests/HelloTest.php
+++ b/tests/HelloTest.php
@@ -11,5 +11,6 @@ final class HelloTest extends TestCase
         $subject = new Hello();

         $this->assertSame('Hello, World!', $subject->to('World'));
+        $this->assertSame('Hello, Miku!', $subject->to('Miku'));
     }
 }
```

引数に`"Miku"`を渡すと`Hello, Miku!`が帰ってくる、というのです。

まあまあ、とりあえずテストケースの追加だけをしてまた実行してみましょう。

<img width="653" alt="スクリーンショット 2020-01-29 3.12.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/64e7f45e-5191-4747-e238-f3672f81437c.png">

この結果は「`Hello, Miku!`が返ってくると思ったけど`Hello, World!`だった」と読めます。

これを実装するのは簡単です。

```diff
diff --git a/src/Hello.php b/src/Hello.php
index d03dbed..4b825af 100644
--- a/src/Hello.php
+++ b/src/Hello.php
@@ -6,6 +6,6 @@ final class Hello
 {
     public function to($name)
     {
-        return 'Hello, World!';
+        return "Hello, {$name}!";
     }
 }
```

これで`./vendor/bin/phpunit`を実行するとテストが通ると思います。

<img width="730" alt="スクリーンショット 2020-01-29 3.18.02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/355b4353-7eaa-6f40-e2be-4bc69cd887fd.png">

成功したら`git commit`したら次に進みましょう。

## 静的解析しよう

**静的解析**という言葉を聞いたことはありますでしょうか。静的ということは、「コードを動かさず(実行せず)に」ソースコードを解析するということです。静的解析の反対語は実際にプログラムを動かして検証するということで、つまりPHPUnitのようにコードを実際に動作させて検証するということです。

静的解析にはいくつものツールがあるので、これからインストールしていきましょう。この記事は慎重さを旨としているので、複数導入していきます。

ツールを導入するのに[bamarni/composer-bin-plugin: No conflicts for your bin dependencies](https://github.com/bamarni/composer-bin-plugin)というものを使います。これはプロジェクトのメインの`composer.json`とは依存関係を分けながらツールを導入するのに使われるものです。

以下のように`composer require --dev`で導入できます。composer-bin-pluginで設定したパッケージは`vendor-bin/`にインストールされるので、これも`.gitignore`に追加していきます。

```sh
$ composer require --dev bamarni/composer-bin-plugin
```

composer-bin-pluginは標準設定では`vendor-bin`というディレクトリにインストールしてこようとします。`vendor`と似ているし微妙に使いにくいので、ここでは`tools`というディレクトリにインストールしたいと思います。`composer.json`に設定を追加するとインストール先を変更できます。

```diff
diff --git a/composer.json b/composer.json
index 00a6f3f..eba9abe 100644
--- a/composer.json
+++ b/composer.json
@@ -28,5 +28,10 @@
     },
     "config": {
         "sort-packages": true
+    },
+    "extra": {
+        "bamarni-bin": {
+            "target-directory": "tools"
+        }
     }
 }
```

手作業で編集した後は`composer update php && composer validate`でエラーがないかどうかをチェックしてくださいね。

`tools/.gitignore`に`vendor`と`composer.lock`を追加して、Gitの管理下に含まれないようにします。`composer.lock`を管理対象にするかどうかは各自の判断で決めてください。私は業務では`composer.lock`をあえて管理対象にしています。

```tools/.gitignore
/*/composer.lock
/*/vendor/
```

## PHPStanをインストールしよう

次に、静的解析ツールの一つ[PHPStan](https://github.com/phpstan/phpstan)をインストールしておきます。

```sh
$ composer bin phpstan require phpstan/phpstan phpstan/extension-installer
```

これを実行すると、上記設定が済んでいれば`tools/phpstan`にPHPStanがインストールされます。セットで`phpstan/extension-installer`をインストールしておくと良いでしょう。これを設定しておくとPHPStan拡張のための設定を減らすことができます。

作業が済んだら早速実行してみましょう。 `./vendor/bin/phpstan analyse src`で実行してみます。

<img width="709" alt="スクリーンショット 2020-01-29 3.58.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/1259428b-1db3-818f-8f93-2c7944680d13.png">


エラーがないと言われました。やりましたね。しかし、**Tip of the Day**としてまめちしきを教えてくれています。PHPStanは`--level`指定ができるのです。

`./vendor/bin/phpstan analyse src --level=max`で再実行してみましょう。

<img width="714" alt="スクリーンショット 2020-01-29 3.58.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/8336006e-f6da-e6cf-12df-473d97f87e8f.png">

なんか怒られましたね。気がかりですが、ここは一旦無視して次に進みましょう。

## Psalmをインストールしよう

[Psalm](https://psalm.dev/docs/)はPHPStanとはまた別の静的解析ツールです。

```sh
$ composer bin psalm require vimeo/psalm
```

すると `tools/psalm/composer.json` というファイルができているはずなので、これも`git add`してコミットしておきます。

Psalmは`./vendor/bin/psalm`で実行できます。ですが、初回実行時は以下のような出力が出るはずです。

```
Could not locate a config XML file in path /Users/megurine/repo/php/hello/. Have you run 'psalm --init' ?
```

メッセージ通りに`./vendor/bin/psalm --init`を実行すると設定ファイルが生成されるので、もう一度実行するとPsalmでコードを解析できます。

<img width="972" alt="スクリーンショット 2020-01-29 4.07.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/cd74085b-2c8b-0618-41c4-cd006cbc856b.png">

またもや型がないことを叱られました。ところで、PSalmの特徴はPsalterというツールが同梱されていて、安全な範囲でコードを自動修正してくれることが特徴です。

ということで、実行してみましょう。

<img width="443" alt="スクリーンショット 2020-01-29 4.12.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4121/0b9e6064-59da-3f09-295e-3d9c890f2237.png">

なんか `src/Hello.php` が変更されたっぽい出力が出てますね。

## 前篇のまとめ

以下のツールについて取り上げました

 * Composer
 * PHPUnit
 * composer-bin-plugin
 * PHPStan
 * Psalm

## まとめ

PHPを解析したりテストしたり構成管理したりするべんりっぽいあれそれは**QAツール**とか呼ばれており、[PHP Quality Assurance](https://phpqa.io/)とか[EdgedesignCZ/phpqa: Analyze PHP code with one command](https://github.com/EdgedesignCZ/phpqa)なんかに並んでますが、玉石混淆なので全部を検証するのは結構大変です。

いつもTwitterとかSlackで「便利だよ！」って言ってもあまり使ってるひとが居ないんじゃないかと疑心暗鬼だったので、今日は具体的な導入方法について書きました。

というか私もsasezakiさんがTwitterでぼそっとつぶやいてるのを見て知ったツールが多いのですが、そのsasezakiさんが昨年12月のPHPカンファレンス2019で発表した「[このPHP QAツールがすごい！2019](https://www.slideshare.net/sasezaki/php-qa2019-200006092?reflesh)」がPHPの背景事情やこの記事ともオーバーラップするツールの詳細な説明などが、ことこまかに解説されています。

## 感想

とても眠い。

えっ、こういうツールを業務でばりばりつかいこなしてるひとたちと直接コミュニケーションがとれるPHPeKaigiってイベントが来月開催されて、まだチケットが発売中なんですか？ *(宣伝)* → 「**[あなたが今年PHPeKaigi2020に参加しなければいけない理由](https://www.phper.ninja/entry/2020/01/19/014417)**」

## 後篇で取り上げる予定のツール

 * Phan
 * PHP-CS-Fixer
 * Infection
 * GitHub Actions
 * slevomat/coding-standard
 * [thecodingmachine/safe](https://github.com/thecodingmachine/safe) (これはツールじゃないけど慎重要素)
 * (あとなんか忘れてそうなので思い出したら)