"Lost in maintenance: criteria of maintainable in Swift" by Paul Taykalo

"Lost in maintenance: criteria of maintainable in Swift" by Paul Taykalo

We rarely start projects from scratch and often blame our predecessors for their code. Problems begin yet upon estimation of live project’s maintainability. In his talk Taykalo Paul, iOS Team Leader at Stanfy, will reveal some particular criteria to consider on existing codebases’ maintainability.
He’ll also share his experience communicating current project’s state and related risks to stakeholders. Paul will show some practical decisions that will help to leave the project in better state than it was previously. Refactoring techniques, unit tests’ coverage, CoreData migrations are here to help.

This talk was made for CocoaHeads Kyiv #12 which took place July 22 2017.

Db84cf61fdada06b63f43f310b68b462?s=128

CocoaHeads Ukraine

July 22, 2017
Tweet

Transcript

  1. Lost in maintenance: criteria of maintainable in Swift by Paul

    Taykalo, Stanfy Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 1
  2. Plan » Derermining project maintainability » Maintaining unmaintainable » Rewriting?

    » Speaking about maintainability Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 2
  3. We've got a project to check Lost in maintenance, by

    Paul Taykalo, #cocoaheadskyiv 3
  4. How we check project status Lost in maintenance, by Paul

    Taykalo, #cocoaheadskyiv 4
  5. How should we check project status Lost in maintenance, by

    Paul Taykalo, #cocoaheadskyiv 5
  6. How should we check project status Lost in maintenance, by

    Paul Taykalo, #cocoaheadskyiv 6
  7. Be objective in your decisions Lost in maintenance, by Paul

    Taykalo, #cocoaheadskyiv 7
  8. Where does this list came from? Lost in maintenance, by

    Paul Taykalo, #cocoaheadskyiv 8
  9. We've got a project to check Be objective Lost in

    maintenance, by Paul Taykalo, #cocoaheadskyiv 9
  10. Everything is analyzed and checked What's next? Lost in maintenance,

    by Paul Taykalo, #cocoaheadskyiv 10
  11. We decided not to take the project Lost in maintenance,

    by Paul Taykalo, #cocoaheadskyiv 11
  12. The end Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 12

  13. Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 13

  14. So, you've got a project Lost in maintenance, by Paul

    Taykalo, #cocoaheadskyiv 14
  15. So, you've got a project First steps Lost in maintenance,

    by Paul Taykalo, #cocoaheadskyiv 15
  16. Knowledge sharing Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 16

  17. Are there any tests? Lost in maintenance, by Paul Taykalo,

    #cocoaheadskyiv 17
  18. Are there any tests? You know the answer :( Lost

    in maintenance, by Paul Taykalo, #cocoaheadskyiv 18
  19. Are there any tests? You know the answer :( Lost

    in maintenance, by Paul Taykalo, #cocoaheadskyiv 19
  20. Documentation Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 20

  21. Documentation Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 21

  22. Documentation Hack How to read documentation Lost in maintenance, by

    Paul Taykalo, #cocoaheadskyiv 22
  23. U is for Understading Lost in maintenance, by Paul Taykalo,

    #cocoaheadskyiv 23
  24. How to deal with Legacy Lost in maintenance, by Paul

    Taykalo, #cocoaheadskyiv 24
  25. Rules Boyscout Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 25

  26. One (two) thing at the time Lost in maintenance, by

    Paul Taykalo, #cocoaheadskyiv 26
  27. Remove Dead Code Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv

    27
  28. Aim Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 28

  29. Rewrite! Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 29

  30. Rewrite? Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 30

  31. Few More things before Lost in maintenance, by Paul Taykalo,

    #cocoaheadskyiv 31
  32. Semantic Meaning Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 32

  33. Semantic Meaning if item.row == 2 { ... } Lost

    in maintenance, by Paul Taykalo, #cocoaheadskyiv 33
  34. Semantic Meaning if item.row == 2 { ... } Lost

    in maintenance, by Paul Taykalo, #cocoaheadskyiv 34
  35. Semantic Meaning if api.version > 2 { ... } Lost

    in maintenance, by Paul Taykalo, #cocoaheadskyiv 35
  36. Semantic Meaning if api.version > 2 { ... } let

    supportsThrottling = api.version > 2 if supportsThrottling { ... } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 36
  37. Semantic Meaning if api.version > 2 { ... } extension

    Api { var supportsThrottling: Bool { return version > 2} } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 37
  38. Semantic Meaning if let object = notification.object as? UIViewController ,

    object == self { ... } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 38
  39. Semantic Meaning if let object = notification.object as? UIViewController ,

    object == self { ... } let notificationWasSentByUs = notification.object == self if notificationWasSentByUs { ... } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 39
  40. Semantic Meaning if let currentUser = User.currentUser(inContext: mainContext) , currentUser.username

    != nil && currentUser.apiToken != nil ... else if let currentUser = User.currentUser(inContext: mainContext) , currentUser.username == nil && currentUser.apiToken != nil ... else Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 40
  41. Semantic meaning let user = User.currentUser(inContext: self.appData.mainContext) let userHasValidUserName =

    user?.username != nil let userHasValidToken = user?.apiToken != nil Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 41
  42. Semantic meaning if userHasValidToken && userHasValidUserName ... else if userHasValidToken

    && userHasNoName ... else Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 42
  43. Do it on daily basis Lost in maintenance, by Paul

    Taykalo, #cocoaheadskyiv 43
  44. Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 44

  45. Always be careful with any changes Lost in maintenance, by

    Paul Taykalo, #cocoaheadskyiv 45
  46. Always be careful with any changes func overloaded(value: Double) ->

    String { return "Double" } func overloaded(value: Any) -> String { return "Any" } let size: Double? = dictionary["size"] let value = size ?? 0.0 let complex = overloaded(size ?? 0.0) // Any let simple = overloaded(value) // Double Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 46
  47. What else can we do? Lost in maintenance, by Paul

    Taykalo, #cocoaheadskyiv 47
  48. What are these functions about? UIImage -> UIImage String ->

    String -> String URL -> UIImage Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 48
  49. Phantom types Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 49

  50. Phantom types PhotoAlbumImage -> TumbnailImage UserID -> AddressID -> Address

    FileURL -> ThumbnailImage Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 50
  51. Phantom types struct FilteredImage { // this will be filtered

    only let image: UIImage } struct BigImage { // in memory image private(set) var inMemoryImage: UIImage? // stored private var storedURL: URL? var image: UIImage { // return from the memory // or load from the fs } } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 51
  52. Phantom types struct FileSystemURL { let url: NSURL // Failable

    initializer init?(url: NSURL) } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 52
  53. Phantom types reasoning Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv

    53
  54. Phantom types » Concrete » Unique behaviour » Control Lost

    in maintenance, by Paul Taykalo, #cocoaheadskyiv 54
  55. Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 55

  56. What else can we do? Lost in maintenance, by Paul

    Taykalo, #cocoaheadskyiv 56
  57. Hell? vs Hell! Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv

    57
  58. Hell? vs Hell! ! Lost in maintenance, by Paul Taykalo,

    #cocoaheadskyiv 58
  59. Hell? vs Hell! ? Lost in maintenance, by Paul Taykalo,

    #cocoaheadskyiv 59
  60. Hell? vs Hell! struct User { let name: String? let

    token: String? } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 60
  61. Hell? vs Hell! struct UnverifiedUser {} struct User { let

    name: String } struct LoggedUser { let user: User let token: String // TokenString } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 61
  62. Hell? vs Hell! // First var itemsPerKey: [Key: Item] =

    [:] // Then var itemsPerKey: [Key: Item] = [:] var isDeleted: [Key: Bool] = [:] Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 62
  63. Hell? vs Hell! enum ItemState { case assigned(let item) case

    deleted var item: Item? { if .assigned(let item) = self { return item } return nil } } var itemsPerKey: [Key: ItemState] = [:] Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 63
  64. Hell? vs Hell! enum UploadingState { case notStarted case uploading(Foundation.Operation)

    case uploaded case failed(Error) func operation() -> Foundation.Operation? { switch self { case .uploading(let op): return op default: return nil } } func isUploading() -> Bool { if case .uploading = self { return true } return false } } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 64
  65. Hell? vs Hell! public enum Result<Value, Error: Swift.Error> { case

    success(Value) case error(Error) } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 65
  66. Results and costs Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv

    66
  67. Rewrite all the things! Lost in maintenance, by Paul Taykalo,

    #cocoaheadskyiv 67
  68. How to make changes in the project Lost in maintenance,

    by Paul Taykalo, #cocoaheadskyiv 68
  69. How to make changes in the project Lost in maintenance,

    by Paul Taykalo, #cocoaheadskyiv 69
  70. How to make changes in the project » What is

    going on? » Freeze current behaviour » Write down desired behaviour » Check » Make sure that all unrelated sidefects still there Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 70
  71. How to make changes in the project » Make tests

    on current behavor » Make change » Check Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 71
  72. Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 72

  73. But I cannot test it because... » I dont understand

    how class works » I cannot instantiate class in test env » I cannot test method - it's too bit » I cannot... Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 73
  74. . . It's too big for testing Lost in maintenance,

    by Paul Taykalo, #cocoaheadskyiv 74
  75. 'But I cannot' solutions » Test method in class »

    Make an helper and use it class Huge { func perform { if object.price as? String == } } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 75
  76. 'But I cannot' solutions class Huge { func perform {

    if let price = object.price as? String } } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 76
  77. 'But I cannot' solutions struct Price { init?(object: [String: Any])

    {} var priceToShow: String {} var discont: String {} } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 77
  78. 'But I cannot' solutions protocol Dispatcher { func background(_ block:

    @escaping (() -> Void)) func main(_ block: @escaping (() -> Void)) func main_from_background(_ block: @escaping(() -> Void)) func background_delay(_ delay: Int64, block: @escaping (() -> Void)) func main_delay(_ delay: Int64, block: @escaping (() -> Void)) } // for everything else class DefaultDispatcher: Dispatcher {} // For tests class SyncDispatcher: Dispatcher {} Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 78
  79. 'But I cannot' solutions » Core Data » Views »

    Snaphots » Hardware? Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 79
  80. This is ... Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv

    80
  81. This is legacy! Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv

    81
  82. L - is for Logs Lost in maintenance, by Paul

    Taykalo, #cocoaheadskyiv 82
  83. M - is for Measurements Lost in maintenance, by Paul

    Taykalo, #cocoaheadskyiv 83
  84. N - is for "No hope without Logs and Measurements"

    Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 84
  85. Now you are allowed to rewrite something Lost in maintenance,

    by Paul Taykalo, #cocoaheadskyiv 85
  86. Small history about scrolling Lost in maintenance, by Paul Taykalo,

    #cocoaheadskyiv 86
  87. Small history about scrolling » App is not using cache

    Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 87
  88. Small history about scrolling » ✅ Not using cache »

    ❌ Freezing Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 88
  89. Small history about scrolling » ✅ Not using cache »

    ✅ Freezing (disk cacke) » ❌ Freezing ( after MW) Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 89
  90. Small history about scrolling » ✅ Not using cache »

    ✅ Freezing (disk cacke) » ✅ Freezing ( after MW) » ❌ Lags (Jpeg Decoding) Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 90
  91. Small history about scrolling » ✅ Not using cache »

    ✅ Freezing (disk cacke) » ✅ Freezing ( after MW) » ✅ Lags (Jpeg Decoding) » ❌ Out of memory crashes Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 91
  92. Small history about scrolling » ✅ Not using cache »

    ✅ Freezing (disk cacke) » ✅ Freezing ( after MW) » ✅ Lags (Jpeg Decoding) » ❌ Out of memory crashes » ??????? Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 92
  93. There's a library for that Lost in maintenance, by Paul

    Taykalo, #cocoaheadskyiv 93
  94. There's a library for that ios-twitter-image- pipeline Lost in maintenance,

    by Paul Taykalo, #cocoaheadskyiv 94
  95. Wanna try something bigger? Lost in maintenance, by Paul Taykalo,

    #cocoaheadskyiv 95
  96. Rewriting Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 96

  97. Rewriting » Modularity » Testing! » Enclosing » Unification Lost

    in maintenance, by Paul Taykalo, #cocoaheadskyiv 97
  98. Modularity What if I tell you that there can be

    more than one storyboard? Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 98
  99. Testing Start writing tests :( - There's no time for

    it - I cannot sell it to the customer - I am supporting a legacy application without unit tests. - QA and User Acceptance Testing is far more effective in finding bugs - I don’t know how to unit test, or I don’t know how to write good unit tests Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 99
  100. Testing There'll be no failed tests if there's no tests

    Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 100
  101. Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 101

  102. Working with Product Owner Lost in maintenance, by Paul Taykalo,

    #cocoaheadskyiv 102
  103. Working with Product Owner Selling and tradeoffs Lost in maintenance,

    by Paul Taykalo, #cocoaheadskyiv 103
  104. Working with Product Owner Are you better? Lost in maintenance,

    by Paul Taykalo, #cocoaheadskyiv 104
  105. Working with Product Owner Facts Lost in maintenance, by Paul

    Taykalo, #cocoaheadskyiv 105
  106. Recap Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 106

  107. Thank you Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 107

  108. Lost in maintenance by Paul Taykalo, Stanfy @TT_Kilew Lost in

    maintenance, by Paul Taykalo, #cocoaheadskyiv 108
  109. The end Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 109