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

swift_clean_code.pdf

 swift_clean_code.pdf

Presentation about swift clean code

[email protected]

September 06, 2019
Tweet

Other Decks in Programming

Transcript

  1. iOSDC Japan 2019
    2019 9/6(Fri) 13:30~14:00 TrackA
    Swift
    ΫϦʔϯίʔυ
    Ξυϕϯνϟʔɹ
    ~೔ʑͷۤ೰Λ৐Γӽ͑ɺ͔֬ͳબ୒Λ͢ΔͨΊʹ~
    ը૾ͷϦϯΫ

    View Slide

  2. VISITS Technologiesגࣜձࣾ
    [email protected]
    shiz(ͣ͠)
    @shiz
    stzn(shiz)
    ։ൃܦݧݴޠ:
    Swift Kotlin Javascript PHP C#
    Java Go…

    View Slide

  3. ΫϦʔϯ
    ίʔυ
    ը૾ͷϦϯΫ

    View Slide

  4. ΫϦʔϯίʔυ
    ͱ͸ʁ

    View Slide

  5. Robert C. Martin
    (Uncle Bob)
    $MFBO$PEF")BOECPPLPG"HJMF4PGUXBSF$SBGUTNBOTIJQ $MFBO$PEFɹΞδϟΠϧιϑτ΢ΣΞୡਓͷٕ
    https://blog.cleancoder.com

    View Slide

  6. ୡਓͨͪᐌ͘
    ͻͱͭͷ͜ͱΛߦͬͯҙਤ͕໌֬ ෺ޠΛಡΉΑ͏ʹಡΊΔ
    ΤϨΨϯτͰޮ཰͕ྑ͍
    ࣄ࣮ʹଈ͍ͯ͠ͳΕ͹ͳΒͳ͍
    ҙຯΛ໊࣋ͬͨલ͕͋Δ
    ґଘੑ͸࠷௿ݶͰ໌֬ʹఆٛ͞Ε͍ͯΔ
    ಡΉͷʹେ͖ͳ౒ྗ͕ඞཁͳ͍
    ڻ͖͕ͳ͍
    ॏෳΛݮΒ͠ɺදݱྗΛߴΊɺ
    ୯७ͳந৅ԽΛૣ͍࣌ظʹ࡞Γ͋͛Δ
    খ͖͜͞ͱ͸ྑ͖͜ͱ
    ݪ࡞ऀҎ֎ͷਓʹ΋ಡΉ͜ͱ͕Ͱ͖ɺ
    ֦ுͰ͖Δίʔυ
    ৗʹ୭͔͕ؾ഑ΓΛ࣋ͬͯॻ͍͍ͯΔΑ͏ʹݟ͑Δ
    Clean Code ΞδϟΠϧιϑτ΢ΣΞୡਓͷٕ Robert C. Martin(ஶ), ՖҪࢤੜ(༁)

    View Slide

  7. Uncle Bobᐌ͘
    ಡΈ΍͍͢ίʔυ
    Clean Code ΞδϟΠϧιϑτ΢ΣΞୡਓͷٕ Robert C. Martin(ஶ), ՖҪࢤੜ(༁)

    View Slide

  8. ը૾ͷϦϯΫ

    View Slide

  9. ΫϦʔϯίʔυಓ৔
    “զʑࣗ਎͕௕͍ؒɺ͔֬Ͱ͋Δ
    ͱߟ͖͑ͯͨ͜ͱͰ͢ɻԿे೥ʹ
    ౉ΔܦݧͱτϥΠΞϯυΤϥʔͷ
    ੵΈॏͶ͔ΒֶΜͩ΋ͷͰ͢ɻ”
    Clean Code ΞδϟΠϧιϑτ΢ΣΞୡਓͷٕ Robert C. Martin(ஶ), ՖҪࢤੜ(༁)

    View Slide

  10. Θ͔Γ΍͍͢
    ҆શͰ͋Δ
    มߋʹڧ͍

    View Slide

  11. Θ͔Γ΍͍͢
    ҆શͰ͋Δ
    มߋʹڧ͍
    ಡΈ΍͢͞ɺཧղͷ͠΍͢͞ etc
    όά͕ൃੜͮ͠Β͍ɺςετ͕༰қ etc
    मਖ਼࣌ͷӨڹൣғ͕ݶఆత
    ػೳ௥Ճ࣌ͷطଘίʔυ΁ͷӨڹ౓খ etc

    View Slide

  12. Kickstarter
    ߏ଄ͷ౷Ұ(ViewModel Input,Output etc)
    SingletonͰDI؅ཧ(Environment)
    ը໘ભҠͷू໿؅ཧ(Router)
    Playgroundۦಈ։ൃ

    View Slide

  13. Kickstarter ios-oss
    https://github.com/kickstarter/ios-oss
    POINT•FREE
    https://www.pointfree.co/
    objc.io iOS at Kickstarter
    https://talk.objc.io/collections/ios-at-kickstarter
    How to Control the World
    https://vimeo.com/291588126
    Reactive view models, simplified
    https://www.youtube.com/watch?v=uTLG_LgjWGA
    Kickstarter ios-ossߏ੒ͷղઆ
    https://note.mu/yimajo/n/ne44c7945279a
    RxSwiftݚڀಡຊ3 ViewModelઃܭύλʔϯೖ໳
    https://booth.pm/ja/items/1223536
    Kickstarter-iOSͷViewModelͷ࡞Γํ͕΢Ϛ͔ͬͨ
    https://qiita.com/muukii0803/items/045b12405f7acff1a9fd

    View Slide

  14. ΫϦʔϯίʔυΛ
    ॻ͘ʹ͸ʁ

    View Slide

  15. ը૾ͷϦϯΫ

    View Slide

  16. δΣωϦοΫ
    ۩ମతͳσʔλܕʹ௚઀
    ґଘͤͣ൚༻తʹར༻Մ
    ೳͳঢ়ଶ

    View Slide

  17. δΣωϦΫε
    (generics)
    GVODTXBQ5XP7BMVFT
    5 @BJOPVU
    5 @CJOPVU
    5

    GVODTXBQ5XP4USJOHT @BJOPVU4USJOH @CJOPVU4USJOH

    GVODTXBQ5XP%PVCMFT @BJOPVU%PVCMF @CJOPVU%PVCMF

    GVODTXBQ5XP*OUT @BJOPVU*OU @CJOPVU*OU

    https://docs.swift.org/swift-book/LanguageGuide/Generics.html

    View Slide

  18. Protocol
    ը૾ͷϦϯΫ

    View Slide

  19. Protocol
    ίϯύΠϧ࣌
    δΣωϦΫεͷܕ੍໿
    ܕ҆શɾ࠷దԽ
    Static
    ࣮ߦ࣌
    ௚઀ܕͱͯ͠࢖༻
    Dynamic Dispatch
    Dynamic
    func F
    (onlyOneType: P)
    let types:[Protocol]
    = [A(), B(), …]

    View Slide

  20. Protocol
    ίϯύΠϧ࣌
    δΣωϦΫεͷܕ੍໿
    ܕ҆શɾ࠷దԽ
    Static
    ࣮ߦ࣌
    ௚઀ܕͱͯ͠࢖༻
    Dynamic Dispatch
    Dynamic
    func F
    (onlyOneType: P)
    let types:[Protocol]
    = [A(), B(), …]

    View Slide

  21. Protocol
    ίϯύΠϧ࣌
    δΣωϦΫεͷܕ੍໿
    ܕ҆શɾ࠷దԽ
    Static
    ࣮ߦ࣌
    ௚઀ܕͱͯ͠࢖༻
    Dynamic Dispatch
    Dynamic
    func F
    (onlyOneType: P)
    let types:[Protocol]
    = [A(), B(), …]

    View Slide

  22. Start With
    a Protocol
    ϓϩτίϧ͔Β࢝ΊΑ
    Protocol-Oriented Programming in Swift WWDC2015

    View Slide

  23. Start With
    a Protocol
    For Everything?
    ͢΂ͯϓϩτίϧ͔Β࢝ΊΑ?

    View Slide

  24. if you want to write a
    generalized sort or
    binary search…Don’t
    start with a class. Start
    with a protocol.
    Protocol-Oriented Programming in Swift WWDC2015

    View Slide

  25. use value types, then if
    you need polymorphism,
    make them conform to
    protocols. Avoid classes.
    https://twitter.com/cocoaphony/status/1104114233288151043
    ϙϦϞʔϑΟζϜ
    ಉ໊͡લͷϝιουΛෳ਺ͷΫϥεͰ࢖༻Ͱ͖ΔΑ͏ʹ͠ɺͦͷϝ
    ιουΛ௨ͯ͠ɺ҉໧తʹෳ਺ͷΠϯελϯεͷಈ࡞Λ੾Γସ͑Δ
    ͜ͱ͕Ͱ͖ΔΑ͏ʹ͢Δ͜ͱ

    View Slide

  26. …we considered a varied number of concrete
    types first. …we’re thinking about a kind of
    protocol that could join them all together. …it’s
    important to think of things as this way around.
    To start with some
    concrete types, and then
    try and unify them with a
    protocol.
    Swift Generics (Expanded) WWDC2018

    View Slide

  27. Don’t Literally
    Start With a Protocol
    Start with a concrete use cases
    Discover a need for generic code
    Try to compose solutions from
    existing protocols first
    Consider a generic type instead of a
    protocol
    Modern Swift API Design WWDC2019

    View Slide

  28. ۩ମతղܾ
    ໰୊
    δΣωϦοΫͳղܾ
    ໰୊ ໰୊
    ໰୊
    ݸʑͷ۩ମత໰୊Λղܾ͠
    δΣωϦοΫͳղܾࡦΛநग़
    ۩ମతղܾ
    ໰୊

    View Slide

  29. ը૾ͷϦϯΫ

    View Slide

  30. struct Item: Codable {
    let id: Int
    let name: String
    }
    struct User: Codable {
    let id: Int
    let name: String
    }
    struct Client {
    let baseURL = URL(string: “…”)!
    }

    View Slide

  31. extension Client {
    func fetchItem(id: Int,
    completion: @escaping
    (Result) -> Void) {
    let urlRequest = URLRequest(url: baseURL
    .appendingPathComponent(“items")
    .appendingPathComponent("\(id)")
    )
    let session = URLSession.shared
    session.dataTask(with: urlRequest) { (data, _, error) in
    if let error = error {
    completion(.failure(error))
    } else if let data = data {
    let decoder = JSONDecoder()
    completion(Result {
    try decoder.decode(Item.self, from: data) })
    }
    }.resume()
    }
    }

    View Slide

  32. extension Client {
    func fetchItem(id: Int,
    completion: @escaping
    (Result) -> Void)
    {
    let urlRequest = URLRequest(url: baseURL
    .appendingPathComponent("items")
    .appendingPathComponent("\(id)")
    )
    }
    }

    View Slide

  33. extension Client {
    func fetchItem(id: Int,
    completion: @escaping
    (Result) -> Void)
    {

    let session = URLSession.shared
    session.dataTask(with: urlRequest) {

    }.resume()

    View Slide

  34. extension Client {
    func fetchItem(id: Int,
    completion: @escaping
    (Result) -> Void)
    {

    let decoder = JSONDecoder()
    completion(Result {
    try decoder.decode(Item.self,
    from: data)
    })
    }
    }

    View Slide

  35. extension Client {
    func fetchUser(id: Int,
    completion: @escaping
    (Result) -> Void)
    {
    let urlRequest = URLRequest(url: baseURL
    .appendingPathComponent(“users")
    .appendingPathComponent("\(id)")
    )
    let session = URLSession.shared
    session.dataTask(with: urlRequest) {
    (data, _, error) in
    if let error = error {
    completion(.failure(error))
    }
    else if let data = data {
    let decoder = JSONDecoder()
    completion(Result {
    try decoder.decode(User.self,
    from: data)
    })
    }
    }.resume()
    }
    }

    View Slide

  36. extension Client {

    func fetch
    Item(id: Int,

    completion:

    @escaping (Result<
    Item, Error>) -> Void)

    {

    let urlRequest = URLRequest(url: baseURL

    .appendingPathComponent("
    items")

    .appendingPathComponent("\(id)")

    )

    let session = URLSession.shared

    session.dataTask(with: urlRequest) {

    (data, _, error) in

    if let error = error {

    completion(.failure(error))

    }

    else if let data = data {

    let decoder = JSONDecoder()

    completion(Result {

    try decoder.decode(
    Item.self,

    from: data)

    })

    }

    }.resume()

    }

    }
    extension Client {

    func fetch
    User(id: Int,

    completion:

    @escaping (Result<
    User, Error>) -> Void)

    {

    let urlRequest = URLRequest(url: baseURL

    .appendingPathComponent("
    users")

    .appendingPathComponent("\(id)")

    )

    let session = URLSession.shared

    session.dataTask(with: urlRequest) {

    (data, _, error) in

    if let error = error {

    completion(.failure(error))

    }

    else if let data = data {

    let decoder = JSONDecoder()

    completion(Result {

    try decoder.decode(
    User.self,

    from: data)

    })

    }

    }.resume()

    }

    }

    View Slide

  37. extension Client {

    func fetch(

    _: Model.Type,

    id: Int,

    completion: @escaping

    (Result) -> Void) {



    let decoder = JSONDecoder()

    completion(Result {

    try decoder.decode(Model.self,

    from: data)

    }

    }

    View Slide

  38. extension Client {

    func fetch(

    _: Model.Type,

    }

    }

    Client().fetch(id: 1) { … }

    Client().fetch(id: 1) {

    (result: Result) … }

    View Slide

  39. Client().fetch(id: 1) {
    (result: Result) …
    }

    View Slide

  40. Client().fetch(User.self, id: 1) { … }

    View Slide

  41. extension Client {
    func fetch(
    …) {
    let urlRequest = URLRequest(url: baseURL
    .appendingPathComponent(“???”)
    .appendingPathComponent(“\(id)")
    )
    }
    }

    View Slide

  42. protocol Fetchable: Decodable {
    static var apiBase: String { get }
    }

    View Slide

  43. extension User: Fetchable {

    static var apiBase: String { return "users" }
    }

    extension Item: Fetchable {

    static var apiBase: String { return “items" }
    }

    View Slide

  44. let urlRequest = URLRequest(url: baseURL

    .appendingPathComponent(Model.apiBase)

    View Slide

  45. extension User: Fetchable {

    static var apiBase: String { return "users" }

    }

    extension Item: Fetchable {

    static var apiBase: String { return “items" }

    }

    View Slide

  46. Retroactive
    Modeling
    ݩͷιʔεʹΞΫηε͢
    Δ͜ͱ͕Ͱ͖ͳ͍ܕͰ΋
    ػೳΛ֦ு͢Δ͜ͱ͕Ͱ
    ͖Δೳྗ
    The swift programming language swift 5.1

    View Slide

  47. ը૾ͷϦϯΫ

    View Slide

  48. extension Client {

    func fetch(

    _: Model.Type, id: Int,

    completion: @escaping (Result) -> Void) {

    let urlRequest = URLRequest(url: baseURL

    .appendingPathComponent(Model.apiBase)

    .appendingPathComponent(“\(id)")

    )

    let session = URLSession.shared
    session.dataTask(with: urlRequest) {

    }.resume()
    }

    }

    View Slide

  49. protocol URLSessionProtocol {

    func dataTask(with request: URLRequest,
    completionHandler: @escaping
    (Data?, URLResponse?, Error?) -> Void)
    -> URLSessionDataTask
    }

    extension URLSession: URLSessionProtocol {}

    View Slide

  50. struct Client {

    let session: URLSessionProtocol
    init(session: URLSessionProtocol) {
    self.session = session
    }
    }

    View Slide

  51. MockͷͨΊͷ
    Protocol
    Mock
    ΦϒδΣΫτͷ໛฿
    Protocol
    δΣωϦοΫͳ໰୊ղܾ

    View Slide

  52. protocol URLSessionProtocol {

    func dataTask(

    with request: URLRequest,

    completionHandler: @escaping

    (Data?, URLResponse?, Error?) -> Void)

    -> URLSessionDataTask

    }

    View Slide

  53. protocol Transport {

    func send(request: URLRequest,

    completion: @escaping

    (Result) -> Void)

    }
    URLRequest -> Result

    View Slide

  54. struct Client {

    let transport: Transport
    init(transport: Transport) {
    self.transport = transport
    }
    }

    func fetch(

    transport.send(request: urlRequest) {



    return try decoder.decode(Model.self,

    from: result.get())

    View Slide

  55. extension URLSession: Transport {

    func send(request: URLRequest,

    completion: @escaping

    (Result) -> Void) {

    dataTask(with: request) { (data, _, error) in

    if let error = error {

    return completion(.failure(error))

    }

    if let data = data {

    completion(.success(data))

    }

    }.resume()

    }

    }

    View Slide

  56. extension URLSession: Transport {

    func send(request: URLRequest,

    completion:

    @escaping (Result) -> Void) {

    }

    }
    Retroactive Modeling

    View Slide

  57. struct Client {
    init(
    transport: Transport = URLSession.shared
    ) { … }
    }
    let client = Client()

    View Slide

  58. sendϝιου͕།Ұͷػೳ
    Foundation಺ͷܕͷΈΛ࢖༻
    URLRequest, Result
    Transport

    View Slide

  59. struct TransportWithToken: Transport {

    let base: Transport

    let token: String

    func send(request: URLRequest,

    completion: @escaping

    (Result) -> Void) {

    var newRequest = request
    newRequest.addValue(token,
    forHTTPHeaderField: "token")
    base.fetch(request: newRequest,
    completion: completion)
    }

    }

    View Slide

  60. final class TestTransport: Transport {

    var requests: [Any] = []
    var responseData: [Data]
    init(responseData: [Data]) {
    self.responseData = responseData
    }
    func send(…) {

    requests.append(request)
    guard let data
    = responseData.removeFirst() else {
    return completion(.success(data))
    }
    completion(.failure(…))


    View Slide

  61. protocol Request {
    associatedtype Response: Fetchable
    var baseURL: URL { get }
    var path: String { get }
    var httpMethod: HTTPMethod { get }
    var parameters: [String: Any] { get }
    }

    View Slide

  62. protocol Request {
    associatedtype Response: Fetchable
    var baseURL: URL { get }
    var path: String { get }
    var httpMethod: HTTPMethod { get }
    var parameters: [String: Any] { get }
    }

    View Slide

  63. protocol Transport {
    func fetch(request: Request)
    }
    ※associatedtype·ͨ͸SelfΛ࢖͏Protocol͸
    δΣωϦΫεͷ੍໿ͱͯ͠࢖༻Ͱ͖Δ͕
    ௚઀ܕͱͯ͠࢖༻Ͱ͖ͳ͘ͳΔ
    PAT(Protocol With AssociatedType)※

    View Slide

  64. protocol Transport {
    func fetch(request: R)
    }

    View Slide

  65. extension Client {

    func multiFetch(requests: [R]) {

    for request in requests {

    transport.send(request: request)

    }

    }

    }

    View Slide

  66. ͜ͷProtocol͸
    ഑ྻͱͯ͠࢖͏͔ʁ

    View Slide

  67. protocol Request {
    func makeURLRequest()
    throws -> URLRequest
    }
    protocol Transport {
    func send(request: Request,
    completion: @escaping
    (Result) -> Void)
    }

    View Slide

  68. struct TransportWithTokenRequest: Request {
    let base: Request
    let token: String
    func makeURLRequest() throws -> URLRequest {
    var newRequest = try base.makeURLRequest()
    newRequest.addValue(token,
    forHTTPHeaderField: "token")
    return newRequest
    }
    }

    View Slide

  69. protocol Request {
    func makeURLRequest()
    throws -> URLRequest
    }
    ʁ

    View Slide

  70. ՄೳͳݶΓ
    δΣωϦοΫʹ

    View Slide

  71. ը૾ͷϦϯΫ

    View Slide

  72. ը૾ͷϦϯΫ

    View Slide

  73. struct Item: Codable {

    let id: Int

    let name: String

    }

    struct User: Codable {

    let id: Int

    let name: String

    }

    View Slide

  74. let itemId = 1
    client.fetch(User.Type, id: itemId) { … }

    View Slide

  75. struct Item: Codable {

    let id: String
    let name: String

    }

    func fetch(

    _: Model.Type,

    id: Int,



    View Slide

  76. protocol Identifiable: Codable, Hashable {
    associatedtype Value
    var value: Value { get }
    init(value: Value)
    }
    extension Identifiable {
    init(_ value: Value) { self.init(value: value) }
    }

    View Slide

  77. protocol Identifiable: Codable, Hashable {
    associatedtype Value
    var value: Value { get }
    init(value: Value)
    }

    View Slide

  78. let ids: [Identifiable] = [
    User.ID(1),
    Item.ID(“item-1”)
    ]
    PAT(Protocol With AssociatedType)

    View Slide

  79. ͜ͷProtocol͸
    ഑ྻͱͯ͠࢖͏͔ʁ

    View Slide

  80. protocol Fetchable: Decodable {
    associatedtype ID: Identifiable
    }

    View Slide

  81. struct Item: Codable {

    struct ID: Identifiable { let value: String }
    let id: ID
    }

    struct User: Codable {

    struct ID: Identifiable { let value: Int }
    let id: ID
    }

    View Slide

  82. func fetch(

    _: Model.Type,

    id: Model.ID,


    View Slide

  83. struct Item: Codable {

    struct ID: Identifiable { let value: String }
    let id: ID

    }

    struct User: Codable {

    struct ID: Identifiable { let value: Int }
    let id: ID

    }

    View Slide

  84. func fetch(
    _: Model.Type,
    id: Model.ID,

    View Slide

  85. struct Item: Codable {
    struct ID: Identifiable { let value: String }
    let id: ID
    }
    struct User: Codable {
    struct ID: Identifiable { let value: Int }
    let id: ID
    }

    View Slide

  86. struct Identifier
    where Value: Codable & Hashable {
    let value: Value
    init(_ value: Value) { self.value = value }
    }
    extension Identifier: Codable, Hashable { … }

    View Slide

  87. protocol Fetchable: Decodable {

    static var apiBase: String { get }

    associatedtype IDType: Codable & Hashable
    typealias ID = Identifier
    var id: ID { get }
    }

    View Slide

  88. struct Item: Codable {
    typealias ID = Identifier
    var id: ID { get }
    }
    struct User: Codable {
    typealias ID = Identifier
    var id: ID { get }
    }

    View Slide

  89. func fetch(
    _: Model.Type,
    id: Model.ID,

    View Slide

  90. protocol Fetchable: Decodable {
    associatedtype IDType: Codable
    typealias ID = Identifier
    var id: ID { get }
    static var apiBase: String { get }
    }
    ࣝผࢠ(Identifier)Λ࣋ͭ
    +
    API͔Βσʔλऔಘ

    View Slide

  91. struct Item: Codable {
    typealias = Identifier
    let id: ID
    }
    struct User: Codable {
    typealias = Identifier
    let id: ID
    }

    View Slide

  92. protocol Identifiable: Codable {
    associatedtype IDType: Codable & Hashable
    typealias ID = Identifier
    var id: ID { get }
    }

    View Slide

  93. protocol Fetchable: Identifiable {
    static var apiBase: String { get }
    }

    View Slide

  94. protocol Identifiable: Codable {
    associatedtype IDType: Codable & Hashable
    typealias ID = Identifier
    var id: ID { get }
    }
    protocol Fetchable: Identifiable {
    static var apiBase: String { get }
    }
    ࣝผࢠ(Identifier)Λ࣋ͭ
    IDΛ࢖ͬͯAPI͔Βσʔλऔಘ

    View Slide

  95. struct Item: Identifiable {
    typealias IDType = String
    let id: ID

    }
    struct User: Identifiable {
    typealias IDType = Int
    let id: ID

    }

    View Slide

  96. POP
    Protocol Oriented
    Programming
    Obsessed
    ※ Obsessed औΓጪ͔ΕΔ

    View Slide

  97. Don’t Literally
    Start With a Protocol
    Modern Swift API Design WWDC2019
    Start with a concrete use cases
    Discover a need for generic code
    Try to compose solutions from existing
    protocols first
    Consider a generic type
    instead of a protocol

    View Slide

  98. ۩ମతղܾ -> δΣωϦοΫ
    ղܾํ๏Λཧղͯ͠બ୒
    Θ͔Γ΍͍͢ɺ҆શͰ͋Δ
    มߋʹڧ͍

    View Slide

  99. ը૾ͷϦϯΫ

    View Slide

  100. ΫϦʔϯίʔυΛ
    ॻ͖ଓ͚Δʹ͸ʁ

    View Slide

  101. ϘʔΠεΧ΢τͷنଇ
    ίʔυΛܧଓతʹ
    վળ͍ͯ͘͠ϓϩҙࣝ
    ίʔυ͸Կ౓΋ચ࿅͠ͳ͚Ε͹ͳ
    Γ·ͤΜ
    Clean Code ΞδϟΠϧιϑτ΢ΣΞୡਓͷٕ Robert C. Martin(ஶ), ՖҪࢤੜ(༁)

    View Slide

  102. Ձ஋ମܥ˞͕ͦ͜໨ඪ
    Ͱ͋Γɺ͜ͷຊͷ
    ςʔϚͩͬͨͷͰ͢ɻ
    Clean Code ΞδϟΠϧιϑτ΢ΣΞୡਓͷٕ Robert C. Martin(ஶ), ՖҪࢤੜ(༁)
    ※ࢥߟɾߦಈ͢Δࡍͷ͋Δಛఆͷ
    ྖҬʹ͓͚ΔՁ஋؍ɾ൑அج४

    View Slide

  103. ը૾ͷϦϯΫ

    View Slide

  104. View Slide

  105. Configurable types
    ~ࣅͯඇͳΔίʔυΛڞ௨ʹѻ͏~
    https://qiita.com/shiz/items/849e483338bd568cb6ab
    ۩ମతͳίʔυ͔Β࢝ΊΑ
    ~ࠓͷ໰୊Λղܾ͠ɺδΣωϦοΫͳίʔυΛݟग़͢~
    https://qiita.com/shiz/items/5755a35887bcb7897464
    มԽʹରԠ͠ຊ࣭Λ࠶ൃݟ͢Δ
    https://qiita.com/shiz/items/7b3bda7c2d84c5a83c0f
    Kickstarter͔ΒֶͿ
    ~ΑΓྑ͍։ൃΛ໨ࢦͨ͢Ίͷ࢓૊Έͱ͸ʁ~
    https://qiita.com/shiz/items/79c7b39f94f32e548df3
    Protocol͸ߏจͷೖΕ෺Ҏ্ͷଘࡏͰ͋Δ
    https://qiita.com/shiz/items/da71d547b59c757cca94
    ิ଍هࣄ

    View Slide

  106. ͋Γ͕ͱ͏͍͟͝·ͨ͠
    ը૾ͷϦϯΫ

    View Slide

  107. Kickstarter ios-oss
    Star with a protocol
    A mockery of protocols
    That’s not a number
    From Problem to Solution
    Protocol-Oriented Programming in Swift
    Swift Generics (Expanded)
    ࢀߟϦϯΫू

    View Slide

  108. Modern Swift API Design
    The swift programming language swift 5.1 Exrtesions
    Protocols are more than Bags of Syntax
    Configurable types in Swift
    ࢀߟϦϯΫू

    View Slide