2014-15年を振り返る / 2016年の抱負
あけましておめでとうございます。2年ぶりの抱負エントリです。
去年は正月の時期を逃してしまい、仕方がないから旧正月に書くことにするか!と思っていたら仕事が忙しくて完全にタイミングを逸してしまいました。
2014年の抱負 として挙げたのは
- blockdiag のバグ/タスクを減らす
- なにか使えるツールをリリースする (少なくとも一本以上)
- 技術書を読み続ける
- 新しい言語でなにかツールを書く
- コードを書く時間を維持する
- 環境整備をしよう
- あたらしいツール/フレームワーク/サービスに触る
- 体重を落とす (目標 -3kg)
の8個でした。
この 2年間は遊んで過ごしていたこともあって、あまり成果らしい成果はでていないので
振り返るほどでもないのですが、反省を兼ねてざっと振り返ります。
blockdiag のバグ/タスクを減らす:✕
完全に放置状態ですね。2年間まるまる手を付けていません。
なにか使えるツールをリリースする (少なくとも一本以上):△
調べてみると
- 2014
- 2015
- flake8-config
- sphinxcontrib-imagehelper
- testing.elasticsearch
- sphinxcontrib-apiblueprint
- sphinxcontrib-markdown
とパッケージを作っていたみたい。
どれもちょっとしたツールで、使えるツールかと言われると悩ましいですね。
そういえば、Sphinx の numfig を作った流れでコミッターになりました。
あまり活動していなかったのですが、年末からぱたぱたと活動を再開しています。
あと、ずっと git 嫌いだったのですが bitbucket の凋落っぷりをみて、あきらめて git + github にスイッチしました。
技術書を読み続ける:◯
安定して新宿 Book-a-thon を開催しています。
読んだのは以下の本らしい。
- 2014
- 2015
- 日本語組版処理の要件 (2014年からの続き)
- DDD Quickly
- リーダブルコード
- Amazon Web Services クラウドデザインパターン設計ガイド
- Amazon Web Services クラウドデザインパターン実装ガイド
- ハイパフォーマンスブラウザネットワーキング
- 実践ドメイン駆動設計 (読み途中)
読んだ中では日本語組版処理の要件が本当におもしろかった。
普段慣れ親しんでいる書籍について、考え方やルールを理解できてとてもいい資料です。
(厳密には本ではないけど、まあいいじゃない)
あと、読む方ではなく、書く方もちょっとやりました。
Software Design の Sphinx の連載記事に 2本ほど寄稿しました。
コードを書く時間を維持する:✕
サボってました。
環境整備をしよう:△ or ✕
ローカルにあれこれ入れたくないとずっと嫌がっていた homebrew を入れることにしたのは
ビッグチェンジだったかもしれません。
体重を落とす (目標 -3kg):◯
がくっと落ちました。-5kg ぐらい。
完全に ingress のおかげです。
最近は忙しくて ingress をやる時間がとれないのですが、その後安定しているのでリバウンドはなさそうな感じ。
tox で環境変数をセットする方法
先日リリースされた tox-2.0.0 から、コマンドを実行する際に環境変数がフィルタされるようになりました。
(new) introduce environment variable isolation: tox now only passes the PATH and PIP_INDEX_URL variable from the tox invocation environment to the test environment and on Windows also SYSTEMROOT, PATHEXT, TEMP and TMP whereas on unix additionally TMPDIR is passed.
http://tox.readthedocs.org/en/latest/changelog.html
いままでテストの制御に環境変数を使ったりすることがありましたが、
tox-2.0.0 ではそのままでは動作しないことになりました。
$ RUN_ALL_TESTS=1 tox # すべてのテストを実行する ... $ SKIP_FOOBAR_TEST=1 tox # あるテストをスキップする ...
ここで登場したのが ``passenv`` という設定です。
参照する環境変数を tox.ini に列挙します。
[testenv] passenv= RUN_ALL_TESTS SKIP_FOOBAR_TEST
* などを用いた glob マッチにも対応しているそうです。
なお、複数列挙する場合はスペース区切りで並べる必要があります。
他の設定項目のように空行区切りをしてしまうと正しく反映されません。
古い pip で --use-wheel を指定してパッケージを入れるとコマンドが生成されないことがある件。
古い pip には wheel まわりの扱いに問題があるようで、
--use-wheel オプションを指定してパッケージを入れたときに
コマンドが生成されないことがあるようです。
具体的には drone.io の環境に入っている pip-1.4.1 では問題が発生しました。
そのため、
pip install --use-mirrors --upgrade wheel pip install --use-mirrors --use-wheel detox detox
のようなスクリプトを実行すると
/home/ubuntu/.build.sh: line 52: detox: command not found
などと言われてしまいます。
解決策は pip を新しくすることなので、wheel を入れるときに pip も新しくするとよいでしょう。
pip install --use-mirrors --upgrade pip wheel
ちなみに新しい pip を --use-wheel でアップデートすると、
pip コマンドが使えなくなるというオチが待っているので、
pip の更新は wheel を使わずに行いましょう。
sphinxcontrib-googleanalytics-0.1 と sphinx-1.3 の組み合わせで Sphinx が落ちる件。
表題の組み合わせだと、こんなエラーを吐いて Sphinx さんが死ぬ。
Traceback (most recent call last):
File "/Users/tkomiya/work/blockdiag.com/lib/python2.7/site-packages/sphinx/cmdline.py", line 244, in main
opts.warningiserror, opts.tags, opts.verbosity, opts.jobs)
File "/Users/tkomiya/work/blockdiag.com/lib/python2.7/site-packages/sphinx/application.py", line 143, in __init__
self.setup_extension(extension)
File "/Users/tkomiya/work/blockdiag.com/lib/python2.7/site-packages/sphinx/application.py", line 449, in setup_extension
if not ext_meta.get('version', None):
AttributeError: 'Sphinx' object has no attribute 'get'
Sphinx-1.3 から、Sphinx 拡張の `setup()` 関数は「拡張モジュールのメタデータ(dict)」か
「何も返さない」ことを期待しているのだけど、
sphinxcontrib-googleanalytics はなぜか Sphinx オブジェクトを返しているので
こんなエラーを吐くことになる。
Sphinx-1.3 以前は返り値はとくに見ていなかったので何も起きなかったのだけど、
バージョンアップですれ違いが起きてしまった。
根本的な解決は sphinxcontrib-googleanalytics が Sphinx-1.3 に対応して、
いい感じの返り値を返すように修正されることなんだけど、
このモジュール、長らくメンテされていないのでいつになるのかとても怪しい…。
というわけで、conf.py でさっくり monkey patch を当てることにした。
# adhoc: Fix sphinxcontrib-googleanalytics does not work with Sphinx-1.3 from sphinxcontrib import googleanalytics original_setup = googleanalytics.setup googleanalytics.setup = lambda app: original_setup(app) and None
とてもひどい。けど動く。でもひどい。
しかたがないので、あとで Sphinx 側を直すことにしよう。
rails-erd でいい感じの ER図を出す
諸事情で ER図をとても作りたくなることってよくありますよね。
rails で開発しているプロジェクトだと rails-erd というツールを使うと
モデル定義から簡単に ER図っぽいものを生成できるのですが、
なにもオプション指定をしないと複雑で読みづらいものができてしまうことがあります。
- Form オブジェクトが表示されてしまう
- 使っている gem のクラス (audit など) が表示されてしまう
- created_by や updated_by など、users モデルの参照がごちゃごちゃしてしまう
- has_many :through の関係が点線で表示されている
- カラムの表示がアルファベット順になっている
また、表示されている内容をよく見ると id や created_at などの標準カラムや、
foreign_key が貼られている参照カラムなども表示されていません。
このあたり、ちょっと整理しないと **ER図** としてはちょっと読みづらいですよね。
というわけで、ちょっと手を入れて見やすい図にする工夫をしてみました。
bundle exec rake erd filetype=dot attributes=foreign_keys,primary_keys,timestamps,inheritance,content indirect=false sort=false ruby -e '\ dot = open("erd.dot").read dot.gsub!(/^\s*".*?::.*?;\n/m, "") # remove Ruby classes (Form, Audit, ...) dot.gsub!(/^.*? -> ".*?::.*?;\n/, "") # remove relation to Ruby classes dot.gsub!(/^(\s*m_User -> .*?;\n)\1{2}/m, "") # remove created/updated/deleted_by releations print dot ' > output.dot dot -Tpdf -o erd.pdf output.dot dot -Tpng -o erd.png output.dot
工夫してるところは以下のとおりです。
- rails_erd
- 出力内容を加工するために画像ではなく dot 形式で出力
- attributes オプションを指定して、すべてのカラムを表示させる
- indirect=False を指定して、has_many :throught の点線を表示しない
- sort=False を指定して、カラムをソートさせない
- フィルタ処理
- Form オブジェクトや gem など、Ruby のクラスっぽいもの (:: を含むもの)を除外
- User モデルへの参照は読みづらいので削除
大したことはやってないのですが、あとで忘れそうなので備忘として。
※ 諸事情でお手伝いしたやつなので、具体的なサンプルはお見せできません。あしからず。
flake8 で coding: utf-8 の有無をチェックする flake8-coding を作った
# -*- coding: utf-8 -*-
というファイルエンコーディングを示す magic comment の有無を lint しようと思ったのだけど
調べてみると Jenkins でやる方法ぐらいしか見当たりませんでした。
drone.io やら travis ci やらでサクッとチェックできるように flake8-coding という flake8 plugin を作りました。
このプラグインを入れると flake8 を実行するだけで magic comment の有無をチェックできます。
$ flake8 setup.py setup.py:0:1: C101 Coding magic comment not found
Jenkins + Warnings Plugin + flake8 で静的解析
ざっとググってもそれっぽい記事が見当たらなかったのでメモを残しておきます。
Jenkins の Warnings Plugin で flake8 の静的解析の結果を集計するには次のように設定します。
flake8 用のパーサーを追加する
Jenkins の管理 > システム設定
ページの コンパイラの警告
セクションで
flake8 用のパーサーを追加します。
項目 | 値 |
---|---|
名前 | flake8 |
リンク名 | flake8 |
推移レポート名 | flake8 |
正規表現 | (.):(\d+):(\d+): (.) |
マッピングスクリプト | (下記参照) |
import hudson.plugins.warnings.parser.Warning import hudson.plugins.analysis.util.model.Priority String fileName = matcher.group(1); int lineNumber = Integer.parseInt(matcher.group(2)); String category = null; String type = "flake8"; String message = matcher.group(4); Priority priority = null; if (message.startsWith('E')) { category = "pep8 errors"; priority = Priority.HIGH; } else if (message.startsWith('W')) { category = "pep8 warnings"; priority = Priority.NORMAL; } else if (message.startsWith('F')) { category = "PyFlakes codes"; priority = Priority.NORMAL; } else if (message.startsWith('C9')) { category = "McCabe complexity plugin mccabe"; priority = Priority.LOW; } else if (message.startsWith('N8')) { category = "Naming Conventions plugin pep8-naming"; priority = Priority.HIGH; } else { category = "Unknown Error"; priority = Priority.HIGH; } return new Warning(fileName, lineNumber, category, type, message, priority);
priority
を決めるところは適当に決めたので、導入時にアレンジしてください。
- E ではじまるエラー(PEP8 Error) は HIGH
- W ではじまるエラー(PEP8 Warning) は NORMAL
- F ではじまるエラー (PyFlakes Error) は NORMAL
- C9 ではじまるエラー (McCabe) は LOW
- N8 ではじまるエラー (pep8-naming error) は HIGH
- その他のエラー(未知)は HIGH
プロジェクトの設定で flake8 を呼び出す
シェルの実行
やその他の方法で、いい感じに flake8 コマンドを実行します。
flake8 src/ --max-complexity=12 --exclude=path/to/tests/ > flake8.log || : cat flake8.log
flake8 でエラーが検出されても、そのまま処理を進めるように || :
とかを挟んでいます。
あと、console output を見て何が起きているのか把握するため、ログを cat しています。
- プロジェクトの設定でコンパイラ警告の集計を設定する
同じくプロジェクトの設定ページで、Warnings plugin の設定を進めます。
項目 | 値 |
---|---|
集計するファイル | flake8.log |
パーサー | flake8 |
flake8 コマンドの出力結果ファイルと、システム設定で追加したパーサーを指定します。
さらに静的解析の結果で通知を制御するために、
高度な設定で ビルドステータスの閾値
を次のように設定してみました。
まとめ
flake8 の解析内容によって success と unstable、 failure を切り替えたかったので、 Jenkins を細かく設定してみました。
追記
Warnings Plugin に PR した方がいいかしら、とリポジトリを眺めていたところ、 パッケージに含まれている PEP8 パーサーは既に flake8 に対応しているようです。
上記で登録したスクリプトとの違いは priority
の決め方ぐらいです。
- E ではじまるエラー(PEP8 Error) は HIGH
- W ではじまるエラー(PEP8 Warning) は HIGH
- F ではじまるエラー (PyFlakes Error) は HIGH
- R ではじまるエラー (??) は NORMAL
- その他のエラー(未知)は LOW
なんだかぞわぞわする…