The Swift Brown Fox Says …

I wanted a way to include several topics in one post for beginner Swifters, so here you go:

  • A silly meme
  • A simple protocol
  • Multiple simple implementations of a protocol
  • Pseudo-random number generation within a range
  • Null (Nil) Object Pattern
  • Make a string lowercase

I’ll be referencing a meme/song, “What Does the Fox Say?“, because I couldn’t think of anything better.

A simple protocol that requires all Animals to “say” something:

public protocol Animal {
    func say() -> String
}

 

Some simple protocol implementations for common animals:

public class Dog: Animal {
    public func say() -> String { return "woof" }
}

public class Cat: Animal {
    public func say() -> String { return "meow" }
}

public class Bird: Animal {
    public func say() -> String { return "tweet" }
}

public class Mouse: Animal {
    public func say() -> String { return "squeak" }
}

public class Cow: Animal {
    public func say() -> String { return "moo" }
}

public class Frog: Animal {
    public func say() -> String { return "croak" }
}

public class Elephant: Animal {
    public func say() -> String { return "toot" }
}

public class Duck: Animal {
    public func say() -> String { return "quack" }
}

public class Fish: Animal {
    public func say() -> String { return "blub" }
}

public class Seal: Animal {
    public func say() -> String { return "ow ow ow" }
}

 

Randomly selecting from a list of “sayings” from an unusual animal:

public class Fox: Animal {
    private let phrases = [ "Ring-ding-ding-ding-dingeringeding!",
                            "Gering-ding-ding-ding-dingeringeding!",
                            "Wa-pa-pa-pa-pa-pa-pow!",
                            "Hatee-hatee-hatee-ho!",
                            "Joff-tchoff-tchoff-tchoffo-tchoffo-tchoff!",
                            "Jacha-chacha-chacha-chow!",
                            "Fraka-kaka-kaka-kaka-kow!",
                            "A-hee-ahee ha-hee!",
                            "A-oo-oo-oo-ooo!",
                            "Woo-oo-oo-ooo!"]
    
    public func say() -> String {
        let numberOfPhrases = UInt32(phrases.count)
        let index = Int(arc4random_uniform(numberOfPhrases))
        return phrases[index]
    }
}

 

One of the things I really think I like about Swift is that if you don’t declare a variable as optional (using the ?), it is guaranteed to have a value. You can leverage the Null(Nil) Object Pattern for unknown animals so that you never have to check for nil:

public class NullAnimal: Animal {
    public func say() -> String { return "..." }
}

 

Converting a string to lowercase for more robust matching:

func whatDoesThe(name: String) -> Animal {
    switch(name.lowercaseString){
        case "dog": return Dog()
        case "cat": return Cat()
        case "bird": return Bird()
        case "mouse": return Mouse()
        case "cow": return Cow()
        case "frog": return Frog()
        case "elephant": return Elephant()
        case "duck": return Duck()
        case "fish": return Fish()
        case "seal": return Seal()
        case "fox": return Fox()
        default: return NullAnimal()
    }
}

 

Playing with our new toy:

whatDoesThe("dog").say() // "woof"
whatDoesThe("fox").say() // randomly selected phrase
whatDoesThe("liger").say() // "..."
Share

Anything you can code, I can code better (The IKEA Effect)

I am fascinated by cognitive biases. I hope you’ll find them interesting, too, because I plan to discuss several of them on this blog as they pertain to software development. The first one I would like to write about is a blind spot that a lot of us have when it comes to code we wrote.

The IKEA Effect boils down to us putting higher value on something that we created or helped create. I have a lot of pride in my work and I’m not suggesting that pride is a bad thing. However, it can become a hinderance to learning and growth when we irrationally defend our creations.

Here are a few examples of things I’ve seen in my career:

  • Custom solutions for common tools like bug tracking software. This doesn’t make a whole lot of sense when there are solutions created by people who focus solely on this problem.
  • Bubble gum and baling wire used to force a tool to perform a task it wasn’t designed to accomplish because someone has experience with that tool. This is also referred to as the “golden hammer“.
  • Reluctance to try a different approach because a lot of effort was put into the current implementation. This is also referred to as “sunk cost” bias.
  • This is the way we’ve always done it… Ugh.

And, here are a few suggestions to help you steer clear of the IKEA effect:

  1. Don’t take an alternative presented by another person as an attack on your solution. I know communication isn’t every developer’s strong suit, but, as a developer, you should learn to see past that and realize everyone is working toward the same goal. Sometimes you will have the best answer and sometimes you won’t, but you’ll never know unless you’re able to consider ideas other than your own.
  2. Remember that our industry covers a breadth so large that none of us can be an expert at everything. Before you decide to roll your own, consider that there may be a solution created by a 3rd party that has invested a lot more time and energy than you are currently able to pour into solving a particular problem.
  3. Don’t be lazy. It is often easier to understand something we’ve created ourselves than to take time understanding how someone else solved the problem. Fight that urge to default to whatever it is you happen to know and use the opportunity to get a different perspective. Even if you stick with your solution, you may pick up a few tricks that will help you improve it.

In the end, your solution may be the best solution. The important thing is to be able to consider alternatives without bias and be happy to learn when someone presents a better solution. If you’re on a team where your ideas always win out, you may want to consider changing teams. Surrounding myself with people who can challenge me has been one of the greatest sources of growth and success in my career.

Share

Failure as a Catalyst for Growth

Several years ago I was contacted by a recruiter from Google. I was really excited and incredibly humbled that I had even been noticed by a company with their reputation. So, I pulled out my Cormen book (Introduction to Algorithms) and started franticly working through random problems using an IDE. My preparation was not only incomplete, but it was also ill-conceived. My naivety and lack of adequate preparation got me about as far as you might expect: nowhere.

Until recently, I only told a few people about this experience. I was embarrassed. I had failed. The funny thing was that I felt like I was at the top of my game at my current job. I had solved some memory management problems that were plaguing our product. I had been the champion for introducing automated testing to our team’s products. My yearly reviews indicated that I was doing exceptionally well. So, where was the disconnect?

The company I was working for afforded me many interesting projects. I even got to work on some machine learning code. Unfortunately, I hadn’t spent a lot of time thinking about how I would explain that work to a non-coworker. Instead, I ended up responding frequently to questions about my resume with: “I don’t remember the details.”

Next was a coding problem. It wasn’t a very hard coding problem. However, there were a few things that I hadn’t rehearsed that made things difficult.

1) I had been practicing in an IDE with code completion and didn’t realize how much I had been relying on it. I had to write my code in a basic text editor, so I didn’t have all my fancy productivity tools like autocompletion.

2) I had not practiced talking about what I was doing as I was doing it. It turns out that this is something that isn’t hard to master with a little practice.

3) I didn’t work nearly enough problems when I was preparing.

As soon as I hung up the phone with the interviewer, I pulled up my IDE and spit out a working solution in 5 minutes. I was so angry with myself.

Of course, this isn’t the end of my story. It turns out that nothing in my career, to this day, has motivated me more than this single experience. I started buying and reading lots of software development and computer science books. I had missed out on so much! I wish I had found Clean Code, The Pragmatic Programmer, and Code Complete when I was in college. But, there is no point in dwelling on the past. I needed to have these gaps exposed in order to fill them.

In an interview years later, I was told by an interviewer, “You should be careful about putting big words like ‘Metaheuristic Optimization’ on your resume because someone might ask you about that.” I was able to confidently respond with, “I came prepared to talk about that in as much detail as you’d like.” I was disappointed when the interviewer’s response was, “No, no need for that.” However, I did get a job offer after that interview.

All this to say, don’t be discouraged by your failures. Seize them as an opportunity to improve. If you aren’t failing frequently, you probably aren’t growing, so make sure to challenge yourself on a regular basis.

Share

The Law of Demeter and the 9th Circle of Hell

There are ways to make your code a living nightmare to test. Most of them involve tight coupling. To me, there is nothing worse than trying to mock multiple layers of dependencies in order to test some otherwise simple block of code.

Consider the following code:

func doubleSomethingUseful(does: Does) -> Int {
    return 2 * does.something().useful().eventually()
}

class Does {
    func something() -> Something {
        return Something()
    }
}

class Something {
    func useful() -> Useful {
        return Useful()
    }
}

class Useful {
    func eventually() -> Int {
        return 1
    }
}

If I’m trying to test doubleSomethingUseful(), I have to mock an instance of the Does class so that the something() method can return a mock of the Something class. The mock of the Something class has to return a mock instance of the Useful class when the useful() method is called. And, all this so that the mock instance of the Useful class can return some predetermined test value when the eventually() method is called.

Enter the Law of Demeter (or principle of least knowledge.) The general idea is that a class should not expose its dependencies to its consumers. Instead, it should expose the functionality of its dependencies through wrapper methods. This is a form of information hiding. Click here for an in-depth explanation.

Here is what it might look like for my contrived example:

class Does {    
    func somethingUsefulNow() -> Int {
        return Something().usefulNow()
    }
}

class Something {
    func usefulNow() -> Int {
        return Useful().eventually()
    }
}

class Useful {
    func eventually() -> Int {
        return 1
    }
}

func doubleSomethingUseful(does: Does) -> Int {
    return 2 * does.somethingUsefulNow()
}

Notice that now I only have to mock the somethingUsefulNow() method on the Does class and have it return the predetermined test value. I don’t have to worry about any of its dependencies.

In Dante’s Inferno, the 9th circle of hell is reserved for traitors. Traitors are there because “their acts involve betraying a special relationship of some kind.” See more on the Wikipedia article. Let’s not betray that special relationship between objects, keeping the details where they belong.

UPDATE: This post addresses the Law of Demeter, but there is more to properly decoupling code! Click here to learn about Dependency Inversion.

Share