Being correct, quicker

Being correct, quicker

0faee5216d2841b23acdbfa28588e2de?s=128

Alex Curran

August 07, 2018
Tweet

Transcript

  1. Being correct, quicker

  2. @amlcurran Where’s the assumption? class TodoItem { var id: String?

    var title: String? var dueDate: Date? var tasks: [String]? var completed: Bool }
  3. @amlcurran Where’s the assumption? class TodoItem { var id: String?

    var title: String? var dueDate: Date? var tasks: [String]? var completed: Bool } when is this nil? is this object valid without an ID? Is this property thread safe? does this change?
  4. let idToDelete = todo.id!

  5. @amlcurran Timeline of messing up Immediate End of the world

    You caught it QA caught it A user told you let idToDelete = todo.id! Merged code Released app
  6. @amlcurran Timeline of messing up Immediate End of the world

    Unit test crashed UI test failed Crash reporting caught it let idToDelete = todo.id! Merged code Released app
  7. @amlcurran How can we improve? class TodoItem { var id:

    String? var title: String? var dueDate: Date? var tasks: [String]? var completed: Bool } Immediate End of the world
  8. @amlcurran How can we improve? class TodoItem { let id:

    String = "" let title: String = "" let dueDate: Date? let tasks: [String] = [] let completed: Bool = false } Immediate End of the world
  9. @amlcurran How can we improve? class TodoItem { let id:

    String let title: String let dueDate: Date? let tasks: [String] let completed: Bool init(...) { } } Immediate End of the world
  10. @amlcurran Removing guesswork • Code didn’t give us enough information,

    we had to assume • An assumption is either right or wrong • Removing the assumption removes the guesses • Still assuming the API is stable, but talk to your API developers ;)
  11. @amlcurran Reducing a feedback loop Immediate End of the world

    A user told you Merged code Released app
  12. @amlcurran Reducing a feedback loop Immediate End of the world

    QA found it
  13. @amlcurran Time is money • Releases are time-expensive • The

    longer until an issue is found, the more work has to be done • Code review, pairing, type-safety all reduce this time
  14. @amlcurran Closing a feedback loop Immediate End of the world

    QA found it Merged code Released app
  15. @amlcurran Closing a feedback loop Immediate End of the world

    UI test failed Merged code Released app
  16. @amlcurran • “Definite” happens more often than “maybe" • Prefer

    to encode expectations into code and tools, rather than knowledge • An open loop requires knowledge to close — can you guarantee this happens? Definite is better than maybe
  17. Have you ever forgotten to set a dataSource or delegate?

  18. @amlcurran Forgetting a delegate let pairInputView = AddPairView() class AddPairView:

    UIVisualEffectView, UITextFieldDelegate { var delegate: AddPairViewDelegate? func textFieldShouldReturn(_ textField: UITextField) -> Bool { delegate?.addPairView(self, didFinishCreating: request()) return true } } Immediate End of the world
  19. @amlcurran Forgetting a delegate let pairInputView = AddPairView() pairInputView.delegate =

    self class AddPairView: UIVisualEffectView, UITextFieldDelegate { var delegate: AddPairViewDelegate? func textFieldShouldReturn(_ textField: UITextField) -> Bool { delegate?.addPairView(self, didFinishCreating: request()) return true } } Immediate End of the world
  20. @amlcurran Forgetting a delegate let pairInputView = AddPairView() class AddPairView:

    UIVisualEffectView, UITextFieldDelegate { var delegate: AddPairViewDelegate? func textFieldShouldReturn(_ textField: UITextField) -> Bool { delegate!.addPairView(self, didFinishCreating: request()) return true } } Immediate End of the world
  21. @amlcurran Forgetting a delegate let pairInputView = AddPairView(delegate: self) class

    AddPairView: UIVisualEffectView, UITextFieldDelegate { let delegate: AddPairViewDelegate func textFieldShouldReturn(_ textField: UITextField) -> Bool { delegate!.addPairView(self, didFinishCreating: request()) return true } } Immediate End of the world
  22. @amlcurran Forgetting a delegate let pairInputView = AddPairView(delegate: self) class

    AddPairView: UIVisualEffectView, UITextFieldDelegate { let delegate: AddPairViewDelegate func textFieldShouldReturn(_ textField: UITextField) -> Bool { delegate!.addPairView(self, didFinishCreating: request()) return true } } Immediate End of the world
  23. @amlcurran Using the compiler • A compile-time error is guaranteed

    to happen • A runtime crash is not (and is worse for the user!) • Flexible is not guaranteed to be safe
  24. @amlcurran Compile time vs runtime Compile time Compile Runtime Compile

    Launch Navigate Hit issue
  25. @amlcurran Swift (generally) helps • Stronger typing in Swift vs

    Obj-C makes compiler more important • Look at your optionals, mutables, and your implicitly unwrapped optionals • IUOs you’ve written can often be written in a less-crashy way • Don’t make things mutable/optional if it doesn’t make sense • Verify (and fail) early
  26. @amlcurran Strong typing helps • Use generics for common behaviour,

    not convenience • Don’t circumvent the compiler using Any • Think whether a primitive type really makes sense • Forcing a strong type can prevent bugs
  27. Quicker feedback is not always about crashes

  28. @amlcurran Tools to reduce feedback • SwiftGen and R.swift reduce

    runtime failures or undefined behaviour to compile errors — much faster! • SwiftLint makes compile time warnings from style guides
  29. @amlcurran “The code doesn’t match our style” Immediate End of

    the world App released Code review
  30. @amlcurran Immediate End of the world App released Pair with

    dev “The code doesn’t match our style”
  31. @amlcurran Immediate End of the world App released Swiftlint +

    compile “The code doesn’t match our style”
  32. @amlcurran Immediate End of the world App released Swiftlint +

    compile PR review “The code doesn’t match our style”
  33. @amlcurran Immediate End of the world App released Swiftlint +

    compile PR review Not open to interpretation Newer members of the team get neutral feedback “The code doesn’t match our style”
  34. @amlcurran Preventing accidents • Removing ability to undo a decision

    that was already made unconsciously • You can still change the rules, but not accidentally • If you have rules that you want people to follow, make it as easy as possible • Don’t add rules around things you can accept changing!
  35. @amlcurran class ServiceLocator { private var references = [String: Any]()

    func register<T>(_ object: T) { references["\(type(of: T.self))"] = object } func retrieve<T>() -> T { let identifier = "\(type(of: T.self))" guard let object = references[identifier] as? T else { preconditionFailure("Didn't register an object of \(type(of: T.self))") } return object } }
  36. @amlcurran let locator = ServiceLocator() locator.register(UserDefaults.standard) // Works let userDefaults:

    UserDefaults = locator.retreive() // Crashes let urlSession: URLSession = locator.retreive()
  37. @amlcurran class Dependencies { lazy var userDefaults: UserDefaults = .standard

    lazy var urlSession: URLSession = .shared } let dependencies = Dependencies() // Works let userDefaults = dependencies.urlSession // immediately doesn't compile let application = dependencies.application
  38. @amlcurran When is this stuff useful? • Old codebase, with

    weak coding practises • Teams with inexperienced developers • Teams with opinionated developers • Teams with high turnover • But really, its always useful
  39. @amlcurran Summing up • Reducing feedback loop time reduces the

    time to realise a mistake • Closing open feedback loops guarantees you feedback • Third-party tools can close Apple’s feedback loops • Think about aiming for certainty, not convenience • If something doesn’t make sense, make it impossible to happen
  40. @amlcurran Agile development • Reducing the time to feedback •

    Ensuring feedback is guaranteed • It is NOT about standups and retros and meetings!
  41. Thanks