Slide 1

Slide 1 text

Yappli Tech Conference 2024.10.17 ヤプリにおける保守課題を解決する モジュール化戦略

Slide 2

Slide 2 text

Speaker 開発統括本部 プロダクト開発本部 開発1部 iOSグループ 三宅 篤史 ● 1994 年⽣まれ ● 2019 年⼊社 (3 社⽬) ● iOS のテックリードを担当

Slide 3

Slide 3 text

⽬次 1. 技術⽬線で Yappli とは 2. 課題 3. 解決のアプローチ 4. ゴールイメージの共有 5. 仕組みを紐解く 6. まとめ

Slide 4

Slide 4 text

技術⽬線で Yappli とは

Slide 5

Slide 5 text

ノーコード で ⾼品質 な ネイティブアプリ を作成できる アプリプラットフォーム 01 技術⽬線で Yappli とは Yappli Tech Conference をご覧の⽅々はご存知!

Slide 6

Slide 6 text

CMS の設定 に応じて 同じコードベース から 各アプリをビルド‧配信 する アプリプラットフォーム 01 技術⽬線で Yappli とは もう少し「技術⽬線」で捉えると

Slide 7

Slide 7 text

01 技術⽬線で Yappli とは もう少し「技術⽬線」で捉えると 約 850 アプリ! CMS の設定 に応じて 同じコードベース から 各アプリをビルド‧配信 する アプリプラットフォーム

Slide 8

Slide 8 text

01 技術⽬線で Yappli とは Analytics 機能 アプリA アプリB アプリC ヘルスケア機能 例えば2つの機能が提供されているとして‧‧

Slide 9

Slide 9 text

01 技術⽬線で Yappli とは Analytics 機能 アプリA アプリB アプリC ヘルスケア機能 2つの機能が有効

Slide 10

Slide 10 text

01 技術⽬線で Yappli とは Analytics 機能 アプリA アプリB アプリC ヘルスケア機能 Analytics 機能のみ有効

Slide 11

Slide 11 text

01 技術⽬線で Yappli とは Analytics 機能 アプリA アプリB アプリC ヘルスケア機能 ヘルスケア機能のみ有効

Slide 12

Slide 12 text

01 技術⽬線で Yappli とは Analytics 機能 アプリA アプリB アプリC ヘルスケア機能 アプリ によって 機能の組み合わせ が異なる

Slide 13

Slide 13 text

CMS の設定 に応じて 同じコードベース から 各アプリをビルド‧配信 する アプリプラットフォーム 01 技術⽬線で Yappli とは

Slide 14

Slide 14 text

01 技術⽬線で Yappli とは オプション機能として実装 CMS の設定 に応じて 同じコードベース から 各アプリをビルド‧配信 する アプリプラットフォーム

Slide 15

Slide 15 text

01 技術⽬線で Yappli とは オプション機能として実装 仕組みを実現する上での課題‧‧‧ CMS の設定 に応じて 同じコードベース から 各アプリをビルド‧配信 する アプリプラットフォーム

Slide 16

Slide 16 text

課題

Slide 17

Slide 17 text

02 課題 Server Script proj App App App

Slide 18

Slide 18 text

02 課題 Server Script proj App App App

Slide 19

Slide 19 text

02 課題 アプリの構成データを取得 Server Script proj App App App

Slide 20

Slide 20 text

02 課題 アプリの構成データを取得 Active Compilation Conditions の更新 Server Script proj App App App

Slide 21

Slide 21 text

02 課題 アプリの構成データを取得 Active Compilation Conditions の更新 A B C ビルド Server Script proj App App App

Slide 22

Slide 22 text

02 課題 アプリの構成データを取得 Active Compilation Conditions の更新 A B C ビルド Server Script proj App App App

Slide 23

Slide 23 text

Active Compilation Conditions 02 課題 Xcode 8.0 から追加された!

Slide 24

Slide 24 text

Active Compilation Conditions 02 課題 1 # i f D E B U G 2 # e l s e 3 # e n d i f

Slide 25

Slide 25 text

Yappli でオプション機能を実装する場合 02 課題 1 # i f A n a l y t i c s E n a b l e d 2 i m p o r t F i r e b a s e A n a l y t i c s 3 s t r u c t A n a l y t i c s { … } 4 # e n d i f 5 6 # i f A n a l y t i c s E n a b l e d 7 l e t a n a l y t i c s = A n a l y t i c s ( ) 8 a n a l y t i c s . s e n d E v e n t ( ... ) 9 # e n d i f

Slide 26

Slide 26 text

Yappli でオプション機能を実装する場合 02 課題 「AnalyticsEnabled」 が定義されているときだけ 実装が有効化する (コンパイルされる) 1 # i f A n a l y t i c s E n a b l e d 2 i m p o r t F i r e b a s e A n a l y t i c s 3 s t r u c t A n a l y t i c s { … } 4 # e n d i f 5 6 # i f A n a l y t i c s E n a b l e d 7 l e t a n a l y t i c s = A n a l y t i c s ( ) 8 a n a l y t i c s . s e n d E v e n t ( ... ) 9 # e n d i f

Slide 27

Slide 27 text

Yappli でオプション機能を実装する場合 02 課題 有効時にしかコンパイルされない‧‧‧ 1 # i f A n a l y t i c s E n a b l e d 2 i m p o r t F i r e b a s e A n a l y t i c s 3 s t r u c t A n a l y t i c s { … } 4 # e n d i f 5 6 # i f A n a l y t i c s E n a b l e d 7 l e t a n a l y t i c s = A n a l y t i c s ( ) 8 a n a l y t i c s . s e n d E v e n t ( ... ) 9 # e n d i f

Slide 28

Slide 28 text

Yappli でオプション機能を実装する場合 02 課題 テスト‧デバッグがしづらい‧‧‧ 有効時にしかコンパイルされない‧‧‧ 1 # i f A n a l y t i c s E n a b l e d 2 i m p o r t F i r e b a s e A n a l y t i c s 3 s t r u c t A n a l y t i c s { … } 4 # e n d i f 5 6 # i f A n a l y t i c s E n a b l e d 7 l e t a n a l y t i c s = A n a l y t i c s ( ) 8 a n a l y t i c s . s e n d E v e n t ( ... ) 9 # e n d i f

Slide 29

Slide 29 text

Yappli でオプション機能を実装する場合 02 課題 有効時にしかコンパイルされない‧‧‧ import が絡むと依存解決など複雑化する‧‧‧ テスト‧デバッグがしづらい‧‧‧ 1 # i f A n a l y t i c s E n a b l e d 2 i m p o r t F i r e b a s e A n a l y t i c s 3 s t r u c t A n a l y t i c s { … } 4 # e n d i f 5 6 # i f A n a l y t i c s E n a b l e d 7 l e t a n a l y t i c s = A n a l y t i c s ( ) 8 a n a l y t i c s . s e n d E v e n t ( ... ) 9 # e n d i f

Slide 30

Slide 30 text

Yappli でオプション機能を実装する場合 02 課題 テスト‧デバッグがしづらい‧‧‧ 有効時にしかコンパイルされない‧‧‧ 1 # i f A n a l y t i c s E n a b l e d 2 i m p o r t F i r e b a s e A n a l y t i c s 3 s t r u c t A n a l y t i c s { … } 4 # e n d i f 5 6 # i f A n a l y t i c s E n a b l e d 7 l e t a n a l y t i c s = A n a l y t i c s ( ) 8 a n a l y t i c s . s e n d E v e n t ( ... ) 9 # e n d i f import が絡むと依存解決など複雑化する‧‧‧

Slide 31

Slide 31 text

解決のアプローチ

Slide 32

Slide 32 text

具象クラスを参照しないよう Protocol を定義して抽象化する × オプショナルな依存関係をマルチモジュールで表現する 03 解決のアプローチ テストのしやすさに繋げる 静的解析‧デバッグ‧依存解決に繋げる

Slide 33

Slide 33 text

ゴールイメージの共有

Slide 34

Slide 34 text

改善前と改善後の⽐較 04 ゴールイメージの共有 Before After 1 # i f A n a l y t i c s E n a b l e d 2 l e t a n a l y t i c s = A n a l y t i c s ( ) 3 a n a l y t i c s . s e n d E v e n t ( ... ) 4 # e n d i f 5 6 # i f A n a l y t i c s E n a b l e d 7 i m p o r t F i r e b a s e A n a l y t i c s 8 s t r u c t A n a l y t i c s { … } 9 # e n d i f 1 i m p o r t A n a l y t i c s 2 3 i f l e t a n a l y t i c s = A n a l y t i c s F a c t o r y . c r e a t e ( ) { 4 a n a l y t i c s . s e n d E v e n t ( ... ) 5 }

Slide 35

Slide 35 text

改善前と改善後の⽐較 04 ゴールイメージの共有 Before 1 # i f A n a l y t i c s E n a b l e d 2 l e t a n a l y t i c s = A n a l y t i c s ( ) 3 a n a l y t i c s . s e n d E v e n t ( ... ) 4 # e n d i f 5 6 # i f A n a l y t i c s E n a b l e d 7 i m p o r t F i r e b a s e A n a l y t i c s 8 s t r u c t A n a l y t i c s { … } 9 # e n d i f After 1 i m p o r t A n a l y t i c s 2 3 i f l e t a n a l y t i c s = A n a l y t i c s F a c t o r y . c r e a t e ( ) { 4 a n a l y t i c s . s e n d E v e n t ( ... ) 5 } Analytics をインスタンス化するときも AnalyticsEnabled のチェックが必要

Slide 36

Slide 36 text

1 # i f A n a l y t i c s E n a b l e d 2 l e t a n a l y t i c s = A n a l y t i c s ( ) 3 a n a l y t i c s . s e n d E v e n t ( ... ) 4 # e n d i f 5 6 # i f A n a l y t i c s E n a b l e d 7 i m p o r t F i r e b a s e A n a l y t i c s 8 s t r u c t A n a l y t i c s { … } 9 # e n d i f 改善前と改善後の⽐較 04 ゴールイメージの共有 Before After 1 i m p o r t A n a l y t i c s 2 3 i f l e t a n a l y t i c s = A n a l y t i c s F a c t o r y . c r e a t e ( ) { 4 a n a l y t i c s . s e n d E v e n t ( ... ) 5 } AnalyticsEnabled が有効なときしか FirebaseAnalytics を import できない

Slide 37

Slide 37 text

1 i m p o r t A n a l y t i c s 2 3 i f l e t a n a l y t i c s = A n a l y t i c s F a c t o r y . c r e a t e ( ) { 4 a n a l y t i c s . s e n d E v e n t ( ... ) 5 } 改善前と改善後の⽐較 04 ゴールイメージの共有 Before モジュールとして Analytics 機能を分離し import することで利⽤する After 1 # i f A n a l y t i c s E n a b l e d 2 l e t a n a l y t i c s = A n a l y t i c s ( ) 3 a n a l y t i c s . s e n d E v e n t ( ... ) 4 # e n d i f 5 6 # i f A n a l y t i c s E n a b l e d 7 i m p o r t F i r e b a s e A n a l y t i c s 8 s t r u c t A n a l y t i c s { … } 9 # e n d i f

Slide 38

Slide 38 text

改善前と改善後の⽐較 04 ゴールイメージの共有 After Active Compilation Conditions を利⽤しない 実装⽅法を⽬指す 1 i m p o r t A n a l y t i c s 2 3 i f l e t a n a l y t i c s = A n a l y t i c s F a c t o r y . c r e a t e ( ) { 4 a n a l y t i c s . s e n d E v e n t ( ... ) 5 } Before 1 # i f A n a l y t i c s E n a b l e d 2 l e t a n a l y t i c s = A n a l y t i c s ( ) 3 a n a l y t i c s . s e n d E v e n t ( ... ) 4 # e n d i f 5 6 # i f A n a l y t i c s E n a b l e d 7 i m p o r t F i r e b a s e A n a l y t i c s 8 s t r u c t A n a l y t i c s { … } 9 # e n d i f

Slide 39

Slide 39 text

仕組みを紐解く

Slide 40

Slide 40 text

オプション機能の参照コード 05 仕組みを紐解く import による複雑化 テストしづらい デバッグしづらい コンパイルされない 1 i m p o r t A n a l y t i c s 2 3 i f l e t a n a l y t i c s = A n a l y t i c s F a c t o r y . c r e a t e ( ) { 4 a n a l y t i c s . s e n d E v e n t ( ... ) 5 }

Slide 41

Slide 41 text

1 i m p o r t A n a l y t i c s 2 3 i f l e t a n a l y t i c s : A n a l y t i c s P r o t o c o l = A n a l y t i c s F a c t o r y . c r e a t e ( ) { 4 a n a l y t i c s . s e n d E v e n t ( ... ) 5 } オプション機能の参照コード 05 仕組みを紐解く 具象クラスを参照しないよう Protocol を定義して抽象化する import による複雑化 テストしづらい デバッグしづらい コンパイルされない

Slide 42

Slide 42 text

オプション機能の参照コード 05 仕組みを紐解く import による複雑化 テストしづらい デバッグしづらい コンパイルされない 1 i m p o r t A n a l y t i c s 2 3 i f l e t a n a l y t i c s : A n a l y t i c s P r o t o c o l = A n a l y t i c s F a c t o r y . c r e a t e ( ) { 4 a n a l y t i c s . s e n d E v e n t ( ... ) 5 } create() AnalyticsFactory.swift

Slide 43

Slide 43 text

Analytics モジュール 05 仕組みを紐解く import による複雑化 テストしづらい デバッグしづらい コンパイルされない i m p o r t A n a l y t i c s P r o t o c o l s # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) i m p o r t A n a l y t i c s I m p l s # e n d i f p u b l i c c l a s s A n a l y t i c s F a c t o r y { s t a t i c f u n c c r e a t e ( ) -> A n a l y t i c s P r o t o c o l ? { # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) r e t u r n A n a l y t i c s I m p l ( ) # e l s e r e t u r n n i l # e n d i f } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14

Slide 44

Slide 44 text

Analytics モジュール 05 仕組みを紐解く テストしづらい Protocol に準拠していれば 差し替えてテストできる import による複雑化 デバッグしづらい コンパイルされない i m p o r t A n a l y t i c s P r o t o c o l s # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) i m p o r t A n a l y t i c s I m p l s # e n d i f p u b l i c c l a s s A n a l y t i c s F a c t o r y { s t a t i c f u n c c r e a t e ( ) -> A n a l y t i c s P r o t o c o l ? { # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) r e t u r n A n a l y t i c s I m p l ( ) # e l s e r e t u r n n i l # e n d i f } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Analytics Protocols モジュール AnalyticsFactory.swift

Slide 45

Slide 45 text

i m p o r t A n a l y t i c s P r o t o c o l s # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) i m p o r t A n a l y t i c s I m p l s # e n d i f p u b l i c c l a s s A n a l y t i c s F a c t o r y { s t a t i c f u n c c r e a t e ( ) -> A n a l y t i c s P r o t o c o l ? { # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) r e t u r n A n a l y t i c s I m p l ( ) # e l s e r e t u r n n i l # e n d i f } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Analytics モジュール 05 仕組みを紐解く import できるか AnalyticsFactory テストしづらい import による複雑化 デバッグしづらい コンパイルされない

Slide 46

Slide 46 text

i m p o r t A n a l y t i c s P r o t o c o l s # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) i m p o r t A n a l y t i c s I m p l s # e n d i f p u b l i c c l a s s A n a l y t i c s F a c t o r y { s t a t i c f u n c c r e a t e ( ) -> A n a l y t i c s P r o t o c o l ? { # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) r e t u r n A n a l y t i c s I m p l ( ) # e l s e r e t u r n n i l # e n d i f } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import できるか AnalyticsFactory Analytics モジュール 05 仕組みを紐解く import できるなら AnalyticsImpl のインスタンスを返却 テストしづらい import による複雑化 デバッグしづらい コンパイルされない

Slide 47

Slide 47 text

i m p o r t A n a l y t i c s P r o t o c o l s # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) i m p o r t A n a l y t i c s I m p l s # e n d i f p u b l i c c l a s s A n a l y t i c s F a c t o r y { s t a t i c f u n c c r e a t e ( ) -> A n a l y t i c s P r o t o c o l ? { # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) r e t u r n A n a l y t i c s I m p l ( ) # e l s e r e t u r n n i l # e n d i f } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import できるなら AnalyticsImpl のインスタンスを返却 Analytics モジュール 05 仕組みを紐解く Analytics Impls モジュール AnalyticsImpl.swift import できるか AnalyticsFactory テストしづらい import による複雑化 デバッグしづらい コンパイルされない

Slide 48

Slide 48 text

05 仕組みを紐解く テストしづらい import による複雑化 デバッグしづらい コンパイルされない Analytics モジュール i m p o r t A n a l y t i c s P r o t o c o l s # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) i m p o r t A n a l y t i c s I m p l s # e n d i f p u b l i c c l a s s A n a l y t i c s F a c t o r y { s t a t i c f u n c c r e a t e ( ) -> A n a l y t i c s P r o t o c o l ? { # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) r e t u r n A n a l y t i c s I m p l ( ) # e l s e r e t u r n n i l # e n d i f } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import できるなら AnalyticsImpl のインスタンスを返却 Analytics Impls モジュール AnalyticsImpl.swift

Slide 49

Slide 49 text

i m p o r t A n a l y t i c s P r o t o c o l s # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) i m p o r t A n a l y t i c s I m p l s # e n d i f p u b l i c c l a s s A n a l y t i c s F a c t o r y { s t a t i c f u n c c r e a t e ( ) -> A n a l y t i c s P r o t o c o l ? { # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) r e t u r n A n a l y t i c s I m p l ( ) # e l s e r e t u r n n i l # e n d i f } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Analytics モジュール 05 仕組みを紐解く Analytics Impls モジュール AnalyticsImpl.swift テストしづらい import による複雑化 デバッグしづらい コンパイルされない import できるか AnalyticsFactory import できない場合には nil を返却

Slide 50

Slide 50 text

Analytics モジュール 05 仕組みを紐解く テストしづらい import による複雑化 デバッグしづらい コンパイルされない i m p o r t A n a l y t i c s P r o t o c o l s # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) i m p o r t A n a l y t i c s I m p l s # e n d i f p u b l i c c l a s s A n a l y t i c s F a c t o r y { s t a t i c f u n c c r e a t e ( ) -> A n a l y t i c s P r o t o c o l ? { # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) r e t u r n A n a l y t i c s I m p l ( ) # e l s e r e t u r n n i l # e n d i f } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 import できるかどうかが オプション機能の有効 / 無効を表現している

Slide 51

Slide 51 text

i m p o r t A n a l y t i c s P r o t o c o l s # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) i m p o r t A n a l y t i c s I m p l s # e n d i f p u b l i c c l a s s A n a l y t i c s F a c t o r y { s t a t i c f u n c c r e a t e ( ) -> A n a l y t i c s P r o t o c o l ? { # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) r e t u r n A n a l y t i c s I m p l ( ) # e l s e r e t u r n n i l # e n d i f } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Analytics モジュール 05 仕組みを紐解く import できる場合と できない場合が存在する テストしづらい import による複雑化 デバッグしづらい コンパイルされない

Slide 52

Slide 52 text

i m p o r t A n a l y t i c s P r o t o c o l s # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) i m p o r t A n a l y t i c s I m p l s # e n d i f p u b l i c c l a s s A n a l y t i c s F a c t o r y { s t a t i c f u n c c r e a t e ( ) -> A n a l y t i c s P r o t o c o l ? { # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) r e t u r n A n a l y t i c s I m p l ( ) # e l s e r e t u r n n i l # e n d i f } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Analytics モジュール 05 仕組みを紐解く 不在の可能性がある Optional な AnalyticsImpls モジュール テストしづらい import による複雑化 デバッグしづらい コンパイルされない

Slide 53

Slide 53 text

05 仕組みを紐解く テストしづらい import による複雑化 デバッグしづらい コンパイルされない l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( ... ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : [ “A n a l y t i c s P r o t o c o l s”, . p r o d u c t ( n a m e : “F i r e b a s e A n a l y t i c s”, p a c k a g e : “f i r e b a s e - i o s - s d k”) ] ) , . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, d e p e n d e n c i e s : [ ] ) ] ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

Slide 54

Slide 54 text

l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( ... ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : [ “A n a l y t i c s P r o t o c o l s”, . p r o d u c t ( n a m e : “F i r e b a s e A n a l y t i c s”, p a c k a g e : “f i r e b a s e - i o s - s d k”) ] ) , . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, d e p e n d e n c i e s : [ ] ) ] ) 05 仕組みを紐解く テストしづらい import による複雑化 デバッグしづらい コンパイルされない 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 FirebaseAnalytics を利⽤するため dependencies に記述

Slide 55

Slide 55 text

l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( ... ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : [ “A n a l y t i c s P r o t o c o l s”, . p r o d u c t ( n a m e : “F i r e b a s e A n a l y t i c s”, p a c k a g e : “f i r e b a s e - i o s - s d k”) ] ) , . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, d e p e n d e n c i e s : [ ] ) ] ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 05 仕組みを紐解く AnalyticsProtocols モジュール テストしづらい import による複雑化 デバッグしづらい コンパイルされない

Slide 56

Slide 56 text

l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( ... ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : [ “A n a l y t i c s P r o t o c o l s”, . p r o d u c t ( n a m e : “F i r e b a s e A n a l y t i c s”, p a c k a g e : “f i r e b a s e - i o s - s d k”) ] ) , . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, d e p e n d e n c i e s : [ ] ) ] ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 05 仕組みを紐解く オプション機能の実装が含まれる AnalyticsImpls モジュール テストしづらい import による複雑化 デバッグしづらい コンパイルされない

Slide 57

Slide 57 text

l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( ... ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : [ “A n a l y t i c s P r o t o c o l s”, . p r o d u c t ( n a m e : “F i r e b a s e A n a l y t i c s”, p a c k a g e : “f i r e b a s e - i o s - s d k”) ] ) , . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, d e p e n d e n c i e s : [ ] ) ] ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 05 仕組みを紐解く AnalyticsImpl 構造体は AnalyticsProtocol に準拠する テストしづらい import による複雑化 デバッグしづらい コンパイルされない

Slide 58

Slide 58 text

l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( ... ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : [ “A n a l y t i c s P r o t o c o l s”, . p r o d u c t ( n a m e : “F i r e b a s e A n a l y t i c s”, p a c k a g e : “f i r e b a s e - i o s - s d k”) ] ) , . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, d e p e n d e n c i e s : [ ] ) ] ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 05 仕組みを紐解く FirebaseAnalytics を依存に追加する テストしづらい import による複雑化 デバッグしづらい コンパイルされない

Slide 59

Slide 59 text

l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( ... ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : [ “A n a l y t i c s P r o t o c o l s”, . p r o d u c t ( n a m e : “F i r e b a s e A n a l y t i c s”, p a c k a g e : “f i r e b a s e - i o s - s d k”) ] ) , . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, d e p e n d e n c i e s : [ ] ) ] ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 05 仕組みを紐解く import による複雑化 AnalyticsImpls だけが FirebaseAnalytics に依存するようになった テストしづらい デバッグしづらい コンパイルされない

Slide 60

Slide 60 text

l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( ... ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : [ “A n a l y t i c s P r o t o c o l s”, . p r o d u c t ( n a m e : “F i r e b a s e A n a l y t i c s”, p a c k a g e : “f i r e b a s e - i o s - s d k”) ] ) , . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, d e p e n d e n c i e s : [ ] ) ] ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 05 仕組みを紐解く Analytics モジュールは どう定義するか import による複雑化 テストしづらい デバッグしづらい コンパイルされない

Slide 61

Slide 61 text

05 仕組みを紐解く import による複雑化 テストしづらい デバッグしづらい コンパイルされない l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : . b u i l d { i f C o n f i g u r a t i o n . a n a l y t i c s E n a b l e d { “A n a l y t i c s I m p l s ” } “A n a l y t i c s P r o t o c o l s” } ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, … . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

Slide 62

Slide 62 text

l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : . b u i l d { i f C o n f i g u r a t i o n . a n a l y t i c s E n a b l e d { “A n a l y t i c s I m p l s ” } “A n a l y t i c s P r o t o c o l s” } ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, … . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 05 仕組みを紐解く resultBuilder を活⽤ import による複雑化 テストしづらい デバッグしづらい コンパイルされない dependencies で if ⽂を利⽤できるように

Slide 63

Slide 63 text

l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : . b u i l d { i f C o n f i g u r a t i o n . a n a l y t i c s E n a b l e d { “A n a l y t i c s I m p l s ” } “A n a l y t i c s P r o t o c o l s” } ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, … . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 05 仕組みを紐解く 条件分岐を利⽤しながら ⼦要素の組み合わせを宣⾔的に記述できる import による複雑化 テストしづらい デバッグしづらい コンパイルされない resultBuilder を活⽤ s t r u c t S a m p l e V i e w : V i e w { v a r b o d y : s o m e : V i e w { T e x t ( “1” ) i f f l a g { T e x t ( “2” ) } } } 1 2 3 4 5 6 7 8

Slide 64

Slide 64 text

l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : . b u i l d { i f C o n f i g u r a t i o n . a n a l y t i c s E n a b l e d { “A n a l y t i c s I m p l s ” } “A n a l y t i c s P r o t o c o l s” } ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, … . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 05 仕組みを紐解く analyticsEnabled が true の時だけ AnalyticsImpls モジュールに依存する import による複雑化 テストしづらい デバッグしづらい コンパイルされない

Slide 65

Slide 65 text

l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : . b u i l d { i f C o n f i g u r a t i o n . a n a l y t i c s E n a b l e d { “A n a l y t i c s I m p l s ” } “A n a l y t i c s P r o t o c o l s” } ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, … . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 05 仕組みを紐解く analyticsEnabled を操作することで Analytics モジュールの依存関係を変更できるようになった import による複雑化 テストしづらい デバッグしづらい コンパイルされない

Slide 66

Slide 66 text

05 仕組みを紐解く import による複雑化 テストしづらい デバッグしづらい コンパイルされない l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : . b u i l d { i f C o n f i g u r a t i o n . a n a l y t i c s E n a b l e d { “A n a l y t i c s I m p l s ” } “A n a l y t i c s P r o t o c o l s” } ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, … . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 モジュール化戦略のポイント 「Package.swift でモジュール構成を⾃由に組み替える」

Slide 67

Slide 67 text

05 仕組みを紐解く import による複雑化 テストしづらい デバッグしづらい コンパイルされない l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : . b u i l d { i f C o n f i g u r a t i o n . a n a l y t i c s E n a b l e d { “A n a l y t i c s I m p l s ” } “A n a l y t i c s P r o t o c o l s” } ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, … . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

Slide 68

Slide 68 text

l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : [ “A n a l y t i c s P r o t o c o l s” ] ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, … . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 05 仕組みを紐解く オプション機能が無効なとき import による複雑化 テストしづらい デバッグしづらい コンパイルされない

Slide 69

Slide 69 text

i m p o r t A n a l y t i c s P r o t o c o l s # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) i m p o r t A n a l y t i c s I m p l s # e n d i f p u b l i c c l a s s A n a l y t i c s F a c t o r y { s t a t i c f u n c c r e a t e ( ) -> A n a l y t i c s P r o t o c o l ? { # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) r e t u r n A n a l y t i c s I m p l ( ) # e l s e r e t u r n n i l # e n d i f } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Analytics モジュール 05 仕組みを紐解く import による複雑化 テストしづらい デバッグしづらい コンパイルされない オプション機能が無効なとき

Slide 70

Slide 70 text

1 i m p o r t A n a l y t i c s 2 3 i f l e t a n a l y t i c s = A n a l y t i c s F a c t o r y . c r e a t e ( ) { 4 a n a l y t i c s . s e n d E v e n t ( ... ) 5 } オプション機能の参照コード 05 仕組みを紐解く import による複雑化 テストしづらい デバッグしづらい コンパイルされない オプション機能が無効なとき

Slide 71

Slide 71 text

05 仕組みを紐解く import による複雑化 テストしづらい デバッグしづらい コンパイルされない l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : . b u i l d { i f C o n f i g u r a t i o n . a n a l y t i c s E n a b l e d { “A n a l y t i c s I m p l s ” } “A n a l y t i c s P r o t o c o l s” } ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, … . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

Slide 72

Slide 72 text

l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : [ “A n a l y t i c s I m p l s ”, “A n a l y t i c s P r o t o c o l s” ] ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, … . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 05 仕組みを紐解く オプション機能が有効なとき import による複雑化 テストしづらい デバッグしづらい コンパイルされない

Slide 73

Slide 73 text

Analytics モジュール 05 仕組みを紐解く import による複雑化 テストしづらい デバッグしづらい コンパイルされない i m p o r t A n a l y t i c s P r o t o c o l s # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) i m p o r t A n a l y t i c s I m p l s # e n d i f p u b l i c c l a s s A n a l y t i c s F a c t o r y { s t a t i c f u n c c r e a t e ( ) -> A n a l y t i c s P r o t o c o l ? { # i f c a n I m p o r t ( A n a l y t i c s I m p l s ) r e t u r n A n a l y t i c s I m p l ( ) # e l s e r e t u r n n i l # e n d i f } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 オプション機能が有効なとき

Slide 74

Slide 74 text

オプション機能の参照コード 05 仕組みを紐解く import による複雑化 テストしづらい デバッグしづらい コンパイルされない 1 i m p o r t A n a l y t i c s 2 3 i f l e t a n a l y t i c s = A n a l y t i c s F a c t o r y . c r e a t e ( ) { 4 a n a l y t i c s . s e n d E v e n t ( ... ) 5 } オプション機能が有効なとき

Slide 75

Slide 75 text

AnalyticsImpls モジュール 05 仕組みを紐解く import による複雑化 テストしづらい デバッグしづらい コンパイルされない 1 i m p o r t A n a l y t i c s P r o t o c o l s 2 i m p o r t F i r e b a s e A n a l y t i c s 3 4 s t r u c t A n a l y t i c s I m p l : A n a l y t i c s P r o t o c o l { 5 f u n c s e n d E v e n t ( ... ) { … } 6 }

Slide 76

Slide 76 text

1 i m p o r t A n a l y t i c s P r o t o c o l s 2 i m p o r t F i r e b a s e A n a l y t i c s 3 4 s t r u c t A n a l y t i c s I m p l : A n a l y t i c s P r o t o c o l { 5 f u n c s e n d E v e n t ( ... ) { … } 6 } AnalyticsImpls モジュール 05 仕組みを紐解く デバッグしづらい テストしづらい 静的解析されない import による複雑化 コンパイルされない Active Compilation Conditions が無くなり AnalyticsImpl がコンパイルされるようになった 常に import できる

Slide 77

Slide 77 text

AnalyticsImpls モジュール 05 仕組みを紐解く デバッグしづらい テストしづらい 静的解析されない import による複雑化 コンパイルされない Active Compilation Conditions が無くなり AnalyticsImpl がコンパイルされるようになった 1 i m p o r t A n a l y t i c s P r o t o c o l s 2 i m p o r t F i r e b a s e A n a l y t i c s 3 4 s t r u c t A n a l y t i c s I m p l : A n a l y t i c s P r o t o c o l { 5 f u n c s e n d E v e n t ( ... ) { … } 6 } 常に import できる

Slide 78

Slide 78 text

05 仕組みを紐解く デバッグしづらい テストしづらい 静的解析されない import による複雑化 コンパイルされない l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : . b u i l d { i f C o n f i g u r a t i o n . a n a l y t i c s E n a b l e d { “A n a l y t i c s I m p l s ” } “A n a l y t i c s P r o t o c o l s” } ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, … . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

Slide 79

Slide 79 text

05 仕組みを紐解く デバッグしづらい テストしづらい 静的解析されない import による複雑化 コンパイルされない l e t p a c k a g e = P a c k a g e ( d e p e n d e n c i e s : [ . p a c k a g e ( u r l : “ h t t p s : / /… / f i r e b a s e - i o s - s d k . g i t ”, … ) ] , t a r g e t : [ . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, d e p e n d e n c i e s : . b u i l d { i f C o n f i g u r a t i o n . a n a l y t i c s E n a b l e d { “A n a l y t i c s I m p l s ” } “A n a l y t i c s P r o t o c o l s” } ) , . t a r g e t ( n a m e : “A n a l y t i c s I m p l s ”, … . t a r g e t ( n a m e : “A n a l y t i c s P r o t o c o l s”, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

Slide 80

Slide 80 text

05 仕組みを紐解く Package.swift デバッグしづらい テストしづらい 静的解析されない import による複雑化 コンパイルされない 1 s t r u c t C o n f i g u r a t i o n { 2 s t a t i c l e t a n a l y t i c s E n a b l e d = t r u e 3 } 4 5 l e t p a c k a g e = P a c k a g e ( ... )

Slide 81

Slide 81 text

1 s t r u c t C o n f i g u r a t i o n { 2 s t a t i c l e t a n a l y t i c s E n a b l e d = t r u e 3 } 4 5 l e t p a c k a g e = P a c k a g e ( ... ) 05 仕組みを紐解く Package.swift スクリプトで Bool 値を変更する デバッグしづらい テストしづらい 静的解析されない import による複雑化 コンパイルされない

Slide 82

Slide 82 text

1 s t r u c t C o n f i g u r a t i o n { 2 s t a t i c l e t a n a l y t i c s E n a b l e d = t r u e 3 } 4 5 l e t p a c k a g e = P a c k a g e ( ... ) 05 仕組みを紐解く Package.swift デバッグしづらい テストしづらい 静的解析されない import による複雑化 コンパイルされない スクリプトで Configuration 構造体を⽣成し 1~3 ⾏⽬を置換している

Slide 83

Slide 83 text

1 s t r u c t C o n f i g u r a t i o n { 2 s t a t i c l e t a n a l y t i c s E n a b l e d = t r u e 3 } 4 5 l e t p a c k a g e = P a c k a g e ( ... ) 05 仕組みを紐解く Package.swift ⼿動で Bool 値を変更するだけで ⾊々な組み合わせを検証できるようになった デバッグしづらい テストしづらい 静的解析されない import による複雑化 コンパイルされない

Slide 84

Slide 84 text

1 s t r u c t C o n f i g u r a t i o n { 2 s t a t i c l e t a n a l y t i c s E n a b l e d = t r u e 3 } 4 5 l e t p a c k a g e = P a c k a g e ( ... ) 05 仕組みを紐解く Package.swift 有効化してデバッグを開始するまでの⼿順が Bool 値を変更するだけになった デバッグしづらい テストしづらい 静的解析されない import による複雑化 コンパイルされない

Slide 85

Slide 85 text

05 仕組みを紐解く Package.swift デバッグしづらい テストしづらい 静的解析されない import による複雑化 コンパイルされない 1 s t r u c t C o n f i g u r a t i o n { 2 s t a t i c l e t a n a l y t i c s E n a b l e d = t r u e 3 } 4 5 l e t p a c k a g e = P a c k a g e ( ... )

Slide 86

Slide 86 text

まとめ

Slide 87

Slide 87 text

06 まとめ Yappli では を に実装し、 ビルド時に を操作することで オプション機能の 有効 / 無効 を切り替えていた。 その仕組みには 、 といった課題があった。

Slide 88

Slide 88 text

06 まとめ Yappli では オプション機能 を に実装し、 ビルド時に を操作することで オプション機能の 有効 / 無効 を切り替えていた。 その仕組みには 、 といった課題があった。

Slide 89

Slide 89 text

06 まとめ Yappli では オプション機能 を 同じコードベース に実装し、 ビルド時に を操作することで オプション機能の 有効 / 無効 を切り替えていた。 その仕組みには 、 といった課題があった。

Slide 90

Slide 90 text

06 まとめ Yappli では オプション機能 を 同じコードベース に実装し、 ビルド時に を操作することで オプション機能の 有効 / 無効 を切り替えていた。 その仕組みには 、 といった課題があった。 Active Compilation Conditions

Slide 91

Slide 91 text

06 まとめ Yappli では オプション機能 を 同じコードベース に実装し、 ビルド時に Active Compilation Conditions を操作することで オプション機能の 有効 / 無効 を切り替えていた。 その仕組みには テスト‧デバッグがしづらく 、 import が絡むと複雑化する といった課題があった。

Slide 92

Slide 92 text

06 まとめ 結果として Active Compilation Conditions を剥がすことができ、 従来の課題が解決できた。 そこでオプション機能を として分離し、 を⾃由に組み換えられるようにした。 を活⽤することで、 で

Slide 93

Slide 93 text

06 まとめ 結果として Active Compilation Conditions を剥がすことができ、 従来の課題が解決できた。 そこでオプション機能を オプショナルなモジュール として分離し、 を⾃由に組み換えられるようにした。 を活⽤することで、 で

Slide 94

Slide 94 text

06 まとめ 結果として Active Compilation Conditions を剥がすことができ、 従来の課題が解決できた。 そこでオプション機能を オプショナルなモジュール として分離し、 Package.swift を⾃由に組み換えられるようにした。 を活⽤することで、 で フラグ

Slide 95

Slide 95 text

06 まとめ そこでオプション機能を オプショナルなモジュール として分離し、 Package.swift を⾃由に組み換えられるようにした。 結果として Active Compilation Conditions を剥がすことができ、 を活⽤することで、 従来の課題が解決できた。 で フラグ モジュール構成

Slide 96

Slide 96 text

06 まとめ オプショナルな依存関係をビルド時に決定する マルチモジュールの仕組み を導⼊して解決した。 ヤプリにおける保守課題を解決するモジュール化戦略として、 そこでオプション機能を オプショナルなモジュール として分離し、 Package.swift を⾃由に組み換えられるようにした。 を活⽤することで、 で フラグ モジュール構成 06 まとめ