building a trivia app – conception

Recently, my wife and I were watching one of our favorite shows and she mentioned that she’s coming up with a series of trivia questions for it. Of course, this isn’t just any show, it’s our absolute favorite show to watch together. And it’s a show that we start over once we reach the end. So as soon as she mentioned the idea, my ears perked up and wheels started turning. I thought: why not build a simple trivia app that we can just iterate on using her style of questions? So I started to plan things out mentally.

I’ve been a software developer for basically all my life, but one thing I’ve never done is make any kind of phone app (though I’ve toyed with many an idea). This will be my first real attempt at getting something into the App Store, and I’m also pondering the idea of charging a small fee for it. But I also don’t want to put the cart before the horse, so I’m in the most exciting phase of any project — conception! And rather than just cobbling something together on the fly, I figured I should plot it out from the lowest layer up, while keeping scalability top of mind.

The first piece of the puzzle is the database. I supposed I just use a local database instance of some kind, which would scale quite nicely, but then I thought about the complexities involved. First, keeping all those separate database instances in sync would be quite a pain; I will most likely cache the hell out of things but the more I thought about using a central database (behind a secure API layer), the more I liked the idea. Sure, it creates a single point of failure, which is not ideal, but there are great ways to create the illusion of a single API interface while securing the data in a robust way (database shards, reverse proxy, etc.). This is important moving forward, especially since I’ll be using NoSQL, which has been tested well for app back-ends.

After I made that decision, busting out a quick proof-of-concept proved simple. I fired up a local MongoDB instance and started planning out the schema. Doing a bit of searching for something close to what I wanted, I went with this tutorial on building a RESTful API using Node.js. I was able to put the schema into an actual model:

'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;


var TriviaSchema = new Schema({
  question: {
    type: String,
    required: 'Enter the question'
  },
  answers: {
    type: Array,
    required: 'Enter possible answers'
  },
  correctAnswer: {
    type: Number,
    required: 'Please enter which of the answers is the correct one.'
  },
  season: {
    type: Number,
    required: 'Please enter the season for this question.'
  },
  episode: {
    type: Number,
    required: 'Please enter the episode for this question.'
  },
  difficultyLevel: {
    type: Number,
    enum: [1, 2, 3, 4, 5],
    required: 'Please enter the difficulty 1-5.'
  },
  created_date: {
    type: Date,
    default: Date.now
  },
});

module.exports = mongoose.model('Trivia', TriviaSchema);

Keep in mind that I’m still in the conception (and thus, proof-of-concept) phase, so this schema will evolve as I think about the different ways this app will present trivia to the user (single choice, multiple choices, etc.). Currently, it supports single choice responses, but it should be trivial to change correctAnswer to an array of correct answers referenced from the answers array. Since answers is an array, I could also just add a flag to each answer to indicate whether it’s correct or not, and as I type this out, that actually seems like a far more flexible solution, but for the time being, the above schema is how things are being inputted into the database. However, the longer I wait to make that change, the more of a pain it will be to export the dataset to the new format.

One thing the aforementioned tutorial does not cover is endpoint security or security in general. At some point, I’ll have to add some proper security to the CUD (Create, Update, Delete) parts, but I’m leaving that concern for later. For now, I just want to be able to easily insert sample data using a Postman template for posting trivia.

Having exposed the simple schema through the Node.js REST endpoints, I decided there isn’t much reason to have a full listing of questions. Instead, it makes more sense to have access to one question at a time via /trivia/:triviaId so I can yield all the information about the specific bit of trivia, and also provide links to other important and related endpoints. For example, interesting facts or even screen captures about the particular episode. And beyond the simple question endpoint (and corresponding episode informational endpoints, which I’ll fill out later on), I just need a way to get a random trivia question. For that, I built out /trivia/random, which gives me a random trivia question out of the dataset.

Thinking about the way I plan to build out the really simple 1.0 version of the app interface, which is going to be sort of a pyramid challenge style, I also need a way to get a random question within a certain difficulty level. So in addition to /trivia/random, I also created /trivia/random/:difficultyLevel, which will only yield questions at the requested difficulty level.

In my mind, “pyramid style” means you have to complete a whole series of questions at difficulty level one before you can reach a smaller set of questions at difficulty level two and so on until you get to the really tough/obscure questions and that’s where you see how far you can get before getting one wrong. Later on, I want a user to be able to enter into any difficulty they want and go until they get one wrong, which would be great to use at parties or on car trips. However, for my starting game style, the pyramid seems to work the best. I’ll do more research on that for the next post.

For now, I have a very simple API going that will allow me to start building out the actual UI for the application.

One thing I didn’t want to have to do to get the app going is use XCode and deal with the learning curve that ends up being insurmountable; instead, I opted to go for React Native. That way, I can use React, which I already know how to use and style everything the way I do at work every day. Using react-community/create-react-native-app, I was able to get a very simple UI going with an emulated version of my own iPhone 6S Plus and now I’m in the process of talking to the API and displaying random questions to the screen. From here, it shouldn’t take long to get a very simple game interface going (present question with multiple possible answers, then allow user to select answers, and get it right/wrong). As I develop this part, I’ll create more updates.

Here’s hoping I don’t get stuck in the conception phase.