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

Merpay Tech Fest 2021_メルペイのスケーラビリティを支えるマルチモジュール開発 / Multi-module development to support scalability of Merpay

Merpay Tech Fest 2021_メルペイのスケーラビリティを支えるマルチモジュール開発 / Multi-module development to support scalability of Merpay

Merpay Tech Fest 2021は5日間のオンライン技術カンファレンスです。

IT企業で働くソフトウェアエンジニアおよびメルペイの技術スタックに興味がある方々を対象に2021年7月26日(月)から7月30日(金)までの5日間、開催します。 Merpay Tech Festは事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知れるお祭りです。 セッションでは事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介予定です。お楽しみに!

■イベント関連情報
- 公式ウェブサイト:https://events.merpay.com/techfest-2021/
- 申し込みページ:https://mercari.connpass.com/event/215035/
- Twitterハッシュタグ: #MerpayTechFest

■リンク集
- メルカリ・メルペイイベント一覧:https://mercari.connpass.com/
- メルカリキャリアサイト:https://careers.mercari.com/
- メルカリエンジニアリングブログ:https://engineering.mercari.com/blog/
- メルカリエンジニア向けTwitterアカウント:https://twitter.com/mercaridevjp
- 株式会社メルペイ:https://jp.merpay.com/

92cdcff298e89e2fcd2fb705155c2d4b?s=128

mercari
PRO

July 27, 2021
Tweet

Transcript

  1. #MerpayTechFest Session Title メルペイ スケーラビリティを支える マルチモジュール開発 Masamichi Ueta Product Engineering,

    iOS team
  2. #MerpayTechFest Product Engineering, iOS team Masamichi Ueta 2018年メルペイに入社し、メルカリ連携や旧メルペイトップ画面 開発を行う。 FlutterやSwiftUIでメルカリ

    TechConfアプリも作ったりしました。
  3. #MerpayTechFest 本日 内容 マルチモジュール開発について メルペイ 構成 モジュール間連携 仕組み マルチモジュールを活用した開発プロセス 02

    03 04 01
  4. #MerpayTechFest マルチモジュール開発について

  5. #MerpayTechFest マルチモジュール開発について • モジュール ◦ フレームワークやライブラリ • マルチモジュール開発 ◦ 複数

    フレームワークやライブラリを組み合わせてアプリを開発すること
  6. #MerpayTechFest アプリ 構成 Monolith • 1つ アプリターゲット • パッケージマネージャーを使ってライ ブラリを管理

    アプリケーション ライブラリ1 ライブラリ2
  7. #MerpayTechFest アプリ 構成 Layer • アプリを各層に分割 ◦ 層が分割されて構成がわかりやすくなる ◦ よく使う機能をまとめておける

    ◦ Extensionでも共通して使える ◦ ビルドタイムを短縮できる場合がある ライブラリ1 ライブラリ2 UI モデル アプリケーション
  8. #MerpayTechFest アプリ 構成 Feature • アプリ 機能を、機能ごとに分割す る ◦ 対象

    機能を備えたサンドボックスアプ リを作って開発できる ◦ 複数チームで同時開発しやすくなる ライブラリ1 ライブラリ2 アプリケーション 機能1 機能2 UI モデル
  9. #MerpayTechFest メルペイ 構成

  10. #MerpayTechFest Design System gRPC client External libraries Shared Merpay Mercari

    Mercari App Core API External libraries Shared Feature NFC Coupon QR more Dynamic framework (Mainly) Static library + Bundle Dependency Injection ※ Mercari depends Merpay shared modules a bit Dynamic framework
  11. #MerpayTechFest Design System gRPC client External libraries Shared Merpay Mercari

    Mercari App Core API External libraries Shared Feature NFC Coupon QR more Dynamic framework (Mainly) Static library + Bundle Dependency Injection ※ Mercari depends Merpay shared modules a bit Dynamic framework • 18個 機能モジュール ◦ スタティックライブラリ +バンドル ◦ モジュール間で 参照 ない • 3個 共通モジュール ◦ ダイナミックフレームワーク • XcodeGenでプロジェクト管理
  12. #MerpayTechFest メルペイ プロジェクト組織構成 iOS team PJ A PJ B PJ

    C Android team Backend team エンジニア
  13. #MerpayTechFest メルペイ プロジェクト組織構成 iOS team PJ B PJ C Android

    team Backend team PJ D PJ A(完了) エンジニア
  14. #MerpayTechFest メルペイ プロジェクト組織構成 iOS team PJ B PJ C Android

    team Backend team PJ D 新規モジュール! PJ A(完了) エンジニア
  15. #MerpayTechFest 新機能開発 • テンプレートから 新モジュールを生成 ./bin/init_framework.sh MerpayTechFestKit • モジュールテンプレートに含まれるも ◦

    XcodeGen 設定ファイル ◦ 各種ターゲット フォルダ ▪ 機能 (スタティックライブラリ + バンドル)、テスト ▪ サンドボックスアプリ ▪ プレビューアプリ • Xcode Previews でUIKitベース アプリ開発を効率化する - iOSDC Japan 2020 @kenmaz • https://speakerdeck.com/kenmaz/xcode-previews-deuikitbesufalseapurikai-fa-woxiao-lu-hua-suru-iosdc-japan-2020
  16. #MerpayTechFest 実際にやってみる ./bin/init_framework.sh MerpayTechFestKit Merpay.xcworkspace/contents.xcworkspacedata

  17. #MerpayTechFest 実際にやってみる

  18. #MerpayTechFest 実際にやってみる public final class MerpayTechFestKitSandboxViewcontroller: SandboxBaseViewController { public override

    init(style: UITableView.Style) { super.init(style: style) sections = [ .init(title: “Sample”, items: [ .init(title: “Hello MerpayTechFest”, action: { // Show View }) ]) ] } }
  19. #MerpayTechFest 現在 構成 利点 • 各プロジェクトで独立して開発しやすい • アプリ全体をフルビルドしなくてもサンドボックスアプリで開発できる ◦ Developing

    Apple Pay In-App Provisioning in merpay @kenmaz ◦ https://speakerdeck.com/kenmaz/developing-apple-pay-in-app-provisioning-in-merpay • スタティックライブラリな で、モジュールが増えても起動時間に影響を与えない ◦ > You can reduce your app’s launch time by limiting the number of frameworks you embed https://developer.apple.com/documentation/xcode/improving_your_app_s_performance/reducing_your_app_s_launc h_time
  20. #MerpayTechFest 現在 構成 利点 • プロジェクトファイルをXcodeGenで管理している でコンフリクトが発生しない ◦ 何らか プロジェクト管理ツール

    必要 • 新プロジェクト立ち上げ時に新モジュールを作ることでモチベーションがあがる ◦ これから育てていく感 ◦ オーナーシップ
  21. #MerpayTechFest チーム内で ナレッジシェア • 自分が関わったモジュール以外 機能がわかりづらい ◦ チームミーティングで具体的なコードや機能をシェアする時間を設ける ◦ 週替わりで発表

    • 他 モジュール 似たようなフローを参考にする
  22. #MerpayTechFest モジュール間連携 仕組み

  23. #MerpayTechFest モジュール間連携 • モジュール間で画面遷移が必要に なる • モジュール間で直接参照すると関係 が複雑になる NFC Coupon

    QR
  24. #MerpayTechFest モジュール間連携 • モジュール間で直接参照しない • Dependency Injectionで連携 できる仕組みを構築 NFC Coupon

    QR Dependency Injection Merpay Feature Core Shared
  25. #MerpayTechFest public enum MerpayScene { case nfcKit(scene: NFCKitScene) case qrKit(scene:

    QRKitScene) case couponKit(scene: CouponKitScene) … } extension MerpayScene { public enum NFCKitScene { case scene1(argument: Scene1Argument) case scene2(argument: Scene2Argument) ... } public enum QRKitScene { case scene1(argument: Scene1Argument) case scene2(argument: Scene2Argument) ... } ... } MerpayScene NFC Coupon QR Dependency Injection Merpay Feature Core Shared
  26. #MerpayTechFest MerpaySceneFactory NFC Coupon QR Dependency Injection Merpay Feature Core

    Shared public protocol MerpaySceneFactoryType { func viewController(for scene: MerpayScene, dependency: Dependency) -> UIViewController? } public class MerpaySceneFactory: MerpaySceneFactoryType { private var factories: [MerpaySceneFactoryType] = [] public func register(factory: MerpaySceneFactoryType) { factories.append(factory) } public func viewController(for scene: MerpayScene, dependency: Dependency) -> UIViewController? { for factory in factories { if let viewController = factory.viewController( for: scene, dependency: dependency) { return viewController } } return nil } }
  27. #MerpayTechFest Dependency NFC Coupon QR Dependency Injection Merpay Feature Core

    Shared public protocol Dependency { ... var sceneFactory: MerpaySceneFactoryType { get } ... }
  28. #MerpayTechFest MerpaySceneFactory NFC Coupon QR Dependency Injection Merpay Feature Core

    Shared import Core final class NFCKitSceneFactory: MerpaySceneFactoryType { func viewController(for scene: MerpayScene, dependency: Dependency) -> UIViewController? { guard case .nfcKit(let scene) = scene else { return nil } switch scene { case .scene1(let argument): return Scene1ViewController( argument:.init(aaa: argument.aaa), dependency: dependency ) case .scene2(let argument): return Scene2ViewController( argument:.init(aaa: argument.aaa), dependency: dependency ) ... } } }
  29. #MerpayTechFest MerpaySceneFactory NFC Coupon QR Dependency Injection Merpay Feature Core

    Shared import Core import NFCKit import QRKit import CouponKit func application(xxx, didFinishLaunchingWithOptions ...) -> Bool { ... let sceneFactory = MerpaySceneFactory() sceneFactory.register(NFCKitSceneFactory()) sceneFactory.register(QRKitSceneFactory()) sceneFactory.register(CouponKitSceneFactory()) let dependency = Dependency( ..., sceneFactory: sceneFactory ) let rootVC = RootViewController(dependency: dependency) window?.rootViewController = rootVC ... }
  30. #MerpayTechFest MerpaySceneFactory NFC Coupon QR Dependency Injection Merpay Feature Core

    Shared import Core final class Scene1ViewController: UIViewController, Instantiatable { init(argument: Argument, dependency: Dependency) { self.dependency = dependency ... } func showQR() { guard let vc = dependency.sceneFactory.viewController( for: .qrKit(.scene1(argument: .init(aaa: aaa)))) else { return } navigationController?.pushViewController(vc, animated: true) } }
  31. #MerpayTechFest モジュール間連携 • モジュール間で直接参照しなくてよい • モジュール内 ViewController 全て internal にできる

    ◦ 同じモジュール内 SceneFactory で生成される ◦ 使う時 UIViewController で抽象化される
  32. #MerpayTechFest マルチモジュールを活用した 開発プロセス

  33. #MerpayTechFest メルペイで 機能開発プロセス • 新規モジュールを作る ./bin/init_framework.sh MerpayTechFestKit • Featureブランチを作る git

    checkout -b feature/merpay-tech-fest • デイリーでmainブランチをマージしつつ開発 • FeatureブランチでメルカリアプリをビルドしてQA
  34. #MerpayTechFest リリース

  35. #MerpayTechFest 問題 • コンフリクト ◦ デイリーでmainブランチをマージする時によくコンフリクトが発生する ◦ 毎日ブランチを管理するコストがかかる • リリース時

    マージ ◦ Feature リリースが重なるとコンフリクトが大きくなる可能性が高い ◦ 本来 全て コードがマージされている状態でQAすべき
  36. #MerpayTechFest 理想 • 開発中 コードもmainブランチにマージ • 新規モジュール リリースまでアプリに入れない ◦ アプリサイズ

    ◦ 情報漏洩
  37. #MerpayTechFest 最近取り入れている方法 • 新モジュール コードをmainブランチにマージ • ただし、アプリ本体に リンクしない ◦ モジュールをリンクしなけれ

    リリースされるバイナリに 含まれない ◦ 機能開発 サンドボックスアプリで進める
  38. #MerpayTechFest 最近取り入れている方法 • Featureブランチ 最終的に 必要 ◦ 既存 機能へ 変更

    ◦ モジュールをリンクしたアプリ QA • それでもFeatureブランチに全部入れておくより ◦ mainブランチと diffがかなり減る ◦ 他 ブランチと コンフリクト 可能性も減る • マルチモジュールだからこそできる開発プロセス ◦ Feature branchを使わないFeature開発 @ku ◦ https://speakerdeck.com/ku0522a/number-merpay-techtalk-feature-branchwoshi-wanaifeaturekai-fa
  39. #MerpayTechFest メルペイ スケーラビリティを支える マルチモジュール開発 • たくさん プロジェクトが同時に進んでいても、それぞれ チームが独立して小さ く速く開発していける構成 •

    モジュールが増えても起動時間に影響しない • モジュール間連携 仕組みによって、モジュール間 依存関係がないクリーンな 構成 • マルチモジュールならで ブランチマネジメント