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

「SOLID原則(一部)」と Testability の関係 iOS 編

Shin Ohno
January 31, 2020

「SOLID原則(一部)」と Testability の関係 iOS 編

YUMEMI.swift #6 テスト書いてる? で話した際のスライドになります。

https://yumemi.connpass.com/event/160329/

Shin Ohno

January 31, 2020
Tweet

More Decks by Shin Ohno

Other Decks in Technology

Transcript

  1. ΞδΣϯμ w ࠓ೔ͷ࿩ͷλʔήοτ w 40-*%ݪଇͱ4561*% w %* 4- OFX w

    %*ݏ͍ͷצҧ͍ w 4XJGUͰͷ%*ͷओͳύλʔϯ w %*Ͱςελϒϧͳ։ൃ΁
  2. 40-*%ݪଇ w 44JOHMFSFTQPOTJCJMJUZQSJODJQMF 431  w 00QFODMPTFEQSJODJQMF 0$1  w

    --JTDPWTVCTUJUVUJPOQSJODJQMF -41  w **OUFSGBDFTFHSFHBUJPOQSJODJQMF *41  w %%FQFOEFODZJOWFSTJPOQSJODJQMF %*1 https://cleancoders.com/videos?series=clean-code&subseries=solid-principles
  3. ݪଇΛकΕ͍ͯͳ͍ͱ w 431͕कΒΕ͍ͯͳ͍ͱ w ҰͭͷΫϥεɺҰͭͷϝιουͰ͍ΖΜͳ৚݅ͷςετΛॻ͘ඞཁ͕͋ Δɻमਖ਼͢ΔࡍͷӨڹൣғ͕େ͖͍ɻ w 0$1͕कΒΕ͍ͯͳ͍ͱ w मਖ਼͢Δ౓ʹΤϯόάͷՄೳੑ͕͋Δ͠ɺӨڹ͕େ͖͍ɻΠϯλʔ

    ϑΣʔεઃܭ͕ϛε͍ͬͯΔɻϞοΫςετ͕ॻ͖ʹ͍͘ɻ w %*1͕कΒΕ͍ͯͳ͍ͱ w ۩ମతͳ࣮૷ʹґଘͯ͠͠·͏ͷͰɺऔΓସ͑ʹ͍͘ɻ·ͨɺ0$1ͷ ҧ൓Λ༠ൃ͢Δɻ
  4. 4561*% w 44JOHMFUPOʢγϯάϧτϯ5ʹͭͳ͕Δʣ w 55JHIU$PVQMJOHʢ͕͜͜ବ໨ͩͱςετॻ͚ͳ͍ʣ w 66OUFTUBCJMJUZʢ5ͷ݁ՌͰ͋Δ͜ͱ͕ଟ͍ʣ w 11SFNBUVSF0QUJNJ[BUJPOʢ࣌ظঘૣͳ࠷దԽʣ w

    **OEFTDSJQUJWF/BNJOHʢΠέͯͳ͍ωʔϛϯάʣ w %%VQMJDBUJPOʢॏෳʣ https://williamdurand.fr/2013/07/30/from-stupid-to-solid-code/ http://nikic.github.io/2011/12/27/Dont-be-STUPID-GRASP-SOLID.html
  5. 40-*%ݪଇͱ4561*% ·ͱΊ w 40-*%ݪଇେࣄ ݪଇΛ஌্ͬͨͰ࠾༻͠ͳ͍͜ͱ΋͋Δ  w զʑͷ࡞͍ͬͯΔιϑτ΢ΣΞ͸Ұ౓࡞ͬͯऴΘΓͰ͸ͳ ͍ɻৼΔ෣͍ͷ࣮૷͕มΘͬͯ΋ྑ͍Α͏ʹ͢Δ΂͖ɻ w

    ૄ݁߹ͳํ͕मਖ਼ʹରͯ͠ɺӨڹൣғΛ཈͑Δ͜ͱ͕Ͱ͖ Δɻີ݁߹͸͔ͳΓະདྷΛಡΉઃܭྗ͕ٻΊΒΕɺ೉͠ ͍ʢυϝΠϯ஌͕ࣝ๛෋Ͱมߋ͠ͳ͍ݻ͞ͷ͋Δ΋ͷͳΒ ͍͚Δ͔΋͘Β͍ʣɻ
  6. %* 4- w ີ݁߹Λආ͚ͯɺૄ݁߹ʹ͢Δύλʔϯ w 4FSWJDF-PDBUPS 4-  w ίϯςφɺϩέʔλʔ͔ΒґଘΛड͚औΔ

    w %FQFOEFODZ*OKFDUJPO %*  w ΠϯλʔϑΣʔεɺϓϩτίϧ͔ΒґଘΛड͚औΔ
  7. Կ͔ॲཧΛ͢ΔαʔϏε Λґଘͤ͞Δ protocol SomethingServiceProtocol: class { func doSomething() } class

    SomethingService: SomethingServiceProtocol { func doSomething() { print("It's never too late to learn.") } } /// γϯάϧτϯͰ static ʹݺͼग़͢৔߹ class SomethingStaticService: SomethingService { static let shared = SomethingStaticService() private override init() { } }
  8. /FXͰੜ੒ ʢີ݁߹ʣ class NewDependency { let service: SomethingServiceProtocol init() {

    service = SomethingService() } func completeWork() { service.doSomething() } } let newDependency = NewDependency() newDependency.completeWork()
  9. TUBUJDͰੜ੒ ʢີ݁߹ʣ class StaticDependency { let service: SomethingServiceProtocol init() {

    service = SomethingStaticService.shared } func completeWork() { service.doSomething() } } let staticDependency = StaticDependency() staticDependency.completeWork()
  10. 4-ʢૄ݁߹ʣ -PDBUPSʹ༧Ίొ࿥ class ServiceLocator { static let shared = ServiceLocator()

    private var container = [String:Any]() private init() { } func register() { container["somethingService"] = SomethingService() } func getSomethingService() -> SomethingServiceProtocol { return container["somethingService"] as! SomethingServiceProtocol } }
  11. 4-ʢૄ݁߹ʣ #VU-PDBUPSʹґଘ class SLDependency { let locator: ServiceLocator init(locator: ServiceLocator)

    { self.locator = locator } func completeWork() { locator.getSomethingService().doSomething() } } ServiceLocator.shared.register() let slDependency = SLDependency(locator: ServiceLocator.shared) slDependency.completeWork()
  12. %*ʢૄ݁߹ʣ ϓϩτίϧʹґଘ class DIDependency { let service: SomethingServiceProtocol init(service: SomethingServiceProtocol)

    { self.service = service } func completeWork() { service.doSomething() } } let diDependency = DIDependency(service: SomethingService()) diDependency.completeWork() ίϯετϥΫλΠϯδΣΫγϣϯ
  13. 7JFX$POUSPMMFS΁ͷґଘղ ܾ͸ٞ࿦͋Γ w 7JFX$POUSPMMFS͕ґଘ͢ΔϚοϓΛ࣋ͭ w %*$ͳͲ ॳظԽॲཧʹ࢓ࠐΉ Λ࢖ͬͯࣗಈతʹηοτ͞ Ε͍ͯΔঢ়ଶΛ࡞ͬͯ͠·͏ w

    %*$ʢ4FSWJDF-PDBUPSʣͷΠϯελϯε͔Β͖࣋ͬͯ ͯɺґଘղܾ͸ͦ͜Ͱߦ͏ɻ ແཧήʔͩ͠ੜ੒͞Ε ͨ΋ͷڞ༗Ͱ͖ͳ͍ʁ Ͳ͜Ͱఆ͍ٛͯ͠Δ͔ Θ͔Γʹ͍͔͘΋ʁ ͋ͷάϩʔόϧͳ γϯάϧτϯΰουʁ
  14. ࣗ෼ͷཱͪҐஔ ཁ͸όϥϯε͓͡͞Μ w 7JFX$POUSPMMFSͳͲॳظԽ͕ίϯτϩʔϧ͠ʹ͍͘΋ͷ ʹ͓͍ͯ͸ɺ%*$ 4FSWJDF-PDBUPS ͔Βґଘ͢ΔαʔϏ εʢ6TF$BTF 7JFX.PEFM౳ʣΛऔಘ͢Δɻ w

    ϩδοΫͷू߹ମͰ͋Δ6TF$BTF૚ɺ4FSWJDF૚ʹ͓͍ͯ ͸ɺ4FSWJDF-PDBUPSͷίϯςφͰ͸ͳ͘ɺ%*ͷϓϩτ ίϧͰґଘ͢ΔαʔϏεΛऔಘ͢Δɻ
  15. $POTUSVDUPS4FUUFS *OKFDUJPO class DIDependency { let service: SomethingServiceProtocol init(service: SomethingServiceProtocol)

    { self.service = service } func completeWork() { service.doSomething() } } let diDependency = DIDependency(service: SomethingService()) diDependency.completeWork()
  16. $BLF1BUUFSO protocol CakePatternProtocol { var service: SomethingServiceProtocol { get }

    func completeWork() } extension CakePatternProtocol { func completeWork() { service.doSomething() } } class Main { } extension Main: CakePatternProtocol { var service: SomethingServiceProtocol { return SomethingService() } } WBSͰఆٛ͢Δͷ͸ͪΐͬͱݏ
  17. ίϯετϥΫλΠϯδΣΫγϣϯ ͷςετ protocol SomethingServiceProtocol: class { func doSomething() -> String

    } class SomethingService: SomethingServiceProtocol { func doSomething() -> String { return "It's never too late to learn." } } let service: SomethingServiceProtocol init(service: SomethingServiceProtocol) { self.service = service } func completeWork() -> String { return "---\(service.doSomething())---" } } ̿SJOU͸͋·Γςετ͸ ҙຯ͕ͳ͍ͷͰɺ 4USJOHΛฦ͢ͷͱ গ͠Ճ޻͢ΔΑ͏ʹ मਖ਼͍ͯ͠·͢
  18. ίϯετϥΫλΠϯδΣΫγϣϯ ͷςετ func testCompleteWorkFailed() { class FailedService: SomethingServiceProtocol { func

    doSomething() -> String { return "FAILED" } } let sut = DIConstructorInjectionDependency(service: FailedService()) XCTAssertNotEqual("FAILED", sut.completeWork()) } func testCompleteWorkSucceeded() { class SuccessService: SomethingServiceProtocol { func doSomething() -> String { return "SUCCEEDED" } } let sut = DIConstructorInjectionDependency(service: SuccessService()) XCTAssertEqual("---SUCCEEDED---", sut.completeWork()) }
  19. $BLF1BUUFSOͷςετ protocol SomethingServiceProtocol: class { func doSomething() -> String }

    protocol CakePatternProtocol { var service: SomethingServiceProtocol { get } func completeWork() -> String } extension CakePatternProtocol { func completeWork() -> String { return "---\(service.doSomething())---" } }
  20. $BLF1BUUFSOͷςετ func testCompleteWorkFailed() { class FailedService: SomethingServiceProtocol { func doSomething()

    -> String { return "FAILED" } } class CakePattern: CakePatternProtocol { var service: SomethingServiceProtocol = FailedService() } let sut = CakePattern() XCTAssertNotEqual("FAILED", sut.completeWork()) } func testCompleteWorkSucceeded() { class SuccessService: SomethingServiceProtocol { func doSomething() -> String { return "SUCCEEDED" } } class CakePattern: CakePatternProtocol { var service: SomethingServiceProtocol = SuccessService() } let sut = CakePattern() XCTAssertEqual("---SUCCEEDED---", sut.completeWork()) }