CTC 教育サービス
[IT研修]注目キーワード Python UiPath(RPA) 最新技術動向 Microsoft Azure Docker Kubernetes
今回は、2019年に公開された論文「Type Migration in Ultra-Large-Scale Codebases」に基づいて、ソースコードの「型移行自動化ツール」を用いた大規模なリファクタリングの事例を紹介します。Google社内では、すべてのソースコードが単一のリポジトリに納められており、自動化ツールを用いた、リポジトリ全体に渡る大規模なリファクタリングを行うことがあります。この論文では、そのようなリファクタリングの一例として、Java言語の「型移行」を実施した例が紹介されています。
はじめに予備知識として、Java言語における「型の移行」ついて簡単に説明しておきます。Java言語では、プログラム内で使用するクラスや関数にはそれぞれの「型」が決められており、ソースコード内で明示的に型を指定する必要があります。この際、言語仕様の改訂により、新しい型が導入されて、これまで使っていた型を新しい型に置き換える事で、プログラムの実行速度が向上するといったことがあります。図1は、論文内で紹介されている簡単な例になります。
図1 型の移行によるリファクタリングの例(論文より抜粋)
図1の左側のソースコードでは、"Function<Double, Double>" という型が用いられています。一般に、"Function<X, Y>" というのは、「X という型のオブジェクトを受け取って、Y という型のオブジェクトを返す関数」を表す汎用的な型になります。このケースでは、X、および、Y として、Double(倍精度の浮動小数点数)が指定されています。実は、このように、X、Yにプリミティブ型(整数や浮動小数点数などの基本的な型)を用いる場合は、"Function<X, Y>" という汎用的な型ではなく、それぞれのプリミティブ型に対応した専用の型を用いることができます。この例にある "Function<Double, Double>" であれば、図1の右側で用いられている "DoubleUnaryOperator" という型に置き換えることができて、これにより、プログラムの実行速度が向上します。
そこで、このプログラムに含まれる "Function<Double, Double>" という型をまとめて "DoubleUnaryOperator" に置き換えると言うリファクタリング作業に取り掛かるわけですが、これは決して単純な作業ではありません。たとえば、図1の左(中段)にあるように、"Function<Double, Double>" という型の関数では、"apply" というメソッドを用いることができますが、"DoubleUnaryOperator" では、これを図1の右(中段)にある "applyAsDouble" というメソッドに置き換える必要があります。そのため、ソースコード全体を見て、"Function<Double, Double>" 型のオブジェクトを格納した変数に対して、"apply" メソッドを用いている部分をすべて発見する必要があります。この程度であれば、手作業でもなんとかなりそうですが、より複雑な例になると、型を変更したクラスのサブクラスに対してもメソッドを変更するなど、複数のファイルにわたるソースコード全体を解析する必要があり、手作業での修正は困難になります。
このような型移行を支援するツールは、これまでにも用いられてきましたが、基本的には、GUIの統合開発環境(IDE)での利用が前提となっており、大量のソースコードに対してバッチで自動処理するという仕組みはありませんでした。冒頭の論文では、Googleのエンジニアが考案して開発した、T2Rと呼ばれるツールが紹介されており、これを用いると図2のようなバッチ処理が可能になります。
図2 T2Rのアーキテクチャー(論文より抜粋)
これは、MapReduceタイプのジョブとして実装されており、図の①のフェーズでは、それぞれのソースコードのファイルに対して個別に並列処理を行い、各ファイル内で使用されている型の情報を収集します。②のフェーズでは収集した型がプログラム全体でどのように関連しているかを示す「型の階層構造」を分析します。最後に③のフェーズでは、これらの情報を元にして、型の移行に必要なソースコードの変更部分をリストアップします。特に①の部分は、型移行の具体的な内容に依存しない一般的な情報を収集するため、ソースコードリポジトリ全体に対して事前に実行しておけば、具体的な型移行のパターンを指定する②以降の処理をより迅速に実行することができます。このツール(T2R)は、Google社内でも実際に使用されており、Google社内の環境では、リポジトリ全体に含まれる3億行ものJavaのソースコードに対して、定期的なバッチ処理が行われています。
T2Rの開発チームでは、T2Rの性能と有用性を評価するために、7種類のオープンソースプロジェクト、および、Google社内のリポジトリに対してT2Rを適用しました。図3は、T2Rが生成した変更をそれぞれの開発チームに対して、性能向上に寄与するパッチとして提案した上で、実際に採用された変更がどの程度あるかを示したものになります。
図3 T2Rの評価結果(論文より抜粋)
全体として130のパッチが生成されて、その中で、コンパイルエラーなどの問題を起こさない126のパッチが提案されましたが、最終的に114のパッチが有用なパッチとして受け入れられたという事です。特にオープンソースプロジェクトに提案したものは、論文執筆時点でレビュー中の10個を除いて、すべてのパッチが受け入れられました。論文の中では、特に、分散データベースのCassandraに提供したパッチに対する開発者からの評価が記載されています。Cassandraは高性能なデータベースとして徹底的なチューニングが行われており、性能向上のための手作業による型移行も頻繁に行われていますが、それでも、T2Rによって15種類の型移行の候補が発見されました。特にその中の1つは、データベースの中核部分に関わるもので、性能向上に非常に重要な影響を持つものだったということです。
また、Google社内のリポジトリへの適用では、T2Rの実行速度の評価も行われました。3億行以上のソースコードに対して、図2の①〜③の処理は33分で完了したということです。
今回は、2019年に公開された論文「Type Migration in Ultra-Large-Scale Codebases」を用いた大規模なリファクタリングの事例を紹介しました。論文内では、ツールが実施する解析の内容についても詳細に解説されていますので、興味がある方は、ぜひ論文にも目を通してみてください。次回は、動画データの処理に特化した、データセンター内の分散処理システムの話題をお届けしたいと思います。
Disclaimer:この記事は個人的なものです。ここで述べられていることは私の個人的な意見に基づくものであり、私の雇用者には関係はありません。
[IT研修]注目キーワード Python UiPath(RPA) 最新技術動向 Microsoft Azure Docker Kubernetes