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.

A928e0a8375d93d165ad90bb860c05d9?s=128

Ronan Rodrigo Nunes

November 09, 2018
Tweet

Transcript

  1. Uma decisão pode custar caro

  2. Sudoku

  3. – Robert C. Martin “A good architecture maximizes the number

    of decisions not made.”
  4. Decisões adiáveis Detalhes que não influenciam o alto nível do

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

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

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

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

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

  10. Decisões não adiáveis

  11. Regras de negócio

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

  13. Comunicação entre componentes*

  14. Por quê adiar uma decisão?

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

  16. Para facilitar a criação de testes

  17. func testListWhenMonthIsGreaterThanTwelveThenPresentError() { gateway = ListFoodStubGateway() presenter = ListFoodStubPresenter() interactor

    = ListFoodByMonthInteractor(gateway, presenter) interactor.list(byMonth: 13) XCTAssertEqual(presenter.presentedError, .invalidMonth) }
  18. Para ter menos acoplamento e possibilitar experimentações

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

    class ListFoodNetworkGateway: ListFoodGateway { // ... } class ListFoodJsonFileGateway: ListFoodGateway { // ... } class ListFoodCoreDataGateway: ListFoodGateway { // ... }
  20. Ou seja, ser software

  21. Como não fazer?

  22. protocol FoodGateway { func fetch(byMonth month: Int) func put(id: Int,

    name: String) func insert(name: String) } protocol ListFoodScreen { func updateLabel(name: String) }
  23. Como fazer?

  24. Interactor para regras de negócio

  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) { /**/ } } }
  26. Gateway para mapear dados de/para fontes externas

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

  28. class ListFoodMemoryGateway: ListFoodGateway { func filter(byMonth month: Int, onComplete: CompletionHandler)

    { let foods = DataSource.allFoods.filter { $0.months.contains(month) } onComplete(.success(foods)) } }
  29. None
  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, ...] // ... }
  31. 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 { //... } } } }
  32. Teste. Você ainda é o mesmo?

  33. func testListWhenMonthIsGreaterThanTwelveThenPresentError() { gateway = ListFoodStubGateway() presenter = ListFoodStubPresenter() interactor

    = ListFoodByMonthInteractor(gateway, presenter) interactor.list(byMonth: 13) XCTAssertEqual(presenter.presentedError, .invalidMonth) }
  34. Obrigado

  35. sou.nu/desafio-cocoaheads