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

あなたはどう書き なぜそう書くのか?

あなたはどう書き なぜそう書くのか?

コードを書き方は何かしらの判断基準や理由を持って決定されます。今回は1つの題材を元にSwiftという多様な表現が可能な言語で、どういう状況で、どういう書き方ができ、なぜそう書くのかについて考えてみました。

[email protected]

March 19, 2019
Tweet

Other Decks in Programming

Transcript

  1. ͋ͳͨ͸Ͳ͏ॻ͖
    ͳͥͦ͏ॻ͘ͷ͔ʁ

    USZ4XJGU1SF5BMLT

    View Slide

  2. ౎಺ͷࣗࣾαʔϏε։ൃձࣾͷ
    J04ΤϯδχΞЋ
    TIJ[!TU[O
    TIJ[ ͣ͠

    !TIJ[
    TU[O TIJ[

    ։ൃܦݧݴޠ
    4XJGU,PUMJO+BWBTDSJQU1)1$+BWB

    View Slide

  3. Ͳ͏΍ͬͯ
    ίʔυͷॻ͖ํΛ
    ܾΊ͍ͯ·͔͢ʁ

    View Slide

  4. ໌֬ͳཧ༝
    ීஈͷ׳श
    ܾఆ
    ࢼߦࡨޡ
    ʜ
    ൑அ

    View Slide

  5. ʁ

    View Slide

  6. ϩάΛૹΔ
    YYYY
    QSPUPDPM

    View Slide

  7. struct AnalyticsEvent {
    var name: String
    var metadata: [String: Any] = [:]
    init(name: String, metadata: [String: Any] = [:]) {
    self.name = name
    self.metadata = metadata
    }
    }
    class AnalyticsManager {
    private let engine: AnalyticsEngine
    init(engine: AnalyticsEngine) {
    self.engine = engine
    }
    func log(_ event: AnalyticsEvent) {
    engine.send(name: event.name, metadata: event.metadata)
    }
    }
    protocol AnalyticsEngine: class {
    func send(name: String, metadata: [String: Any])
    }
    struct Book {
    let name: String
    }
    final class Library {
    private var library: [Book] = []
    func add(_ book: Book) -> Book {
    library.append(book)
    return book
    }
    }

    View Slide

  8. final class BookDetailViewController: UIViewController {
    func addBook(book: Book) {
    library.add(book)
    let event = AnalyticsEvent(name: "bookOdded")
    analytics.log(event)
    }
    }
    wλΠϓϛεΛ͢ΔՄೳੑ͕͋Δ
    wमਖ਼͕ෳ਺ՕॴʹೖΔ
    final class BookListViewController: UIViewController {
    func addBook(book: Book) {
    library.add(book)
    let event = AnalyticsEvent(name: "bookAdded")
    analytics.log(event)
    }
    }

    View Slide

  9. FOVN

    View Slide

  10. enum AnalyticsEvent {
    case bookAdded(Book)
    var name: String {
    switch self {
    case .bookAdded:
    return "bookAdded"
    }
    }
    var metadata: [String: Any] {
    switch self {
    case .bookAdded(let book):
    return ["book": book.name]
    }
    }
    }
    final class BookListViewController: UIViewController {
    func addBook(book: Book) {
    library.add(book)
    analytics.log(.bookAdded(book))
    }
    }
    final class BookDetailViewController: UIViewController {
    func addBook(book: Book) {
    library.add(book)
    analytics.log(.bookAdded(book))
    }
    }
    ɾλΠϓϛε͕ͳ͘ͳΔ
    ɾίϯύΠϧ࣌ʹνΣοΫ͕Ͱ͖Δ

    View Slide

  11. enum AnalyticsEvent {
    case loginScreenViewed
    case loginAttempted
    case loginFailed(reason: LoginFailureReason)
    case loginSucceeded
    case bookListViewed
    case bookAdded(Book)
    case bookSelected(Book)
    case bookDeleted(Book)
    var name: String {
    switch self {
    case .loginScreenViewed, .loginAttempted,
    .loginSucceeded, .bookListViewed:
    return String(describing: self)
    case .loginFailed:
    return "loginFailed"
    case .bookAdded:
    return "bookAdded"
    case .bookSelected:
    return "bookSelected"
    case .bookDeleted:
    return "bookDeleted"
    }
    }
    var metadata: [String: Any] {
    switch self {
    case .loginScreenViewed, .loginAttempted,
    .loginSucceeded, .bookListViewed:
    return [:]
    case .loginFailed(let reason):
    return ["reason" : String(describing: reason)]
    case .bookAdded(let book):
    return ["book" : book.name]
    case .bookSelected(let index):
    return ["book" : book.name]
    case .bookDeleted(let book):
    return ["book" : book.name]
    }
    }
    }
    w4XJUDIจ͕େྔʹͳΔ
    wએݴͱม਺ͷఆ͕ٛ෼͔ΕΔ
    ͲΜͲΜ૿͍͑ͯ͘ɻɻɻ

    View Slide

  12. Ϟδϡʔϧͷ෼ׂ͕Ͱ͖ͳ͍
    Πϕϯτ͕૿͑Δ
    enumʹcaseΛ௥Ճ
    enumͷextensionͷमਖ਼
    YYYY
    QSPUPDPM

    View Slide

  13. struct

    View Slide

  14. struct AnalyticsEvent {
    let name: String
    let metadata: [String : Any]
    private init(name: String, metadata: [String: Any] = [:]) {
    self.name = name
    self.metadata = metadata
    }
    }
    • ҰՕॴͰએݴͰ͖Δ
    • ݺͼग़͠ํ͸enumͷ࣌ͱมΘΒͳ͍
    final class BookListViewController: UIViewController {
    func addBook(book: Book) {
    library.add(book)
    analytics.log(.bookList_BookAdded(book))
    }
    }
    extension AnalyticsEvent {
    static func bookList_BookAdded(_ book: Book) -> AnalyticsEvent {
    return AnalyticsEvent(
    name: "bookList_BookAdded",
    metadata: ["book" : book.name]
    )
    }
    }

    View Slide

  15. Ϟδϡʔϧͷ෼ׂ͕Ͱ͖Δ
    extensionʹ͢Δ͜ͱͰଞʹӨڹΛ༩͑ͳ͍
    YYYY
    QSPUPDPM

    View Slide

  16. w໊લͷিಥ
    final class BookListViewController: UIViewController {
    func addBook(book: Book) {
    library.add(book)
    analytics.log(.bookList_BookAdded(book))
    }
    }
    extension AnalyticsEvent {
    static func bookList_BookAdded(_ book: Book) -> AnalyticsEvent {
    return AnalyticsEvent(
    name: "bookList_BookAdded",
    metadata: ["book" : book.name]
    )
    }
    static func bookDetail_BookAdded(_ book: Book) -> AnalyticsEvent {
    return AnalyticsEvent(
    name: “bookDetail_BookAdded",
    metadata: ["book" : book.name]
    )
    }
    }
    final class BookDetailViewController: UIViewController {
    func addBook(book: Book) {
    library.add(book)
    analytics.log(.bookDetail_BookAdded(book))
    }
    }

    View Slide

  17. ݺͼग़͠ଆͰॳظԽͷํ๏Λ
    TUSVDUͷ౎߹ʹ߹ΘͤΔඞཁ͕͋Δ
    extension AnalyticsEvent {
    static func bookDetail_BookRead(_ book: Book, count: Int) -> AnalyticsEvent {
    return AnalyticsEvent(
    name: “bookDetail_BookAdded",
    metadata: ["book": book.name, “read_count”: count]
    )
    }
    }

    View Slide

  18. init(book: Book, count: Int) {
    self.init(
    name: "bookRead",
    metadata: ["book" : book.name, "read_count":
    count]
    )
    }
    init(a: String) {
    self.init(name: a)
    }
    init(b: String) {
    self.init(name: b)
    }
    init(c: String) {
    self.init(name: c)
    }
    init(d: String) {
    self.init(name: d)
    }

    DVTUPNJOJUΛఆٛͰ͖Δ͕ʜ
    ͲΜͲΜ૿͍͑ͯ͘ɻɻɻ

    View Slide

  19. protocol

    View Slide

  20. • ৽͍͠Πϕϯτͷ࡞੒͕༰қ(case΍extensionͷ௥Ճඞཁͳ͠)
    • ಠࣗͷΠχγϟϥΠβΛఆٛͰ͖ݺͼग़͠ଆͷෛ୲Λ૿΍͞ͳ͍
    • enum΋struct΋class΋࢖͑Δ
    • Xcodeͷࣗಈิ׬΋໰୊ͳ͠
    protocol AnalyticsEvent {
    var name: String { get }
    var metadata: [String: Any] { get }
    }
    struct BookReadErrorAnalyticsEvent: AnalyticsEvent {
    var name: String {
    return "BookReadError"
    }
    var metadata: [String: Any] {
    return ["code": reason.code,
    "description": reason.description]
    struct Reason {
    let code: Int
    let description: String
    }
    private let reason: Reason
    init(reason: Reason) {
    self.reason = reason
    }
    }

    View Slide

  21. final class ProductionAnalyticsEngine: AnalyticsEngine {
    func log(_ event: AnalyticsEvent) {
    let name = "Production-\(event.name)"
    AnalyticsAPI.send(name: name, metadata: event.metadata)
    }
    }
    final class DevAnalyticsEngine: AnalyticsEngine {
    func log(_ event: AnalyticsEvent) {
    let name = "Dev-\(event.name)"
    AnalyticsAPI.send(name: name, metadata: event.metadata)
    }
    }
    final class StagingAnalyticsEngine: AnalyticsEngine {
    func log(_ event: AnalyticsEvent) {
    let name = "Staging-\(event.name)"
    AnalyticsAPI.send(name: name, metadata: event.metadata)
    }
    }
    final class TestAnalyticsEngine: AnalyticsEngine {
    func log(_ event: AnalyticsEvent) {
    let name = "Test-\(event.name)"
    AnalyticsAPI.send(name: name, metadata: event.metadata)
    }
    }
    ಉ͡Α͏ͳܕͷఆ͕ٛ૿͍͑ͯ͘

    View Slide

  22. • ܕΛఆٛ͢Δඞཁ͕ͳ͘ͳΔ
    • ΧελϚΠζ͕ࣗ༝ʹͳΔ
    struct AnalyticsEngine {
    let log: (Event) -> Void
    init(log: @escaping (Event) -> Void) {
    self.log = log
    }
    }
    final class BookListViewController: UIViewController {
    private let engine: AnalyticsEngine
    }
    let prefix = "Production-"
    let bookListEngine = AnalyticsEngine { event in
    let name = "\(prefix)\(event.name)"
    AnalyticsAPI.send(name: name, metadata: event.metadata)
    }
    let collection = Library()
    let vc = BookListViewController(library: collection, engine: bookListEngine)
    let bookDetailEngine = AnalyticsEngine { event in
    let name = "\(prefix)\(event.name)"
    AnalyticsAPI.send(name: name, metadata: event.metadata)
    }

    View Slide

  23. struct MultipleAnalyticsEngine {
    let log: ([Event]) -> Void
    init(log: @escaping ([Event]) -> Void) {
    self.log = log
    }
    }
    let multiEngine = MultipleAnalyticsEngine { events in
    events.forEach {
    AnalyticsAPI.send(name: $0.name, metadata: $0.metadata)
    }
    }
    let book = Book(name: "ΧϥϚʔκϑͷܑఋ")
    multiEngine.log([BookListAnalyticsEvent.bookAdded(book),
    BookDetailAnalyticsEvent.bookAdded(book)])
    struct MultipleAnalyticsEngine {
    let log: ([AnalyticsEvent]) -> Void
    init(log: @escaping ([AnalyticsEvent]) -> Void) {
    self.log = log
    }
    }
    let book = Book(name: "ΧϥϚʔκϑͷܑఋ")
    multiEngine.log([BookListAnalyticsEvent.bookAdded(book),
    BookListAnalyticsEvent.bookAdded(book)])
    ຊ౰͸BookDetailAnalyticsEvent.bookAdded(book)])ΛૹΓ͔ͨͬͨɻɻɻ

    View Slide

  24. ͦ΋ͦ΋

    View Slide

  25. protocol AnalyticsEvent {
    var name: String { get }
    var metadata: [String: Any] { get }
    }
    "OBMZUJDTʹΑͬͯ͸
    ࠶ม׵ͷඞཁ͕ग़ͯ͘Δ

    View Slide

  26. ʁ

    View Slide

  27. ·ͱΊ

    View Slide

  28. -FU`T
    USZBOEFSSPS
    -FU`T
    FOKPZUSZTXJGU

    View Slide

  29. ͋Γ͕ͱ͏
    ͍͟͝·ͨ͠
    ʁ

    View Slide

  30. ࢀরϦϯΫ
    IUUQTXXXTXJGUCZTVOEFMMDPNQPTUTCVJMEJOHBOFOVNCBTFEBOBMZUJDT
    TZTUFNJOTXJGU
    IUUQTNBUUEJFQIPVTFDPNXIFOOPUUPVTFBOFOVN
    IUUQTEBWFEFMPOHDPNCMPHNJTVTJOHFOVNT
    IUUQTXXXZPVUVCFDPNXBUDI W1OR+J+7D1

    View Slide