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
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
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
App Storeの外へ──日本のiOSサイドローディング入門 for iOSDC Japan 2026
yuukiw00w
0
220
Intent as Code
shoppingjaws
6
1k
AHC070解法紹介
eijirou
0
120
WebRTC映像をAirPlayに対応させる挑戦.pdf
monolithic_adam
0
280
AI × TiDD / 2026.09.05 Redmine 大阪
tokudiro
1
170
すこし踏み込む CancellationToken
htkym
1
480
Family mrubyの進捗
kishima
1
130
AWS Step Functions 大規模並列の壁を越える / jaws-sonic-2026-niigata-step-functions
kasacchiful
PRO
1
480
Java 27新機能 / Java 27 new features
kishida
2
150
FreeBSDでZabbixを動かす
kenkino
0
300
WebAssembly in Android Apps 〜 WASMはJNIの夢を見るか
keiji
1
110
thread_parallel_with_free-threaded_Python_and_NumPy.pdf
riku_sakamoto
0
340
Featured
See All Featured
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6.1k
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
280
Getting science done with accelerated Python computing platforms
jacobtomlinson
2
480
The browser strikes back
jonoalderson
0
1.7k
Accessibility Awareness
sabderemane
1
210
A Tale of Four Properties
chriscoyier
163
24k
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
290
Building Experiences: Design Systems, User Experience, and Full Site Editing
marktimemedia
1
610
sira's awesome portfolio website redesign presentation
elsirapls
0
410
The Limits of Empathy - UXLibs8
cassininazir
1
680
A better future with KSS
kneath
240
18k
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!!