Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

Atsushi Miyake
October 18, 2024
2

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

Atsushi Miyake

October 18, 2024
Tweet

Transcript

  1. ⽬次 1. 技術⽬線で Yappli とは 2. 課題 3. 解決のアプローチ 4.

    ゴールイメージの共有 5. 仕組みを紐解く 6. まとめ
  2. 01 技術⽬線で Yappli とは もう少し「技術⽬線」で捉えると 約 850 アプリ! CMS の設定

    に応じて 同じコードベース から 各アプリをビルド‧配信 する アプリプラットフォーム
  3. Active Compilation Conditions 02 課題 1 # i f D

    E B U G 2 # e l s e 3 # e n d i f
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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
  9. 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 が絡むと依存解決など複雑化する‧‧‧
  10. 改善前と改善後の⽐較 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 }
  11. 改善前と改善後の⽐較 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 のチェックが必要
  12. 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 できない
  13. 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
  14. 改善前と改善後の⽐較 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
  15. オプション機能の参照コード 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 }
  16. 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 による複雑化 テストしづらい デバッグしづらい コンパイルされない
  17. オプション機能の参照コード 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
  18. 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
  19. 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
  20. 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 による複雑化 デバッグしづらい コンパイルされない
  21. 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 による複雑化 デバッグしづらい コンパイルされない
  22. 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 による複雑化 デバッグしづらい コンパイルされない
  23. 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
  24. 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 を返却
  25. 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 できるかどうかが オプション機能の有効 / 無効を表現している
  26. 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 による複雑化 デバッグしづらい コンパイルされない
  27. 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 による複雑化 デバッグしづらい コンパイルされない
  28. 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
  29. 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 に記述
  30. 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 による複雑化 デバッグしづらい コンパイルされない
  31. 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 による複雑化 デバッグしづらい コンパイルされない
  32. 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 による複雑化 デバッグしづらい コンパイルされない
  33. 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 による複雑化 デバッグしづらい コンパイルされない
  34. 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 に依存するようになった テストしづらい デバッグしづらい コンパイルされない
  35. 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 による複雑化 テストしづらい デバッグしづらい コンパイルされない
  36. 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
  37. 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 ⽂を利⽤できるように
  38. 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
  39. 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 による複雑化 テストしづらい デバッグしづらい コンパイルされない
  40. 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 による複雑化 テストしづらい デバッグしづらい コンパイルされない
  41. 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 でモジュール構成を⾃由に組み替える」
  42. 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
  43. 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 による複雑化 テストしづらい デバッグしづらい コンパイルされない
  44. 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 による複雑化 テストしづらい デバッグしづらい コンパイルされない オプション機能が無効なとき
  45. 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 による複雑化 テストしづらい デバッグしづらい コンパイルされない オプション機能が無効なとき
  46. 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
  47. 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 による複雑化 テストしづらい デバッグしづらい コンパイルされない
  48. 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 オプション機能が有効なとき
  49. オプション機能の参照コード 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 } オプション機能が有効なとき
  50. 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 }
  51. 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 できる
  52. 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 できる
  53. 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
  54. 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
  55. 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 ( ... )
  56. 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 による複雑化 コンパイルされない
  57. 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 ⾏⽬を置換している
  58. 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 による複雑化 コンパイルされない
  59. 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 による複雑化 コンパイルされない
  60. 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 ( ... )
  61. 06 まとめ Yappli では を に実装し、 ビルド時に を操作することで オプション機能の 有効

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

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

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

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

    Compilation Conditions を操作することで オプション機能の 有効 / 無効 を切り替えていた。 その仕組みには テスト‧デバッグがしづらく 、 import が絡むと複雑化する といった課題があった。
  66. 06 まとめ 結果として Active Compilation Conditions を剥がすことができ、 従来の課題が解決できた。 そこでオプション機能を オプショナルなモジュール

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

    Conditions を剥がすことができ、 を活⽤することで、 従来の課題が解決できた。 で フラグ モジュール構成