Share
Embed
Transcript
109 slides
-
Lost in maintenance: criteria of maintainable in Swift by Paul
Taykalo, Stanfy Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 1 -
Plan » Derermining project maintainability » Maintaining unmaintainable » Rewriting?
» Speaking about maintainability Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 2 -
We've got a project to check Lost in maintenance, by
Paul Taykalo, #cocoaheadskyiv 3 -
How we check project status Lost in maintenance, by Paul
Taykalo, #cocoaheadskyiv 4 -
How should we check project status Lost in maintenance, by
Paul Taykalo, #cocoaheadskyiv 5 -
How should we check project status Lost in maintenance, by
Paul Taykalo, #cocoaheadskyiv 6 -
Be objective in your decisions Lost in maintenance, by Paul
Taykalo, #cocoaheadskyiv 7 -
Where does this list came from? Lost in maintenance, by
Paul Taykalo, #cocoaheadskyiv 8 -
We've got a project to check Be objective Lost in
maintenance, by Paul Taykalo, #cocoaheadskyiv 9 -
Everything is analyzed and checked What's next? Lost in maintenance,
by Paul Taykalo, #cocoaheadskyiv 10 -
We decided not to take the project Lost in maintenance,
by Paul Taykalo, #cocoaheadskyiv 11 -
So, you've got a project Lost in maintenance, by Paul
Taykalo, #cocoaheadskyiv 14 -
So, you've got a project First steps Lost in maintenance,
by Paul Taykalo, #cocoaheadskyiv 15 -
Are there any tests? Lost in maintenance, by Paul Taykalo,
#cocoaheadskyiv 17 -
Are there any tests? You know the answer :( Lost
in maintenance, by Paul Taykalo, #cocoaheadskyiv 18 -
Are there any tests? You know the answer :( Lost
in maintenance, by Paul Taykalo, #cocoaheadskyiv 19 -
Documentation Hack How to read documentation Lost in maintenance, by
Paul Taykalo, #cocoaheadskyiv 22 -
U is for Understading Lost in maintenance, by Paul Taykalo,
#cocoaheadskyiv 23 -
How to deal with Legacy Lost in maintenance, by Paul
Taykalo, #cocoaheadskyiv 24 -
One (two) thing at the time Lost in maintenance, by
Paul Taykalo, #cocoaheadskyiv 26 -
Few More things before Lost in maintenance, by Paul Taykalo,
#cocoaheadskyiv 31 -
Semantic Meaning if item.row == 2 { ... } Lost
in maintenance, by Paul Taykalo, #cocoaheadskyiv 33 -
Semantic Meaning if item.row == 2 { ... } Lost
in maintenance, by Paul Taykalo, #cocoaheadskyiv 34 -
Semantic Meaning if api.version > 2 { ... } Lost
in maintenance, by Paul Taykalo, #cocoaheadskyiv 35 -
Semantic Meaning if api.version > 2 { ... } let
supportsThrottling = api.version > 2 if supportsThrottling { ... } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 36 -
Semantic Meaning if api.version > 2 { ... } extension
Api { var supportsThrottling: Bool { return version > 2} } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 37 -
Semantic Meaning if let object = notification.object as? UIViewController ,
object == self { ... } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 38 -
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 -
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 -
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 -
Semantic meaning if userHasValidToken && userHasValidUserName ... else if userHasValidToken
&& userHasNoName ... else Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 42 -
Do it on daily basis Lost in maintenance, by Paul
Taykalo, #cocoaheadskyiv 43 -
Always be careful with any changes Lost in maintenance, by
Paul Taykalo, #cocoaheadskyiv 45 -
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 -
What else can we do? Lost in maintenance, by Paul
Taykalo, #cocoaheadskyiv 47 -
What are these functions about? UIImage -> UIImage String ->
String -> String URL -> UIImage Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 48 -
Phantom types PhotoAlbumImage -> TumbnailImage UserID -> AddressID -> Address
FileURL -> ThumbnailImage Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 50 -
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 -
Phantom types struct FileSystemURL { let url: NSURL // Failable
initializer init?(url: NSURL) } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 52 -
Phantom types » Concrete » Unique behaviour » Control Lost
in maintenance, by Paul Taykalo, #cocoaheadskyiv 54 -
What else can we do? Lost in maintenance, by Paul
Taykalo, #cocoaheadskyiv 56 -
Hell? vs Hell! ! Lost in maintenance, by Paul Taykalo,
#cocoaheadskyiv 58 -
Hell? vs Hell! ? Lost in maintenance, by Paul Taykalo,
#cocoaheadskyiv 59 -
Hell? vs Hell! struct User { let name: String? let
token: String? } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 60 -
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 -
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 -
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 -
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 -
Hell? vs Hell! public enum Result<Value, Error: Swift.Error> { case
success(Value) case error(Error) } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 65 -
Rewrite all the things! Lost in maintenance, by Paul Taykalo,
#cocoaheadskyiv 67 -
How to make changes in the project Lost in maintenance,
by Paul Taykalo, #cocoaheadskyiv 68 -
How to make changes in the project Lost in maintenance,
by Paul Taykalo, #cocoaheadskyiv 69 -
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 -
How to make changes in the project » Make tests
on current behavor » Make change » Check Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 71 -
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 -
. . It's too big for testing Lost in maintenance,
by Paul Taykalo, #cocoaheadskyiv 74 -
'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 -
'But I cannot' solutions class Huge { func perform {
if let price = object.price as? String } } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 76 -
'But I cannot' solutions struct Price { init?(object: [String: Any])
{} var priceToShow: String {} var discont: String {} } Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 77 -
'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 -
'But I cannot' solutions » Core Data » Views »
Snaphots » Hardware? Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 79 -
L - is for Logs Lost in maintenance, by Paul
Taykalo, #cocoaheadskyiv 82 -
M - is for Measurements Lost in maintenance, by Paul
Taykalo, #cocoaheadskyiv 83 -
N - is for "No hope without Logs and Measurements"
Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 84 -
Now you are allowed to rewrite something Lost in maintenance,
by Paul Taykalo, #cocoaheadskyiv 85 -
Small history about scrolling Lost in maintenance, by Paul Taykalo,
#cocoaheadskyiv 86 -
Small history about scrolling » App is not using cache
Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 87 -
Small history about scrolling » ✅ Not using cache »
❌ Freezing Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 88 -
Small history about scrolling » ✅ Not using cache »
✅ Freezing (disk cacke) » ❌ Freezing ( after MW) Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 89 -
Small history about scrolling » ✅ Not using cache »
✅ Freezing (disk cacke) » ✅ Freezing ( after MW) » ❌ Lags (Jpeg Decoding) Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 90 -
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 -
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 -
There's a library for that Lost in maintenance, by Paul
Taykalo, #cocoaheadskyiv 93 -
There's a library for that ios-twitter-image- pipeline Lost in maintenance,
by Paul Taykalo, #cocoaheadskyiv 94 -
Wanna try something bigger? Lost in maintenance, by Paul Taykalo,
#cocoaheadskyiv 95 -
Rewriting » Modularity » Testing! » Enclosing » Unification Lost
in maintenance, by Paul Taykalo, #cocoaheadskyiv 97 -
Modularity What if I tell you that there can be
more than one storyboard? Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 98 -
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 -
Testing There'll be no failed tests if there's no tests
Lost in maintenance, by Paul Taykalo, #cocoaheadskyiv 100 -
Working with Product Owner Lost in maintenance, by Paul Taykalo,
#cocoaheadskyiv 102 -
Working with Product Owner Selling and tradeoffs Lost in maintenance,
by Paul Taykalo, #cocoaheadskyiv 103 -
Working with Product Owner Are you better? Lost in maintenance,
by Paul Taykalo, #cocoaheadskyiv 104 -
Working with Product Owner Facts Lost in maintenance, by Paul
Taykalo, #cocoaheadskyiv 105 -
Lost in maintenance by Paul Taykalo, Stanfy @TT_Kilew Lost in
maintenance, by Paul Taykalo, #cocoaheadskyiv 108