Blog

Thinking Like a Programmer Part 1

About eleven years ago I started a journey that’s radically changed the direction of my life; I became a programmer. I didn’t have the training for it so I mostly had to teach myself. I say mostly because I had some friends at the time that answered many of my questions. I’m not sure I would have made it without them. But with a little help from then and thousands of hours spent programming, I made it. There’s always more to learn and I’m still getting better. But I eventually made it. I have a career that I love.

I’m trying to be that helper for someone right now (we’ll call him “G”). He is trying to learn how to program starting with iOS, which is not the easiest place to start. But this is what he’s most interested in, so we are starting there (we have climbed mountains together in Greece so we can accomplish this, right G?). We’ve had sporadic conversations for quite a while now but I’ve decided to start committing some of the ideas to writing so he can review. I figured I would put it up on my blog just in case someone else can benefit from it.

These posts will be a mixture of abstract ideas and concrete implementations, generally with iOS with the Swift programming language. I’m not proficient in either, so in some cases we will be figuring things out together. I won’t be covering everything with Xcode as he’s been messing around with it for a few months now but I’ll try not to leave too much out. He’s also spent enough time with programming languages (a little JavaScript, some Objective-C and for a few weeks some Swift) that he knows how they basically work. But he doesn’t think like a programmer would think yet, so that’s what we’ll focus on. If you have never used Xcode and never seen a programming language, this series of posts is not for you. But if you have and you don’t think you quite get programming yet, you have a much better chance of these posts helping you.

If you are interested in following along with the code, I am checking it all into Github here.

Intros are boring. Let’s get started.

Breaking Down Ideas

There are a billion flashcard apps in the store but G and I are going to start learning programming with Swift by making another one. I like it because I like these types of apps for language learning but also the basic function is simple enough to approach for a beginner while being complex enough that it will require actual thinking, unlike some Hello World example. So let’s start by defining what we want the app to do.

I want to build a flashcard app.

The problem with this is that it’s too big. Computers are brainless and you have to tell them what to do very precisely. As a human, when I see “flashcard app”, I basically know what we’re talking about. A programming language does not know this. You can’t type in flashcardApp.makeOne() (or some other incantation) in Xcode and expect to get anything.

But you have to start somewhere. To find that place to start, you break down the idea into smaller ideas. And then you break those down and so forth until the ideas are small enough that they can be implemented. That’s what we will do now. You do things in programming languages in very small chunks of ideas, not large chunks of ideas. So let’s try this again. If we thinking about the word "flashcard", we have two concepts. The first is that of a card, the second is that of flashing. Let’s see if we can express that.

I want to build a flashcard app. It is an app that has cards. These cards have a front and a back side. I want my app to help me learn these cards by showing them to me one side at a time.

Cards

This is an improvement but we still have a ways to go. Let’s focus on the card aspect and break that out. When you have a noun like “card” that you need to represent in code, you will generally need to represent that somehow in the code. Languages like Swift commonly do this with things called classes. Languages also let you associate data with these classes, which are called variables or properties. So let’s build that into the definition.

I want to build a flashcard app. It is an app that has cards. These cards have a front and a back side. So I will create a class called "Card", which will have properties for the front and back.

I want my app to help me learn these cards by showing them to me one side at a time.

But we’re not just dealing with a card. We have cards, plural, to deal with. So we’ll add that concept in.

I want to build a flashcard app. It is an app that has cards. These cards have a front and a back side. So I will create a class called "Card", which will have properties for the front and back. Because there are multiple cards, cards will be in a list.

I want my app to help me learn these cards by showing them to me one side at a time.

Defining Some Behavior

I think we have done enough with the idea of a card to move on. We’ve actually made a split here between two things, data (card) and behavior (flashing). This is actually a common way (though certainly not the only way) of splitting things up while programming. Let’s keep it this way for now.

So, flashing. The flashing behavior of a flashcard app has to do with a few ideas. First, there are two sides and you only see one at a time and try to recall the other side based on the one you saw first. Second, you move through a list of cards. You don’t see the front side of all the cards at one time. You see one front side at a time, have the option of turning it over to see the other side, and then move on to the next card. So let’s change our app definition.

I want to build a flashcard app. It is an app that has cards. These cards have a front and a back side. So I will create a class called "Card", which will have properties for the front and back. Because there are multiple cards, cards will be in a list.

I want my app to help me learn these cards. We will move through the sequence of cards one at a time, showing the front side of the card each time. We can then turn the card over to see the other side. Or we can advance to the next card.

There are a number of other features that you can add to a flashcard app (e.g. randomization, keeping track of progress, customizing flashcards). We will get to those and more. But for now we want to start with the simplest implementation that we can think of, even if it is nowhere close to our goal of making the world’s best flashcard app. This at least gives us something to start with.

Coding - Modeling Cards

Now to code! We start by creating a new project, a Single View Application in the new project. A new project of this type will contain two important files at startup related to what we want to build this time, Main.storyboard (the user interface) and ViewController.swift (the code for controlling the view that is defined in the Storyboard). We will do all of our coding in the view controller class and make a rudimentary interface.

Let’s start at the beginning of our definition and work our way down. The first actionable item is to create our Card class. The one I created looked like this.


class Card {
    let front: String
    let back: String
    init(front: String, back: String) {
        self.front = front
        self.back = back
    }
}

The first line defines a class. The next two lines of code defines two properties, both of type String, that define the front and back of the card. I use let instead of var because I want them to be read-only. At this point I have no reason to change a card once it is created. Maybe we’ll change this later, but for now, this will work. And I also create these as non-optional because at this point we have no concept of a blank card. Cards must have both a front and back. Since both are non-optional, we must supply an initializer to set both, so we create one of those as well.

Now for the next part of the definition. “Because there are multiple cards, cards will be in a list.” So we need a list of words. The easiest thing to do is to create this list in our view controller. And while we are at it, we will add some words for us to test with. An array would work great for implementing our list, so we will use one of those. Our view controller would look like this.


class ViewController: UIViewController {
    let words: Array<Card> = [
        Card(front: "τόξον, τό", back: "bow"),
        Card(front: "μνηστήρ, ὁ", back: "suitor"),
        Card(front: "κλίμαξ, ἡ", back: "ladder")
    ]
    //created by Xcode. Ignore this for now.
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}

As you can see, we create a property on the view controller called “cards”, which is our array of cards. Because we will only put Card objects in this array and Swift supports generics, we will make this a Array<Card>. Now we can only put a Card object in it, which is good, because that’s all we want. And so we have some sample data to work with, I added three cards, some Greek words from book 21 of Homer’s Odyssey.

We are done modeling a Card in our app. We have successfully completed the first part of the definition. It is time to get something running.

Coding - Showing Cards

Let’s remind ourselves what we need to accomplish next. I’ll highlight our first task.

I want my app to help me learn these cards. We will move through the sequence of cards one at a time, showing the front side of the card each time. We can then turn the card over to see the other side. Or we can advance to the next card.

So we need to show our first card. To do this, we go to the storyboard and add a UITextLabel. We hook this up to the view controller by opening the Assistant editor while we have the view selected, holding down the control key and dragging to the open code file on the right. We will call it cardLabel and create it as an Outlet. You will see something like this.

Because we have now referenced the label, we can use it in code. Let’s get the front text of first card and assign it to the label. If we run the app, we see that we are sorta showing the text.

The word is clipped, so we would expand the size of the label (to do that, go to the storyboard and made the label wider) so the next time we run the app it won’t be truncated. It will still be an ugly app but at least we will be able to read the text. Here’s the code.


class ViewController: UIViewController {
    @IBOutlet var cardLabel: UILabel
    let cards: Array<Card> = [
        Card(front: "τόξον, τό", back: "bow"),
        Card(front: "μνηστήρ, ὁ", back: "suitor"),
        Card(front: "κλίμαξ, ἡ", back: "ladder")
    ]
    override func viewDidLoad() {
        super.viewDidLoad()
self.cardLabel.text = self.cards[0].front
    }
}

We have referenced the first card by getting the first element of the array, which is at position zero. We now need to be able to move through the cards, so we can’t just hard-code the zero like that. Instead we will want to create a variable to store our location and in response to user action, we will increase the number variable and use that when getting the card out of the array.

So first we drag a button to the view in the storyboard and hook it up like we did the label, except we hook it up as an Action instead of an Outlet. We will call it nextTapped. In that action we increment the variable. Here’s is how the code would look now.


class ViewController: UIViewController {
    @IBOutlet var cardLabel: UILabel
    let cards: Array<Card> = [
        Card(front: "τόξον, τό", back: "bow"),
        Card(front: "μνηστήρ, ὁ", back: "suitor"),
        Card(front: "κλίμαξ, ἡ", back: "ladder")
    ]
var currentCard = 0
    override func viewDidLoad() {
        super.viewDidLoad()
        self.cardLabel.text = self.cards[0].front
    }
    	

    @IBAction func nextTapped(sender: AnyObject) {
        self.currentCard++
        self.cardLabel.text = self.cards[self.currentCard].front
    }

}

This works okay. When we tap the button, it shows the front of the next card. But we have some bad code. We set the text label twice in the file and that leads to messy code. So we will take the duplicated code and put it in a function that we can call from viewDidLoad and nextTapped.


class ViewController: UIViewController {
    @IBOutlet var cardLabel: UILabel
    let cards: Array<Card> = [
        Card(front: "τόξον, τό", back: "bow"),
        Card(front: "μνηστήρ, ὁ", back: "suitor"),
        Card(front: "κλίμαξ, ἡ", back: "ladder")
    ]
    var currentCard = 0
    override func viewDidLoad() {
        super.viewDidLoad()
showCard()
    }
    @IBAction func nextTapped(sender: AnyObject) {
        self.currentCard++
showCard()
    }

    func showCard() {
        self.cardLabel.text = self.cards[self.currentCard].front
    }
    
}

We now have showing cards and advancing through the stack. We need to be able to turn the cards over. Once we do that, we will be finished with what we set out to do. For now we will turn a card over using another button. So we drag that to the storyboard, hook up an action (I will call it flipCardTapped) and then show the text on the back. We can start with this implementation.


class ViewController: UIViewController {
    @IBOutlet var cardLabel: UILabel
    let cards: Array<Card> = [
        Card(front: "τόξον, τό", back: "bow"),
        Card(front: "μνηστήρ, ὁ", back: "suitor"),
        Card(front: "κλίμαξ, ἡ", back: "ladder")
    ]
    var currentCard = 0
    override func viewDidLoad() {
        super.viewDidLoad()
        showCard()
    }
    @IBAction func nextTapped(sender: AnyObject) {
        self.currentCard++
        showCard()
    }
    @IBAction func flipCardTapped(sender: AnyObject) {
        self.cardLabel.text = self.cards[self.currentCard].back
    }

    func showCard() {
        self.cardLabel.text = self.cards[self.currentCard].front
    }
}

This sorta works, unless you want to flip the card back to the front. That’s not possible now. So we will do the same thing with the side of the card that we did with keeping track of the current card. We will store the value in a property, change that whenever we want to flip the card, and use that value when displaying the card. Since there are only two options for sides, I’ll use a boolean to indicate if we want to show the front or the back.


class ViewController: UIViewController {
    
    @IBOutlet var cardLabel: UILabel
    
    let cards: Array<Card> = [
        Card(front: "τόξον, τό", back: "bow"),
        Card(front: "μνηστήρ, ὁ", back: "suitor"),
        Card(front: "κλίμαξ, ἡ", back: "ladder")
    ]
    
    var currentCard = 0
var showFront = true
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        showCard()
    }
    @IBAction func nextTapped(sender: AnyObject) {
        self.currentCard++
        showCard()
    }
    
    @IBAction func flipCardTapped(sender: AnyObject) {
if (self.showFront) {
            self.showFront = false
        }
        else {
            self.showFront = true
        }
        showCard()
    }
    
    func showCard() {
if (self.showFront) {
            self.cardLabel.text = self.cards[self.currentCard].front
        }
        else {
            self.cardLabel.text = self.cards[self.currentCard].back
        }
    }
}

And now we can move through the list, showing cards along the way and flip them from front to back.

And Usually You Miss Things

We took the time to break down the idea of our app but you never remember to do everything the first time. If you run the app as-is, you will notice a couple things that seem wrong. And we’re also missing a back button, which would be nice since we might want to look at the previous card. Let’s start with the back button then discuss and fix the bugs.

Implementing the back button is a piece of cake as it’s the reverse of the next button. So we’ll add a button to the storyboard, hook it up as an action called backTapped. Here’s our new view controller.


class ViewController: UIViewController {
    
    @IBOutlet var cardLabel: UILabel
    
    let cards: Array<Card> = [
        Card(front: "τόξον, τό", back: "bow"),
        Card(front: "μνηστήρ, ὁ", back: "suitor"),
        Card(front: "κλίμαξ, ἡ", back: "ladder")
    ]
    
    var currentCard = 0
    var showFront = true
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        showCard()
    }
    @IBAction func nextTapped(sender: AnyObject) {
        self.currentCard++
        showCard()
    }
@IBAction func backTapped(sender: AnyObject) {
        self.currentCard--
        showCard()
    }
    
    @IBAction func flipCardTapped(sender: AnyObject) {
        if (self.showFront) {
            self.showFront = false
        }
        else {
            self.showFront = true
        }
        showCard()
    }
    
    func showCard() {
        if (self.showFront) {
            self.cardLabel.text = self.cards[self.currentCard].front
        }
        else {
            self.cardLabel.text = self.cards[self.currentCard].back
        }
    }
}

And now the bugs. The first bug happens if you hit Next more than three times or if you hit back from the beginning of the list of cards. In both cases, you get an error caused by trying to access the array using an invalid index, which we represent with our currentCard property. Since the array has three elements, currentCard can be one of three values: 0, 1, and 2. If we hit back from the beginning, currentCard is -1 and we get an error that says “fatal error: Negative Array index is out of range”. If we hit next at the end, currentCard is 3 and we get an error that says “fatal error: Array index out of range”. And in both cases our app totally crashes. Let’s do the simplest solution, which is to make sure the numbers never move outside the bounds of our array and nothing else. For the -1 case, we can change the backTapped function to never allow a value less than zero. For the case of 3, we will be prescient and realize that hard-coding a check for a value of 3 is stupid and we should just check the count of cards in the array.


class ViewController: UIViewController {
    
    @IBOutlet var cardLabel: UILabel
    
    let cards: Array<Card> = [
        Card(front: "τόξον, τό", back: "bow"),
        Card(front: "μνηστήρ, ὁ", back: "suitor"),
        Card(front: "κλίμαξ, ἡ", back: "ladder")
    ]
    
    var currentCard = 0
    var showFront = true
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        showCard()
    }
    @IBAction func nextTapped(sender: AnyObject) {
        self.currentCard++
if (self.currentCard >= self.cards.count) {
            self.currentCard = self.cards.count - 1
        }
                
        showCard()
    }
    
    @IBAction func backTapped(sender: AnyObject) {
        self.currentCard--
if (self.currentCard < 0) {
            self.currentCard = 0
        }
        
        showCard()
    }
    
    @IBAction func flipCardTapped(sender: AnyObject) {
        if (self.showFront) {
            self.showFront = false
        }
        else {
            self.showFront = true
        }
        showCard()
    }
    
    func showCard() {
        if (self.showFront) {
            self.cardLabel.text = self.cards[self.currentCard].front
        }
        else {
            self.cardLabel.text = self.cards[self.currentCard].back
        }
    }
}

And finally, our last bug. If you are viewing the front of a card and flip it over then hit the button to view either the next or previous card, the back side of the other card is shown. We don’t want that. When you change cards, we want the front of the card to show. The easiest way to do that is to reset the boolean value for showing the front every time the next/back buttons are tapped, like this.


class ViewController: UIViewController {
    
    @IBOutlet var cardLabel: UILabel
    
    let cards: Array<Card> = [
        Card(front: "τόξον, τό", back: "bow"),
        Card(front: "μνηστήρ, ὁ", back: "suitor"),
        Card(front: "κλίμαξ, ἡ", back: "ladder")
    ]
    
    var currentCard = 0
    var showFront = true
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        showCard()
    }
    @IBAction func nextTapped(sender: AnyObject) {
        self.currentCard++
self.showFront = true
        
        if (self.currentCard >= self.cards.count) {
            self.currentCard = self.cards.count - 1
        }
        
        showCard()
    }
    
    @IBAction func backTapped(sender: AnyObject) {
        self.currentCard--
self.showFront = true
        
        if (self.currentCard < 0) {
            self.currentCard = 0
        }
        
        showCard()
    }
    
    @IBAction func flipCardTapped(sender: AnyObject) {
        if (self.showFront) {
            self.showFront = false
        }
        else {
            self.showFront = true
        }
        showCard()
    }
    
    func showCard() {
        if (self.showFront) {
            self.cardLabel.text = self.cards[self.currentCard].front
        }
        else {
            self.cardLabel.text = self.cards[self.currentCard].back
        }
    }
}

Here is the final screenshot of the app. It’s ugly and is not a full-featured flashcard application. But we will get there.

Decomposition

And at this point we are done. We started with an idea, broke it down into smaller ideas then took each idea one at a time. The ability to decompose larger ideas is absolutely essential to being a good programmer. And once the ideas are broken down, it’s a lot easier to build what you want.

In many ways being a good programmer is a lot like being good at building things with Lego pieces. There are a set number of pieces that you start with. You can look at the individual lego pieces as all the things that the compiler will let you do. Each line of code above is relatively unremarkable, like every individual Lego piece. But if you put them together right, you can create something awesome.

When most people start buying Lego sets, they start with the instructions. They go step-by-step through the instructions and build the set that they bought according to the specifications. But after a while that gets boring so we create something new, something that isn’t in the instructions. After you play with Lego enough, this actually becomes very natural. But you don’t start there. You start with the instructions. Eventually you become familiar enough with the pieces that your imagination can kick in and you can start combining them in ways that the Lego maker could never think of. Programming is similar. At first you are obsessed with figuring out how it works. Eventually you learn enough to make cool stuff.

Programming at a job is generally like this latter state of Lego use. You never get step-by-step instructions on building things in the real world. You’ll see step-by-step instructions in blog posts (like this one) and books but when you work at a job, this won’t be the case. Someone will come to you and say “I want to build a flashcard app” and you’ll have the task of breaking that down into something that you can build. Sometimes you will be able to do it yourself though more often than not you’ll have to learn a lot from the person who wants the app so you can turn their over-simplified request into actionable ideas. This is part of the challenge and the fun. They may have forgotten their lessons from playing with Lego bricks. As a programmer, you get to re-enact your playtime and get paid for it.

Done for Now

As it is the app is totally ugly and not very useful. But we’ve implemented one of the core ideas of a flashcard app. Next we’ll move it forward a bit, getting it a little closer to something cool and learn some things while we are at it.

Enough Node for Building a Simple Website

Enough Node.js

Mobile ASP.NET MVC 5 - Published!

A Plants vs Zombies Halloween

older posts