Building a simple HN reader for iOS with GitHub Copilot, Part 2

In the series, I will build a simple Hacker News reader for iOS using Firebase, SwiftUI and GitHub Copilot X. In part 2, I use GitHub Copilot X to tackle the following:

  • Model files for Stories and TopStories
  • Code for TopStoriesModelView
  • Use Copilot Chat to resolve “Cannot find Firestore in scope” error

1. Story model generated by Copilot

Here’s the prompt and resulting model file GitHub Copilot X generated for a Hacker News story:

import Foundation

// create a Codable struct for a Story
// the struct should have the following properties:
// 1. id: Int
// 2. title: String
// 3. url: String
// 4. by: String
// 5. time: Int
// 6. score: Int
// 7. descendants: Int
// 8. kids: [Int]
struct Story: Codable {
    let id: Int
    let title: String
    let url: String
    let by: String
    let time: Int
    let score: Int
    let descendants: Int
    let kids: [Int]
    
    enum CodingKeys: String, CodingKey {
        case id
        case title
        case url
        case by
        case time
        case score
        case descendants
        case kids
    }
}

Once I started typing the comment, Copilot autocompleted the the rest of the comments (line by line though) and then the code which looks spot on.

2. Code for TopStoriesModelView

When I first started prompting Copilot with comments, the autocomplete went over the top. It kept recommending another comment/prompt and I kept accepting them even through I really just wanted it to try to complete the code. I let that go on for too long and had to remove the comments and restart.

Ultimately, I looked up some generic example code and starting to write the code instead of pure prompting. I used Copilot Chat on how to import and initialize a Firebase database in an iOS add and that was helpful and generally accurate.

Ultimately, after starting the class, Copilot X generated the following:

import Foundation
import Firebase

// using Firebase, get the top 500 stories
// https://hacker-news.firebaseio.com/v0/topstories.json

class TopStoriesModelView: ObservableObject {
    @Published var story = [Story]()

    init() {
        let db = Firestore.firestore()
        db.collection("topstories").getdocuments { (snapshot, error) in
            if let error = error {
                print(error.localizedDescription)
            } else {
                if let snapshot = snapshot {
                    for document in snapshot.documents {
                        let story = Story(id: document.data["id"] as! Int,
                                title: document.data["title"] as! String,
                                url: document.data["url"] as! String,
                                by: document.data["by"] as! String,
                                time: document.data["time"] as! Int,
                                score: document.data["score"] as! Int,
                                descendants: document.data["descendants"] as! Int,
                                kids: document.data["kids"] as! [Int])
                        self.story.append(story)
                        print(story)
                    }
                }
            }
        }
    }
}

and this looked accurate. And while the code compiles (after I add the Firestore SDK via SPM and clear the build cache thanks to a hint from Copilot), I ultimately learned that Firestore was not the correct Firebase database technology to use for connecting to the HN Firestore API. Of course, resolving this issues took quite a while and was in no small part due to my lack of experience with Firebase and iOS.

However, this is one of the big challenges with a coding copilot if you are new to a language: debugging code that doesn’t work can be extremely difficult. While the debugging I performed was it was in between meetings over a period of days (highly inefficient context switching), it still took hours to resolve. I go into this in more detail in Part 3 but it’s an important lesson to share!

Interestingly, if you look at the initial Copilot Chat answer, it was pretty much correct. It recommended creating a Database reference (although it did not specify the url and was generic in nature) vs. the code that was autogenerated which incorrectly used Firestore! ><

3. GitHub Copilot X thoughts - part 2

After my second coding session, I was still quite happy with Copilot’s ability to help me code. Generating a Story model is mostly just tedious work and syntax. I would have had to look up the syntax multiple times so having Copilot quickly write that code was a huge time saver. It also prompted me for properties that I would have had to check against the spare HN API docs.

Similarly, while Copilot chose the wrong Firebase database type, it did generate the majority of the code which would have taken me a while to write.

Lastly, GitHub Copilot Chat was quite accurate and it even helped me resolve a build issue. So the Chat has been a very productive capability to use for this project.