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

よりよいネーミングを目指して / 20171003 #orecon_ios #akibaswift

takasek
October 03, 2017

よりよいネーミングを目指して / 20171003 #orecon_ios #akibaswift

俺コン Vol.1 / Day. 2 - connpass
https://orecon.connpass.com/event/64285/
での発表資料です。

# 参考資料

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice) | Dustin Boswell, Trevor Foucher, 須藤 功平, 角 征典 |本 | 通販 | Amazon
https://www.amazon.co.jp/dp/4873115655

Amazon | 新装版 リファクタリング―既存のコードを安全に改善する― (OBJECT TECHNOLOGY SERIES) | Martin Fowler, 児玉 公信, 友野 晶夫, 平澤 章, 梅澤 真史 通販
https://www.amazon.co.jp/dp/427405019X

takasek

October 03, 2017
Tweet

More Decks by takasek

Other Decks in Programming

Transcript

  1. 3

  2. 4

  3. 4 update() Ͱಛఆͷ৚݅Ͱ͸updateͤͣʹ໭ Δ 4 σʔλߋ৽ޙ΋ը໘͸ߋ৽͞Εͳ͍… ͱࢥͬͨΒॲཧ్͕தͰguard͞Εͯͨ ! 4 fetch()

    ͱ͍͍ͭͭUIͷߋ৽΋ͯ͠Δ 4 ࢥΘ͵࣌ʹදࣔ͞ΕΔAlert ⚠ 4 ໊લʹࠔͬͯ func didReceive(hoge: Hoge) 4 isFetching: Bool ͷ؅ཧՕॴ͕෼ࢄʂ # 11
  4. ʮ໊લʹ৘ใΛ٧ΊࠐΉʯ 2 1. ໌֬ͳ୯ޠΛબͿ 2. ൚༻తͳ໊લΛආ͚Δʢ͋Δ͍ ͸ɺ࢖͏ঢ়گΛબͿʣ 3. ந৅తͳ໊લΑΓ΋۩ମతͳ໊લ Λ࢖͏

    4. ઀ඌࣙ΍઀಄ࣙΛ࢖ͬͯ৘ใΛ௥ Ճ͢Δ 5. ໊લͷ௕͞ΛܾΊΔ 6. ໊લͷϑΥʔϚοτͰ৘ใΛ఻͑Δ 2 ʮϦʔμϒϧίʔυʯDustin Boswell, Trevor Foucher, 2012 P10 15
  5. ʮ໊લʹ৘ใΛ٧ΊࠐΉʯᶃ ໌֬ͳ୯ޠΛબͿ ❌ employees.remove(x) view.dismiss(false) let text = words.split(12) ⭕

    employees.remove(at: x) view.dismiss(animated: false) let text = words.split(maxSplits: 12) 17
  6. ʮ໊લʹ৘ใΛ٧ΊࠐΉʯᶄ ൚༻తͳ໊લΛආ͚Δ ʢ͋Δ͍͸ɺ࢖͏ঢ়گΛબͿʣ ❌ final class HogeViewController { private let

    margin: CGFloat = 2.0 private let defaultSize = CGSize(width: 100, height: 50) ... } !ԿͷϚʔδϯͱαΠζ΍ͶΜ 18
  7. ʮ໊લʹ৘ใΛ٧ΊࠐΉʯᶄ ൚༻తͳ໊લΛආ͚Δ ʢ͋Δ͍͸ɺ࢖͏ঢ়گΛબͿʣ ⭕ func calculateComponentWidth (paralleling contentSizes: [CGSize]) ->

    CGFloat { return contentSizes.reduce(margin) { result, size in let margin: CGFloat = 2 result + size.width + margin } } !Ͱ΋͜ΕͳΒڐͤΔɻείʔϓ͕ڱ͍ͷͰɻ 19
  8. ʮ໊લʹ৘ใΛ٧ΊࠐΉʯᶄ ൚༻తͳ໊લΛආ͚Δ ʢ͋Δ͍͸ɺ࢖͏ঢ়گΛબͿʣ ⭕ var userID: Int? { switch self.userState

    { case .id(id): return id case .entity(e): return e.id case .unavailable: return nil } } ͋͑ͯࡶͳ໊લΛ͚ͭͯʮҰ࣌తͳ΋ͷʯͩͱࣔ͢ 20
  9. ʮ໊લʹ৘ใΛ٧ΊࠐΉʯᶅ ந৅తͳ໊લΑΓ΋ ۩ମతͳ໊લΛ࢖͏ ❌ class HogeListViewController : UIViewController { ...

    func fetch() func fetchBackground() func fetchReally(_ id: String, show: Bool) ... } ͲΕ͕Ͳ͏͍͏໾ׂʁ! 21
  10. class HogeListViewController : UIViewController { /// ௨৴ͯ͠ɺࣦഊͨ͠ΒΞϥʔτΛදࣔ͢Δ func fetch() {

    fetchReally(textField.text!, show: true) } /// ௨৴ͯ͠ɺࣦഊͯ͠΋Ξϥʔτ͸දࣔ͠ͳ͍ func fetchBackground() { fetchReally(textField.text!, show: false) // !Ͳ͏΍ΒʮΞϥʔτΛදࣔ͠ͳ͍ʯ͔Βbackgroundͱ͍͏Β͍͠ɻӕͩΖ!? } func fetchReally(_ id: String, show: Bool) { api.fetch(id) { [weak self] models in self?.didReceive(models: models, showsAlertIfFailed: show) } // !ʮ۩ମతͳ௨৴ॲཧ͕ॻ͍ͯ͋Δʯ͔Βreallyͱ͍͏Β͍͠ } } 22
  11. ʮ໊લʹ৘ใΛ٧ΊࠐΉʯᶅ ந৅తͳ໊લΑΓ΋ ۩ମతͳ໊લΛ࢖͏ ❌ func fetch() func fetchBackground() func fetchReally(_

    id: String, show: Bool) ⭕ func startFetchingHogesWithFailureAlert() func startFetchingHogesWithoutFailureAlert() func fetchHoges(withID id: String, showsAlertIfFailed: Bool) 23
  12. ʮ໊લʹ৘ใΛ٧ΊࠐΉʯᶆ ઀ඌࣙ΍઀಄ࣙΛ࢖ͬͯ ৘ใΛ௥Ճ͢Δ ❌ let text1 = "100%25%E5%8B%87%E6%B0%97" let text2

    = text1.removingPercentEncoding! // "100%༐ؾ" let text3 = text2.removingPercentEncoding! // CRASH" ⭕ let encodedText = "100%25%E5%8B%87%E6%B0%97" let decodedText = encodedText.removingPercentEncoding! // "100%༐ؾ" // ΋͏$͸decodeࡁΈͩͱΘ͔Δ 24
  13. Swift ͷ API design guideline ʹै͏ https://swift.org/documentation/api-design-guidelines/#naming 4 ྲྀெͳӳจʹݟ͑ΔΑ͏ʹ 4

    ม਺ɾҾ਺ɾ෇ଐܕͷωʔϛϯά͸ɺͦͷ੍໿ΑΓ΋໾ׂʹԠͯ͡ߦ͏ 4 ϝιου໊ͷ඼ࢺΛɺ෭࡞༻͋Δͳ͠ͰมԽͤ͞Δ 4 ෭࡞༻ͳ͠: ໊ࢺɺಈࢺͷաڈ෼ࢺɺݱࡏ෼ࢺΛ࢖͏ 4 e.g. array.sorted 4 ෭࡞༻͋Γ: ಈࢺͷ໋ྩܗΛ࢖͏ɻ͋Δ͍͸ form Λ಄ʹ͚ͭΔ 4 e.g. array.sort ɹ/ɹ y.formUnion() 4 લྫΛ࠾༻͠·͠ΐ͏ 4 etc... 30
  14. Swift Foundation / Cocoaͷྲّྀʹ ै͏ API design guidelineͷ "લྫΛ࠾༻͠·͠ΐ͏" Λ࠾༻͠·͠ΐ͏

    4 Bool ܕ ͸ isʙ ɺcanʙ ɺneedsʙ ͳͲͰ࢝·Δ 4 delegate ϝιουͷ໊෇͚ํ 4 ❌ func willBlog(_ blog: Blog) ⭕ func atendeeWillBlog(_ blog: Blog) 4 APIΛશମݕࡧͰ͖ΔΑ͏ʹ͓ͯ͘͠ͱศར 4 https://developer.apple.com/search/?q={query} &type=Reference 31
  15. class HogeListViewController : UIViewController { ... func startFetchingHogesWithFailureAlert() { fetchHoges(withID:

    textField.text!, showsAlertIfFailed: true) } func startFetchingHogesWithoutFailureAlert() { fetchHoges(withID: textField.text!, showsAlertIfFailed: false) } func fetchHoges(withID id: String, showsAlertIfFailed: Bool) { api.fetchHoges(withID: id) { [weak self] hoges in self?.didReceive( hoges: hoges, showsAlertIfFailed: showsAlertIfFailed ) } } ... } 33
  16. ద੾ͳωʔϛϯά͕Ͱ͖ͳ͍ྫᶃ ඇಉظॲཧ func fetchHoges(withID id: String, showsAlertIfFailed: Bool) { api.fetchHoges(withID:

    id) { [weak self] hoges in self?.didReceive( hoges: hoges, showsAlertIfFailed: showsAlertIfFailed ) } } !fetchޙͷ׬ྃॲཧ΋୲͍ͬͯΔΜ͔ͩΒɺ ɹfetch ͬͯϝιου໊͚ͩͰ͸͓͔͘͠ͳ͍ʁ 34
  17. ద੾ͳωʔϛϯά͕Ͱ͖ͳ͍ྫᶃ ඇಉظॲཧ ඇಉظॲཧ͸ callback ΍ Promiseύλʔϯ Λ࢖ͬͯ Α͏΍͘ਖ਼͘͠ݴ͍දͤΔ ! func

    fetchHoges(withID id: String, showsAlertIfFailed: Bool) "callback func fetchHoges(withID id: String, completion: ([Hoge] -> Void)) #promise func fetchHoges(withID id: String) -> RxSwift.Single<[Hoge]> 37
  18. ద੾ͳωʔϛϯά͕Ͱ͖ͳ͍ྫᶄ ʁʁʁʁʁʁʁʁʁ func postProfileWith(name: String?, address: String?, tel: String?, profileImage:

    UIImage?, profileImageURL: URL?) -> RxSwift.Single<Bool> γϯϓϧͰ෼͔Γ΍͍͢ϝιου໊… 38
  19. ద੾ͳωʔϛϯά͕Ͱ͖ͳ͍ྫᶄ ʁʁʁʁʁʁʁʁʁ func postProfileWith(name: String?, address: String?, tel: String?, profileImage:

    UIImage?, profileImageURL: URL?) -> RxSwift.Single<Bool> γϯϓϧͰ෼͔Γ΍͍͢ϝιου໊… ͬͯɺຊ౰ʁ 39
  20. ద੾ͳωʔϛϯά͕Ͱ͖ͳ͍ྫᶄ Ҿ਺ͷදݱྗ͕ऑ͍ func postProfileWith(name: String?, address: String?, tel: String?, profileImage:

    UIImage?, profileImageURL: URL?) -> RxSwift.Single<Bool> 4 Optional͹͔Γ͚ͩͲɺඞਢύϥϝʔλ͸Կͳͷ͔ 4 tel ☎ ͸Ͳ͏͍͏ϑΥʔϚοτͰจࣈྻԽ͢Ε͹͍͍ͷ͔ 4 Կނ profileImage ͱ profileImageURL ͕྆ํ͋Δͷ͔ɻͲͪ Β΋౉ͨ͠Βɺ͋Δ͍͸ͲͪΒ΋౉͞ͳ͔ͬͨΒͲ͏ͳΔͷ͔ɻ 40
  21. Ҿ਺ͷදݱྗΛߴΊΔ func postProfileWith(name: String?, address: String?, tel: String?, profileImage: UIImage?,

    profileImageURL: URL?) -> RxSwift.Single<Bool> ɹɹɹɹɹɹɹɹɹɹɹɹɹɹɹ! func postProfileWith(textData: ProfileTextData?, imageData: ProfileImageData) -> RxSwift.Single<Bool> 42
  22. // ͢΂ͯͷཁૉ͕ඞཁͳ৔߹ (AND) ͸ struct ͰදݱͰ͖Δ struct ProfileTextData { let

    name: String let address: String let tel: Tel? } // ͍ͣΕ͔ͷཁૉ͕ඞཁͳ৔߹ (OR) ͸ enum ͰදݱͰ͖Δ enum ProfileImageData { case image(UIImage) case url(URL) } 43
  23. Ҿ਺ͷදݱྗΛߴΊΔ func postProfileWith(textData: ProfileTextData?, imageData: ProfileImageData) -> RxSwift.Single<Bool> 4 ProfileTextData

    (name & address & tel?) ͸ 4 ἧ͑ͯ౉͢ or ׬શεϧʔ 4 ProfileImageData (UIImage | URL) ͸ 4 ͍ͣΕ͔Λ౉͢ ͳΔ΄Ͳʂ! 44
  24. ʮϝιουΦϒδΣΫτʯ ϝιουࣗ਎ → ໊ࢺԽͯ͠ܕ(ΦϒδΣΫτ) ʹ શͯͷϩʔΧϧม਺ → ܕͷϓϩύςΟ ʹ ϝιου

    → ܕ಺ͷϝιου܈ ʹ class ProfilePoster { let textData: ProfileTextData? let imageData: ProfileImageData func run() -> RxSwift.Single<Bool> private func ... } 49
  25. ʮಛੑͷԣ࿀ูʯ ʢ͋Δϝιου͕ɺࣗ෼ͷΫϥεΑΓ΋ଞͷΫϥεʹڵຯΛ࣋ͭʯঢ়ଶʣ ❌ class ProfilePoster { ... private func isTelValid(tel:

    String) -> Bool { return (try! NSRegularExpression(pattern: "^[0-9]+-[0-9]+-[0-9]+$")) .firstMatch(in: tel, range: NSRange( location: 0, length: (tel as NSString).length )) != nil } } ※isTelValid(tel:) ͷڵຯ͸ ʮϓϩϑΟʔϧͷฤूը໘ʯͰ͸ͳ͘ʮ☎ి࿩൪߸ʯ 50
  26. ʮಛੑͷԣ࿀ูʯ ʢ͋Δϝιου͕ɺࣗ෼ͷΫϥεΑΓ΋ଞͷΫϥεʹڵຯΛ࣋ͭʯঢ়ଶʣ ☎͕ڵຯͷத৺Ͱ͋ΔܕΛ࡞Γɺ isTelValid(tel:) ΛҠಈ ⭕ struct Tel { let

    value: String var isValid: Bool { return try! value.matches(pattern: "^[0-9]+-[0-9]+-[0-9]+$") // ※ String.matches(pattern:) ͸ String ʹੜ΍ͨ͠ extension } } 51
  27. ओޠͱͳΔܕʹॲཧΛୗ͢͜ͱͰɺ ໌ྎ؆ܿͳωʔϛϯάʹͳΔ !before! ProfilePoster.isTelValid(tel: String) -> Bool "after" Tel.isValid: Bool

    4 ॲཧର৅͕selfͱͳΔ 4 ϝιουج෦ʹॻ͍͍ͯͨॲཧର৅Λɺܕࣗ਎͕આ໌ͯ͘͠Ε Δ 4 ॲཧର৅Λ͋ΒΘ͢Ҿ਺΋ফ͑Δ 52
  28. ͪͳΈʹ Tel.isValid: Bool ΑΓ΋ྑ͍ઃܭ: init࣌ʹόϦσʔτͯ͠ɺͦ΋ͦ΋ෆਖ਼ͳ Tel ܕ Λ࡞Εͳ͍Α͏ʹ͢Δ struct Tel

    { enum Error: Swift.Error { case invalidFormat } let value: String init(value: String) throws { guard try value.matches(pattern: "^[0-9]+-[0-9]+-[0-9]+$") else { throw Error.invalidFormat } self.value = value } } 53
  29. returns Optional vs throws struct Tel { enum Error: Swift.Error

    { case invalidFormat } let value: String ! init(value: String) throws { guard try value.matches(pattern: "^[0-9]+-[0-9]+-[0-9]+$") else { throw Error.invalidFormat } self.value = value } } init?(value: String) ͱ͍͏ख΋͋Δ͚Ͳ…ʁ 59
  30. returns Optional vs throws returns Optional 4 ! ͓खܰ؆୯ʹѻ͑Δ 4

    " ෇Ճ৘ใ͕๡͍͠ ྫ֎ॲཧ(throws) 4 !ʮࣦഊ͠͏Δʯ͜ͱΛ໌֬ʹදͤΔ 4 ! try? ߏจͰOptionalʹม׵Մೳ 4 ! Error Λఆٛͯ͠ࡉ΍͔ʹࣦഊݪҼΛ఻͑ΒΕΔ 4 " Error Λఆٛ͢Δඞཁ͕͋Δ 60
  31. ݴޠػೳΛۦ࢖͠Α͏ 4 ࣗ෼ࣗ਎ͷܕΛฦ͢static func 4 operator 4 ه߸ʹΑΔॲཧΛఆٛ͢Δ 4 લஔɾதஔɾޙஔ

    4 subscript 4 e.g.ɹ reversiBoard[x: 10, y: 8] 4 ෳ਺ͷҾ਺ɺϥϕϧ෇༩΋Մೳ 61