Realays Logo Realays
← Back to Blog
DevLog 2025/12/10

[Dalendar DevLog 6] より良いコードのために - アプリ性能改善とコードリファクタリング

初期プロトタイプを超えて、論文ベースの最適化アルゴリズムを適用してコードをリファクタリングし、性能を改善した経験を共有します。

[Dalendar DevLog 6] より良いコードのために - アプリ性能改善とコードリファクタリング

6編: より良いコードのために - アプリ性能改善とコードリファクタリング

Introduction

「より良いコードのために」シリーズの以前の文章では基本的な機能を備えたカレンダーアプリを作る過程を扱いました。ひとまず作動するプロトタイプを完成した後、私の次の目標は性能最適化とコードリファクタリングでした。今回の文章では単に作動することを超えて、アプリの核心ロジックをより効率的で優雅に改善する私の旅程を共有しようと思います。

1. 初期実装の限界: 「ただのカレンダー」のコアロジック

初期カレンダーアプリはAndroid開発の標準的な方式に従いました。RecyclerViewを使用してUIレンダリング自体は効率的に行われましたが、問題はその下にある日付計算ロジックにありました。標準的な方式で実装された計算ロジックはユーザーが月を速くスクロールするたびに数多くの日付計算を繰り返して性能低下の主な原因になりました。

2. 性能ボトルネック現象発見と解法探索

すべてのカレンダーアルゴリズムの心臓には「ラタダイ(rata die)」変換過程があります。この変換作業は必然的に整数の割り算と余り演算を多く使用するようになりますが、この演算がCPUで最も遅い基本算術演算だという点が問題でした。プロファイリング結果、CPUが単純な整数割り算と余り演算に想像以上の時間を消耗していたのです。

3. リファクタリングの核心: 割り算を掛け算に変える

論文で提示した核心概念は 「強度縮小最適化(strength reduction optimization)」 です。これは計算費用が高い演算をはるかに速い演算に代替する技法です。

3.1. 事例 1: 年度計算リファクタリング (Before & After)

Before: 標準的な割り算と余り演算使用

n2 = 4 * r1 + 3;
q2 = n2 / 1461;
r2 = n2 % 1461 / 4;

After: マジックナンバーを使用した掛け算とビットシフト演算に代替

n2 = 4 * r1 + 3;
u2 = 2939745 * n2;             // あらかじめ計算されたマジックナンバーを掛ける
q2 = u2 / 2^32;                 // 商は64ビット掛け算結果の上位32ビット
r2 = u2 % 2^32 / 2939745 / 4; // 余りは下位32ビットから派生する

ここでq2は64ビット掛け算結果であるu2の上位32ビットから計算されます。本当の魔法はr2が計算される方式にあります。u2の下位32ビットを使用してq2の計算結果なしでも余りを正確に再構成できます。

3.2. 事例 2: 月計算リファクタリング (Before & After)

Before:

n3 = 5 * r2 + 461;
q3 = n3 / 153;
r3 = n3 % 153 / 5;

After:

n3 = 2141 * r2 + 197913;
q3 = n3 / 2^16;                 // 商は結果の上位ビットから計算 (16ビット右シフト)
r3 = (n3 % 2^16) / 2141;        // 余りは下位ビットから派生する

4. 単純な速度改善その以上: データ従属性除去

これは単純な命令語入れ替えではなく、データ従属性を除去するための計算の根本的な再構成でした。既存コードでCPUはq2計算が終わるまで待たなければr2計算を始められませんでしたが、リファクタリングされたバージョンではu2値が準備されるやいなや2つの計算を同時に始めることができます。これは現代スーパースカラプロセッサで 「命令語レベル並列性(instruction-level parallelism)」 を可能にする完璧な実際事例です。

5. 結論: すっきりして速いコードに向けた旅

今回のリファクタリングを通じてカレンダーアプリはより速く反応性が良くなっただけでなく、計算的により優雅ですっきりしたコードベースを備えることになりました。これこそが「より良いコード」を作成するという原則を実現する過程でした。

関連記事