Upgrade to Pro — share decks privately, control downloads, hide ads and more …

日経iOSプロジェクトのマルチモジュール戦略

Go Takagi
September 13, 2023

 日経iOSプロジェクトのマルチモジュール戦略

Go Takagi

September 13, 2023
Tweet

More Decks by Go Takagi

Other Decks in Technology

Transcript

  1. ⽇経 iOS プロジェクトの

    マルチモジュール戦略


    Go Takagi 
    2
    02 3
    /
    09
    /
    13
    After iOSDC LT Night 〜 ピクシブ×⽇経×タイミー 〜

    View Slide

  2. Me ( Go Takagi )
    ‣ID


    • shimastripe / shimastriper


    • bento.me/shimastripe


    ‣Work at


    • 株式会社 ⽇本経済新聞社


    ‣ iOS エンジニア


    ‣ iOSDC NOC チーム


    ‣Like


    • Swift / ⾃動化 / 柴⽝
    2
    電⼦版広報⽝デンシバ
    iOSDC
    2
    023
    UIContentCon
    fi
    guration!!

    View Slide

  3. iOSDC
    20 23

    View Slide

  4. スポンサーセッション⾯⽩かった!

    View Slide

  5. SPM MultiModule
    5
    Application
    Monolith


    App Feature
    Feature
    Feature
    Usecase Common
    Usecase Common
    Repository Common
    ...........
    ...........
    ...........
    Swift Package Manager の各パッケージ
    App

    View Slide

  6. 既存プロジェクトの移⾏例の紹介
    ‣ 必ずしもすぐマルチモジュール移⾏できる状態ではない...(ですよね)


    • 既存アーキテクチャとの兼ね合い


    • そもそも依存がきれいに分割されているか


    ‣ プロジェクトの状態を正確に把握する必要性がある


    • どういう効果を期待しているのか


    ‣ ⽇経がどういう技術選定をして移⾏しているか


    • ベースの基盤刷新も兼ねつつ、移⾏しています
    6

    View Slide

  7. ⽇経電⼦版のアプリ
    7

    View Slide

  8. OSの機能を数多くサポート
    8
    アプリ内課⾦ WatchOSサポート
    Widgets
    Apple Pencil サポート
    ステッカー

    View Slide

  9. KPIツリーと施策効果から⾒るアプリの役割
    9
    ݱ৔ͷࢪࡦͷࣄۀߩݙΛ໌֬ʹ
    ࣄۀՁ஋ (LTV)
    ܧଓ݄਺ F V
    ๚໰ස౓
    ফඅهࣄຊ਺
    ղ໿཈ࢭ
    Net ARPPU
    ηοτ঎඼୯Ձ
    ηοτ঎඼ߪೖ਺
    ൢചख਺ྉ
    ೔ܦIDܾࡁൺ཰
    ిࢠ൛ϓϥϯൺ཰
    ՝ۚऀ਺ MAU
    ৽نདྷ๚ऀ
    ࠶དྷ๚ऀ
    ແྉτϥΠΞϧਃ

    ॳճ՝ۚ཰
    ՝ۚ཰
    ిࢠ൛ͷࣄۀՁ஋ΛߴΊΔͨΊʹ͸ɺ՝ۚऀ਺Λ૿΍͢ɺ
    ՝ۚ୯ՁΛ্͛Δɺܧଓ݄਺Λ૿΍͢͜ͱ͕ඞཁ

    View Slide

  10. 成⻑し増加する画⾯‧Extension間のコード共有
    ‣ マクロ分岐


    • #ifdef IS_APP 等があちこちに......


    ‣ TargetMembership


    • 依存関係の把握が必要‧ビルド時間も伸びる


    ‣ WatchApp との兼ね合い


    • UserDefaults や Keychain が繋がっていない


    ‣ ⾮同期処理‧DataBindingの管理


    • App は RxSwift、AppExtension は Combine でそれぞれ重複実装していた


    • Concurrencyに移⾏したい........
    1
    0

    View Slide

  11. 過去にEmbeddedFrameworkを作ったが
    ‣ EmbeddedFramework の性質‧プロジェクト構造の不理解


    • GodCommonを作ってしまって結局戻した
    1
    1
    https://speakerdeck.com/shimastripe/embedded-frameworkfalsesusume

    View Slide

  12. 改善したい、抱えている痛み
    ‣ 古いモジュールの改善‧それに伴う⼗分なドキュメントの整備


    • メンテしづらい‧AppExtension の制約等の考慮


    • テストを書きつつ現代ではいらないコードを消したい


    ‣ 依存⽅向をきちんと管理


    • 無視した変更が⼊れづらい設計を保証する仕組みにしたい


    ‣ ⾮同期処理周り


    • RxSwift‧Combine のコードを Concurrency に移⾏したい


    ‣ ビルド時間の改善


    • 画⾯数が多いため、ビルド時間が⻑くて開発効率に響いている
    1
    2

    View Slide

  13. 改善の変遷

    View Slide

  14. AppExtension をまず整理
    ‣ App の Subset であるため取り組みやすかった


    • Core になる仕組みを整理していく


    • 前処理Macroの整理‧共有している最⼩限のロジック群を把握


    ‣ WatchOSの考慮


    • Keychain‧UserDefaults など永続化周りを抽象化してAppの場合と住み分ける


    ‣ Combine ベースの⾮同期処理を Concurrency に置き換える


    • API‧DB などの Data 層の処理まで⼀旦 Concurrency 移⾏


    • ⼀定サイズを移⾏後、Usecase や UI 層にも⼿を付け移⾏していく


    • App も RxSwift 向けに変換して利⽤する形で部分的に移⾏‧徐々に割合を増やしていく
    1
    4

    View Slide

  15. Package.swift でレイヤー依存関係を定義
    1
    5
    // MARK: - Utility


    // ֤ϨΠϠʔͷύοέʔδΛ༻ҙ͢Δศརؔ਺


    protocol TargetProtocol {


    var category: String { get }


    var name: String { get }


    var hasTest: Bool { get }


    var testDependencies: [TargetDependency] { get }


    var allDeps: [TargetDependency] { get }


    /// default extension


    var dependency: TargetDependency { get }


    var targets: [Target] { get }


    }

    View Slide

  16. レイヤー間の依存関係を制御
    1
    6
    extension Data {


    static let orgUserRepository: Self = .init(


    name: "OrgUser",


    layer: .repository,


    dataDeps: [.keychainKit],


    domainDeps: [.model, .repositoryProtocol],


    hasTest: true


    )


    }

    View Slide

  17. MultiModule に移しつつコードを刷新する
    ‣ global な Extension の整理


    • MultiModule に移して思わぬビルドエラーを踏んで把握


    ‣ ⾮同期処理


    • Concurrency で書き直して、RxSwift を持ち込まない


    • Combine は場合によって許容


    ‣ DI


    • pointfree/swift-dependencies を採⽤して @Environment ベースで DI


    ‣ テスト


    • スコープを絞って整理が進むのできちんと書いていく
    1
    7

    View Slide

  18. 開発環境はどう変化してきたか
    1
    8
    Project CLI ツール
    パッケージマネージャー CI
    Nikkei.xcodeproj Fastlane / Make
    fi
    le
    Carthage Bitrise
    (3年前)

    View Slide

  19. 開発環境はどう変化してきたか
    1
    9
    Project CLI ツール
    パッケージマネージャー CI
    XcodeGen Mint
    SwiftPM Bitrise (Fastlane)
    (1年前)

    View Slide

  20. 開発環境はどう変化してきたか
    2
    0
    Project CLI ツール
    パッケージマネージャー
    CI
    XcodeGen


    +

    MultiModule


    +


    Swift Playgrounds
    Mint
    SwiftPM + Renovate
    Bitrise (Fastlane)
    (今)

    View Slide

  21. Project 構成 (workspace)
    2
    1
    設定ファイル (yml)
    Swift Playgrounds
    SPM MultiModule
    App (本体)

    View Slide

  22. MultiModule + Swift Playgrounds へ移⾏中
    2
    2
    Application
    Monolith


    App Feature
    Feature
    Feature
    Usecase Common
    Usecase Common
    Repository Common
    ...........
    ...........
    ...........
    Swift Package Manager の各パッケージ
    App

    View Slide

  23. MultiModule + Swift Playgrounds へ移⾏中
    2
    3
    Application
    Feature
    Feature
    Feature
    Usecase Common
    Usecase Common
    Repository Common
    ...........
    ...........
    ...........
    保存記事App
    More...
    紙⾯選択画⾯App
    該当箇所のみビルドしてミニアプリ⽣成

    View Slide

  24. Swift Playgrounds ミニアプリ
    ‣ アプリを画⾯単位で確認したい


    • 通常分割は⼤変


    • エントリーポイントを変える仕組みもない


    • 設定ファイルもたくさん必要


    ‣ Swift Playgrounds をミニハック


    • iPad (+ Mac) で Swift だけでアプリを作れる


    • 簡単なアプリしか作れない...?


    • マルチモジュールを Import してミニアプリを作れる


    • Package.swift の書き換えは想定されていない⽅法なことだけ注意
    2
    4
    https://www.apple.com/jp/swift/playgrounds/
    Demo.swiftpm


    ├── Package.swift


    └── Sources/MyApp/MyApp.swift
    エントリーポイントを容易に追加できて嬉しい

    View Slide

  25. Xcode Preview との使い分けは悩み中
    ‣ Preview 安定しない問題


    • 特定のライブラリに依存して失敗するようになりやすい


    • 回避できるけど問題は"気づいたら"壊れているのが⾟い


    ‣ 現状のミニアプリの利点


    • 安定してビルドして確認できる


    • 設定をユースケースに応じて動的に変えたりリッチなPreviewが作れて嬉しい


    • ミニアプリで有効な機能はApp側のDebug機能に移すことも
    2
    5

    View Slide

  26. Stricted Concurrency Checking
    ‣ MultiModuleでもまだ ON にはしてない


    • 古いコードからの移⾏がつらくなるため


    • 度々⼿元でオンにしてみて様⼦⾒


    • 特に UI レイヤーで ON にすると⼀気に⼤変な量のエラーに 😇
    2
    6

    View Slide

  27. TestPlanを⾃動整備
    ‣ TestTarget‧TestModule がどんどん増えていく


    • 内部の JSON はシンプル


    • 以下のコマンドでモジュールの⼀覧は取れる


    • xcrun --sdk macosx swift package --package-path MultiModule describe --type json


    • ビルド時に jq で TestPlan の⾃動アップデート
    2
    7
    {
    "containerPath": "container:MultiModule",
    "identifier": "UseCase",
    "name": "UseCase"
    }

    View Slide

  28. Xcode Template を整備
    ‣ 標準ベースで書き直したモジュールに Template を⽤意


    • APIRequest‧DB


    • swift-dependencies 周りの Template


    • ただ基本シンプルなものしか作れない


    • より複雑なTemplateが必要になったら Sourcery を検討する予定
    2
    8
    https://github.com/krzysztofzablocki/Sourcery

    View Slide

  29. DoCCを整備 (したい)
    ‣ いくつか問題点を抱えてまだ導⼊できず


    • plugin が platform: Mac 専⽤


    • Xcode の generate docs でも


    • 特定のライブラリの docc ファイルを⾒てエラー.......


    • 複数 Scheme をまとめるドキュメント⽣成ができない
    2
    9
    https://github.com/apple/swift-docc-plugin/issues/
    38
    DoCC の運⽤ Tips ぜひ知りたいです!

    View Slide

  30. まとめ
    ‣ Project の状態は様々


    • MultiModuleへの移⾏は⼀般に時間がかかる


    • 痛みを認識し、そこから取り組んでいったほうが効果が実感できて良い


    • アプリが⼤きくなるとより継続性が⼤事


    ‣ ⽇経のマルチモジュール移⾏→標準ベースのリアーキテクチャも兼ねる


    • OSの機能をリッチに活かしながらモダンな技術を利⽤できる環境


    • OSの機能はアプリチームが⼀番詳しいので積極的に起案して作ってます


    • まだまだ⼀部だけで移⾏中。興味を持った⽅、弊社にぜひ声かけてください!
    3
    0

    View Slide