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

Uma decisão pode custar caro

Uma decisão pode custar caro

Os exemplos foram extraídos do projeto: https://github.com/ronanrodrigo/Sensazonal

Decisões adiáveis e não tão adiáveis
Você não precisa decidir o banco de dados que vai usar quando tá começando a fazer seu aplicativo. Durante a apresentação será demonstrado os pontos de atenção de decisões mais comuns quando estamos construindo um aplicativo.

Por quê adiar uma decisão
Vantagens de ter adiado uma escolha que podem parecer vantagens semelhantes a utilizar um protocolo. Contudo, até mesmo a construção de um protocolo pode sofrer influência de decisões precipitadas. Você descobrirá como escapar dessa cilada, bino.

Experiências de decisões precipitadas e como adiar decisões
Com exemplos de códigos já construídos, será apresentado como é um código agnóstico de decisão e também como é um código que foi construído pensando em detalhes. Programar e pensar desse jeito, tem diferenças que vão além da semântica.

Ronan Rodrigo Nunes

November 09, 2018
Tweet

More Decks by Ronan Rodrigo Nunes

Other Decks in Programming

Transcript

  1. Uma decisão pode custar caro

    View Slide

  2. Sudoku

    View Slide

  3. – Robert C. Martin
    “A good architecture maximizes the number of
    decisions not made.”

    View Slide

  4. Decisões adiáveis
    Detalhes que não influenciam o alto nível do Software

    View Slide

  5. Construção de telas
    XIB, Storyboard, XML*, código…
    *github.com/schibsted/layout

    View Slide

  6. Transmissão de dados
    Rest, GraphQL, gRPC, SOAP…

    View Slide

  7. Dados externos
    Não se preocupe com o formato do dado

    View Slide

  8. Persistência
    SQLite, CoreData, Realm, Plist, JSON, nada…

    View Slide

  9. Protocolos de comunicação
    HTTP, HTTPs, FTP, HLS, XMPP, Web Socket…

    View Slide

  10. Decisões não adiáveis

    View Slide

  11. Regras de negócio

    View Slide

  12. Características e restrições
    da plataforma

    View Slide

  13. Comunicação entre componentes*

    View Slide

  14. Por quê adiar uma decisão?

    View Slide

  15. Para não tomar a
    decisão errada

    View Slide

  16. Para facilitar a criação de
    testes

    View Slide

  17. func testListWhenMonthIsGreaterThanTwelveThenPresentError() {
    gateway = ListFoodStubGateway()
    presenter = ListFoodStubPresenter()
    interactor = ListFoodByMonthInteractor(gateway, presenter)
    interactor.list(byMonth: 13)
    XCTAssertEqual(presenter.presentedError, .invalidMonth)
    }

    View Slide

  18. Para ter menos acoplamento e
    possibilitar experimentações

    View Slide

  19. protocol ListFoodGateway {
    func foods(byMonth month: Int, onComplete: CompletionHandler)
    }
    class ListFoodNetworkGateway: ListFoodGateway {
    // ...
    }
    class ListFoodJsonFileGateway: ListFoodGateway {
    // ...
    }
    class ListFoodCoreDataGateway: ListFoodGateway {
    // ...
    }

    View Slide

  20. Ou seja, ser software

    View Slide

  21. Como não fazer?

    View Slide

  22. protocol FoodGateway {
    func fetch(byMonth month: Int)
    func put(id: Int, name: String)
    func insert(name: String)
    }
    protocol ListFoodScreen {
    func updateLabel(name: String)
    }

    View Slide

  23. Como fazer?

    View Slide

  24. Interactor para regras de
    negócio

    View Slide

  25. class ListFoodByMonthInteractor {
    private let gateway: ListFoodGateway
    private let presenter: ListFoodPresenter
    init(gateway: ListFoodGateway, presenter: ListFoodPresenter) {
    self.gateway = gateway
    self.presenter = presenter
    }
    func list(byMonth month: Int) {
    guard GregorianMonth.isValid(month: month) else {
    return presenter.presentError(.invalidMonth)
    }
    gateway.foods(byMonth: month) { /**/ }
    }
    }

    View Slide

  26. Gateway para mapear dados
    de/para fontes externas

    View Slide

  27. protocol ListFoodGateway {
    func foods(byMonth month: Int, onComplete: CompletionHandler)
    }

    View Slide

  28. class ListFoodMemoryGateway: ListFoodGateway {
    func filter(byMonth month: Int, onComplete: CompletionHandler) {
    let foods = DataSource.allFoods.filter {
    $0.months.contains(month)
    }
    onComplete(.success(foods))
    }
    }

    View Slide

  29. View Slide

  30. struct DataSource {
    private static let yam = Food(name: "YAM", months: [...])
    private static let kiwi = Food(name: "KIWI", months: [...])
    private static let bay = Food(name: "BAY", months: [...])
    private static let pea = Food(name: "PEA", months: [...])
    static let allFoods = [yam, kiwi, bay, pea, ...]
    // ...
    }

    View Slide


  31. View Slide

  32. class ListFoodJsonFileGateway: ListFoodGateway {
    func foods(byMonth month: Int, onComplete: CompletionHandler) {
    // ...
    queue.async {
    do {
    let foodsData = try Data(contentsOf: fileURL, ...)
    let foods = try JSONDecoder()
    .decode([FoodCodable].self, from: foodsData)
    .filter { $0.months.contains(month) }
    // ...
    DispatchQueue.main.async {
    onComplete(.success(foods))
    }
    } catch { //... }
    }
    }
    }

    View Slide

  33. Teste. Você ainda é o
    mesmo?

    View Slide

  34. func testListWhenMonthIsGreaterThanTwelveThenPresentError() {
    gateway = ListFoodStubGateway()
    presenter = ListFoodStubPresenter()
    interactor = ListFoodByMonthInteractor(gateway, presenter)
    interactor.list(byMonth: 13)
    XCTAssertEqual(presenter.presentedError, .invalidMonth)
    }

    View Slide

  35. Obrigado

    View Slide

  36. sou.nu/desafio-cocoaheads

    View Slide