ソースコード・リーディング・ワークショップ2010へ行ってきた

1月最後の土曜日、ソースコード・リーディング・ワークショップ2010へ行ってきました。

主催は、奈良先端科学技術大学院大学の森崎先生で、共催は、IBMさんです。

先週、ソースコード・リーディング・ワークショップ in デブサミ2010が終わってネタバレの心配が消えたので、1月に参加した時のメモをアップしておきます。

最後にも感想を書きましたが、参加して非常に良かったです。学んだことのエッセンスを、仕事の場で共有したいです。

以下のメモは、要約なので、誤りや講演された方の意図と異なる部分があるかもしれません。気づいたら、教えてもらえると嬉しいです。また、もしも、研究のデータ収集上問題が起こりうるような記述があれば、ご連絡ください。>関係者の方

講演「ソースコード理解と勉強会」よしおかひろたかさん

ご本人が、ブログで発表資料を公開してくださっています。

# 以下は、発表資料と重複しますが、自分のメモから(特に感銘を受けたお話)

トラブルシューティングや、テストを書くという本はあるが、ソースコードを読む、デバッグすることに特化した本は少ない。だから、ワークショップで情報交換する意義がある。ソースコードを読むことは、技術者の付加価値であり、陳腐化しにくい技術である。

コードはHow、テストはWhat、ドキュメントはWhyが書かれる。

よしおかさん自身は、とりあえず動かして、ブレークポイントを置き、その前後を見る、という読み方をしている。

コードを理解するためにテストを書くというアプローチを取る。レガシーコードでの派生開発では、まずテストを書く。テストを書いて、どういう動作が正しいのかが分かるようにしておく。直しやすくするため、また、正しく直すために、まずテストを書く

ハンズオン概説とハンズオン

Q ハンズオンとは何ですか?
実際に手を動かしていただくことを指します。今回のワークショップでは、主催者が用意する2つのソースコード(バージョン1.0と2.0)を、読んでいただき、バージョンアップが妥当なものであるかをご判断いただきます。(後略)
http://se.naist.jp/events/srw2010.html

Javaアプレットのコードがあって、それぞれのパッチをあててよいかというのを判定するというのを実際のコードを読みながら行う。

ソースコードリーディングワークショップ2010に行ってきた。- 未来のいつか/hyoshiokの日記

というわけで、配布された1600行程度のJavaのコードを2時間半かけて読みました(パッチも含めると2000行くらい)

読む方法として、画面か紙を選択します。自分は、持ち込んだノートPCを使って画面で読みました。PCを使うといっても、実行やデバッグ実行をしながら読むことはしません。ハンズオンの目的どおり、あくまでも静的な状態で読みました。

参加者間でのディスカッション

5つくらいの質問項目が書かれたシートを元に、4人1組でグループを作って議論しました。

# ディスカッションの内容は省略します。が、ディスカッション中に、この後の講演をされた細川さんが立ち寄って、色々ヒントをくださいました。その時のお話だけ、ちょっと残しておきます。

「元のソースコードの足りないところを補うように読む」
  • どこから書いたかを推測する
    • たとえば、case0からcase5まであるswitch文で、中身の処理はコピーアンドペーストを少し変更しただけのソースコードがあるとする。そのとき、最初のcase0にのみコメントがあったら、どのように考えるか
      • コメントも含めてコピーアンドペーストした後、(各caseに合わせてコメントを編集するならまだしも)わざわざ消すだろうか?
      • そもそも、caseを0から書き始めるか?
    • こういった点から、「case1から書き、最後にcase0が必要と気づいて、追加したのではないか」と推測してみる
  • ソースコードがセーフティか、セキュアかを見る。書いた人に、セキュアプログラミングの知識があったかどうかを推測する
  • 仕様書のバグを見つけるには、音読が有効である

講演「コードリーディング・テクニック―明日から使えるコードリーディングの技術とその真価―」細川宣啓さん

インスペクションの専門家の細川さんによる講演です。ソースコードに書かれた意図を読み取る方法について、具体的なお話をしてくださいました。

# 話術と内容に圧倒されて、メモをあまり取っていません(ご本人曰く「Twitter殺し」=tsudaることもできない速度のトーク)。次の記事が参考になると思います。

下から読む

ソースコードは、上から読まない。クラスの下から読んでいく。後から付け加えた部分は、たいていコードの下の方にある。名前の付け方や、書き癖などで、「この部分は元のコードを書いた人と別の人が書いたな」と分かる。

ヘッダコメントを読む

ヘッダコメントの行数をスクリプトで抽出してみる。そもそも書かれているか/省略されているか。"Date"とあったら、それは作成日なのか、更新日なのか、など。

ファイル名を見る

ソースコードのファイルすべてが、同じ命名規則に従っておらず、違うものが混じっていたら注意する。そのファイルだけ、他のソースコードを書いた人と別の人が書いた可能性がある。

た、どのように違っているかに着目することで、混入しているバグの種類を推測する。

  • ファイル名にハイフンを使っている
    • PL/ICOBOLの経験者が書いた可能性がある
      • 例外処理の漏れがないかを疑いつつ読む
  • ファイル名にアンダーバーを使っている
    • C/C++の経験者が書いた可能性がある
      • Null Pointer のエラーがないかを疑いつつ読む

などなど、仮説を持ってソースコードを読む。

ソースコード全体に占めるコメント率を見る

コメントが100%だったり、クラス宣言だけして残り98%がコメントだったりすると、水増しのためのソースコードであるとか、プログラマがギブアップしたソースコードであるなどの可能性を疑う。

コードを遠くから見る

ソースコードMicrosoft Wordにコピーアンドペーストして、思いきりズームアウトし、次の箇所に注目して読む。

  • 黒く密集している部分:複雑な処理がある
  • 逆「く」の字の部分:ネストが深い

図形として見ることで、パターンやメソッドの数を把握する。たとえば、同じようなパターンが繰り返し現れる場合、1つのメソッドをコピーして書いたコードかもしれない。コピー後の変更漏れが残っている可能性がある。

行単位でソートしてみる

まず、秀丸を使って、ソースコードを行単位でソートする。次に、行頭のタブを消す。すると、似た構造の行を一覧で比較して見ることができる。

たとえば、分岐のコメント部分をまとめて読むことで、処理の抜けの可能性に気づく。if(A)とif(B)という分岐があり、if(A)ではhoge()とmoga()、if(B)ではhoge()しかしていなければ、if(B)ではmoga()が抜けているかもしれない。

試験性を考えずに書いた仕様書をもとにコードを書くと、このような抜けが起こりうる。

コメントを読む

コメントが叙述的だったり、読点が多かったりするのは、書いた人が自信のない部分である。その箇所は、設計が不十分な可能性がある。

ソースコードから、書いた人の習性や生活習慣までをも読み取る

書いた人が、無意識に、自分の習性をソースコードに入れ込んでいることがある。たとえば、変数名と値の関係など。そういう箇所は、計算結果が正確でも、内部処理が悪い場合があるので、注意して読む。 # 分かりやすい例を挙げてくださいましたが、題材のソースコードの中身に直結しているため、割愛します。

コメントのばらつきにも気を配る。体言止めかどうかや、句読点の有無などの情報から、ソースコードを何人で書いたか、1日で書いたか/複数の日に分けて書いたか、同じ時間帯に書いたものかどうか、といったことまで推測できる。

その他

キャストのエラー、チェック漏れ、ダウンキャストは、チェックするべきポイント。

また、パフォーマンスに関する観点としては、繰り返し構文の条件式に関数を入れると、繰り返し回数が多いときに、思わぬパフォーマンスの劣化を招くので、注意して見る。

パネルディスカッション「私ならこう読む」明日に活かすソースコード読解の戦略

  • モデレータ
    • 新野淳一さん
パネリスト各氏のソースコード・リーディングのツールと使用方法
  • よしおかさん
    • ツール:emacsgdb、cscope
    • ツールの動作速度を重視して、GUIではない画面で読んでいる
    • emacsで読み、動くところを見たくなったらgdb、変数を見たくなったらcscope、と行き来する
    • cscopeは、特に手を加えず、素のままで使っている
  • ひがさん
    • ツール:Eclipse
    • Ctrlキーで、他のクラスやインタフェースに移動する操作を多用。行ってすぐ戻って来られて便利
    • Eclipseはほぼ素のままで使っている
    • コードレビュー時は、紙を使うこともある
    • 最近は、紙よりも、プロジェクタでスクリーンに写して、皆で見る方が多い
  • 戸島さん
    • ツール:cscope、vimlxr
    • ある程度の規模のモジュールを見る時、grepではしんどいのでcscope
    • Firefoxでviのキーバインドができるようにして、lxrを使っている
  • 細川さん
    • ツール:紙、赤ボールペン
    • 1500行程度ならよいが、1500クラスあると目視ではムリ
    • 印刷して、壁に貼り出すこともある
ワークショップの分析結果の傾向に関するお話(森崎さん)

# 書いてよいかわからないので省略します。分析結果の活用方法の可能性については、次の記事に詳しいです。

どんなふうに読んでいるか、さらに詳しく
  • よしおかさん
    • ソースコード中の注目しているあたりにブレークポイントを置いて、実行してみる
    • 自分なりの仮説を持ってソースコードに対峙して、検証していく
    • (使用ツールがGUIではないので)入力値と出力値。予定された値と合っているかどうかを見る
    • パフォーマンスを見るときは、プロファイラで実行コストの高い部分にあたりをつけて読む
  • ひがさん
    • 他人のソースコードをなるべく読みたくない。特に他人のソースコードデバッグは嫌
    • でも、技術を知りたいときは、本よりもOSSの実装を読む
      • 例えば、Appサーバに興味があったときは、JBOSSを読んだ
    • テストコードを読むとき
      • 1つのテスト(JUnitでいうと#&64;Testの中)で沢山テストしているのは良くない場合が多い
      • メソッド名とテストしたいことが対応しているのが大事
      • ソースコードの重複が多少あっても、メソッド名―テストしたいことの対応が良い方が大事
  • 戸島さん
    • 自分の中でイメージがつかめるまで読む
    • 大きな構造や関係性をつかむという意味で、細川さんの講演で行われた"Wordに貼ってズームアウトして見る"と同じことを自分の頭の中でする。ある程度の規模のソースコードを読む時は、データ、スレッド、ロックのスコープなどがどうなっているのか、自分なりにまとめて絵にする。
    • 同じソースコードを読んだ人と一緒に、想定や境界条件が同じかどうか確認する
  • 細川さん
    • 過酷なスケジュールの中で、人命がかかったシステムのソースコードを読まなければならないケースが多く、集中力が必要とされる
    • 集中力を切らせないために、「まだ集中はもってるか?」「まだいけるか?」と問いかけながらやる
    • トラブル判断のためにマインドマップを使うこともある。「変数多い」とか「名前が変」とか何でも印象をメモする
    • メモリマップを描きながら読む。面倒だけど必要なこと
  • 森崎さん
    • 仮説を立てて、その仮説の中だけに限定して検証する、というコツがある
      • もちろん、仮説を立てられるくらいには、読み込む必要がある

ここで、集中力の話題になりました。集中力を維持するコツとしては、「前日寝ること」、「打ち切ること」(by 細川さん)。「トータルで生産性を高めるためには、長時間働かず、短い時間で集中することが大事」(by ひがさん)

「レビュー観点」のお話(森崎さん)

ソースコードレビューについては、方法、メソッド、Howが書かれたものが多く、何をレビューすればよいのかが分かりづらいのが現状である。Whatを知るには、もうすぐできるレビュー標準を参考にされることをお勧めする。これは、欠陥特定、観点特定の標準であり、日本らしい観点を大事にしている。

複数人でのレビューのコツには、次のようなものがある。

  • 1回ごとに部分を限定して見る。例えば、「今日は例外処理だけ」と決めて読む。良い空気でレビューできる。『情報処理』の特集を見て欲しい。(※追記参照)
  • バグ票を見て、前回のバージョンで時間がかかっていたものを観点に持ってくる。
  • レビューをする人たちに、各人の得意分野のバグを探してもらう。発見するバグが重複しなくなる。

(追記)

この時に紹介された『情報処理』の特集というのは、おそらく次の記事だと思います。

  • 森崎修司氏:「ソフトウェアレビュー/ソフトウェアインスペクションと欠陥予防の現在」,情報処理,情報処理学会,Vol.50,No.5,p.p.375-417,2009.5.

手元にあったので、読んでみました。特集中、森崎さんの記事「ソフトウェアインスペクションの動向」では、レビューの方法について、実施形態、参加メンバやフェーズが解説されています。細川さんの記事「第三者インスペクションによる品質検査と欠陥予防」では、日本IBMでの取り組みが紹介されていて、「実施例」として様々な観点が載っています。たしかに参考になります :-)

質疑応答

  • [質問1] (バグ検出のためというよりも)ソースコードの全貌を見るためには、どのように読めばよいか。
  • [回答1]
    • ブラックボックスのテストケースを作る
    • 規模を見る、ディレクトリ構成を見る、といった形式的アプローチ
    • OSSであれば、ReadMeやインストール方法を読むあたりから
    • クラスの上の方に書かれている1番目、2番目の機能だけを見て、そのクラスを抽象化できるか考える
      • コメントがなくても意味が通じるか?
    • 順序、ブロック、インタフェース、ファサードで全体像を把握する。ひとりリバースエンジニアリングをする
  • [質問2] これまでに、「これはビックリした!」というソースコードがあれば、教えて欲しい。
  • [回答2]
    • #各氏が面白い話を披露してくれましたが、面白すぎて、書いてよいか不安なので、割愛 ;-)
    • 良い意味でびっくりしたのが、Google Guice。読んでみることをおすすめするよ。(by ひがさん)

感想

冒頭のワークショップ主旨に関する説明で、森崎さんが、「空中戦でなく共通の題材に基づく(ソースコードレビューの)議論」ができる場だ、とお話しされていました。そのとおり、貴重な体験をさせてもらいました。

「もっと速く深く大量に読めるようになりたい」というのが、一番の感想です。ハンズオンで、読むのに時間がかかったわりには、確信を持って欠陥を指摘できませんでした。くやしい ;-P

自分はソースコードを読む方も書く方も未熟なヘッポコですが、(だからこそ?)今回のワークショップはとても参考になりました。欠陥を見つけるためと全体像を把握するため、両方のソースコードリーディングに役立つ知識を得ることができました。実際に今、仕事と趣味でソースコードを読む時に、学んだことを取り入れています。

それにしても、細川さんのお話には圧倒されました。レビューの観点を聞いていると、まるで探偵のようです。ソースコードを書いた人の意図を読み取るを究めると、ソースコードの中身に踏み込む前に、バグの匂いを嗅ぎ取れる境地に達するんですね。

EclipseなしでJavaのコードを追いかけて、へとへとに疲れましたが、面白かったです。ありがとうございました。