Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
最初が肝心!技術的負債解消に向けて最初にやるべきこと/first-step-to-pay-of...
Search
Takehiro Kaneko
April 11, 2023
Programming
1.4k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
最初が肝心!技術的負債解消に向けて最初にやるべきこと/first-step-to-pay-off-technical-debt
Takehiro Kaneko
April 11, 2023
More Decks by Takehiro Kaneko
See All by Takehiro Kaneko
大規模UIKitベースアプリへのTCAの段階的導入/gradual-adoption-of-tca-in-a-large-scale-uikit-based-app
takehilo
2
700
むやみにActionを送信してはいけない/do-not-send-actions-thoughtlessly
takehilo
3
1.8k
SwiftUI+TCAに挑戦!NewsPicks iOSアプリのリアーキテクチャ/re-architecture-newspicks-ios-app-with-swiftui-and-tca
takehilo
1
3.2k
iOSアプリ開発に MVVM+Redux パターンを使い始めた話/ios-mvvm-redux-pattern
takehilo
1
1.5k
RxBlocking Deep Dive
takehilo
1
1.1k
RxTest/RxBlockingテストパターン / RxTest RxBlocking Test Patterns
takehilo
5
1.7k
Other Decks in Programming
See All in Programming
Building an Out-of-Order CPU
latte72
1
790
AHC070解法紹介
eijirou
0
130
フロントエンドUIフレームワークのこれまでとこれから
ssssota
5
2.9k
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
510
[GoCon2026] When Goroutines Are Not Enough: Runtime Locality in High-Throughput Go
takehaya
6
2.4k
WebRTC映像をAirPlayに対応させる挑戦.pdf
monolithic_adam
0
290
Kiroで創り、AgentCoreで繋ぐ!AWSで実践する「AI-DLC」から「AIエージェント統合」までの最新地図
licux
4
740
モジュールの視点からSwiftを読み解く #iosdc
s_shimotori
0
190
Jetpack Compose メカニズム
skydoves
0
460
TiDB Cloudのカスタムコントローラーによるオートスケール対応
takaidohigasi
0
130
個人開発基盤をまるごとCloudflareに引っ越して爆速で総合的体験を向上させた話
tinykitten
0
200
Java 27新機能 / Java 27 new features
kishida
2
160
Featured
See All Featured
YesSQL, Process and Tooling at Scale
rocio
174
15k
[RailsConf 2023] Rails as a piece of cake
palkan
59
7k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.6k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
1k
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
550
Applied NLP in the Age of Generative AI
inesmontani
PRO
4
2.5k
Between Models and Reality
mayunak
4
460
Context Engineering - Making Every Token Count
addyosmani
9
1.1k
Neural Spatial Audio Processing for Sound Field Analysis and Control
skoyamalab
0
510
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
1
610
AI Search: Where Are We & What Can We Do About It?
aleyda
0
8k
Agile Actions for Facilitating Distributed Teams - ADO2019
mkilby
0
280
Transcript
最初が肝心! 技術的負債解消に向けて最初にやるべきこと 2023.04.12 モバイルアプリの技術的負債 みんなで学ぶ Lunch LT NewsPicks iOSエンジニア /
金子 雄大
00 自己紹介 ©NewsPicks Inc. All Rights Reserved. 金子 雄大
NewsPicks iOSエンジニア @takehilo_kaneko takehilo takehilo
00 NewsPicksについて ©NewsPicks Inc. All Rights Reserved.
00 前回登壇のイベント ©NewsPicks Inc. All Rights Reserved. • 今日と同じく技術的負債の解消がテーマ
• アーカイブ動画が公開されてるので、今日と合わ せて是非ご参考に https://uzabase-tech.connpass.com/event/253143/
©NewsPicks Inc. All Rights Reserved. 01 リアーキテクチャ実施の背景
01 ビジネス優先で走り続けてきた ©NewsPicks Inc. All Rights Reserved. iOSアプリのコードは限界に来ていた... •
NewsPicksはリリースからまもなく10年を迎える • その間、何度もUIがリニューアルされてきた • 一方で、コードの保守性は置き去りにされたまま ここまで来てしまった
01 技術的負債解消のアプローチ ©NewsPicks Inc. All Rights Reserved. • 既存のアーキテクチャのまま負債を返済していくことはもはや不可能 •
ただし、ゼロから作り直すための時間とリソースは無い 新しいアーキテクチャを作成し、既存の画面・機能を少しずつ新しい アーキテクチャで作り直していくことにした
01 今日伝えたいこと ©NewsPicks Inc. All Rights Reserved. 作り直しに取りかかる前にやっておいたほうが良いことがある • 技術的負債が生まれにくくすること
• たとえ技術的負債が生まれても、返済可能な状態を維持できるようにすること 具体的に何をすべきかをこの後話していく
©NewsPicks Inc. All Rights Reserved. 02 作り直しをする前に 最初にやるべきこと
02 最初にやるべきこと ©NewsPicks Inc. All Rights Reserved. • コードをレイヤー分けしてマルチモジュール化し、依存の方向を強制する •
ユニットテストの実装を強制する環境を作る 強制するというのがポイント!
©NewsPicks Inc. All Rights Reserved. 02 マルチモジュール化して 依存の方向を強制する
02 レイヤー分けと依存の方向の例 ©NewsPicks Inc. All Rights Reserved. • 新しいアーキテクチャのモジュールから古い コード(Legacy)を参照できないようにする
• PresentationとInfrastructureはDomainにの み依存し、直接参照し合わないようにする
02 なぜ依存の方向を強制するのか? ©NewsPicks Inc. All Rights Reserved. • フォルダ分けをしただけでシングルモジュール構成のままだと、新しいコードから古 いコードを利用できてしまう
◦ 負債を返済しているつもりが、新たな負債を生み出すことに... • モジュールを分けて依存の方向を強制してしまえば、これができなくなる 「古いコードは参照しない」というルールを決めても、それを継続し続 けるのは実は難しい ルールを強制してあげることで、新しいコードをキレイな状態に保ちな がら、負債を返済していくことができる
02 依存の方向を強制することによるその他のメリット ©NewsPicks Inc. All Rights Reserved. • 何でも屋クラスが作られづらくなり、各クラスの責務が明確になる。さらに、その状 態を維持しやすい
• ライブラリへの依存がモジュールに閉じるので、ライブラリを使ったコードが散らば らないし、ライブラリの更新、差し替えもしやすくなる 負債が生まれにくく、かつ生まれても返済可能な状態を維持できる!
02 どうしても古いコードを使いたいときは ©NewsPicks Inc. All Rights Reserved. • Adapterパターンを使って古いコードを参照する(後述) ◦
戻り値の型を新しいコードのものに変換するなどして、新しいコードの都合に 合わせるようにする • 利用は最低限にすること
02 Adapterパターンを使った古いコードの利用方法 ©NewsPicks Inc. All Rights Reserved. • 利用したいクラス(例: SelfLogic)がLegacyモジュールにあるとする
• Domainモジュールに利用したい機能のインタフェースを定義したプロトコル(例: SeflLogicAdapter)を作成する • SelfLogicをSelfLogicAdapterに準拠させる • DIコンテナがPresentationモジュールのクラスにSelfLogicをインジェクトする
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 } } • インジェクションをどうやるかはプロ ジェクトによって異なる
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<Action> { ... selfLogic.someLogic() } } • DependencyValuesを使ってReducerに SelfLogicをインジェクトしている
©NewsPicks Inc. All Rights Reserved. 02 ユニットテストの 実装を強制する
02 ユニットテストの実装を強制している例 ©NewsPicks Inc. All Rights Reserved. • 例えば、変更したファイルのカバレッジが ◦%以下ならPRをマージできないようにして
しまう
02 なぜユニットテストの実装を強制するのか? ©NewsPicks Inc. All Rights Reserved. • ユニットテストを実装するためには、テスタブルな設計にしなければならない。その結 果、ロジックがシンプルで、可読性が高くなりやすい
◦ 何でも屋クラスや、複雑過ぎるメソッドが作られづらくなる(負債化しにくくな る) • ユニットテストの実装がしづらいと感じたら、プロダクションコードを見直すことにな り、より良い設計にしようという意識が働く ◦ どうすれば良い設計になるかをチームで議論する機会が明らかに増えた • ユニットテストがあると、リファクタしやすくなる ◦ 負債を継続的に返済していくための環境ができる 負債が生まれにくく、かつ生まれても返済可能な状態を維持できる!
02 ユニットテストはバランスが大事 ©NewsPicks Inc. All Rights Reserved. • マルチモジュール化して依存の方向を強制したり、テスタブルにした結果、テストする までもないシンプルなコードが多くなった
◦ ロジックがほとんどないシンプルなコード、変わることがほとんどないコードにつ いては、テストを書いてもコスパが悪い • 比較的変更の多いプレゼンテーションロジックを中心にテストを書くのが良い
©NewsPicks Inc. All Rights Reserved. 03 さいごに
03 新しく作ったコードもすぐに負債になり得る ©NewsPicks Inc. All Rights Reserved. • 新しく作ったコードが完璧なものとは限らない •
設計に不備があったり、納期を優先しなければならない状況は常に発生する 技術的負債を返済可能な状態を維持していることが重要! 技術的負債解消プロジェクトを何度もやることにならないように 最初にしっかり準備をしよう!
03 偉人の金言 ©NewsPicks Inc. All Rights Reserved. 自信過剰による再設計は、元のプロジェクトと同じように崩壊する 速く進む唯一の方法は、うまく進むことである Clean
Architecture 達人に学ぶソフトウェアの構造と設計 より
©NewsPicks Inc. All Rights Reserved. Thank you!!