Assignment 1 and 3 Post Mortem

These are the highlights of things I’ve learnt from the last seven weeks of CS3216. I have meant to do a post-mortem after assignment 1, but Assignment 3 and school got in the way, so instead here’s a 2-in-1 deal - a post mortem of both assignments 1 and 3.

Assignment 1 - Would You?

Would You? is a social game modeled after the classic party/icebreaker game Kiss, Shag, Marry. We want to one-up other online versions of the game by bringing the thrill of playing against your friends in real life to Facebook via this Facebook application.

Admit it, you'd marry RDJ too if you had the chance.

The game is built as a traditional server-side rendered web application. The backend uses Django on Python hosted on Digital Ocean while the frontend uses select components from Bootstrap and jQuery for DOM manipulation and Ajax. For this project I took on almost all technical aspects of it, from server management, build tools and deployment, to database design and models and backend coding, to translating design mockups to HTML and CSS and writing the interactivity with JavaScript. This is an experience I wouldn’t want to repeat. Although none of these were new or particularly challenging individually, juggling all of them at once kept me well past midnight on far too many nights.

What we did right

The scope of the project is small and manageable. This allowed us to get quite a bit more polish in than most of the other teams. I had the app ready for testing four days before the deadline, and so manged to get a good deal of testing and feedback into the app from both friends and the teaching staff. This allowed us to resolve some fairly critical design issues with our game (“why are you building a game that is not fun to play”) before the deadline.

I’m lucky to have a really good designer You Jing on our team who helped polish up the UI of the app. This allowed me to focus more on the backend as well as designing the interactive aspects of it, since I was the only one in the group with any experience with JavaScript.

What could have gone better

Django wasn’t a good fit for the application. I choose the framework because I assumed we could get productive with it relatively quickly, but we were hampered by the amount of abstraction the framework provided and the fact that the documentation was incomplete in many places. This is especially apparent in the Form classes - part of the reasons why Django’s forms are extremely difficult to use in anything more than the most trivial of use cases is that even though you are expected to extend these classes, most of their innards are undocumented, and you have to dig through their sources to find the correct method or property to override.

Database design and backend should have landed more quickly. The database for this project was a bit of a mess. I started with the assumption we only needed 4 tables. By the end of it we had 8, and half a dozen more join tables. This was in part caused by me not fully understanding the data requirements of the project, and also because in some aspects we were hitting against the limitations of traditional relational database design. The former was due to me having to switch context a lot as I tried to work on all parts of the stack at once - it was difficult keeping the big picture in mind while while also working on the implementation at the same time.

Not using a frontend framework. To be fair what we did was probably the right decision in our situation, as I definitely had no time to pick up a frontend framework in addition to a backend framework in three short weeks. That said, even this simple game was straining at the limits of what you could do purely with the DOM (and jQuery, of course) while still maintaining a sane level of code quality.

Going slightly off topic here, I find that scripting languages like PHP, JavaScript and even Python (and pretty much every dynamic language that’s in use today) become unmanageable very quickly if they are written in procedural style and exceed a surprisingly low number of lines of code - usually on the order of two to three hundred. This is exacerbated on frontend JavaScript due to its unintuitive syntax for declaring constructors and inheritance, and it’s lack of native support on browsers for modules. There exist ad-hoc specifications like AMD and CommonJS, but they feels like a poor man’s version of the module system that comes with every other scripting language. Frameworks and ES6 import statement plus transpilation solves that issue, but you need to figure out the right incantations and plugins required to operate the magic box known as WebPack. In a lot of cases it’s just not worth the time - at least until it’s too late and you realize you have to pay back all of the accrued technical debt, plus interest.

The other problem with writing uncompiled, frameworkless JavaScript is that state management quickly becomes overwhelming. In procedural style code they either get attached ad-hoc style onto whichever DOM element is around, or worse, directly into the global object. This makes the code unmaintainable, and difficult to reason about once the codebase starts scaling up.

I guess the main point here is that even though it’s much easier getting started with a language like JavaScript, Ruby and Python, writing good, maintainable code in them is harder and takes a lot more discipline and experience than a language like Java.

Assignment 3 - PinPoint

PinPoint uses augmented reality (AR) to help track and locate your friends in real time. If you’ve ever tried to meet a friend in an unfamiliar location you’d know the pain. We solve this problem by overlaying your friend’s location on a 3D map controlled by your own movement or over real world imagery directly from your phone’s camera, and synchronizing both of your locations in real time.

Left: Actual conversation between our group member illustrating the problem we are trying to solve. Middle: Our app in map mode. Note that this is debug mode, so a set of predefined markers are used instead. Right: Our app in Augmented Reality mode.

For this project we used Ruby on Rails 5 for the backend, and Vue.js 2.0 on the frontend. We used OpenStreetMaps Buildings, three.js and the threeVR motion controller for the AR rendering, and hand-rolled the rest of the geolocation, device orientation and camera access code. For this project I worked solely on the front-end, focusing on the core AR functionality, implementing user interface and interfacing with device sensors.

What we did right

Our idea was right, and the technology was right. Modern smartphones are miniature computers. Most of us computing students know this fact at some intellectual level, but it really hit home when I discovered that OpenStreetMap Buildings, the library we used to render 3D buildings you see in the app, could run smoothly on a smartphone. The result is, if I dare say so myself, incredibly cool.

Vue.js is pretty awesome. I was skeptical of modern frontend JavaScript frameworks. They are either difficult to pick up, doesn’t have sufficiently clear separation of concerns, or just plain ugly (or a combination of all three - looking at you, Angular 1. Using Vue.js changed my opinion in an instant. Unlike React’s literally hundreds boilerplate, there is just one, and you can get immediately productive with it. There was very little to learn - Vue’s single file component format means you’re the exact same HTML, CSS and JavaScript you were writing before. The HTML also supports simple templating logic through custom attributes like v-if and v-for that are instantly familiar to anyone who have used server-side templates before, and because components are described as simple JavaScript objects, creating components requires very little ceremony. Similarly dropping in SASS support was extremely easy. We simply had to install the Webpack plugin and add lang="scss" to the <style> tags. No need to configure loaders, webpack plugin, sourcemaps, making sure that it minifies correctly on production, etc.

What could have gone better

Underpromise and overdeliver, not vice-versa. Apparently our module coordinator really really really likes Augmented Reality. We found out the hard way what happens when an unstoppable force (Colin) meets an immovable object (Safari Mobile’s lack of support for getUserMedia()).

Authentication was a huge time sink. We assumed this would be relatively easy - after all, every modern web framework comes with an auth framework, right? Nope. Turns out the gems we chose didn’t work well at all - only after wrestling with it for about a weekend did we finally beat it into submission. The worst thing is that all that time spent building the authentication, we didn’t have time to actually build the planned features that requires it. Oh the irony!

Two way data synchronization is hard. Yet another hard earned lesson. It was so easy designing the application’s data model on paper - send your address token, get a list of addresses to observe, listen to them on WebSocket. Simple, right? Nope. By the end of the project we were pretty much halfway to establishing our own informal handshake protocol just to get the user’s data properly synchronized with the server. It didn’t help that the code for client-side address data layer is written by Yichen, while I was writing the code that consumed this information to display to the user. We tried establishing a clean interface between our individual codebase at first, but the abstraction quickly started leaking and in the end bugs can only be squashed when both of our heads were knocked together.

Life’s too short for documentation and proper naming convention, but sometimes much too short without them. Is that thing on your screen a marker, or an address? Do coordinate objects have latitude and longitude, or lat and lng? When I ask localStorage for the address that was shared with the user, should I look for an Observing address, or an Observer address? Even a project with only four developers and a three week lifetime needs proper documentation, otherwise that short three week would become that much shorter as we step on each other’s toes writing code that broke in stupid and non-obvious ways.