My GitHub contributions over the years

I came across this website that goes into your GitHub profile and generates an image of the contributions that you’ve made over the years.

Here’s mine:

It’s nice to see that I’ve managed to (mostly) avoid working on weekends.

Credits: Sallar on Twitter.

Publicado en Journal, Programming | Comentarios desactivados en My GitHub contributions over the years

Continuous Deployment of Mobile Software at Facebook

Facebook published a pretty interesting paper where they describe their strategy for doing CI/CD of their mobile apps, both on iOS and Android.
They describe the whole enchilada: from the general release cycle of their apps, to what they test for and how they test for that. But also, they share what they found after analyzing their strategy, looking for signs of how it impacted their development workflow.
The data they looked at goes back to 2009:

A significant aspect of our study is that the data we base our analysis on is extensive (§3). The data we analyzed covers the period from January, 2009 to May, 2016. It includes all of the commit logs from revision control systems, all app crashes that were captured, all issues reported by FB staff and customers, and all issues identified as critical during the release process.

That’s a crazy amount of information, and the conclusions they draw after crunching all the numbers are really interesting also, but perhaps not all-that surprising to people with experience in this industry. For instance:

We believe we are the first to show two compelling findings: (i) the number of developers modifying a file is inversely correlated to the quality of software in that file, and (ii) the software changes pushed on the day of the release cut from the Master branch are of lower quality than the files pushed on other days.

I had that empiric knowledge. It’s nice to have the data to back it up.
Also interesting:

Productivity remains constant even as the number of engineers working on the code base grows by a factor of 15. This is the case for both Android and iOS developers, and whether measured by LoC pushed or number of pushes.

If you do mobile development and are interested in stuff beyond the hottest new design pattern of the week, this is a great read. I really enjoyed it.

Publicado en Software | Comentarios desactivados en Continuous Deployment of Mobile Software at Facebook

Today's workout

I was finally able to do a “regular” workout session after a week vacationing in Mazatlán, Sinaloa, with my in-laws (post for a later time).

It is really interesting how after a year and a half of working out at least 4 days a week, my body now asks for exercise. I really feel the need to do something that lets off some steam, and burn some calories while doing so.

Exercise has become a mind palace where I can just “lay back” (I’m actually running or walking briskly, or doing jumping jacks, or something) and let my mind breathe and wander around. Exercising without headphones on has been an unexpected joy lately, although I’m not going exclusively headphone-free most of the time, since that’s also one of my favorite moments to catch up with my ever-growing list of podcasts that I want to listen to.

Publicado en Journal | Comentarios desactivados en Today's workout

Writing Code Long Before You Need It

Brent Simmons, writing for Inessential.com:

Along the way I’ve had many moments where a thing I’d written years before — because I knew I would need it — suddenly becomes useful. For instance, I wrote the OPML parser early on (one of the very first things), and it was only years later when I added OPML import to the app. (There wasn’t even an app at all when I wrote the OPML parser.)
Those moments are great. The pieces start to click together, and you realize you planned well.

I’ve had these moments before. I only expect them to become more common once Marzipan arrives in the hands of developers.

Publicado en Programming | Comentarios desactivados en Writing Code Long Before You Need It

One more argument for using descriptive variable names

Not too long ago someone asked me if I thought that rejecting (or requesting changes to) a GitHub PR because a variable or property is not named correctly was “a valid thing to do.”
I said: yeah. I’ve had that happen to me before, and I don’t think that’s an unreasonable thing to do within a healthy team environment.
The argument that you read code an order of magnitude more times than you write it has been beaten to death before, so I present to you yet another reason why naming things correctly is more than a matter of just style or personal preference: it helps your tools help you.


A common thing to do within the Objective-C runtime is to copy objects, calling -[object copy]. There’s no - copy method to implement on objects, though. The actual copying happens within the class method - copyWithZone:.
At this point, trying to get a list of all the places in the code that copy an instance of an object is impossible, because - copyWithZone: is not called directly from anywhere. So what did I do? Search for correctlyNamedObject copy].


Within our team, one of our guidelines is that things have to be named correctly, and not doing so is grounds for someone requesting changes to a Pull Request. I didn’t write all the calls to - copy, someone else did, and because we have that rule in place, I can make an educated guess of how an instance of an object of a certain class is likely to be named.
Consistency only makes our lives as developers easier.

Publicado en Programming | Comentarios desactivados en One more argument for using descriptive variable names

40% down in 15 minutes

Just watched my MacBook Pro’s battery level go from 70% to 30% in about 15 minutes while running the analyzer in Xcode.
I’m traveling this week, and the fact that I really can’t rely on my work computer to do actual work while on the go is kinda frustrating. To be able to do anything meaningful, I need to always be near a power outlet, which kind of nullifies the benefits of having a powerful, mobile computer.

Publicado en Journal | Comentarios desactivados en 40% down in 15 minutes

First impressions on the Kindle Paperwhite

Recently decided to get a Kindle Paperwhite. I got rid of my iPad, so I ended up with no device to read lengthy pieces comfortably on the road or on bed, so the Kindle seemed like the best option.
First impressions: it’s nicer than I expected, and my girlfriend seems to be the one enjoying it the most.


It’s a shame there’s not a simple way to get my read-later items on to it, though. The Kindle seems like the perfect device to have a built-in RSS reader.

Publicado en Journal | Comentarios desactivados en First impressions on the Kindle Paperwhite

Breaking the #inout habit

A couple of weeks ago, the leadership at PSPDFKit decided that the #inout Slack channel, which we used to punch in and out of work via and “in” or “out” message, was no longer relevant.
They communicated that they don’t see the benefit of having it anymore, since the team has grown to a bunch of different timezones, but, more importantly (to me, that is), they trust us with how we manage our time, and they don’t need to keep tabs on how we decide to go about completing our daily work hours.
Was a bit of a challenge to break the muscle memory if typing “Command-T + inout + out” when finishing my day, but I gotta say: being a part of a trusting team is refreshing. I highly recommend it.

Publicado en Work | Comentarios desactivados en Breaking the #inout habit

Moving my journal to Swanros.com

I’ve been trying really hard to avoid social media for the past few weeks. I noticed that I was devoting much more time to it that what I felt comfortable with: my performance and attention to important stuff started to suffer from it.
So I’ve decided to write more on my blog instead. You can expect more content here as my main outlet, instead of Twitter.

Publicado en Journal | Comentarios desactivados en Moving my journal to Swanros.com

Handling routes from an API in a type-safe way with Swift

I’m working on an application that has to handle some kind of routing directions coming from an API in the following form:

{
    "title": "Tap to go to your profile!",
    "destination": "profile"
}

These items would show in a form of timeline of events, that when tapped, would take you to specific parts of the application.
I was thinking about how I could leverage Swift’s type-safety to make sure the application validates the destinations for each of these items and make a more robust solution for this.
Immediately, enums came to mind. I can easily define an enumeration with raw values:

enum Destination: String {
    case profile
    case info
    case feed
}

But then, I looked closely at the API’s documentation, and noticed that some destinations could come with attached metadata:

{
    "title": "Tap to go to Oscar's profile!",
    "destination": "profile:859928508374784884"
}

As you can probably guess, tapping on the item above should take you to the profile screen for the user with id 859928508374784884. I thought of enums with associated values, but that wouldn’t cut it. Associated values in enumerations prevent me from inflating instances from raw values.
I decided to come up with my alternative for enumerations to handle this specific case so I could build destination instances in a type-safe manner directly from the JSON objects coming from the API.


First, I started with a structure. Since I’m interested in being able to convert a raw string to an instance of my type and viceversa, RawRepresentable is the protocol to adopt.

struct Destination: RawRepresentable {
    private let _identifier: String
    var rawValue: String {
        return _identifier
    }
    init?(rawValue: String) {
        _identifier = rawValue
    }
}

Now, I need to check whether the raw value passed to the initializer is a valid one. For that, I defined a string set that contained all the possible identifiers for a Destination, and check for that on the failable initializer from RawRepresentable.

struct Destination: RawRepresentable {
    // ...
    private static let options: Set<String> = [
        "info",
        "profile",
        "feed",
        "event"
    ]
    init?(rawValue: String) {
        guard Destination.options.contains(rawValue) else {
            return nil
        }
        _identifier = rawValue
    }
}

The only thing missing right now would be handling the attached metadata for the available destinations.
For that, I added a value property that would hold the destination’s metadata (if any), and a couple more checks to the the initializer:

struct Destination: RawRepresentable {
    // ...
    var value: String?
    public var rawValue: String {
        return _identifier + (value != nil ? ":(value!)" : "")
    }
    init?(rawValue: String) {
        // Split the raw value
        let ids = rawValue.split(separator: ":")
        // Check that the identifier exists
        guard let identifier = ids.first else {
            return nil
        }
        // Convert from String.SubSequence
        let id = String(identifier)
        // Make sure this identifier is valid
        guard Destination.options.contains(id) else {
            return nil
        }
        _identifier = id
        // If metadata exists, add that metadata to value
        if ids.count == 2 {
            value = String(ids[1])
        }
    }
}

Now, conform with Codable so that Destination can be parsed from and to raw data:

struct Destination: RawRepresentable {
    // ...
    enum DestinationError: Error {
        case unsupportedDestination
        case wrongFormat
    }
    enum CodingKeys: String, CodingKey {
        case _identifier = "destination"
    }
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(_identifier, forKey: ._identifier)
    }
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let rawValue = try container.decode(String.self, forKey: ._identifier)
        let ids = rawValue.split(separator: ":")
        guard let identifier = ids.first else {
            throw DestinationError.wrongFormat
        }
        let id = String(identifier)
        guard Destination.options.contains(id) else {
            throw DestinationError.unsupportedDestination
        }
        _identifier = id
        if ids.count == 2 {
            value = String(ids[1])
        }
    }
}

Unfortunately, I coulnd’t find an elegant way to extract the initialization checks to another method (because scope initialization, etc), so the initializer from RawRepresentable has to be basically duplicated on the one from Decodable.
One last step would be making Destination conform with Hashable:

struct Destination: RawRepresentable, Codable, Hashable {
    // ...
    var hashValue: Int {
        return _identifier.hashValue
    }
}
func ==(lhs: Destination, rhs: Destination) -> Bool {
    return lhs.hashValue == rhs.hashValue
}

Note that hashValue takes only into account the identifier for the destination, not it’s attached value. That way, profile:859928508374784884 and a profile are considered equal, even though the first one has attached metadata.

This is super specific in this case, because I only care about the route and the metadata is treated as optional. However, in your own implementation, taking value into consideration for Hashable might make sense.

And that’s it. A quick hack would be to add static properties to Destination with prebuilt values so that they can be treated as enumeration cases:

struct Destination: RawRepresentable {
    static let info = Destination(rawValue: "info")!
    static let profile = Destination(rawValue: "profile")!
    static let feed = Destination(rawValue: "feed")!
    static let event = Destination(rawValue: "event")!
    static func profile(value: String) -> Destination? {
        return Destination.rawValue("profile:(value)")
    }
}

Here’s how all that comes together:

let json = ["destination": "profile:859928508374784884"]
let jsonData = try! JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)
let decoder = JSONDecoder()
let parsedDestination = try? decoder.decode(Destination.self, from: jsonData)
let simpleDestination = Destination.profile
let profileDestination = Destination.profile(value: "859928508374784884")!
parsedDestination == profileDestination // #=> true

And of course, you can switch on Destination values as well:

switch parsedDestination! {
case .profile:
    router.navigateToProfile(parsedDestination)
default:
    // Handle other cases.
}

I thought this could make for a nice example on how to leverage Swift’s flexibility to help when the default data structures are not compatible with our use cases.
If you have any comments or idea, or I missed something, feel free to ping me on Twitter @Swanros.
Thanks for reading!

Publicado en iOS | Etiquetado , , , , , , , | Comentarios desactivados en Handling routes from an API in a type-safe way with Swift