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

Why 600 beats 3000

Why 600 beats 3000

Strategies to reduce the size of large classes.

David Hoerl

August 08, 2016
Tweet

More Decks by David Hoerl

Other Decks in Technology

Transcript

  1. How 600 beats 3000! Every day of the week! David

    Hoerl (dhoerl at mac dot com)
  2. 2 Always glad to share the marquee with Orta -

    he always draws a big crowd! Orta was the co-speaker at my first iOSoho in 2014. This photo taken Jan 26, 2015 - the day a huge blizzard was predicted. You can see flurries out the window. It took me 4 hours to get home to NJ. The PATH and NJ Transit trains were overflowing. NYC shut the subway down. In the end, NYC barely got any snow at all!
  3. Taming and Preventing Monster Code Files How do I know

    I have a problem? Actionable strategies to help “The Usual Wrap”™ 3 What follows is actionable by you! No need to be an expert on Swift or iOS!
  4. …but after a while. A few thousand lines of code

    Good intentions—but, got to get this added ASAP Objective(s) now murky 6
  5. What’s to be done? ! 9 The two very best

    tools to solve problems: 1) Think about what you need to do before you code! Plan! So important!!! 2) Not sure what to do? Then take a walk and mull on it. You’d be amazed at what comes to mind on a solitary walk.
  6. Grade Your Code How easy to add or remove a

    feature Time needed for a new dev to understand this class Time needed to find all parts of a feature 10 If it takes a long time to add something (because you cannot figure out what methods you can use to help), you have a problem. If a new person gag when asked to learn this class? Give one feature provided by the class, how easy is it to find all the relative pieces?
  7. Local Reasoning “LOCAL REASONING means that when you look at

    the code right in front of you, you don't have to think about how the rest of your code interacts with that one [thing].” Protocol and Value Oriented Programming in UIKit Apps WWDC2016 Session 419 –Be like Crusty 11
  8. A real 600 example. 12 If method navigation menu scrolls

    off your screen, you have too many methods/ivars!!!
  9. Strategies ObjectiveC and Swift: “Perfect Together” Big ObjectiveC classes: Swift

    NSObject based helpers Big Swift classes: many many options 13 Using Swift from ObjectiveC has worked well from Day 1. Objective C cannot deal with Swift structures.
  10. 1) Use Structs Use a struct to hold necessary information

    to satisfy a consuming receiver Uses structs as lightweight helpers to offload specific tasks Use structs to provide backing data for table cells 14 Advanced: Watch “dotSwift 2016 - Rob Napier - Beyond Crusty: Real-World Protocols” Swift structs can hold Objective C objects, Swift class objects, and Swift value types such as Ints and structs. Rob Napier gave a talk recently on his journey to solve a problem with Swift Protocols, structs, and functions.
  11. 1) Use Structs struct TitleItem { private let box: UIView

    private let title: String private let label: UILabel private let underline: UIView private var position: Int func bottomAnchor() -> NSLayoutAnchor { return box.bottomAnchor } func constrainTopToAnchor(anchor: NSLayoutAnchor) { box.topAnchor.constraintEqualToAnchor(anchor).active = true } mutating func updateState(state: TitleItemState) { label.text = title switch state { case .Normal: label.alpha = 1 underline.alpha = 0 case .Selected: label.alpha = 1 underline.alpha = 1 case .Dimmed: label.alpha = dimText underline.alpha = 0 } } } 15 The circled items are backed by an array of “TitleItem” structs. Note the mix of objects (UIViews) and constants (Ints) as well as helper methods.
  12. struct SBFormParser { let title: String let body: String var

    required: Bool let ppText: String? let tosText: String? var formGroupCount: Int { return self.formGroups.count } private let pp: NSAttributedString private let tos: NSAttributedString private let style: NSParagraphStyle private let font: UIFont private var formGroups: [SBFormGroup] = [] private var formItems: [Int: SBFormItem] = [:] // MARK: initialization init(jsonDict: [String: AnyObject]) { guard let ppURL = NSURL(string: "file://pp/"), tosURL = NSURL(string: "file://tos/") else { fatalError("NSURL FAILED") } Bigger helper - ~300 lines 1) Use Structs 16 This helper struct is about 300 lines of code.
  13. Simple Booth™ Capture Form “Houston, we have a problem…” 17

    I was all set to go on about what a great job I did…when I found I had a ~1000 line file (a view controller, big surprise right?)
  14. protocol SBFormBuildView : class { var parser: SBFormParser {get} var

    titleView: UILabel! {get set} var titleTextView: UITextView! {get set} var formView: UIView! {get set} var closeBox: UIStackView! {get set} var boxes: [TitleItem] {get set} var formContentView: UIView {get set} var triangleView: SBTrianglePointerView! {get set} var submitButton: UIButton {get} var backButton: UIButton {get} func buttonSelector() -> Selector func closeButtonSelector() -> Selector func label(lines lines: Int, textSize: Int, bold: Bool) -> UILabel func checkWidth() -> CGFloat } 2) Use Protocols 18 This struct was created in the hour I spent separating the view construction from my View Controller. Reduced the View Controller from 1000+ lines to 740. Process: - grab big chunk of code and copy it into a new file. Comment out the original code in the VC - create a new protocol, make the VC adopt it. - try to build, and add items to the protocol until I can build. - test! Must use “class” because the using the adopter as a button target.
  15. Simple Booth™ Capture Form Structs where possible (ObjectiveC interface forbids

    structs) Lots of local protocols between helpers and core View Controller Resulting File line length: - 13 files (in their own directory) - max: 730 - min: 95 - avg: 279 19
  16. protocol SBFormControls: class { func stackView() -> UIStackView? func dataFor(key

    key: String) -> String? func updateDataFor(key key: String, data: String?) func updateUI(incrementSelectedGroup incrementSelectedGroup : Int) func itemWithID(id: Int) -> SBFormItem func theSelectedGroup() -> SBFormGroup func sendSubmit() func isFormDone() -> Bool func ppText() -> String? func tosText() -> String? func displayText(text: String, title: String) func presentViewController(viewController: UIViewController, byTextField: UITextField) func temporarilySuppressKeyboardChanges() } 3) Use Helpers final class SBFormControlsDelegate: NSObject { private weak var delegate: SBFormControls! private var currentLocale: NSLocale private var dateFormatter: SBFormValidateDate private var phoneFormatter: SBFormValidatePhone private var postalFormatter: SBFormValidatePostcode private var dataToLocale: [SBFormDataType: String] = [:] private var localeChanged = false // MARK: - Methods init(delegate: SBFormControls) { extension SBFormControlsDelegate: UITextFieldDelegate { 20 One class handles delegate methods: UITextView, UITextField, UIButton, SBFormItem Each set of delegate methods in its own extension. Delegates do NOT need to be weak if you create a structure, use it, then discard it. Good ideas here: http://blog.flaviocaetano.com/post/a-better-way-to-organize-swift-classes/
  17. 4) Localize UI Changes // General Purpose View Model ->

    View Refresh func updateUI(animated: Bool) { button.enabled = … // lots more - all your view logic // including visible cells for cell in tableView.visibleCells { updateCell(cell, atIndex: tableView.indexPathForCell(cell)) } } // Cell creation func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier("List", forIndexPath: indexPath) // add/change visible elements, backgrounds, etc cell.backgroundColor = UIColor.blueColor() updateCell(cell, atIndex: indexPath) // code in one method return cell } // Single place where cell elements refreshed func updateCell(cell: UITableViewCell, atIndex indexPath: NSIndexPath) { // use indexPath to get appropriate data cell.textLabel?.text = “Hi” + String(indexPath.row) } 21 Only ever update the UI from one place. Call it after viewDidLoad (or viewWillAppear) to to the initial setup, then whenever something changes post a message in a dispatchBlock.
  18. 5) Use Container View Controllers iOS: UITabBarController, UISplitviewController, UIPageViewController Can

    put all views into the container view, or swap them in and out Container view controllers can use xibs or storyboard Use a protocol to connect the children to the parent 22 Apple provides several container View Controllers as standard UIKit components. Developers can easily create their own in IB or in code (Matt Neuburg’s book has a nice section on the latter).
  19. 5) Use Container View Controllers 23 Ugh, why the colors?

    I put this together using Xcode 7 in about 15 minutes (I hadn’t done it in IB before!) Note the garish colors - when designing UIs, its often nice to know exactly where views extend, and their stacking order.
  20. Recap 1. Use structs whenever possible 2. Connect with Protocols,

    not full knowledge of all classes 3. Use helpers—lots of helpers! Might want to locate in one directory. 4. Localize UI Changes 5. Container view controllers: complex views with simpler code Adding Swift code to older Objective C projects works GREAT!!! 24 Start adding Swift to your Objective C apps NOW! Take small steps - when you get comfortable take bigger steps.
  21. More Tools: Dash 3 26 $24.99 in the App Store.

    Companion iOS app too. You cannot do well coding in Swift without this app!
  22. More Tools: OmniGraffle 27 A tool I’ve used for years!

    You can schematize a complex interaction (login, update, etc), use actual class and method names, then insure your code does each transition as you believe it does.
  23. More Tools: PopClip 28 $6.99 in the App Store, 95

    5-star ratings, 2 4-star Since I use the mouse with my left hand, this is invaluable. However, I’m sure its a valuable tool for anyone. * Swap current selection with Clipboard * Append current selection to the Clipboard Write you own extensions!
  24. More Tools: iOS References 29 Thought provoking Swift Book: “Advanced

    Swift” By Chris Eidhof and Airspeed Velocity. A Swift 3 version is forthcoming.
  25. More Tools: Swiftify 30 I subscribe to this service. It

    makes that first step just so much easier. However, you can do some conversions for free.
  26. Swift Related BLOGS: Erica Sadun: http:/ /ericasadun.com
 (lots on Playgrounds,

    lively, this new mother never sleeps!) Natasha `The Robot’: http:/ /natashatherobot.com
 Swift Conference (in NYC!, Sept 1-2): https:/ /www.tryswiftnyc.com 31 Erica Sadun must never sleep: mother, writer, blogger, very active on Swift migrations: http://ericasadun.com http://natashatherobot.com Only a few seats left for Try Swift: https://www.tryswiftnyc.com
  27. artist: Randall Munroe Link in notes. Find this talk on

    SpeakerDeck: https:/ / speakerdeck.com/ dhoerl Just google SpeakerDeck and dhoerl to find it! 32 https://medium.freecodecamp.com/coding-explained-in-25-profound-comics-8847ea03819c#.u4orsnuri Author: Randall Munroe