この記事の要点
- Developer Spotlight は世界の興味深い Swift 開発者を紹介するシリーズです。本記事は Pacific Tech Graphing Calculator の作者 Ron Avitzur によるもので、1985年から続く老舗の数式グラフ電卓アプリを C++ から Swift へ全面的に書き換えた 経験がまとめられています。
- 35年分の技術的負債(technical debt)が蓄積し、新機能の追加が困難になっていたため、著者は段階的な改修ではなく ゼロからの書き直し を選びました。あわせて構文解析・並行処理・文字列処理・UI・グラフィックスのすべてを近代的な技術へ移行しています。
- 結果として、ソースコードは 約152,000行から約29,000行へ(約81%削減) となり、機能・性能をほぼ損なうことなく、はるかに保守しやすく読みやすいコードベースになりました。
- 一方で、長年の低レベル最適化に匹敵する 速度の達成が最大の課題 であり、特に式ツリーを辿る際の ARC の retain/release オーバーヘッドが残る課題として挙げられています。
採用前の課題
Graphing Calculator は1985年、128K Macintosh 向けに C で書き始められました。16ビット整数、白黒 QuickDraw、MMU も FPU も GPU もない 8MHz の 68000 CPU という時代のソフトウェアです。以来、CPU は 68K から PowerPC、Intel、ARM へと移り変わり、API も Inside Macintosh から Carbon、Cocoa(AppKit / UIKit)、そして SwiftUI へと変遷してきました。
著者は「壊れていないなら直すな」という方針を長く守ってきましたが、そのぶんコードには、当時は理にかなっていたものの今では役に立たない過去の名残が数多く残っていました。たとえば、1980年代に書かれたスレッドセーフでないコードを動かすために、Classic Mac OS 9 の協調的スレッド API を今なお使い続けていたほどです。こうして数十年分の技術的負債が積み重なると、新規開発はリスクの高いものになります。
ゼロからの全面書き直しは、レガシーコードに刻まれた長年の教訓を失う危険があり、テスト対象がすべて新規になるため、本来はめったに良い選択ではありません。それでも著者は、35年間先送りしてきた問題に正面から向き合うには、すべてを見直して土台から書き直すのが最善だと判断しました。
言語を変えた直接のきっかけは、Apple の AR(拡張現実)技術への感銘でした。AR を数学教育に活かすプロトタイプを作る中で、ARKit によるビジョンや機械学習は Objective-C でも可能ではあるものの、Swift の方がはるかに扱いやすく、今後の Apple の新技術でもそれは同様だろうと感じたことが、Swift への移行を後押ししました。
Swiftでどう改善したのか
著者はまず、Graphing Calculator の中核である数式処理システム(computer algebra system)を Swift へ移植することから学習を始めました。当初は学習用の練習でしたが、やがて実現可能性の検証へと発展し、パンデミック下の在宅プロジェクトとして本格化しました。この移植は、次のように複数の技術移行を同時に伴うものでした。
| 移行元 | 移行先 |
|---|---|
| C++ / Objective-C / Objective-C++ | Swift |
| Lex / YACC | Swift |
| pthreads | Swift の structured concurrency |
| C++ の char | Swift の String |
| AppKit / UIKit | SwiftUI |
| OpenGL | SceneKit と Metal |
著者が移植を通じて評価している Swift の特徴は次のとおりです。
- 簡潔で明快な構文。 C++ で必要だった繰り返しの多いボイラープレートの多くが姿を消し、ロジックを表すために必要なコードだけが残って意味が明確になりました。型推論、optional、クロージャ、関連値を持つ
enum、ヘッダーファイルが不要な点なども、簡潔で表現力の高いコードに寄与しました。 - 値型とコレクション。 コレクションが値型であることで、その振る舞いを推論しやすくなりました。シンタックスシュガーによって扱いも容易で、内部的には ARC と copy-on-write によりほとんどの用途で高い性能が得られます(ただし、この性質の限界を探ることが性能最適化上の大きな課題でもあります)。
Stringによる Unicode 対応。 Swift のStringは Unicode を標準でサポートするため、C++ の char、UTF-8、UTF-16 が入り混じった分かりにくい状態を解消し、コードの整理と推論が容易になりました。- SwiftUI による宣言的 UI。 SwiftUI を使うことで view controller が完全に不要になり、命令的プログラミングに対する宣言的プログラミングの大きな利点が得られました。
最終的に、ソースコードは約152,000行から約29,000行へと減りました。個々の機能を移植すると、Swift のコードは対応する C++ コードのおおむね30%程度の量に収まったといいます。行数はそれほど有用な指標ではないものの、コードが少ないことはデバッグ・読解・理解の負担が小さいことを意味し、それだけで保守を容易にします。
実運用から得られる示唆
著者は、Swift が 安全で・高速で・表現力のあるコード という約束を、SwiftUI が 最小限のコードで Apple プラットフォーム全体に優れた UX を提供する という約束を、いずれも果たしていると総括しています。一方で、実際の移植から得られた示唆もいくつか示されています。
- 性能の達成が最大の難所だった。 数十年にわたる反復的な最適化が高い性能の基準を作っていたため、それに匹敵する速度を出すのは大きな挑戦でした。性能が要となる箇所では Swift の数々の Unsafe API を使いこなす必要があり、難しくはあったものの効果的でした。
- ARC の retain/release オーバーヘッド。 残る最大の課題は、式ツリーを辿る際の ARC の retain/release コストの削減です。C++ 版は式のメモリ管理を手動で行っており、壊れやすい一方で非常に高速でした。Swift 版は小さく正しく書きやすい反面、ツリーの走査が参照カウントを変えないと分かっていても、その retain/release が不要だとコンパイラに伝える手段がない、という課題が挙げられています。
- オープンソースかどうかの差。 Swift の言語・ライブラリ・ランタイムはドキュメントが充実し、いざとなればオープンソースの実装を確認できます。対照的にクローズドソースの SwiftUI は、想定どおりに動くときは魔法のように快適でも、想定外の挙動をしたり規定の経路から外れたいときには、制約の理解や回避が難しいことがあると述べられています。
著者は、書き直しによってコードベースの状態に強い満足を得ており、将来的には数式組版・編集・数値計算・記号計算・グラフ描画のための独立した Swift パッケージとして公開できる手応えを得たとしています。重い計算を伴う長寿命のアプリにおいても、Swift が保守性・安全性・性能を両立しうることを示す事例です。
関連リンク
- Pacific Tech Graphing Calculator
- Graphing Calculator: macOS 版 / iOS 版