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
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Takehiro Kaneko
April 11, 2023
Programming
1.5k
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
Vue Fes Japan 2026 タイムテーブル徹底解説
448jp
1
650
設計次第でAIコードの読む量は減らせる / designing-for-code-reading
minodriven
34
16k
AIに “答え“を書かせるのを やめてみた
___akari11
0
120
Simple Storage Service(S3) is not simple
iwatsukayura
0
250
コードレビューのボトルネックを"する側"と"される側"の両面から解消する
yub0n
2
1.6k
RAG の “R” を Swift で覗いてみる 〜「意味から探す」検索の仕組み〜
nao_randd
0
140
JRuby: Past, Present, and Future
headius
0
230
GemmaをJevのように使ってみる / Use Gemma like Jev
kishida
5
760
Kubernetes祭り #2 OP/ED
bells17
0
110
難しいけど、読めた。- OSSの入口に立った話。
sts11142
0
150
Streamlitで実現する自然言語データアプリ開発
ayumu_yamaguchi
1
360
速習iPhone Duo対応
yuukiw00w
2
980
Featured
See All Featured
We Have a Design System, Now What?
morganepeng
55
8.4k
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
560
Navigating Team Friction
lara
192
16k
Are puppies a ranking factor?
jonoalderson
2
4k
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.4k
Joys of Absence: A Defence of Solitary Play
codingconduct
1
540
Building Applications with DynamoDB
mza
96
7.2k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.2k
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2.2k
Git: the NoSQL Database
bkeepers
PRO
433
67k
sira's awesome portfolio website redesign presentation
elsirapls
0
450
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!!