はじめに
こんにちは。 iOS アプリを開発している小野です。
この記事は Gunosy Advent Calendar 2024 の 9 日目の記事です。 8 日目の記事は skozawa さんの データ基盤のコストを Amazon S3 Intelligent-Tiering で削減する でした。
私は 2024 年 10 月に Gunosy に入社しました。 今回は 2024 年アドベントカレンダーの機会に、入社からこの 1 ~ 2 ヶ月を振り返っていきます。
自己紹介
埼玉県在住の 25 歳です。 Gunosy は 2 社目で初めての転職となります。
前職は toB 向けのアプリ開発に従事しており、 Swift メインと Objective-C で開発していました。
転職の背景
転職活動の軸として、 1 つのアプリに長く携わりたいと考えていました。 具体的には、開発して終わるのではなく、その後も継続的に事業として成長させていきたいという思いがありました。 このような思いを抱きながら転職活動を進め、 Gunosy の面接を受けさせていただきました。
面接を通じて、 Gunosy で働くエンジニアの方々と一緒に仕事をすることで、自分の成長につながると感じ、 Gunosy への転職を決意しました。
( Gunosy を初めて知ったのは私が高校生の頃です。 当時スマホが普及し始めており、私もスマホを持ち始めた頃にニュースアプリとして Gunosy をインストールしていました。 Gunosy の CM を見ていた記憶があります。あの CM 制作に携わっていたと話す社員の方がいたのでちょっと驚きました。)
Gunosy の文化
入社から振り返って、 Gunosy に入社していいなと感じた文化を挙げていきます。
① 毎日のコードレビュー
iOS チームではその日に書いたコードはその日のうちにコードレビューを実施しています。 PR を提出して各自確認する時間を取ろうとすると PR が溜まっていく危惧があるため、 MTG の時間を設けて実施しています。
これに感じるメリットとして、リモートが多い環境下で毎日決まった時間に MTG があるので、質問しやすいという点があります。 もちろん Slack 等でも質問はできますが、通話を繋ぐことでより具体的に伝えられ、早く課題を解決することができます。 また、コードレビュー時にコードの意図を説明する必要があるため、復習にもなりエンジニアとしての学習にも繋がると実感してます。
② 数値確認
毎朝の MTG で、各アプリの数値確認を行っています。
売上や DAU (日間アクティブユーザー数)等を確認したり、クラッシュ率やインプレッション数を見てアプリに異常がないかを確認します。また、新しい施策が利用者に効果的だったかを諸々確認しています。 特にニュースアプリということで、どの記事が利用者に読まれたのかも見ることができ、世間の関心のあることが何かがわかるのも興味深いです。
アプリ内でログ収集をしているので、どの経路でユーザーが流入したのかも確認することができたり、画面の表示やクリック率等も確認することができます。 自分の開発した機能がどのくらいのユーザーに利用されているかも確認でき、開発した機能の良し悪しも判断できるので、開発者としては非常に役立ちます。
③ 技術ブログ
Gunosy ではテックブログやデータ分析ブログで技術記事を書く文化があります。 業務の中で得た知識をブログに書くことで、自分の中で整理することができます。同時にオープンに情報を共有することで、社内で何をしているのかを Gunosy に興味を持ってくれている方に届けられます。 私も転職活動の際に企業調査の一環として、確認させてもらっていました。
入社後も拝見することが度々あり、特に auサービスToday 開発初期の設計思想が記載された記事は、アプリの設計を理解するのに役立ちました。
2021年にSwiftUIを部分利用しつつ新規のiOSアプリを作った - Gunosy Tech Blog
新環境で習得したスキルと知識
① Swift Concurrency
私が現在従事している開発は「 auサービスToday 」の iOS アプリです。 auサービスToday は MVVM + Clean Architecture を採用しており、その中で Swift Concurrency や Combine を使用しています。
この技術の習得には苦戦しました。前職では非同期処理に DispatchQueue や Closure を多用していたため、 Swift Concurrency に馴染みが薄かったのです。
理解を深めるために活用できたのが、 Swift Concurrency のチートシートです。
Swift Concurrency チートシート
この資料はチームメンバーが Swift Concurrency を導入した当初の輪読会で活用していたものと聞いております。
これさえ読んで理解すれば大体のことを掴めました。特に馴染みのなかったactor
について詳細に学べたのは良かったです。
actor
を使用することで、同時にアクセスできる Task
が一つに限定され、データ競合が発生せず整合性が保たれることが保証されます。
また、actor
のプロパティは外部から直接更新できないため、不適切なアクセスや変更を防ぐことができ、開発者として安心感があります。
本アプリでなぜこの技術を使用しているかをチームメンバーに聞きながら理解を深めていくことで、追加実装の際にも本質を理解しながら開発を進められています。
② Combine
Combine も同様に苦戦しました。
リアクティブプログラミング自体を使った経験がなかったためです。
特に注意が必要だったのがUITableViewCell
を使用した際の処理です。
コーディングの書き方によりますが、tableView (_:cellForRowAt:)
で Combine の Publisher を購読した場合 UITableViewCell
は再利用されるためインスタンス破棄による購読解除ができず、prepareForReuse
メソッドでSet<AnyCancellable>()
を初期化する必要があります。
(awakeFromNib
で監視処理をセットした場合は、再利用時にメソッドが呼ばれないため、初期化は不要となります。)
初期化をしないことで、再利用前のサブスクリプションが残ったままとなり、多重購読が発生し、同じイベントに対して複数回の処理が実行される危険性がありました。
リアクティブプログラミングを使用することでどのようなメリットがあるのか、入社当初は理解が不足しておりましたが、実際に開発を進めるうちに私なりのメリットを感じるようになりました。
疎結合
Combine を使用することで、ViewModel
がViewController
を直接保持することなく処理を行うことができ、疎結合な設計が可能になります。宣言的な記述と再利用性の向上
データの変化に対する反応を宣言的に記述できるため、コードの再利用性が高まります。統一されたコーディングスタイル
設計が統一されているため、後からプロジェクトに参加した開発者でも実装に入りやすいというメリットがあります。リアクティブプログラミングに不慣れだった私でも、コーディングの統一性によりスムーズに実装を進めることができました。 一箇所を理解すれば、他の箇所も同様の処理であることが多いため、わかりやすいです。
一度取得してしまえば、これほど便利なものはありません。 より便利なものを取り入れようとするチームメンバーの姿勢を見習っていきたいです。
③ SwiftUI の活用
auサービスToday は SwiftUI と UIKit のハイブリッドアプリ開発を行っています。
前職では UIKit と Objective-C での開発経験しかなかったため、 SwiftUI のようなモダンな環境は非常に新鮮でした。
SwiftUI を触ったことはありましたが、実務での経験はありませんでした。
UIKit と SwiftUI のハイブリッド開発では、UIHostingController
を使用することで、 UIKit のライフサイクルや画面遷移を活用しつつ、 UIKit の画面の子要素として SwiftUI で UI を実装しています。
依然として UIKit には高度なカスタマイズや細かい制御が可能なコンポーネントが存在します。 SwiftUI はコードベースで UI を実装できるため、コードレビューや UI の変更が容易になります。 両方の良いところを取り入れることで、開発者として非常に満足しています。
また、 SwiftUI と Combine は相性が良く、@ObservedObject
を使用して監視対象オブジェクトの変更を検知し、 View を更新することが可能になることから、 ViewModel 側でプロパティの保持が実現できています。
SwiftUI が監視対象の更新ごとに再描画を行う仕組みを理解することで、より深い理解が得られました。
④ A/B テスト
toC 向けアプリでは、利用者のフィードバックを直接受け取るのが難しいため、 A/B テストやログ収集をアプリ内に組み込むことで機能の改善やユーザーのニーズを把握しています。 このログ収集は先述の数値確認にも繋がっています。 A/B テストでは、新機能を特定のユーザー数 % にのみ適用し、反映前と比較します。 その結果を分析し、新機能が良い数値をもたらせば全てのユーザーに反映させ、逆に数値が下がったり売上が減少する場合は新機能を撤退させるフローになっています。 このプロセスを通じてユーザーのニーズや行動が明確になり、新しい施策の考案にも繋がっているようです。 より多くのユーザーにアプリを利用してもらえるような施策を考える上で、 A/B テストは非常に重要な役割を果たしていると感じました。
実装に関しても A/B テスト処理の組み込みは容易なものでしたので、どのアプリに導入しても良さそうな手法だと思います。
入社後のタスク
初めのオンボーディング期間では簡単な機能の追加を担当しました。 その際、アーキテクチャや設計思想を理解するために、余裕を持った時間を設けていただきました。
環境にも慣れ始めた頃、施策の一つとして記事リストに新しい形式のコンテンツを追加する実装を行いました。 記事リストは本アプリの根幹部分であり、内部処理の複雑性が増しています。 それでも、メンテナンス性の高い設計が施されていたため、新しいコンテンツ追加時の影響範囲は小さく、開発をスムーズに進めることができました。
実装期間でサーバーサイドとの API 通信の動作確認時に、設計時に考案した通りに動作しない事態が発生し、新規 API の実装が必要となりました。 サーバーサイドとの認識に齟齬があったことが原因でした。 原因の調査に際しては、多くのメンバーを巻き込んで迅速に問題を発見することができ、その後のサーバー側の新規 API の実装も早く、結果としてクライアント側のスケジュールを遅らせることなく進めることができました。
これは Gunosy のエンジニア皆様が高い能力を持ち、一人一人が当事者意識を持つ環境であること。 これにより素早い開発体制、リリース頻度を高く維持できていると感じました。
最後に
Gunosy には技術に関心が高い方が多く、非常に学びの多い環境です。 また、エンジニアとして技術面だけでなく、施策の考案や施策の分析も行います。 ビジネス志向の視点も身につけることができ、自分の領域を広げる機会も多いと感じました。 実際にエンジニアからビジネス寄りのポジションに移られた方もいらっしゃいます。 こうした環境下で、私自身もとても楽しく働くことができています。 全員でより良いものを作り上げていこうという姿勢が全面にあり、その雰囲気にも惹かれています。
私もより一層、精進していきたいと思います。
明日は uemura さんが Lexical で文章の修正提案機能を自作する についてお話します。お楽しみに!