Upgrade to Pro — share decks privately, control downloads, hide ads and more …

データサイエンスレガシーコードに立ち向かう #reprotech

データサイエンスレガシーコードに立ち向かう #reprotech

2019/04/04に開催された、 Repro Tech #7 Practical AI Supported by NAVITIME で発表した資料です。
https://repro-tech.connpass.com/event/124326/

Sho Shimauchi

April 04, 2019
Tweet

More Decks by Sho Shimauchi

Other Decks in Technology

Transcript

  1. 仕様化テスト 手動チェックしているテストがあるとする - 自分が正しいと認識している手動チェッ クの結果をコピーする - 手動チェックの手順をそのままテストに 落とし込む 「バグを見つけることは重要ですが、直近の目 標は変更をより確実に行うための役立つテスト

    環境を作ることです」――レガシーコード改善 ガイド、p.200 この本では、この手法を仕様化テストと呼んで いる DON'T > result = すごいデータサイエンス関数(データ) > print(result) 期待する結果か目視で確認 DO def test_すごい関数(): result = すごいデータサイエンス関数(データ) assert 期待する結果 == result
  2. pytest-cov テストカバレッジを計測する $ pytest --cov=source_dir --cov-report=html 実行後、 htmlcov というディレクトリができる ので、

    $ open htmlcov/index.html (MacOSの場合) あるいはWebブラウザで上記ファイルを開く と、カバレッジを可視化することができる 詳細は「テスト駆動Python」7.2 参照 https://github.com/python-attrs/attrs/blob/master/src/attr/_mak e.py
  3. scripttest コマンド実行をそのままテストに落とし込むための、機 能テストツール $ pip install scripttest pipなどのテストに使われている Jupyter等で手動チェックをしている手順をまるごとそ のままテストにできる

    コードが複雑すぎて容易に単体テストを作成できない、 しかし短期間で大きく変更しなければならない、という 状況ではかなり便利 ないよりマシという程度なのであくまで一時しのぎと認 識すべき import pytest import scripttest @pytest.fixture def env(): env = scripttest.TestFileEnvironment("./test-output") return env def test_func(env): result = env.run("target.py") assert result.returncode == 0
  4. scripttestの基本 env = scripttest.TestFileEnvironment("./test-output") 引数の文字列は、ファイル出力時のルートディ レクトリかつ実行時のルートディレクトリ。 内容が保持されることを保証しないので、絶対 に既存のファイルを含むディレクトリを指定し ないこと ターゲットスクリプト実行時にはこのディレク

    トリからの相対パスで指定する。 TestFileEnvironment.run(コマンド実行文字列) オプション expect_stderr = True デフォルトだとstderrに出力されると実行失敗 扱いとなるが、このオプションで無効化可能 レガシーコードだとstderrにWARNING出しな がら実行しているとかがザラにある
  5. env.run()の実行結果 response = env.run(コマンド)を実行したとする response.returncode コマンドのリターンコードを含む assert response.returncode == 0

    は基本。 files_created / files_deleted / files_updated それぞれ、作成・削除・更新されたファイル、 ディレクトリの一覧を {ファイル名: FoundFile, ディレクトリ名: FoundDir} という辞書で返す
  6. flake8 言わずとしれた、コードフォーマットチェッ カー兼静的解析ツール レガシーコードではコードのフォーマットがバ ラバラという事態は頻繁に発生する とりあえず以下のコマンドを叩くこと $ pip install flake8

    $ flake8 target.py コードのフォーマットが統一されないまま、テ ストなしであれこれ変更したコードを動作確認 なしでそのまま渡されるケースに対処する場合 フォーマット直してる余裕はないので、静的解 析によるエラー検出だけに集中する $ flake8 --select=F target.py
  7. プロファイリング 自分の手でいじって実行している場合、多少の 遅さは気にしないというデータサイエンティス トは多い 保守の観点からは非常に深刻な問題となる - テストの実行に時間がかかる - よって改修やバグ修正にも時間がかかる -

    それにより様々な業務に影響が出る 明らかに不必要に遅いコードは直すこと 過度な最適化はしないこと!! 今日紹介するツール cProfile : 標準プロファイラ gprof2dot: cProfileの結果をグラフで可視化 おまけ: tqdm 処理の進捗を可視化 直感的なボトルネックの探索だけでなく、実行 待ちストレスの軽減にもなる
  8. gprof2dot プロファイルを可視化する $ pip install gprof2dot $ gprof2dot -f pstats

    test.prof | dot -Tpng -o output.png 要graphviz。Mac なら brew install graphviz で インストール可能 https://github.com/jrfonseca/gprof2dot
  9. まとめ 今日紹介した話 - pytestプラグイン - scripttest - flake8 - cProfile

    - gprof2dot - tqdm 頑張ってレガシーコードに立ち向かおう 「レガシーコード改善ガイド」と「テスト駆動 python」は買おう 〜おしまい〜 @shiumachi
  10. Q. カバレッジはどの程度気にしているのか? A. いきなりプロダクションレベルの品質でテストを書くのは不可能なので、以 下のように優先度をつけてテストを書いています。 - 正常系1つ (最低限のテストでの保護) - 経験上明らかに頻出すると予想される異常系

    - 実際に遭遇したエラー ここでいうテストは、品質管理というよりも「確認作業の自動化」くらいの意味 にとらえておけばいいです。 あくまで一時しのぎなので、本当に品質管理しようと思ったら書き直すことも検 討すべきでしょう。