Shopify's Ruby on Rails app statistics

Shopify published amazing/epic stats for their Ruby on Rails “app”:

  • 860k LoC
  • 1:1.3 code–test ratio
  • 2300 model classes
  • most classes <10 methods
  • most methods way <10 lines

Makes you wonder:

  • can you live with more types?
  • can you shrink down existing types?

Swift changed the game a bit. Now it’s very convenient to create a new type. You don’t need to do the .h/.m file dance anymore but can start a new type declaration wherever you are. (Except when you’re inside a generic type.) That makes it more likely we devs stop to shy away from smaller types.

But it’s still a job for our community’s culture to unlearn coding huge classes (massive view controller syndrome, anyone?) and splitting stuff.

Ruby has a long tradition of super-focused methods and very small classes. Swift is just as terse and powerful in that regard. Now it’s your turn to experiment with writing types for very simple tasks. Like the Extract Parameter Object refactoring, where you lift things that go together into a new type.

Can be as easy as writing:

struct DateRange {
    let start: Date
    let end: Date
}

Et voilà, there you have a new explicit concept in your code base.

How to Refactor Messy Apps for a New Architecture?

When facing a legacy code base, changing the mess to an orderly architecture can cause confusion: where to start? What to do? An exemplary question: How do I refactor a Big Ball of Mud into layered architecture? Refactoring1 the existing code base seems like a logical step; after all, refactorings are designed to improve existing code, and improvement is what you’re up to.

Continue reading …

Splitting the View Models of TableFlip, a Short Aftermath

Teaser image

I executed my plan from earlier this week to split TableFlip’s monolithic view model into sub-view models. The process wasn’t too complicated. The highlights: The current hierarchy of controllers in the view layer is as follows: The window doesn’t look too complicated and there truly are not that many view components involved, but still it’s quite some work to keep things well coordinated. The TableViewController file clocks in at about 400 lines of code although it mostly delegates stuff to other objects. There’s still room for improvement, but I have to see patterns, first. I even extracted NSTableViewaDataSource and NSTableViewDelegate into different objects months ago. Today I doubt this was a good idea in the first place. We’ll see.

Continue reading …

I'll Split Up the Monolithic View Model in TableFlip. Here's What I Expect to Happen

The upcoming changes in TableFlip’s user experience made me ponder how I structured the app’s modules. The bottleneck I created in my app is simple: there’s one presenter which transforms the model into a view model; the presenter defines a protocol for the view it expects and passes the view model to the object that satisfies this contract.

Continue reading …

Location Matters

The location of a piece of code always matters. I was fiddling with the Charts library today and found out that if you set a chart’s data to nil, it renders some informative text by default. My data source doesn’t pass nil but an empty array around, though, so I had to convert empty arrays to nil to make use of this feature.

Continue reading …

Configuration Objects and the Then Microframework

When parameter lists grow or two kinds of parameters seem to go together a lot, it’s time use the extract parameter object refactoring for greater good – then you can even specify sensible defaults.

This is a typical way to pass a set of options to an objects during initialization in a language like Swift. In languages like JavaScript or Ruby, dictionaries of key–value pairs can work just as well. Using dictionaries in Swift for this can be a pain, though.

Now Soroush wrote about a way that uses the Then microframework as a replacement for configuaration dictionaries. This way you don’t have to promote every property to the initializer’s list of parameters. Here’s a before and after, where you can see that without then you have to write a lot of repeating boilerplate:

// Before

struct FieldData {
    let title: String
    let placeholder: String
    let keyboardType: UIKeyboardType
    let secureEntry: Bool
    let autocorrectType: UITextAutocorrectionType
    let autocapitalizationType: UITextAutocapitalizationType

    init(title: String,
        placeholder: String = "",
        keyboardType: UIKeyboardType = .Default,
        secureEntry: Bool = false,
        autocorrectType: UITextAutocorrectionType = .None,
        autocapitalizationType: UITextAutocapitalizationType = .None)
        {
            self.title = title
            self.placeholder = placeholder
            self.keyboardType = keyboardType
            self.secureEntry = secureEntry
            self.autocorrectType = autocorrectType
            self.autocapitalizationType = autocapitalizationType
    }
}

let fieldData = FieldData(title: "Password", secureEntry: true)

Now with then, making non-mandatory properties mutable and getting rid of the boilerplate:

// After

struct FieldData {
    let title: String
    var placeholder = ""
    var keyboardType = UIKeyboardType.Default
    var secureEntry = false
    var autocorrectType = UITextAutocorrectionType.No
    var autocapitalizationType = UITextAutocapitalizationType.None

    init(title: String) {
        self.title = title
    }
}

let fieldData = FieldData(title: "Password").then({
    $0.secureEntry = true
})

That’s a Swift alternative to Ruby’s hash-based option initializers. There, the dictionary’s key is used as the setter’s name which is then invoked like so:

class Example
  attr_reader :name, :age
  
  def initialize(args)
    args.each do |k,v|
      instance_variable_set("@#{k}", v) unless v.nil?
    end
  end
end

e1 = Example.new :name => 'foo', :age => 33
#=> #<Example:0x3f9a1c @name="foo", @age=33>

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.

Parameter Objects Simplify Your API Versions

I watched an AltConf about API design the other day. I cannot seem to find which talk it was, though. Anyware, the presenter talked about using parameter objects when the parameter list grows too long or is open for change in future versions. Parameter objects can change internally and evolve with the API. You can add or remove attributes, for example, while the API calls of old client code don’t have to change: they still pass the same type in. That makes framework updates a bit less painful because method signatures stay the same.

Continue reading …

Tips to Conquer Massive View Controllers

View Controllers should only be responsible for view lifecycle events, Marcus Zarra reminds us. That means they should populate views with data, and show and hide them – stuff like that. View controllers should not do the work of views.

While I like his overall advice, it contains a few problematic points:

  • Put Core Data out of the view controller. His solution to provide a single data source tied to a NSManagedObjectContext will not scale well as I’ve experienced. – Still, don’t tie it to the view controllers. That makes matters worse.
  • His definition of “business logic” is odd. Business logic is not reducible to I/O code. It’s not just about fetching data from a device and doing network requests – except when your app is a very, very simplistic display for data with CRUD operations. Business logic can exceed data-centric rules and entail a real domain with complex behavior without much imagination.
  • Views should be responsible for displaying data, agreed. Since validation problems will be presented to the user, validation error messages will be part of that data, too. But views should not validate. Validation rule objects (WWDC’14 talk) should be the strategies that do validation.

If we create an object to sit between the view and the view controller then we are creating unnecessary additional objects.

Where do presenters sit? Between view and and view controller – but they make it easier to read and extend the code. They’re hardly unnecessary.

I strongly believe that it’s impossible to give advice about how to code and architect something if the problem domain isn’t part of the example. Because everything depends on the problem space in the end.

Remember to take every advice with a grain of salt. Collect things like Marcus’ tips to obtain new tools, but don’t take the tool for the solution of modelling a program to solve real problems.

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 …

Refactoring Legacy Code: Replace Free Function in Tests, Even Swift's Own Functions

Teaser image

Refactoring Legacy Code is hard. There are a few safe refactorings you can do with caution. But most chirurgical cuts require you to put the code in a test harness first to guard against regression. With C and Swift, you can create free functions as part of your app. To verify your objects use that function, you need to find a way to insert a test double.

Continue reading …

Success and Error Callbacks in Objective-C: a Refactoring

I’m refactoring code of Calendar Paste 2 some more. Since I like what I learned using Swift so much, one of today’s changes was about making a view controller method do less by factoring object creation and error handling into its collaborators. The resulting code handles far less of the action involved. Instead, it delegates the action to a new command-like object. And instead of querying an event template for data and assembling an actual event with start and end dates, it delegates event creation to the template itself. Tell, Don’t Ask saved the day.

Continue reading …

Making Good Use of Singletons in Refactoring the iOS App Calendar Paste

Like I promised last weekend, I am going to write about the process of cleaning up the already rotten source code of Calendar Paste. In order to break massive view controllers into manageable pieces and un-tangle everything, I have to make sure that I don’t break the current implementation. Calendar Paste didn’t have any automated tests in place. To change this fact is my first priority.

Continue reading …