コードクローンの分類に基づいた メソッド引き上げ手順の提案とその有効性評価

Slides:



Advertisements
Similar presentations
API 呼び出し列の差分を利用した Android アプリケーション比較ツールの 試作 井上研究室 神田 哲也.
Advertisements

シーケンス図の生成のための実行履歴圧縮手法
Javaのための暗黙的に型定義される構造体
アルゴリズムとプログラミング (Algorithms and Programming)
Myoungkyu Song and Eli Tilevich 発表者: 石尾 隆(大阪大学)
情報伝播によるオブジェクト指向プログラム理解支援の提案
研究の背景 コードクローン ソースコード中に存在する一致または類似したコード片
リファクタリングのための 変更波及解析を利用した テスト支援ツールの提案
メソッド名とその周辺の識別子の 相関ルールに基づくメソッド名変更支援手法
川口真司 松下誠 井上克郎 大阪大学大学院情報科学研究科
ソースコードに対する適用可能な修正手順を 可視化するリファクタリング支援手法の提案
プログラム実行履歴を用いたトランザクションファンクション抽出手法
大規模ソースコード集合を対象とした 類似関数集合群の抽出
ギャップを含むコードクローンの フィルタリング手法の提案
コーディングパターンと キーワードを用いて生成したコードスニペットの推薦
コードクローンに含まれるメソッド呼び出しの 変更度合の分析
コードクローンに含まれるメソッド呼び出しの 変更度合の調査
識別子の命名支援を目的とした動詞-目的語関係の辞書構築
細かい粒度で コードの再利用を可能とする メソッド内メソッドと その効率の良い実装方法の提案
ソードコードの編集に基づいた コードクローンの分類とその分析システム
オブジェクト指向 プログラミング 第十一回 知能情報学部 新田直也.
オブジェクト指向 プログラミング 第十三回 知能情報学部 新田直也.
動的スライスを用いた バグ修正前後の実行系列の比較
暗黙的に型付けされる構造体の Java言語への導入
リファクタリング中に生じる コンパイルエラーの自動解消手法
ポインタ解析におけるライブラリの スタブコードへの置換の効果
シーケンス図を用いて実行履歴を可視化するデバッグ環境の試作
利用関係に基づく類似度を用いたJavaコンポーネント分類ツールの作成
クローンセットに対する主要編集者の分析法の提案と調査
Javaプログラムの変更を支援する 影響波及解析システム
社会シミュレーションのための モデル作成環境
コードクローン検出ツールを用いた ソースコード分析システムの試作と プログラミング演習への適用
プログラミング言語論 第五回 理工学部 情報システム工学科 新田直也.
リファクタリング支援のための コードクローンに含まれる識別子の対応関係分析
プログラム動作理解支援を目的とした オブジェクトの振舞いの同値分割手法
ソースコードの特徴量を用いた機械学習による メソッド抽出リファクタリング推薦手法
コードクローンの動作を比較するためのコードクローン周辺コードの解析
コードクローンに対する一貫性のない変更に起因する欠陥の検出
柔軟に変更可能な字句解析機構を持つ コードクローン検出ツールの開発
ソースコード縮退による ソースコード理解 神谷年洋 科学技術振興事業団 さきがけ研究21 オブジェクト指向シンポジウム2003.
UMLモデルを対象とした リファクタリング候補検出の試み
コードクローン検出に基づくデザイン パターン適用支援手法の提案と実現
オブジェクト指向 プログラミング 第十ニ回 知能情報学部 新田直也.
○ 後藤 祥1,吉田 則裕2 ,井岡 正和1 ,井上 克郎1 1大阪大学 2奈良先端科学技術大学院大学
ソフトウェア保守のための コードクローン情報検索ツール
コードクローンの理解支援を目的としたコードクローン周辺コードの解析
コンパイラ 2011年10月20日
コードクローン分類の詳細化に基づく 集約パターンの提案と評価
既存ソフトウェア中の 頻出コード片を用いた コード補完手法の提案
コーディングパターンの あいまい検索の提案と実装
アルゴリズムとプログラミング (Algorithms and Programming)
コードクローン間の依存関係に基づく リファクタリング支援環境の実装
C#プログラミング実習 第3回.
プログラムスライスを用いた凝集度メトリクスに基づく 類似メソッド集約候補の順位付け手法
設計情報の再利用を目的とした UML図の自動推薦ツール
コードクローン間の依存関係に基づく リファクタリング支援手法の提案と実現
メソッドの同時更新履歴を用いたクラスの機能別分類法
第5回 プログラミングⅡ 第5回
オブジェクト指向言語論 第五回 知能情報学部 新田直也.
コードクローン間の依存関係に基づく リファクタリング支援手法の提案と実現
UMLモデルを対象とした リファクタリング候補検出手法の提案と実現
JAVA入門⑥ クラスとインスタンス.
Webページタイプによるクラスタ リングを用いた検索支援システム
プログラムの一時停止時に 将来の実行情報を提供するデバッガ
コードクローン解析に基づく デザインパターン適用候補の検出手法
Javaとは Javaとはオブジェクト指向言語でJava VM(Java仮想マシン)と呼ばれるプログラム上で動作します。
メソッド抽出リファクタリングが 行われるメソッドの特徴調査
オブジェクト指向言語における セキュリティ解析アルゴリズムの提案と実現
オブジェクト指向メトリクスを用いた 開発支援に関する研究 --- VC++とMFCを用いた開発を対象として ---
Presentation transcript:

コードクローンの分類に基づいた メソッド引き上げ手順の提案とその有効性評価 それでは、コードクローンの分類に基づいたメソッド引き上げ手順の提案とその有効性評価というタイトルで 井上研の吉岡が発表します 井上研究室  吉岡一樹

コードクローン ソースコード中のコード片で,同一または類似した コード片を持つもの コード片の修正 → コードクローンすべてに検討を 修正 コード片の修正 → コードクローンすべてに検討を 修正 修正を検討 ソースファイルF1 ソースファイルF2 クロ―ンペア クローンペア まず、研究の背景としてコードクローンについて説明します。 コードクローンとはソースコード中のコード片で,同一または類似したコード片を持つものです。 ここで表示されている例だとF1に二つの同一のコード片が、F2ににも同一のコード片があります。 これらをコードクローンと呼び,コードクローンの対のことをクローンペアと呼びます もしもコード片に 修正 クローンペア

リファクタリングパターンの開発は未熟な開発者の手助けに 外部的振る舞いに変更を加えずに内部的振る舞いを修 正することをリファクタリングという[1] 特に繰り返し行われる修正を,修正をする状況と手順をまと めてリファクタリングパターンという Fowlerはコードクローンに対する代表的なリファクタリン グパターンを提案している[1] 同一クラスのコードクローン → メソッドの抽出 兄弟クラスのコードクローン → メソッドの引き上げ リファクタリングパターンの開発は未熟な開発者の手助けに [1] Fowler.:Refactoring:”Improving The Design Existing Code”,Addison Wesley (1999)

より詳細なリファクタリングパターンを作成することで 既存のパターンの問題点 Fowlerのパターンでは,あいまいさを残すことで修正に 柔軟に対応するようにしている 対応できるだけの開発者の技術が必要になる 未熟な開発者が利用するには手順の詳細化が必要 数が少ないことの問題点 あいまいなことの問題点 ジョシュアも引用してみる? ×開発者の能力によらない より詳細なリファクタリングパターンを作成することで 未熟な開発者の手助けになる

コードクローンの分類 徳永らが提案したもの[2]でコードクローンの特徴ごとに分類 し,分類ごとにリファクタリングパターンを提案していく 分類項目は以下の7つ クローンペアの差異 クローンペアの位置 クローン部の長さ メソッド抽出の際に引数となるオブジェクト メソッド抽出の際に戻り値となるオブジェクトの数 制御構造要素の有無 Instanceof演算子の有無 上記の分類によってコードクローンを分類し,手順を詳細化 できるようにする 言わなくていい 後に必要になる奴だけいう [2]徳永将之ら,“コードクローンの分類に基づくリファクタリングパターンの提案に向けて”,ウインターワークショップ2011

本研究の提案内容 分類の一つを用いてリファクタリングパターンを提案 提案したパターンを用いて実験として被験者がリファクタ リング Fowlerが提唱している既存パターンとの比較実験 提案したパターンの既存パターンの比較評価をアンケー ト アンケートでってはっきり言う 提案したパターンを既存パターンとの比較評価を行ってもらう

提案したパターン 要約 状況 ユーザ記述データ,定数を差異に持つ 兄弟クラス間クローンを親クラスに引き上げ 差異:上記の差異 ブロック単位 引数の権限:private 戻り値となるオブジェクトの数:0,もしくは1 制御構造要素なし Instanceof演算子なし リファクタリングパターンは, 状況 手順 実例 からなる文章で記述される 必要なとこだけ読む 本パターンは文章であらわした。 アイテマイズ //clear

以下の2つのコードは兄弟クラス間のクローンである 銀行口座のオブジェクト生成 顧客名のセット : Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate (ORDINARY_RATE); : Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate ( FIXED_RATE); 顧客名のセット 顧客番号のセット 顧客番号のセット  !!アニメーション使う!! 差異

手順1:親クラスのメソッド宣言 手順1-1: メソッドの宣言,コンパイル 手順1-2: クローン部の引き上げ 手順1-3: 変数,オブジェクトの処理 手順1-4: 戻り値の処理 手順1-5: 差異の処理 手順1-6: 親クラスのコンパイル,テスト 手順2:子クラスのメソッド宣言

手順1-1: メソッドの宣言,コンパイル : : Account customer = Account customer = 手順1-1: メソッドの宣言,コンパイル : Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = (ORDINARY_RATE; : Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = FIXED_RATE); 親クラスに処理を記述する

メソッドの名前はメソッドの役割,処理の内容から決める 手順1-1: メソッドの宣言,コンパイル メソッドの名前はメソッドの役割,処理の内容から決める : Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = (ORDINARY_RATE; : Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = FIXED_RATE); void  initialAccount(){ }

手順1:親クラスのメソッド宣言 手順1-1: メソッドの宣言,コンパイル 手順1-2: クローン部の引き上げ 手順1-3: 変数,オブジェクトの処理 手順1-4: 戻り値の処理 手順1-5: 差異の処理 手順1-6: 親クラスのコンパイル,テスト 手順2:子クラスのメソッド宣言

手順1-2:クローン部の引き上げ : : Account customer = Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = (ORDINARY_RATE; : Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = FIXED_RATE); void  initialAccount(){ }

手順1-2:クローン部の引き上げ : : void initialAccount(){ Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = (ORDINARY_RATE; : Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = FIXED_RATE); void  initialAccount(){ Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate (ORDINARY_RATE); } コピー&ペースト

手順1:親クラスのメソッド宣言 手順1-1: メソッドの宣言,コンパイル 手順1-2: クローン部の引き上げ 手順1-3: 変数,オブジェクトの処理 手順1-4: 戻り値の処理 手順1-5: 差異の処理 手順1-6: 親クラスのコンパイル,テスト 手順2:子クラスのメソッド宣言

手順1-3:クローン部の差異以外の変数,オブジェクトの引数を用意する Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = (ORDINARY_RATE; : Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = FIXED_RATE); void  initialAccount(){ Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate (ORDINARY_RATE); }

手順1-3:クローン部の差異以外の変数,オブジェクトの引数を用意する Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = (ORDINARY_RATE; : Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = FIXED_RATE); void  initialAccount( String name,int number){ Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate (ORDINARY_RATE); } 変数の名前をそのまま,引数に宣言する 右下簡潔に

手順1:親クラスのメソッド宣言 手順1-1: メソッドの宣言,コンパイル 手順1-2: クローン部の引き上げ 手順1-3: 変数,オブジェクトの処理 手順1-4: 戻り値の処理 手順1-5: 差異の処理 手順1-6: 親クラスのコンパイル,テスト 手順2:子クラスのメソッド宣言

手順1-4:戻り値があるならオブジェクトのreturnを追加し,メソッドの型を戻り値の型にする Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = (ORDINARY_RATE; : Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = FIXED_RATE); void  initialAccount( String name,int number){ Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate (ORDINARY_RATE); } 右下簡潔に

手順1-4:戻り値があるならオブジェクトのreturnを追加し,メソッドの型を戻り値の型にする Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = (ORDINARY_RATE; : Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = FIXED_RATE); Account  initialAccount( String name,int number){ Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate (ORDINARY_RATE); return customer; } 戻り値がないときにはこの手順での操作はない

手順1:親クラスのメソッド宣言 手順1-1: メソッドの宣言,コンパイル 手順1-2: クローン部の引き上げ 手順1-3: 変数,オブジェクトの処理 手順1-4: 戻り値の処理 手順1-5: 差異の処理 手順1-6: 親クラスのコンパイル,テスト 手順2:子クラスのメソッド宣言

手順1-5:差異のための引数を作成し,差異を引数で置き換える Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = (ORDINARY_RATE; : Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = FIXED_RATE); Account  initialAccount( String name,int number){ Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate (ORDINARY_RATE); return customer; }

手順1-5:差異のための引数を作成し,差異を引数で置き換える Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = (ORDINARY_RATE; : Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate () = FIXED_RATE); Account  initialAccount( String name,int number ,int rate){ Account customer = new Account(); customer.setName(name); customer.setNumber( number); customer.setRate (rate); return customer; } 共通部分を名前にしている ソースコード的にする 手順1-6:親クラスをコンパイルして,テストする

手順1:親クラスのメソッド宣言 手順1-1: メソッドの宣言,コンパイル 手順1-2: クローン部の引き上げ 手順1-3: 変数,オブジェクトの処理 手順1-4: 戻り値の処理 手順1-5: 差異の処理 手順1-6: 親クラスのコンパイル,テスト 手順2:子クラスのメソッド宣言

手順2:元の子クラスのクローン部を取り除き,メソッド呼び出しを追加する Account customer = initialAccount(name, number, ORDINARY_RATE ); : Account customer= initialAccount(name, number, FIXED_RATE ); 何が変わったかわからない 各クラスをコンパイルして,テストする

適用実験の準備 提案したパターンを用いて、オープンソースソフトウェア Sootを用いて実際のコードでリファクタリングを行った コードクローン検出ツールを用いてコードクローンを見つけた のち,手作業で分類にかけたもの 被験者三名に、3つのクローンペアに対し、提案したパ ターンとファウラーのパターンを比較してリファクタリング を行ってもらった 被験者はコンピュータサイエンス専攻のM1,M2,研究生の 三名 66個のJUnitテストを用いてリファクタリングが正常に行われた ことを確認する 口頭では口語

適用実験の結果(1/2) 提案手法が優れていると評価された点 提案手法が劣っていると評価された点 引数に対する扱い 戻り値があるときの扱い 手順1-3:変数,オブジェクトの処理を評価 戻り値があるときの扱い 手順1-4:戻り値の処理を評価 差異に対する扱い 手順1-5:差異の処理を評価 提案手法が劣っていると評価された点 手順全体の柔軟さ 詳細化を進めたために好みの手順でプログラミング出来ない

提案したパターンの手順の優位性を示している 適用実験の結果(2/2) 66個のJUnitテストケースを用いてリファクタリングパターンの妥当性を確認 被験者A 被験者B 被験者C 引数に対する扱い ✓ 戻り値があるときの扱い 差異に対する扱い 手順全体の柔軟さ スライド増やす 良かった点悪かった点を次のスライドで詳しく文章で 評価実験でいいところを手順で強調する ヴぉいdの話出す 開発者の要求に応じて手順変えれるようにする ↓ 時間は同じ 今のスライド 三名の評価で提案パターンが既存のパターンよりも優れていると 評価している箱の三点 ×禁止 悪い点も良い点と同様に表す 提案したパターンの手順の優位性を示している

まとめと今後の課題 まとめ 今後の課題 コードクローンの分類に基づいたメソッド引き上げ手順を提案 した コードクローンの特徴ごとの分類の自動化 他の分類に対してのリファクタリングパターンの提案 ×Ccファインダー使うこと最初に言う

終わり