ソースコードリーディング ワークショップ 2010 ソースコード理解と勉強会 よしおかひろたか 楽天株式会社 / カーネル読書会主宰 2010 年 1 月 30 日
自己紹介 よしおかひろたか、 楽天株式会社開発部 技術理事、 セキュリティ&プログラミングキャンプ、プログラミング部門主査、 Debug Hacks 著者、 ISBN 978-4873114040 カーネル読書会主宰、  YLUG( 横浜 Linux Users Group) 、 勉強会勉強会
自己紹介、日記とか 未来のいつか /hyoshiok の日記 http://d.hatena.ne.jp/hyoshiok ユメのチカラ(前職でのブログ) http://blog.miraclelinux.com/yume/ [email_address] http://twitter.com/hyoshiok
お題 ソースコード理解と勉強会 ソースコードを読むテクニック わたしの事例
プログラマに必要なチカラ ソースコードを読むチカラ デバッグのチカラ テストのチカラ 上記のチカラは学校では教えてくれない。経験から自ら獲得しないといけない。
ソースコードを読むチカラ プログラマの基礎体力 ソフトウェア開発コストの大部分は保守 不具合修正、改良、機能追加にはコードの理解が必須 技術者の付加価値 陳腐化しにくい プロフェッショナルとしての研鑚 すぐれた技術者はソースコードを上手に読む
プロフェッショナルとして ソースコードを読むチカラを向上させたい。 だから今ここにいる。 だからベストプラクティスを共有したい。
コードの読み方 なぜ、コードを読むのか どのように、読むのか
なぜコードを読むのか? 仕事だから(目的中心) トラブルシューティング(不具合修正) 機能修正、機能開発 自己研鑚、勉強 趣味だから(興味中心) 楽しいから 自己啓発(知的好奇心) 不純な動機 形から入る
なぜコードを読むのか 目的中心の場合 対象に対する基礎知識は必要 アーキテクチャ OS、プログラミング言語、RDBMS、… 定番の教科書で知識を得る
トラブルシューティング トラブルシューティングと問題の理解 時間の制約 環境の制約 実践的なコードの理解
なぜコードを読むのか 興味中心の場合 人それぞれ、人生いろいろ 無目的でもいいじゃないか 熟読、濫読、積読、黙読、音読、再読、誤読、精読、速読、耽読、通読、復読、輪読、朗読、輪読、…
コードの理解 プログラムは思ったとおり動かない、書いたとおり動く。 書いたもの(ソースコード)から、プログラマの意図を推定する作業
コード、テスト、ドキュメント コードはHOW テストはWHAT ドキュメントはWHY この3つで理解を深める
勉強会 情報交換の場。 プロとしてのプログラマ 昔はほとんどなかった。 オープンソースのおかげで、ソースコードの細部に付いても議論できる。 HOWだけではなく、WHATやWHYを議論できる IT勉強会カレンダーで検索 なければ勉強会を作る
事例:カーネル読書会 きっかけ。 1999年、Linuxのコードを読みたくなった 1999/4 カーネル読書会。楽しかった。 …、2009/10 第100回Linusも参加
カーネル読書会 コードを読むのはきっかけ。 技術者が楽しく生き生きとして豊かな社会 もっと、技術的にも高みに登りたい 技術者同士の交流(会社や組織の壁を越えて) 最近はOSSにまつわる様々な技術について議論している
コードを読むテクニック編
コードの理解について モットー: コードは読むな、 理解しろ〜
どのようにコードを理解するのか 個人的な方法を紹介する 唯一あるいはベストな方法というわけでもない 適材適所、もっと良い方法があると思う 主にUnix/Linux系のソフトウェア環境 公開することによって進化したい(もっと良い方法への模索)
ソースコードを読む視点
理解の仕方、読み方 静的、動的理解 微視的、巨視的 規模の把握 ツールの利用 事例
静的理解、動的理解 静的理解 字面での理解 動的理解 動作による理解
静的、動的構造 静的構造 規模 ディレクトリ構造 名前つけ規約 動的構造 呼び出し経路 プロファイリング 実行結果
微視的、巨視的 微視的:細部からの理解 最終的にはコードの一行 巨視的:全体からの理解 規模、構造、機能など。実行結果(性能?) 俯瞰図、鳥瞰図。
規模の把握(巨視的理解) 規模重要 規模(相手)を知らずして作戦を立てられない 大局的な地図、俯瞰図、鳥瞰図 大規模になればなるほど、システマティックな方法論が必要になってくる 巨視的な理解
規模の把握 小規模: 100K 行未満程度、 ファイル数 100 未満 10 人未満 中規模: 100K 行〜 1M 行程度 ファイル数 100 〜 1000 未満 100 人未満 大規模: 1M 行以上 ファイル数 1000 以上 100 人以上 ざっくりの規模感
規模の把握(例) find -type f -name "*.[ch]"|wc find -type f -name "*.[ch]"|xargs wc|grep total
ディレクトリ構造 トップディレクトリは、ソフトウェアの論理的構造を表している doc ドキュメント lib ライブラリ関係 test テスト src ソースコード ソースツリーの把握
ドキュメント README, INSTALL, COPYING, … 内部ドキュメント(Docs) リリースノート ChangeLog 変更の経緯
変更の履歴 ChangeLog/Release Notes コード管理システム 例:Linux git/Subversion/CVS Mailing List Wiki blog 変更(時間軸)の微視的理解
ドキュメント、情報収集 マニュアルを読む サーチエンジン(Google)に聞く Mailing List Bug database 開発者との会話(シンポジウムなど) 勉強会
ソースコードを読む視点
いよいよコードを読む? ツール エディタ:emacs デバッガ:gdb クロスレファレンス:cscope カーネルの場合、クラッシュダンプ(crash)
動的理解 ビルド
動的理解 ともかく動かす make strace ltrace gdb oprofile リグレッションテスト ベンチマークテスト
make とりあえず、make 実行環境の構築 gcc -g (デバッグシンボルを付加する) 通常はMakefileのCFLAGSなどに設定 cscopeのインデックスを作成 ビルドはemacsのshellなどから行い、ビルドのログを取得しておくと便利
strace システムコールのトレース $ strace ruby -v execve("/usr/local/bin/ruby", ["ruby", "-v"], [/* 39 vars */]) = 0 uname({sys="Linux", node="asianux2.miraclelinux.com", ...}) = 0 brk(0)  = 0x976a000 access("/etc/ld.so.preload", R_OK)  = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY)  = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=89946, ...}) = 0 old_mmap(NULL, 89946, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7fea000 close(3)  = 0 open("/lib/libdl.so.2", O_RDONLY)  = 3
gdb デバッガはコードを理解するためにある ∴コードを読むために使う http://savannah.gnu.org/projects/gdb
gdbで読むための準備 gcc -g でコンパイル コンパイルしたコードサイズが大きくなる以外、特に副作用はない printfデバッグは有害無益
gdb ブレークポイントを設定 ウオッチポイント(変数の変更) run 止まった時点で bt  スタックフレームの表示 p  変数の表示 c  実行再開、 s  ステップ実行(関数に潜る)、 n  ステップ実行(関数に潜らない) 繰り返す
oprofile プロファイラー 実行時のボトルネックを発見 # opcontrol --start テストの実行 # opcontrol --stop # opreport -l http://oprofile.sourceforge.net/news/
oprofile CPU: Core Solo / Duo, speed 2666.77 MHz (estimated) Counted DCACHE_PEND_MISS events (Weighted cycles of L1 miss outstanding) with  a unit mask of 0x00 (Weighted cycles) count 100000  vma  samples  %  linenr info  app name symbol name 000000000042be50 244787  33.2383  gc.c:1661  ruby  os_each_obj 000000000042bfac 1  4.1e-04  gc.c:1599 000000000042bfb9 5  0.0020  gc.c:1599 000000000042bfbe 6  0.0025  gc.c:1599 000000000042bfd0 4862  1.9862  gc.c:1601 000000000042bfd3 228573  93.3763  gc.c:1601 000000000042bfd6 2698  1.1022  gc.c:1601 000000000042bfd8 250  0.1021  ruby.h:672
oprofile 高速道路で、ズバリ最もコストのかかっているところに連れて行ってくれる コードを読まないで、理解する極意
テスト コードを理解するために、テストを書くというアプローチ。(ブラックボックステスト) 詳細ドキュメントを書く暇があったらテストを書け。 テストのないコードは不完全。テストとコードは一対になっている。
微視的理解 ひたすらコードを読む 王道はない ↑身もふたもない データ構造、変数などに注目し、どこで定義され、参照され、代入(変更)されているかという観点でみる デバッガとエディタ、クロスリファレンスツールを駆使
微視的理解 $ time find -type f -name \ '*.[ch]' -or -name '*.cpp' \  -or -name '*.cxx' | xargs \ egrep -l hogehoge $ time grep -r \ –include='*.[ch]' hogehoge .  hogehoge を含むファイルを検索
微視的理解 クロスリファレンスツール 変数の定義(型情報)、変更(代入)、参照 変数(関数)が、どのように定義されていて、どのように参照、変更されているかを追う cscope http://cscope.sourceforge.net/ lxr http://lxr.linux.no/ GNU GLOBAL http://www.gnu.org/software/global/ ack-grep
ソースコードを読む視点
参考書 Linux 詳解LINUXカーネル第三版 ISBN:487311313X Linuxカーネル2.6解読室 ISBN:4797338261 コードリーディング  ISBN:4839912653 DEBUG HACKS ISBN:978-4873114040 Ruby ソースコード完全解説  ISBN:4844317210( 品切れ中) http://i.loveruby.net/ja/rhg/
ユメのチカラ(ブログ) http://blog.miraclelinux.com/yume/ ブックマークで見た人気エントリー ソースコードの読み方(524個) http://blog.miraclelinux.com/yume/2007/08/post_d6bd.html デバッグ方法論(99個) http://blog.miraclelinux.com/yume/2007/08/post_d3eb.html 多くの人に興味がある話題
ブログ:ユメのチカラ http://blog.miraclelinux.com/yume/ 未来のいつか /hyoshiok の日記 http://d.hatena.ne.jp/hyoshiok/

Sourcecode Reading Workshop2010