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

iOSアプリの設計とDependency Injection

iOSアプリの設計とDependency Injection

iOSオールスターズ2
https://eventdots.jp/event/602872

Kenichi Yonekawa

November 20, 2016
Tweet

More Decks by Kenichi Yonekawa

Other Decks in Programming

Transcript

  1. @yonekawa
    J04ΞϓϦͷઃܭͱ
    %FQFOEFODZ*OKFDUJPO

    View Slide

  2. View Slide

  3. View Slide

  4. View Slide

  5. View Slide

  6. %FQFOEFODZ*OKFDUJPO

    View Slide

  7. Dependency?
    TUSVDU5XFFUFS\
    GVODUXFFU UXFFU4USJOH
    \
    MFUBQJ5XJUUFS"QJ

    BQJQPTU5XFFU UXFFU

    ^
    ^
    TUSVDU5XJUUFS"QJ\
    GVODQPTU5XFFU UXFFU4USJOH
    \
    MFUDPOGJH/463-4FTTJPO$POGJHVSBUJPOEFGBVMU4FTTJPO$POGJHVSBUJPO

    MFUTFTTJPO/463-4FTTJPO DPOGJHVSBUJPODPOGJH

    MFUSFRVFTUCVJMESFRVFTU
    TFTTJPOEBUB5BTL8JUI3FRVFTU SFRVFTU

    ^
    ^
    MFUUXFFUFS5XFFUFS

    UXFFUFSUXFFU )FMMP

    Tweeter TwitterApi HTTP Client

    View Slide

  8. Dependency?
    TUSVDU5XFFUFS\
    GVODUXFFU UXFFU4USJOH
    \
    MFUBQJ5XJUUFS"QJ

    BQJQPTU5XFFU UXFFU

    ^
    ^
    TUSVDU5XJUUFS"QJ\
    GVODQPTU5XFFU UXFFU4USJOH
    \
    MFUDPOGJH/463-4FTTJPO$POGJHVSBUJPOEFGBVMU4FTTJPO$POGJHVSBUJPO

    MFUTFTTJPO/463-4FTTJPO DPOGJHVSBUJPODPOGJH

    MFUSFRVFTUCVJMESFRVFTU
    TFTTJPOEBUB5BTL8JUI3FRVFTU SFRVFTU

    ^
    ^
    MFUUXFFUFS5XFFUFS

    UXFFUFSUXFFU )FMMP

    Tweeter TwitterApi HTTP Client

    View Slide

  9. Problem
    • TwitterApi͕௨৴ͷ΍Γํʹґଘ͍ͯ͠Δɻ௨৴ͷ΍ΓํΛ
    ม͔͑ͨͬͨΒTwitterApi΋ಉ࣌ʹม͑ͳ͍ͱ͍͚ͳ͍ɻ
    • ʮπΠʔτΛ౤ߘ͢ΔʯλεΫʹؔ܎ͷͳ͍ॳظԽॲཧ͕ଟ
    ͘ͳΓϝιουͷؔ৺ࣄ͕૿͑Δ
    • ௨৴ͷίʔυ͕ີ݁߹͍ͯ͠ΔͨΊpostTweetͷςετ͕ॻ
    ͖ͮΒ͍

    View Slide

  10. Solution
    TUSVDU5XFFUFS\
    MFUBQJ5XJUUFS"QJ
    GVODUXFFU UXFFU4USJOH
    \
    BQJQPTU5XFFU UXFFU

    ^
    ^
    TUSVDU5XJUUFS"QJ\
    MFUIUUQ$MJFOU)551$MJFOU
    GVODQPTU5XFFU UXFFU4USJOH
    \
    MFUSFRVFTUCVJMESFRVFTU
    IUUQ$MJFOUTFOE SFRVFTU

    ^
    ^
    MFUBQJ5XJUUFS"QJ IUUQ$MJFOU)UUQ$MJFOU8JUI63-4FTTJPO


    MFUUXFFUFS5XFFUFS BQJBQJ

    UXFFUFSUXFFU )FMMP

    View Slide

  11. Solution
    TUSVDU5XFFUFS\
    MFUBQJ5XJUUFS"QJ
    GVODUXFFU UXFFU4USJOH
    \
    BQJQPTU5XFFU UXFFU

    ^
    ^
    TUSVDU5XJUUFS"QJ\
    MFUIUUQ$MJFOU)551$MJFOU
    GVODQPTU5XFFU UXFFU4USJOH
    \
    MFUSFRVFTUCVJMESFRVFTU
    IUUQ$MJFOUTFOE SFRVFTU

    ^
    ^
    MFUBQJ5XJUUFS"QJ IUUQ$MJFOU)UUQ$MJFOU8JUI63-4FTTJPO


    MFUUXFFUFS5XFFUFS BQJBQJ

    UXFFUFSUXFFU )FMMP

    View Slide

  12. Dependency Injection Pattern
    • ίϯϙʔωϯτͷؒͷґଘؔ܎Λιʔείʔυ͔Βഉআ͠ɺ
    ֎෦͔Β஫ೖͰ͖ΔΑ͏ʹ͢ΔσβΠϯύλʔϯ
    • ίϯϙʔωϯτ͔ΒΠϯελϯεͷੜ੒΍ͦͷ۩ମతͳ࣮૷
    ͱ͍ͬͨຊདྷඞཁͳ͍ؔ৺ࣄ͕औΓআ͔Ε࣮ͯ૷͕γϯϓϧ
    ʹͳΔ
    • ֎෦͔Βίϯϙʔωϯτͷ࣮૷Λ੍ޚͰ͖ΔͷͰɺ௨৴෦෼
    ͚ͩϞοΫͨ͠ΓϢχοτςετ͕΍Γ΍͘͢ͳΔ

    View Slide

  13. Problem
    • Tweeter͕૿͑ͨΒຖճTwitterApiͱHTTP ClientΛॳظԽ͠
    ͯ౉͔ͯ͠Βݺͼग़͞ͳ͍ͱ͍͚ͳ͍
    • ࠶ར༻͢ΔͨΊʹίϯϙʔωϯτԽͯ͠ΔͷʹͦΕΛ࢖͏ͨ
    Ίͷ४උ͕ଟ͘ͳͬͯ໘౗͍͘͞

    View Slide

  14. DI Container
    • ґଘίϯϙʔωϯτͷੜ੒ͱ஫ೖΛผͷίϯϙʔωϯτʹ
    ೚ͤΔɻDIίϯςφͱ͔DIϑϨʔϜϫʔΫͱݺ͹ΕΔ΋ͷ
    • ίϯςφ͸ίϯϙʔωϯτͷੜ੒ํ๏ͱ஫ೖํ๏Λ஌͍ͬͯ
    ͯɺίϯϙʔωϯτؒͷґଘؔ܎Λղܾͯ͠ΦϒδΣΫτΛ
    ฦͯ͘͠ΕΔ
    DI Container
    Client Code
    Tweeter
    TwitterApi
    HTTP Client

    View Slide

  15. Pseudocode
    SFHJTUFS )551$MJFOUTFMG
    \
    )551$MJFOUJO
    SFUVSO)UUQ$MJFOU8JUI63-4FTTJPO

    ^
    SFHJTUFS 5XJUUFS"QJTFMG
    \
    5XJUUFS"QJJO
    MFUVSM4FTTJPODPNQPOFOU /463-4FTTJPOTFMG

    SFUVSO5XJUUFS"QJ VSM4FTTJPOVSM4FTTJPO

    ^
    SFHJTUFS 5XFFUFSTFMG
    \
    5XFFUFSJO
    MFUBQJDPNQPOFOU 5XJUUFS"QJTFMG

    SFUVSO5XFFUFS BQJBQJ

    ^
    MFUUXFFUFSDPNQPOFOU 5XFFUFSTFMG

    UXFFUFSUXFFU )FMMP

    View Slide

  16. Pseudocode
    SFHJTUFS )551$MJFOUTFMG
    \
    )551$MJFOUJO
    SFUVSO"MBNPGJSF$MJFOU

    ^
    SFHJTUFS 5XJUUFS"QJTFMG
    \
    5XJUUFS"QJJO
    MFUVSM4FTTJPODPNQPOFOU /463-4FTTJPOTFMG

    SFUVSO5XJUUFS"QJ VSM4FTTJPOVSM4FTTJPO

    ^
    SFHJTUFS 5XFFUFSTFMG
    \
    5XFFUFSJO
    MFUBQJDPNQPOFOU 5XJUUFS"QJTFMG

    SFUVSO5XFFUFS BQJBQJ

    ^
    MFUUXFFUFSDPNQPOFOU 5XFFUFSTFMG

    UXFFUFSUXFFU )FMMP

    View Slide

  17. Clean Architecture
    • ϩδοΫͷ૚ͱ໾ׂΛ෼ׂ͢Δ͜ͱͰͦΕͧΕͷ੹຿Λ໌
    ֬ʹͯ͠ઃܭͷڞ௨ೝࣝΛ࡞ΔΞʔΩςΫνϟઃܭ
    • ໾ׂΛ෼ׂͤ͞Δʹ͸ͦΕͧΕͷίϯϙʔωϯτͷґଘؔ܎
    Λ੾Γ཭͢ඞཁ͕͋Δ
    • Clean Architecture͸DIΛੵۃతʹ׆༻ͨ͠ʢ׆༻Ͱ͖Δʣ
    ΞʔΩςΫνϟ

    View Slide

  18. %*'SBNFXPSLGPSJ04

    View Slide

  19. Typical DI Frameworks
    • Typhoon
    • Swinject
    • Cleanse

    View Slide

  20. Typhoon
    • Objective-C࣌୅͔Β͋Δ࿝ฮͷDIίϯςφ
    • Storyboard͔ΒͷΠϯελϯεੜ੒αϙʔτ΍ɺplistͰͷґ
    ଘؔ܎ͷఆٛͳͲػೳ͸๛෋
    • ࣮૷͕Objective-Cϕʔεͷ͍͔ͤSwiftͩͱܕͷѻ͍͕͋·
    Γ͏·͘ͳ͍

    View Slide

  21. Swinject
    • Pure SwiftͰॻ͔ΕͨDIϑϨʔϜϫʔΫ
    • ContainerΦϒδΣΫτʹܕͱBlockΛొ࿥ͯ͠ܕΛى఺ʹґ
    ଘΛղܾ͢Δ
    • Typhoonͱҧ͍ɺຊମʹೖΕͨ͘ͳ͍͕ศརͳػೳ͸֦ு
    ͷܗͰఏڙ͍ͯ͠Δɻ

    View Slide

  22. Swinject Style
    MFUDPOUBJOFS$POUBJOFS

    DPOUBJOFSSFHJTUFS "OJNBM5ZQFTFMG
    \@JO$BU OBNF.JNJ
    ^
    DPOUBJOFSSFHJTUFS 1FSTPO5ZQFTFMG
    \SJO
    1FU0XOFS QFUSSFTPMWF "OJNBM5ZQFTFMG


    ^
    MFUQFSTPODPOUBJOFSSFTPMWF 1FSTPO5ZQFTFMG

    QFSTPOQMBZ

    View Slide

  23. Cleanse
    • Square੡ͷDIίϯςφ
    • SwinjectͷContainerʹ૬౰͢Δ΋ͷ͸ແ͘ɺComponentͱ
    Moduleͷ૊Έ߹ΘͤͰ֤ΦϒδΣΫτͷґଘΛ؅ཧ͢Δ
    • JavaͷDIϑϨʔϜϫʔΫ(Dagger)ʹΠϯεύΠΞ͞Ε͍ͯ
    ΔͷͰ༻ޠ͸ࣅ͍ͯΔ͕ɺSwiftͷݴޠ࢓༷ʹ߹Θͤͯઃܭ
    ͞Ε͍ͯΔ

    View Slide

  24. Cleanse Style
    TUSVDU"OJNBM.PEVMF$MFBOTF.PEVMF\
    GVODDPOGJHVSF##JOEFS CJOEFSCJOEFS#
    \
    CJOEFSCJOE "OJNBM5ZQFTFMG
    UP WBMVF$BU OBNF.JNJ


    ^
    ^
    TUSVDU0XOFS$PNQPOFOU$MFBOTF$PNQPOFOU\
    UZQFBMJBT3PPU1FSTPO5ZQF
    GVODDPOGJHVSF##JOEFS CJOEFSCJOEFS#
    \
    CJOEFSJOTUBMM NPEVMF"OJNBM.PEVMF


    CJOEFSCJOE 1FSTPO5ZQFTFMG
    UP GBDUPSZ1FU0XOFSJOJU

    ^
    ^
    MFUQFSTPOUSZ0XOFS$PNQPOFOU
    CVJME

    QFSTPOQMBZ

    View Slide

  25. Swinject vs Cleanse
    • Cleanse͸ίϯϙʔωϯτఆٛͰ΍Δ͜ͱ͕ଟ͍ͷͰ࠷ॳ͸
    ໘౗ɻSwinject͸ContainerʹܕͱBlockΛ౉͚ͩ͢Ͱ͍͍ͷ
    ͰΧδϡΞϧʹ࢖͑Δɻ
    • ίϯϙʔωϯτͷੜ੒ํ๏Λίϯϙʔωϯτ୯ҐͰఆٛ͢
    ΔCleanseͷ΄͏͕ΠϯλϑΣʔεͱͯ͠͸ے͕Αͦ͞͏ɻ
    Swinject͸Containerͷ؅ཧͱ͍͏ผͷ໰୊͕͋Δɻ
    • Cleanse͸·ͩbetaͰ͋·ΓίϛϡχςΟͷಈ͖͕ͳ͍

    View Slide

  26. J04%*1SBDUJDF

    View Slide

  27. Protocol Oriented
    • ίϯϙʔωϯτؒΛૄ݁߹ʹ͢Δʹ͸ίϯϙʔωϯτͷΠ
    ϯλϑΣʔεΛ໌ࣔతʹ͠ͳ͍ͱ͍͚ͳ͍ɻΠϯλϑΣʔε
    ͕ಉ͡ͳΒ࣮૷ͷࠩ͠ସ͕͑༰қʹͳΔɻ
    QSPUPDPM)551$MJFOU\
    GVODTFOE

    ^
    DMBTT/463-4FTTJPO$MJFOU)551$MJFOU\
    GVODTFOE
    \
    /463-4FTTJPO
    EBUB5BTL8JUI3FRVFTU ǘ

    ^
    ^
    DMBTT"MBNPGJSF$MJFOU)551$MJFOU\
    GVODTFOE
    \
    "MBNPGJSFSFRVFTU ǘ

    ^
    ^

    View Slide

  28. Constructor Injection vs Property Injection
    • Property Injection͸֎෦ʹϓϩύςΟΛެ։͢Δඞཁ͕͋
    ΓMutableʹ͠ͳ͍ͱ͍͚ͳ͍ͷͰجຊతʹ͸Constructor
    InjectionΛ͓קΊ͍ͨ͠
    • CleanseͷυΩϡϝϯτͰ͸Property Injection͸
    AppDelegate΍StoryboardͳͲΠϯελϯεੜ੒Λ੍ޚͰ
    ͖ͳ͍έʔεͰ࢖͏ͱ͞Ε͍ͯΔ

    View Slide

  29. prepareForSegue
    • ભҠݩͷViewController͕ભҠઌͷViewControllerʹ͍ͭͯ
    ஌Βͳ͍ͱ͍͚ͳ͍ɻભҠઌͷ࢓༷͕มΘͬͨΒભҠݩΛ
    ௚͞ͳ͍ͱ͍͚ͳ͍ɻ
    • ΠϯελϯεԽ͸StoryboardʹΑͬͯߦΘΕΔͷͰ
    PropertyInjectorΛ࢖ͬͯ஫ೖ͢Δ
    PWFSSJEFGVODQSFQBSF'PS4FHVF TFHVF6*4UPSZCPBSE4FHVF TFOEFS
    "OZ0CKFDU
    \
    JGMFUWDTFHVFEFTUJOBUJPO7JFX$POUSPMMFSBT /FYU7JFX$POUSPMMFS\
    MFUJOKFDUPSUSZ/FYU7JFX$POUSPMMFS$PNQPOFOU
    CVJME

    JOKFDUPSJOKFDU1SPQFSUJFT JOUPWD

    ^
    ^

    View Slide

  30. DI with arguments
    • Πϯελϯεੜ੒Λίϯςφʹ೚ͤͯ͠·͏ͷͰɺϢʔβʔ
    ೖྗͳͲͷಈతͳύϥϝʔλ͸Ͳ͏౉͢΂͖͔
    • Cleanse͸ComponentFactoryͱ͍͏ػೳͰͦΕΛ࣮ݱͰ͖
    Δ͕·ͩ։ൃதɻݱঢ়Ͱ͸ComponentͷॳظԽ࣌ʹύϥ
    ϝʔλΛ౉ͯ͠Moduleͷੜ੒ʹ࢖͏͔͠ͳͦ͞͏
    • Swinject͸ґଘΦϒδΣΫτΛresolve͢Δ࣌ʹੜ੒ίʔυ
    ΁ͷύϥϝʔλ͕౉ͤΔ

    View Slide

  31. DI with arguments (Cleanse)
    TUSVDU/FYU7JFX$PNQPOFOU$MFBOTF$PNQPOFOU\
    MFUJUFN*UFN
    UZQFBMJBT3PPU1SPQFSUZ*OKFDUPS/FYU7JFX$POUSPMMFS
    GVODDPOGJHVSF##JOEFS CJOEFSCJOEFS#
    \
    CJOEFSJOTUBMM NPEVMF7JFX.PEFM.PEVMF


    CJOEFS
    CJOE1SPQFSUZ*OKFDUJPO0G /FYU7JFX$POUSPMMFSTFMG

    UP\ WD/FYU7JFX$POUSPMMFS WJFX.PEFM7JFX.PEFM
    JO
    WJFX.PEFMJUFNJUFN
    WDWJFX.PEFMWJFX.PEFM
    ^
    ^
    ^
    PWFSSJEFGVODQSFQBSF'PS4FHVF TFHVF6*4UPSZCPBSE4FHVF TFOEFS"OZ0CKFDU
    \
    JGMFUWDTFHVFEFTUJOBUJPO7JFX$POUSPMMFSBT /FYU7JFX$POUSPMMFS\
    MFUJUFN
    MFUJOKFDUPSUSZ/FYU7JFX$PNQPOFOU JUFNJUFN
    CVJME

    JOKFDUPSJOKFDU1SPQFSUJFT JOUPWD

    ^
    ^

    View Slide

  32. DI with arguments (Cleanse)
    TUSVDU/FYU7JFX$PNQPOFOU$MFBOTF$PNQPOFOU\
    MFUJUFN*UFN
    UZQFBMJBT3PPU1SPQFSUZ*OKFDUPS/FYU7JFX$POUSPMMFS
    GVODDPOGJHVSF##JOEFS CJOEFSCJOEFS#
    \
    CJOEFSJOTUBMM NPEVMF7JFX.PEFM.PEVMF


    CJOEFS
    CJOE1SPQFSUZ*OKFDUJPO0G /FYU7JFX$POUSPMMFSTFMG

    UP\ WD/FYU7JFX$POUSPMMFS WJFX.PEFM7JFX.PEFM
    JO
    WJFX.PEFMJUFNJUFN
    WDWJFX.PEFMWJFX.PEFM
    ^
    ^
    ^
    PWFSSJEFGVODQSFQBSF'PS4FHVF TFHVF6*4UPSZCPBSE4FHVF TFOEFS"OZ0CKFDU
    \
    JGMFUWDTFHVFEFTUJOBUJPO7JFX$POUSPMMFSBT /FYU7JFX$POUSPMMFS\
    MFUJUFN
    MFUJOKFDUPSUSZ/FYU7JFX$PNQPOFOU JUFNJUFN
    CVJME

    JOKFDUPSJOKFDU1SPQFSUJFT JOUPWD

    ^
    ^

    View Slide

  33. Mock Testing
    • API௨৴෦෼ͳͲΛϢχοτςετͷ࣌ʹ͸ϞοΫ࣮૷ʹࠩ
    ͠ସ͍͑ͨɻ
    • Cleanse͸ModuleΛOverride͢Δ͜ͱ͕Ͱ͖ΔͷͰϞοΫ
    ࣮૷ͱͷࠩ͠ସ͕͑༰қ͚ͩͲɾɾɾ
    TUSVDU'BLF.PEVMF0WFSSJEF.PEVMF\
    UZQFBMJBT0WFSSJEFT5XFFUFS$PNQPOFOU
    GVODDPOGJHVSF##JOEFS CJOEFSCJOEFS#
    \
    CJOEFSJOTUBMM NPEVMF'BLF5XJUUFS"QJ.PEVMF


    ^
    ^
    JGVTF'BLF.PEF\
    JOKFDUPSUSZ$PNQPOFOU
    XJUI0WFSSJEFT PWFSSJEF.PEVMF'BLF.PEVMF

    CVJME

    ^FMTF\
    JOKFDUPSUSZ$PNQPOFOU
    CVJME

    ^

    View Slide

  34. Do Not Use Fake Mode
    • ίϯϙʔωϯτఆٛΛ্ॻ͖͢Δͷ͸ίϯϙʔωϯτؒͷґଘͷ
    ࿈࠯ΛಡΈͮΒ͘͢ΔͷͰΑ͘ͳ͍ʢCleanseͰ΋͜ͷػೳΛ࡟
    আ͢ΔPR͕ग़ͯΔʣ
    • ૉ௚ʹϢχοτςετ࣌ʹϞοΫ͢Δ΂͖ɻґଘΦϒδΣΫτ͸
    ԿΒ͔ͷܗͰ֎෦͔Β౉ͤΔઃܭʹͳ͍ͬͯΔ͔Β؆୯ͳ͸ͣ
    DMBTT5XJUUFS"QJ5FTUT9$5FTU$BTF\
    WBSTVCKFDU5XJUUFS"QJ
    MFUTFTTJPO.PDL63-4FTTJPO

    PWFSSJEFGVODTFU6Q
    \
    TVQFSTFU6Q

    TVCKFDU5XJUUFS"QJ TFTTJPOTFTTJPO

    ^
    ^

    View Slide

  35. Swiftʹ͓͚Δݱ࣮తͳϞοΫ
    https://realm.io/jp/news/tryswift-veronica-ray-real-world-mocking-swift/

    View Slide

  36. ·ͱΊ

    View Slide

  37. ·ͱΊ
    • ෳࡶͳΞϓϦͰมߋʹڧ͍ΞʔΩςΫνϟΛ࡞ΔͨΊʹ͸·
    ͣɺίϯϙʔωϯτؒͷґଘΛഉআ͢Δ͜ͱ͕ॏཁɻDIʹ
    Αͬͯͦͷ౔৕Λ࡞Δ͜ͱ͕Ͱ͖Δ
    • SwiftͷProtocol΍ܕγεςϜΛ͏·͘࢖ͬͨDIϑϨʔϜϫʔ
    ΫΛ࠾༻͢ΔͱΞϓϦέʔγϣϯ͕ΑΓݎ࿚ʹͳΔ
    • ͍·ϓϩμΫγϣϯʹೖΕΔͳΒSwinject͕Αͦ͞͏͕ͩɺ
    Cleanse͸ΠϯλϑΣʔε͕Α͘Ͱ͖͍ͯΔͷͰظ଴͍ͨ͠

    View Slide

  38. Improving Existing Apps with Modern Best Practices
    https://developer.apple.com/videos/play/wwdc2016/213/

    View Slide