Refactoring to Clean Value Transformations in Swift

Daniel Steinberg’s presentation “Ready for the Future: Writing Better Swift” teaches us a lot about readable code. He refactors a calculation into many functions with very specific responsibilities. The resulting functions are super slim.

The result is this:

let lastWeeksRevenues = lastWeeksSales
                        » anArrayOfDailySales
                        » replaceNagiveSalesWithZeroSales
                        » calculateRevenuesFromSales

When you read that code it should be very clear what’s going on. The function names communicate their intent.

Now the implementation:

func anArrayOfDailySales(rawSales: AppSales) -> [Int] {
    return rawSales.map{$0}
}

func replaceNagiveSalesWithZeroSales(sales: [Int]) -> [Int] {
    return sales.map(negativeNumbersToZero)
}

func negativeNumbersToZero(number: Int) -> Int {
    return max(0, number)
}
    
func calculateRevenuesFromSales(sales: [Int]) -> [USDollars] {
    return sales.map(revenuesInDollarsForCopiesSold)
}

func revenuesInDollarsForCopiesSold(numberOfCopies: Int) -> USDollars {
    return numberOfCopies
        » revenuesForCopiesSold
        » toTheNearestPenny
}

let unitPrice = 1.99
let sellersPercentage = 0.70

func revenuesForCopiesSold(numberOfCopies: Int) -> USDollars {
    return Double(numberOfCopies) * unitPrice * sellersPercentage
}

infix operator » {associativity left}

func »<T, U>(input: T, transform: T -> U) -> U {
    return transform(input)         
}

Apart from the » operator which merely changes foo.map(bar) to foo » bar, the functions are very small, easy to read. This reminds me of the result of 3/4 of Sandi Metz’s arbitrary rules for writing Ruby code:

  1. Classes must be shorter than 100 lines
  2. Methods must be shorter than 5 lines
  3. Always pass less than 4 parameters into a method

Of course the result is a lot of functions for a rather simple algorithm. But it works well because it is easy to read in the long term. Even newcomers can grasp what’s going on without knowing much about the language or typical Cocoa-programmer conventions.

Bonus: you can unit test each function to check if the parts of the overall algorithm works as expected.

Blocks: Useful to Perform Actions In Context

Something short and sweet I want to share with you because I love how it reads: restoringSelection is a function that takes a block and performs whatever the block does while restoring the current selection in a table view (here: NSTableView). Here’s the implementation. The resulting code from above reads so much nicer than querying selection() first and restoring it afterwards. It communicates very clearly that some state from before will be preserved (or restored).

Continue reading …

Symmetry

At first, this was all there was:

protocol DisplaysDateRange {
    func showDateRange(dateRange: DateRangeData)
}

class DateRangeViewController: NSViewController, DisplaysDateRange {
    @IBOutlet var dateRangeButton: NSButton!

    func showDateRange(dateRange: DateRangeData) {
        dateRangeButton.title = dateRange.range
    }
}

Then I implemented a sub-view controller and delegated to it, too:

class DateRangePickerController: NSViewController, DisplaysDateRange { 
    // ... 
}

class DateRangeViewController: NSViewController, DisplaysDateRange {
    @IBOutlet var dateRangeButton: NSButton!
    @IBOutlet var dateRangePickerController: DateRangePickerController!

    func showDateRange(dateRange: DateRangeData) {
        dateRangeButton.title = dateRange.range
        dateRangePickerController.showDateRange(dateRange)
    }
}

Then, by habit, I remembered Kent Beck’s advise to keep symmetry high for clean and maintainable code:

class DateRangeButton: NSButton, DisplaysDateRange {
    func showDateRange(dateRange: DateRangeData) {
        title = dateRange.range
    }
}

class DateRangeViewController: NSViewController, DisplaysDateRange {
    @IBOutlet var dateRangeButton: DateRangeButton!
    @IBOutlet var dateRangePickerController: DateRangePickerController!
    
    func showDateRange(dateRange: DateRangeData) {
        dateRangeButton.showDateRange(dateRange)
        dateRangePickerController.showDateRange(dateRange)
    }
}
petals
Photo credit: Layers of petals by n.a.t.u.r.e. License: CC BY-NC-ND 2.0

Sure, now there’s a subclass of NSButton that doesn’t do much and will not be reused in the app. But the intent of delegating DateRangeData to the sub-components is clearer.

Clean and maintainable code will help you see what’s going on when you read the code. title = dateRange.range doesn’t convey everything showDateRange(dateRange) does.

Small Helper Objects Take You Far

Teaser image

Integrating new functionality is fun. But revisiting 18-months old code isn’t. Back then I created a protocol InvokesWindows to define methods like -showPreferencesWindow which I imported in the menu bar controller to show the preferences when the user selects a pop-up menu item. But I didn’t actually delegate to any instance of InvokesWindows. I used NSApp. (Insert facepalm here.)

Continue reading …

What is CLEAN Code?

Writing clean code makes your life better in the long term, and I find it’s more fun initially. According to Bernstein, CLEAN is an acronym:

  • Cohesive
  • Loosely Coupled
  • Encapsulated
  • Assertive
  • Non-Redundant

His book “Beyond Legacy Code. Nine Practices to Extend the Life (and Value) of Your Software” seems to be a good read. Not through, yet.1

  1. Affiliate link; I get a small kickback from the vendor if you buy from my link but it won’t cost you anything. 

Clean Coding is a Programming Misnomer for a Software Engineering Principle

Teaser image

I found a cute info-graphic on how to become an iOS developer by John Kim. This study guide contains a passage with a very interesting distinction between programming and engineering. Thanks to it, I found out a detail about what it means to write “clean code.”

Citing from the graphic:

Programming is like building the bridge. You need to know how to use the tools to get your end result. In this way, you need to know the programming language to build your “bridge”

Software engineering is like knowing how to design a bridge. You need to know the proven industry design rules to make a long lasting and reliable “bridge”. In this way you need to learn software engineering to design great software

Learning the Syntax and grammar of a programming language is pretty straight foward [sic!]

Understanding software engineering is the hard part about becoming an iOS developer

Learn BOTH but focus on Software Engieering [sic!]

Software engineering is about the design principles. It’s the necessary condition to plan the components of object-oriented projects like those for iOS and Mac. It is required to write clean code.

Programming itself is about API knowledge, understanding the language grammar and the like.

Of course we write clean code, but we’re able to write it only because we’re able to make a clean design up in the first place. So there’s not much clean coding, but a lot more clean design.