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

Merpay Tech Fest 2021_メルペイのスケーラビリティを支えるマルチモジュール...

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/

mercari

July 27, 2021
Tweet

More Decks by mercari

Other Decks in Technology

Transcript

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

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

    機能を備えたサンドボックスアプ リを作って開発できる ◦ 複数チームで同時開発しやすくなる ライブラリ1 ライブラリ2 アプリケーション 機能1 機能2 UI モデル
  3. #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
  4. #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でプロジェクト管理
  5. #MerpayTechFest メルペイ プロジェクト組織構成 iOS team PJ B PJ C Android

    team Backend team PJ D 新規モジュール! PJ A(完了) エンジニア
  6. #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
  7. #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 }) ]) ] } }
  8. #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
  9. #MerpayTechFest 現在 構成 利点 • プロジェクトファイルをXcodeGenで管理している でコンフリクトが発生しない ◦ 何らか プロジェクト管理ツール

    必要 • 新プロジェクト立ち上げ時に新モジュールを作ることでモチベーションがあがる ◦ これから育てていく感 ◦ オーナーシップ
  10. #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
  11. #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 } }
  12. #MerpayTechFest Dependency NFC Coupon QR Dependency Injection Merpay Feature Core

    Shared public protocol Dependency { ... var sceneFactory: MerpaySceneFactoryType { get } ... }
  13. #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 ) ... } } }
  14. #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 ... }
  15. #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) } }
  16. #MerpayTechFest モジュール間連携 • モジュール間で直接参照しなくてよい • モジュール内 ViewController 全て internal にできる

    ◦ 同じモジュール内 SceneFactory で生成される ◦ 使う時 UIViewController で抽象化される
  17. #MerpayTechFest メルペイで 機能開発プロセス • 新規モジュールを作る ./bin/init_framework.sh MerpayTechFestKit • Featureブランチを作る git

    checkout -b feature/merpay-tech-fest • デイリーでmainブランチをマージしつつ開発 • FeatureブランチでメルカリアプリをビルドしてQA
  18. #MerpayTechFest 問題 • コンフリクト ◦ デイリーでmainブランチをマージする時によくコンフリクトが発生する ◦ 毎日ブランチを管理するコストがかかる • リリース時

    マージ ◦ Feature リリースが重なるとコンフリクトが大きくなる可能性が高い ◦ 本来 全て コードがマージされている状態でQAすべき
  19. #MerpayTechFest 最近取り入れている方法 • Featureブランチ 最終的に 必要 ◦ 既存 機能へ 変更

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

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