負債を返済し続けた7ヶ月
この記事はnoteのみんな Advent Calendar 2020の8日目の記事です。記事を書いているのはiOSアプリの開発をしているかっくんです。
noteにジョインしていつの間にか7ヶ月が経過しました。
少し前にnoteのiOSチームのインタビューをしてもらって、内容もよくまとまってたので勢いでエントリーしてしまったアドベントカレンダーに何を書くか非常に迷いました。
そこでこの記事では上記の記事とは別の視点で、7ヶ月間で負債をどう返済していったのかを振り返ります。入社してから本当にいろいろやったなと思いますが、表に見えない苦労もいろいろありました。とりあえずわかりやすい指標としてGitHubのコントリビューションを見てみましょう。
iOSアプリのリポジトリ内でコミット数では6年間で一番になってしまいました。コミット数だけが全てではもちろん無いですがどれだけいろいろやったかは伝わるかなと思います。以下にもう少し詳細を見てみます。
Objective-Cのコードの減量
6年以上iOSアプリが運用されていると当たり前のようにObjective-Cのコードが鎮座しています。主に利用される画面から奥の方にあるような画面まで幅広く存在していました。まずは入社時のコード量を見てみます。
----------------------------------------------
Language files blank comment code
----------------------------------------------
Objective-C 196 8655 2262 28942
Swift 361 3945 3761 21364
XML 109 0 19 8131
JSON 294 0 0 5863
C/C++ Header 201 1478 895 2915
----------------------------------------------
SUM: 1161 14078 6937 67215
----------------------------------------------
続いて現在(12/3時点)のコード量です。
----------------------------------------------
Language files blank comment code
----------------------------------------------
Swift 869 10215 8121 58193
Objective-C 106 3789 1085 12240
XML 100 0 12 7817
JSON 345 0 0 6841
C/C++ Header 109 751 482 1608
----------------------------------------------
SUM: 1529 14755 9700 86699
----------------------------------------------
コード総数は増えてるけどObjective-CとSwiftの量が逆転してることがわかります。Objective-Cのコード量は半分程度になりましたね。(まだまだ残っているということもよくわかりました)消えたObjective-Cのコードは主に画面系のコード(ViewControllerやView)です。Swift化・Auto Layout化・UIのモダン化を進めた結果ですね。残っている物はあまり表に出てこない(気付きづらい)画面やモデル情報系が主な物です。今後も引き続きObjective-Cのダイエットには注力したいと思います。
古いサードパーティ製のライブラリの排除
現在のnoteのiOSアプリではライブラリをCocoaPodsとSwift Package Managerを利用して管理しています。6年もアプリを運用していると更新が滞るライブラリも出てきます。その間にはUIに関する変化だとSafe Areaが出てきたり、Sceneという概念ができて複数ウィンドウを持つアプリの実装が可能になったりしました。ライブラリの更新が追いつかないことで明らかに見た目的に不具合だと感じる箇所もありました。(例: ライブラリで出してるUIがSafe Areaの外に出て隠れてしまう等)また、アプリをビルドしているとライブラリの中でdeprecatedの警告が出ることもあります。僕が入社時に利用していたライブラリは33個あり、その内15個を削除することに成功しました。ただ、その後増えているライブラリもあるので現時点の総数としては34個と少し増えてしまっています。今後も剥がせるライブラリを剥がしてなるべく軽量なアプリをキープしていきたいです。
不具合修正やパフォーマンス改善
残り続ける不具合も技術的負債と呼んでしまっていいと思います。入社前から気になっていた不具合もあれば、日々開発を続ける中で生んでしまった不具合もあります。再現性のある不具合を見つけては修正したり、再現性が無くてもCrashlyticsで検知した物はあたりをつけて対処したり、パフォーマンスが気になった画面はInstrumentsを利用して原因を特定したりをして改善していきました。
また、画面の作り方によって非常に悪いパフォーマンスの画面もありました。一つ個人的に面白かったパフォーマンスの不具合としては、端末の写真を選択するような画面で端末が持ってる写真に全てアクセスしてアプリ内で扱いやすいようにラップするようなコードがありました。僕のiPhoneには3万枚以上の写真があったので画面の表示が完了するまでに時間がかかってしまうという問題がありました。アプリ全体でラッパーに依存するような作りになっていたので、画面を作る時に一気にラッパーを作るのではなく、写真の選択が完了したタイミングに選択済みの写真だけラップするような方式に変えただけでパフォーマンスが随分改善しました。
再利用性・拡張性の低いコードの置換
既存のObjective-Cで書かれたコードは往々にして再利用性・拡張性が低い作りになっていました。例えば見た目はほぼ同じだけど取得したいAPIが異なる場合にenumを渡してswitch文で呼ぶAPIを変更するような作りの画面がありました。Swiftのコードにすると下記のような感じ。
enum NoteList {
case top
case recommend
}
final class NoteListViewController: UIViewController {
func fetch(with list: NoteList) {
switch list {
case .top:
fetchTopApi()
case .recommend:
fetchRecommendApi()
}
}
}
こういう場合は新しく同様の画面を増やそうとすると元の画面にも修正を入れなければいけませんでした。現在はVIPER(厳密にはRouterはあまり使ってないのでMVPに近い)のView, Presenter, Interactorをprotocolを利用してDIするような設計に変更しているので呼ぶAPIのInteractorを増やしてInjectするだけで新しい画面が作れるようになっています。(テストもしやすくなりました。)
まとめ
長い歴史のあるアプリならではの問題や負債がいろいろ溜まっていたので細かく対処していたら気づけばかなりの量の対処ができていました。今後も並行してアプリの機能追加や改善も行っていきますが、現時点でもまだ対処し切れていない負債ももちろんあるので、目には見えない負債も解消して開発のしやすいアプリにしていきたいと思います。明日はSREチームから@varu3です。お楽しみに。
この記事が気に入ったらサポートをしてみませんか?