コロナになった

4回目のワクチンから6ヶ月たったし5回目のワクチン受けるかー、あれ接種対象者じゃないから受けれないのか、と言っているうちにコロナになってしまった。

発症当日は喉の痛みだけで発症したことに気付いていなかった。 その日は一日中会話していたのでその会話によって喉を痛めたのだと思いこんでいた。

コロナは本当につらく、寝ようとしても39.5度近くの高熱のせいか「1つのことを無限に考えさせられる状態」に陥って寝れないときが一番つらかった。 このとき自分は何故かサッカーのイングランド代表のことしか考えられなかった。

さらに喉の痛みも普通の風邪とは比にならない痛みで、つばを飲み込むだけでも痛かった。喉は痛いけど薬は飲まないといけないしで地獄だった。

体温と体調(10段階)を記録していたのでグラフにすると次のようになった。

体温と体調の時間変化

まだ味覚、嗅覚が1~2割しかない状態なのと働きすぎると後遺症が発生しうるらしい(ググった情報)のでしばらくはゆったりと暮らしたい。

Perlでモジュールを自動でインポートするためのツールを作った

普段仕事で Perl を書いている。

Perl はモジュールを利用するために use 文を書く必要がある。

モジュールを足すごとに use 文を忘れずに書くのは意外と大変で「use漏れ」というコミットをこれまでたくさん積み重ねてきた。

この作業を自動化するために、過去には VSCode で自動でインポートする拡張機能を作った。

marketplace.visualstudio.com

しかし、以下の課題があった。

  1. 普段使っているのが IntelliJ (作った当時はVSCodeに移行を試みていた)でメンテナンスする気分になれない
  2. TypeScript で頑張ってパースしているが Perl の自由度に敗北している
  3. エクスポートされているシンボルを静的解析するのに限界がある
    このように動的に作られたりするとどうしようもない

そこで、それぞれの課題に対処する新たな自動インポートツールを作ろうと考えた。

  • 課題1 → 特定の IDE に依存しないように CPAN モジュールにする
  • 課題2 → PPI で解析することで Perl の自由度に対処する
  • 課題3 → 動的にモジュールをロードしてシンボルテーブルに登録されているシンボルを取得する

できたのがこちら。

github.com

インストールするには GitHub のレポジトリを指定する。CPAN にアップロードするのをサボっている(アカウント作成時に理由が雑すぎたのがrejectされてしまった…)

cpanm https://github.com/tjmtmmnk/pau.git

使い方はシンプル。 自動インポートしたいファイルを入力して Pau->auto_use に渡すと、使っていないモジュールは削除され、必要なモジュールは追加される。

use Pau;
my $source = "";

while (<STDIN>) {
    $source .= $_;
}
my $formatted = Pau->auto_use(
    # 自動インポートしたい内容
    source    => $source,
    # 利用しているライブラリのパス
    lib_paths => ['lib', 't/lib', 'cpan/lib/perl5'],
);
print(STDOUT $formatted);

パッケージ名を指定しない場合も対象になるのがポイント。 例えば、args my $foo => 'Int' としているときに lib_paths で指定したパス内に Smart::Argsモジュールがあれば、use Smart::Args qw(args) と追加される。

さらに、数千ものライブラリファイルがあってもキャッシュ無しで5秒程度、キャッシュありで1秒程度で実行できるのもポイント。 Parallel::ForkManagerで並列処理したり、ファイルに保存して差分更新することで高速化している。

一方でデメリットもある。

前述した通り、エクスポートされているシンボルを取得するために動的にモジュールをロードしている。 しかし、動的にモジュールをロードするのはセキュリティ上の懸念があると考えている。 ロードするモジュールの BEGINブロックの中で悪意のあるコードが含まれているとロード時に実行されてしまうからである。

そのため、利用しているモジュールが問題ないことを確認し、最小構成になっている仮想環境上で Pau を利用することを推奨する。

※追記

moose か mouse か迷う時とか無いのかな

あります。現在は複数のモジュールから同名のシンボルがエクスポートされている場合、インポートされるモジュールはランダムになっています。

これでは不便なので、インタラクティブにインポートするモジュールを選択するモードの追加や、このシンボルはこのモジュールからインポートするというマッピングを設定できるようにすることを検討しています。

※追記ここまで


以上の開発を元に WEB+DB PRESS Vol.133 の Perl Hackers Hub に「モジュールの自動インポートによる開発効率向上」というタイトルで寄稿させていただきました。

自動インポートってどういう仕組みで動いているの?という疑問にフォーカスして、Perl で一般的にインポート/エクスポートを実現するための Exporter モジュールの仕組みを知るところから始まり、具体例を通して、Perlで簡易的な自動インポートが実現できる構成になっています。

明日 2/24 から発売されます!是非チェックしてみてください!

gihyo.jp

プロトタイプは2回作りたい

最近難しい設計をすることがあってプロトタイプによる実現可能性の検討を行った。

そこでは次の2段階のプロトタイプを作った。

  1. つながりを確認して自分が納得するためのプロトタイプ
  2. ちゃんと考えてみんなが納得するためのプロトタイプ

プロトタイプを2回作ることで不確実性が下がって手戻りなく本実装を進めることができた。 自分にはこの方法が合っていたのでまとめておく。

1回目は繋がるかどうかだけを確認する

1回目のプロトタイプは自分の中で実装のイメージを付けるために行う。

そのためには既存の処理を拡張するにしろ新規の処理を追加するにしろ、繋がるかどうかの確認をするとよい。

具体的には、様々な関数を呼ぶ一連の処理があるときに処理のボトムから関数の引数だけを求める形に変更して、その引数を満たすことができるかどうかを確かめていった。 funcA -> funcB -> funcC と依存があるときに funcC の引数を変えて funcB がその引数を渡すことができるか、funcB の引数を変えて… といった調子。

繋がるかどうかだけを気にしているので、テストが落ちまくっていても気にしないし、コードがどれだけ適当でも気にしない。 自分が実装できそうなイメージが掴めればオッケー。 1回目のプロトタイプは速度を重視するとよい。

実装のイメージが付いたら、あとはそのイメージをどうやってきれいに実装するかを考える必要がある。

2回目はちゃんと考えて本実装はあとはやるだけ状態にする

2回目のプロトタイプは自分なりにちゃんと考えたあとにレビューを受けて本実装に入る前にレビュアーを含めてやることの共通認識を作っておくために行う。

プロトタイプと言いながら本実装と同じぐらいの本気度で命名や処理の流れを考える。 ただしテストは書かなくてもよいと言うのが本実装との違い。

この時点でレビューを受けることでソースコードレベルで議論を行うことができる。 具体的には、この命名はおかしいんじゃない?とか新しい概念がいっぱい登場して難しいですねといったフィードバックを受けて、よりシンプルで既存のコードとも雰囲気の揃ったものに変更することができた。

2回目のプロトタイプが完成した時点で本実装は「あとはやるだけ」になる。 自分もレビュアーもこのあとの本実装で何が実装されるのかがわかっているのでレビュアーの負担も減るはず。


考え方としてはこの記事とかなり近いと思う。タイトルも寄せました🙏

bufferings.hatenablog.com