$30 off During Our Annual Pro Sale. View Details »

最初が肝心!技術的負債解消に向けて最初にやるべきこと/first-step-to-pay-off-technical-debt

 最初が肝心!技術的負債解消に向けて最初にやるべきこと/first-step-to-pay-off-technical-debt

Takehiro Kaneko

April 11, 2023
Tweet

More Decks by Takehiro Kaneko

Other Decks in Programming

Transcript

  1. 最初が肝心!
    技術的負債解消に向けて最初にやるべきこと
    2023.04.12 モバイルアプリの技術的負債 みんなで学ぶ Lunch LT
    NewsPicks iOSエンジニア / 金子 雄大

    View Slide

  2. 00 自己紹介
    ©NewsPicks Inc. All Rights Reserved. 

    金子 雄大
    NewsPicks iOSエンジニア
    @takehilo_kaneko
    takehilo
    takehilo

    View Slide

  3. 00 NewsPicksについて
    ©NewsPicks Inc. All Rights Reserved. 


    View Slide

  4. 00 前回登壇のイベント
    ©NewsPicks Inc. All Rights Reserved. 

    ● 今日と同じく技術的負債の解消がテーマ
    ● アーカイブ動画が公開されてるので、今日と合わ
    せて是非ご参考に
    https://uzabase-tech.connpass.com/event/253143/

    View Slide

  5. ©NewsPicks Inc. All Rights Reserved.

    01
    リアーキテクチャ実施の背景

    View Slide

  6. 01 ビジネス優先で走り続けてきた
    ©NewsPicks Inc. All Rights Reserved. 

    iOSアプリのコードは限界に来ていた...
    ● NewsPicksはリリースからまもなく10年を迎える
    ● その間、何度もUIがリニューアルされてきた
    ● 一方で、コードの保守性は置き去りにされたまま
    ここまで来てしまった

    View Slide

  7. 01 技術的負債解消のアプローチ
    ©NewsPicks Inc. All Rights Reserved.

    ● 既存のアーキテクチャのまま負債を返済していくことはもはや不可能
    ● ただし、ゼロから作り直すための時間とリソースは無い
    新しいアーキテクチャを作成し、既存の画面・機能を少しずつ新しい
    アーキテクチャで作り直していくことにした

    View Slide

  8. 01 今日伝えたいこと
    ©NewsPicks Inc. All Rights Reserved.

    作り直しに取りかかる前にやっておいたほうが良いことがある
    ● 技術的負債が生まれにくくすること
    ● たとえ技術的負債が生まれても、返済可能な状態を維持できるようにすること
    具体的に何をすべきかをこの後話していく

    View Slide

  9. ©NewsPicks Inc. All Rights Reserved.

    02
    作り直しをする前に
    最初にやるべきこと

    View Slide

  10. 02 最初にやるべきこと
    ©NewsPicks Inc. All Rights Reserved.

    ● コードをレイヤー分けしてマルチモジュール化し、依存の方向を強制する
    ● ユニットテストの実装を強制する環境を作る
    強制するというのがポイント!

    View Slide

  11. ©NewsPicks Inc. All Rights Reserved.

    02
    マルチモジュール化して
    依存の方向を強制する

    View Slide

  12. 02 レイヤー分けと依存の方向の例
    ©NewsPicks Inc. All Rights Reserved.

    ● 新しいアーキテクチャのモジュールから古い
    コード(Legacy)を参照できないようにする
    ● PresentationとInfrastructureはDomainにの
    み依存し、直接参照し合わないようにする

    View Slide

  13. 02 なぜ依存の方向を強制するのか?
    ©NewsPicks Inc. All Rights Reserved.

    ● フォルダ分けをしただけでシングルモジュール構成のままだと、新しいコードから古
    いコードを利用できてしまう
    ○ 負債を返済しているつもりが、新たな負債を生み出すことに...
    ● モジュールを分けて依存の方向を強制してしまえば、これができなくなる
    「古いコードは参照しない」というルールを決めても、それを継続し続
    けるのは実は難しい
    ルールを強制してあげることで、新しいコードをキレイな状態に保ちな
    がら、負債を返済していくことができる

    View Slide

  14. 02 依存の方向を強制することによるその他のメリット
    ©NewsPicks Inc. All Rights Reserved.

    ● 何でも屋クラスが作られづらくなり、各クラスの責務が明確になる。さらに、その状
    態を維持しやすい
    ● ライブラリへの依存がモジュールに閉じるので、ライブラリを使ったコードが散らば
    らないし、ライブラリの更新、差し替えもしやすくなる
    負債が生まれにくく、かつ生まれても返済可能な状態を維持できる!

    View Slide

  15. 02 どうしても古いコードを使いたいときは
    ©NewsPicks Inc. All Rights Reserved.

    ● Adapterパターンを使って古いコードを参照する(後述)
    ○ 戻り値の型を新しいコードのものに変換するなどして、新しいコードの都合に
    合わせるようにする
    ● 利用は最低限にすること

    View Slide

  16. 02 Adapterパターンを使った古いコードの利用方法
    ©NewsPicks Inc. All Rights Reserved.

    ● 利用したいクラス(例: SelfLogic)がLegacyモジュールにあるとする
    ● Domainモジュールに利用したい機能のインタフェースを定義したプロトコル(例:
    SeflLogicAdapter)を作成する
    ● SelfLogicをSelfLogicAdapterに準拠させる
    ● DIコンテナがPresentationモジュールのクラスにSelfLogicをインジェクトする

    View Slide

  17. 02 Adapterパターンを使った古いコードの利用方法
    ©NewsPicks Inc. All Rights Reserved.

    // MARK: - Domainモジュール
    protocol SelfLogicAdapter {
    func someLogic()
    }
    // MARK: - Legacyモジュール
    class SelfLogic {
    func someLogic() {...}
    }
    // SelfLogicAdapterに準拠させる
    extension SelfLogic: SelfLogicAdapter {}
    // MARK: - Presentationモジュール
    class NewsFeedresenter {
    private let selfLogic: SelfLogicAdapter
    init(selfLogic: SelfLogicAdapter) {
    // 実体はSelfLogicインスタンス
    self.selfLogic = selfLogic
    }
    }
    ● インジェクションをどうやるかはプロ
    ジェクトによって異なる

    View Slide

  18. 02 The Composable ArchitectureでのDIの例
    ©NewsPicks Inc. All Rights Reserved.

    // MARK: - Domainモジュール
    public enum SelfLogicAdapterKey: TestDependencyKey {
    public static let testValue: SelfLogicAdapter = MockSelfLogic()
    public static let previewValue: SelfLogicAdapter = MockSelfLogic()
    }
    public extension DependencyValues {
    var selfLogic: SelfLogicAdapter {
    get { self[SelfLogicAdapterKey.self] }
    set { self[SelfLogicAdapterKey.self] = newValue }
    }
    }
    // MARK: - Legacyモジュール
    extension SelfLogicAdapterKey: DependencyKey {
    public static let liveValue: SelfLogicAdapter = SelfLogic.shared
    }
    // MARK: - Presentationモジュール
    struct NewsFeedReducer: ReducerProtocol {
    @Dependency(\.selfLogic) var selfLogic
    func reduce(into state: inout State, action: Action) -> EffectTask {
    ...
    selfLogic.someLogic()
    }
    }
    ● DependencyValuesを使ってReducerに
    SelfLogicをインジェクトしている

    View Slide

  19. ©NewsPicks Inc. All Rights Reserved.

    02
    ユニットテストの
    実装を強制する

    View Slide

  20. 02 ユニットテストの実装を強制している例
    ©NewsPicks Inc. All Rights Reserved.

    ● 例えば、変更したファイルのカバレッジが
    ○%以下ならPRをマージできないようにして
    しまう

    View Slide

  21. 02 なぜユニットテストの実装を強制するのか?
    ©NewsPicks Inc. All Rights Reserved.

    ● ユニットテストを実装するためには、テスタブルな設計にしなければならない。その結
    果、ロジックがシンプルで、可読性が高くなりやすい
    ○ 何でも屋クラスや、複雑過ぎるメソッドが作られづらくなる(負債化しにくくな
    る)
    ● ユニットテストの実装がしづらいと感じたら、プロダクションコードを見直すことにな
    り、より良い設計にしようという意識が働く
    ○ どうすれば良い設計になるかをチームで議論する機会が明らかに増えた
    ● ユニットテストがあると、リファクタしやすくなる
    ○ 負債を継続的に返済していくための環境ができる
    負債が生まれにくく、かつ生まれても返済可能な状態を維持できる!

    View Slide

  22. 02 ユニットテストはバランスが大事
    ©NewsPicks Inc. All Rights Reserved.

    ● マルチモジュール化して依存の方向を強制したり、テスタブルにした結果、テストする
    までもないシンプルなコードが多くなった
    ○ ロジックがほとんどないシンプルなコード、変わることがほとんどないコードにつ
    いては、テストを書いてもコスパが悪い
    ● 比較的変更の多いプレゼンテーションロジックを中心にテストを書くのが良い

    View Slide

  23. ©NewsPicks Inc. All Rights Reserved.

    03
    さいごに

    View Slide

  24. 03 新しく作ったコードもすぐに負債になり得る
    ©NewsPicks Inc. All Rights Reserved.

    ● 新しく作ったコードが完璧なものとは限らない
    ● 設計に不備があったり、納期を優先しなければならない状況は常に発生する
    技術的負債を返済可能な状態を維持していることが重要!
    技術的負債解消プロジェクトを何度もやることにならないように
    最初にしっかり準備をしよう!

    View Slide

  25. 03 偉人の金言
    ©NewsPicks Inc. All Rights Reserved.

    自信過剰による再設計は、元のプロジェクトと同じように崩壊する
    速く進む唯一の方法は、うまく進むことである
    Clean Architecture 達人に学ぶソフトウェアの構造と設計 より

    View Slide

  26. ©NewsPicks Inc. All Rights Reserved.

    Thank you!!

    View Slide