Minimizing Decision Fatigue to Improve Team Productivity

Preview:

Citation preview

MINIMIZING DECISION FATIGUE

TO IMPROVE TEAM PRODUCTIVITY

TRY! SWIFT MARCH, 2017

DEREK LEE @DEREKLEEROCK

☀ 🌛?

Class Struct

🤔

Tabs SpacesCocoapods CarthageStoryboards CodeA BUIKit ReactNative

?

A B

🤔

???

?? ?

??? ??? ?

???

? ?????

? ???

?

?????? ?

??

???? ?

??

?

??????

???? ?

??? ?? 😓

A B

😓

A B

😓

A B

😓

A B

😓

A B

😓

A B

😓

A B

😓

A DAY IN THE LIFE @ PIVOTAL LABS

BREAKFAST!

🕣8:45am

MORNING OFFICE STANDUP

🕘9:06am

🕘9:15am

PROJECT STANDUP

PROJECT ORGANIZATION

Open Quickly ⌘+⇧+O

Filter in Navigator ⌘+⌥+J

Reveal in Navigator ⌘+⇧+J

Find in Files ⌘+⇧+F

HOW CAN WE FIND FILES IN XCODE?

“Hunt and Peck”

HOW DO WE REALLY FIND FILES IN XCODE?

“Helpers” FolderNo organization

WHAT WE’D LIKE TO AVOID

MVC?

APPLICATION ・ COMPONENTS ・ UI

APPLICATION

COMPONENTS

UI

PAIR PROGRAMMING

🕙10:00am

PAIR PROGRAMMING - SETUP

▸ Ping-Pong

PAIR PROGRAMMING - STYLES

+

▸ Driver + Navigator

PAIR PROGRAMMING - IN ACTION▸ We pair 99% of the time

▸ All disciplines pair: Engineering, Design, PMs

▸ Change pairs daily

▸ Regularly switch tracks of work

LUNCHTIME TECH TALK

🕧12:30pm

BACK TO PAIRING

🕜1:30pm

IMPROMPTU TEAM DISCUSSION

🕝2:30pm

SWIFT FILE ORGANIZATION

VIEW CONTROLLER: SHOW DOCUMENT ITEMS: ^ + 6class CountingRepeaterViewController: UIViewController { fileprivate let repeater: Repeater fileprivate let maximumCountValue: Int fileprivate var counterValue: Int

let countingLabel: UILabel

init(repeater: Repeater, maximumCountValue: Int) { ... } required init?(coder aDecoder: NSCoder) { ... }

override func viewDidLoad() { ... }

override func viewWillDisappear(_ animated: Bool) { ... }

func addSubviews() { ... }

func addConstraints() { ... }

... }

With “// MARK:”Without Annotations With “// MARK: —“MARK ANNOTATION COMPARISON

VIEW CONTROLLER ORGANIZATIONclass CountingRepeaterViewController: UIViewController { // MARK: - Properties fileprivate let repeater: Repeater fileprivate let maximumCountValue: Int fileprivate var counterValue: Int

// MARK: - View Elements let headerLabel: UILabel let countingLabel: UILabel

// MARK: - Initialization init(repeater: Repeater, maximumCountValue: Int) { ... } required init?(coder aDecoder: NSCoder) { ... }

// MARK: - Lifecycle Methods override func viewDidLoad() { ... }

override func viewWillDisappear(_ animated: Bool) }

// MARK: - Private Methods fileprivate extension CountingRepeaterViewController { func addSubviews() { ... }

func addConstraints() { ... }

VIEW CONTROLLER ORGANIZATIONclass CountingRepeaterViewController: UIViewController { // MARK: - Properties fileprivate let repeater: Repeater fileprivate let maximumCountValue: Int fileprivate var counterValue: Int

// MARK: - View Elements let headerLabel: UILabel let countingLabel: UILabel

// MARK: - Initialization init(repeater: Repeater, maximumCountValue: Int) { ... } required init?(coder aDecoder: NSCoder) { ... }

// MARK: - Lifecycle Methods override func viewDidLoad() { ... }

override func viewWillDisappear(_ animated: Bool) { ... } }

// MARK: - Private Methods fileprivate extension CountingRepeaterViewController { func addSubviews() { ... }

func addConstraints() { ... }

// MARK: - Lifecycle Methods override func viewDidLoad() { ... }

override func viewWillDisappear(_ animated: Bool) { ... }

class CountingRepeaterViewController: UIViewController { // MARK: - Properties fileprivate let repeater: Repeater fileprivate let maximumCountValue: Int fileprivate var counterValue: Int

// MARK: - View Elements let headerLabel: UILabel let countingLabel: UILabel

// MARK: - Initialization init(repeater: Repeater, maximumCountValue: Int) { ... } required init?(coder aDecoder: NSCoder) { ... }

// MARK: - Lifecycle Methods override func viewDidLoad() { ... }

override func viewWillDisappear(_ animated: Bool) }

// MARK: - Private Methods fileprivate extension CountingRepeaterViewController { func addSubviews() { ... }

func addConstraints() { ... }

CREATE TEMPLATE FROM XCODE SNIPPETS

PROTOCOL CONFORMANCEstruct DefaultCustomer: Customer { let name: String private(set) var rentals: [Rental]

init(name: String) { ... }

mutating func addRental(rental: Rental) { ... }

func createTextStatement() -> String { ... }

func createHtmlStatement() -> String { ... }

func getTotalCharge() -> Double { ... }

func getTotalFrequentRenterPoints() -> Int { ... } }

PROTOCOL CONFORMANCEstruct DefaultCustomer: Customer { // MARK: - Properties let name: String private(set) var rentals: [Rental]

// MARK: - Initialization init(name: String) { ... }

mutating func addRental(rental: Rental) { ... }

func createTextStatement() -> String { ... }

func createHtmlStatement() -> String { ... }

func getTotalCharge() -> Double { ... }

func getTotalFrequentRenterPoints() -> Int { ... } }

PROTOCOL CONFORMANCEstruct DefaultCustomer { // MARK: - Properties let name: String private(set) var rentals: [Rental]

// MARK: - Initialization init(name: String) { ... } }

// MARK: - Customer extension DefaultCustomer: Customer { mutating func addRental(rental: Rental) { ... }

func createTextStatement() -> String { ... }

func createHtmlStatement() -> String { ... }

func getTotalCharge() -> Double { ... }

func getTotalFrequentRenterPoints() -> Int { ... } }

PROTOCOL CONFORMANCEstruct DefaultCustomer { // MARK: - Properties let name: String private(set) var rentals: [Rental]

// MARK: - Initialization init(name: String) { ... } }

// MARK: - Customer extension DefaultCustomer: Customer { mutating func addRental(rental: Rental) { ... }

func createTextStatement() -> String { ... }

func createHtmlStatement() -> String { ... } }

// MARK: - Private Methods fileprivate extension DefaultCustomer { func getTotalCharge() -> Double { ... }

func getTotalFrequentRenterPoints() -> Int { ... } }

PING-PONG BREAK

🕞3:30pm

CROSS-FUNCTIONAL PAIRING

🕓4:00pm

Engineering x Design

STYLING UI OBJECTS

extension UIFont { class func abcMediumFont(size: CGFloat) -> UIFont { return UIFont(name: "AvenirNext-Medium", size: size)! }

class func abcBoldFont(size: CGFloat) -> UIFont { return UIFont(name: "AvenirNext-Bold", size: size)! } }

DEFINING FONTS

extension UIColor { class var abcDarkSkyBlue: UIColor { return UIColor( red: 52.0 / 255.0, green: 152.0 / 255.0, blue: 219.0 / 255.0, alpha: 1.0 ) }

class var abcBlueish: UIColor { return UIColor( red: 41.0 / 255.0, green: 128.0 / 255.0, blue: 185.0 / 255.0, alpha: 1.0 ) } }

DEFINING COLORS

enum UIButtonStyle { case primary, negative

func applyTo(button: UIButton) { switch (self) {

case .primary: button.titleLabel?.font = UIFont.abcMediumFont(

size: 15 )

button.setTitleColor(UIColor.white, for: .normal) button.backgroundColor = UIColor.abcDarkSkyBlue button.layer.borderColor = UIColor.abcBlueish.cgColor button.layer.borderWidth = 1.0 break

case .negative: // ... break } } }

DEFINING STYLES

APPLYING STYLESextension UIButton { func apply(style: UIButtonStyle) { style.applyTo(button: self) } }

class MyViewController: UIViewController {

let confirmButton: UIButton let cancelButton: UIButton

...

fileprivate func applyStyles() { confirmButton.apply(style: .primary) cancelButton.apply(style: .negative) } }

RETROSPECTIVE (RETRO)

🕔5:00pm

RETROS - INGREDIENTS

🙂🙂

🙂

🙂

🙂

🙂

Core Team Members Food & Snacks

🍓🧀

🍙🍪

Drinks

☕🍵

🍷🍺

RETROS @ PIVOTAL LABS

😃Discuss

😭Keep

😕Improve

RETROS @ PIVOTAL LABS

▸ Reflect → Continuous improvement

▸ Building Trust

▸ Honest communication

▸ Identify & solve problems early

▸ Team brainstorming

Kent Beck, Extreme Programming Explained

THE COURAGE TO SPEAK TRUTHS, PLEASANT OR UNPLEASANT,

FOSTERS COMMUNICATION AND TRUST.

SUMMARY

▸ Project Standup

▸ Pair Programming

▸ Lunchtime Tech Talk

▸ Impromptu Team Discussions

▸ Cross-Functional Pairing

▸ Retrospectives

▸ Project Organization

▸ Swift File Organization

▸ Styling UI Objects

A B

😓

A B

😓

A B

😓

A B

😓

A B

😓

A B

😓

😓😓 😓

😓😓 😓

😓😓 😓

😓😓 😓

😁😃 😛

🙃😎 😅

Thank you!

try! Swift March 2017

@DEREKLEEROCK Thank you!

try! Swift March 2017

Recommended