Louie in "Paradise"

Okay lah, this is actually a compulsory CS3216 blog.

Week 13.1: Tips to juniors — November 7, 2016

Week 13.1: Tips to juniors

To survive…

1. Think of your app ideas early

Try to think of a fantastic app idea for the final project while you still have time, and do a half-implementation during Assignment 1 / 3. That’ll reduce the workload for the final project and you have more time to worry about marketing.

2. Scope your project well

The 80/20 rule is a rule of thumb that states that 80% of some effects come from 20% of some causes. For the CS3216 assignments, don’t bother coming up with full-fledged functionality with all the bells and whistles that make it usable long-term. That was our mistake for Assignment 1 — we implemented too many functionalities which caused a lot of backend headaches, yet the DB logs reveal that the TAs only used a tiny fraction of the full functionalities implemented. There were entire modules that were not visited at all.

Do the bare minimum of functionalities (the 20%) required to make the app usable, and do it damn well. Make sure the app design is a pleasant sight to behold and the interface is sleek.

3. Do your weekly blogs weekly

Don’t be like me and leave it to the end to backdate blog posts, like this one right now.

To get the best out of CS3216…

4. Pick your teammates well

One thing I somewhat regret is choosing to work solely in teams that I am familiar with. This proved to be an issue because the people I am familiar with are all alike – everyone is familiar with Rails, and are all equally good backend developers and equally shitty frontend designers. As such, while we did learn stuff along the way together, there is considerably less we could have learnt from each other.

If you’re a backend developer, work with a frontend designer at least once. That way, you’ll be able to see things from a UI/UX perspective instead of a functional perspective. And vice-versa for frontend designers.

5. Be daring with your ideas

Prof. Ben likes to say how if someone came up to him many years ago and pitched the idea of a social networking app that only allows posts less than 140 characters long, he would say that it’s stupid and crazy.

Many ideas may sound stupid at the beginning, but don’t just throw them out (else you’ll be stuck with no project). Give them a chance to develop and validate them rigorously.

6. Don’t do CS2103 + CS3216

CS2103 is yet another project-heavy module out there, and unless you have it well planned out, you’re extremely likely to end up with at least one burden teammate. If you’re lucky, he’ll slack and simply not do any work. If you’re unlucky, he’ll write such bad code that everyone has to clean up / redo afterwards, expect the entire team to babysit him, and to top it off he’ll throw a huge tantrum at the end of the semester about how the whole world has wronged him.

Rant aside, CS2103 took up even more time than CS3216 because we were down to a (3 – 1 = 2)-man team (thank god my other teammate was extremely capable, though equally screwed because he also took CS3216 simultaneously with me >_<). Software engineering in Java is extremely tedious and laborious, and you’ll find yourself spending a lot of time trying to whack Java to do what would have been two lines of code in any other language.

Week 13: It’s over! — November 6, 2016

Week 13: It’s over!

STePS is over. WOOHOO!

No final report. DOUBLE WOOHOO!

Now that we’ve got the celebrations out of the way, it’s a good time to look over what I hoped to learn in CS3216 at the start of the semester.

1. Code is code, right? (Better coding practices)

Nope. In fact, rather the opposite. In the span of doing the three projects under strict deadlines, I’ve learnt that code quality can take a back seat to making things work, well, as long as it’s not like this diarrhea code from my CS2103 teammate. For example, in Assignment 1, we spent time fixing N + 1 problems that should not have been a priority. In the final project, we bickered over schema design practices – whether to represent all the possible timeslots as rows in a sentient table (making unions convenient), or to denormalize them into enums to be used everywhere (better design).

In both situations, the effect on the end-user experience is actually negligible. The N + 1 problem would only be noticeable with large amounts of data which 4 TAs and a lecturer couldn’t possibly generate. The schema design is a completely backend thing that the user wouldn’t even know about.

The bottom line is that while code quality is definitely important, writing “beautiful code” does not necessarily translate into a better product, which is what matters most at the end of the day. Just make sure to tidy up your code eventually.

2. What more is there to coding? (SE nature)

A whole list.

  • Ideation (for the final project, we pivoted three times)
  • Project scoping (we initially overengineered our app, and subsequently scaled it down to a manageable level so that we can actually show something during STePS)
  • UI/UX considerations (this is the first time I am working on an app that has such a high standards for UI/UX, and we got promptly blasted by Yangshun for our Assignment 1 app looking like a CVWO website, but uglier.
  • …the list goes on. CS2103 lecture notes may do a better job listing them out.

3. Automatic merge failed; fix conflicts and then commit the result. (Team communication)

The nature of working in small teams like in CS3216 (and CS2103) means that, like in traditional school projects, there is very little hierarchy, if at all. We are familiar with working in such environments (e.g. JC PW), but it’s different when it comes to writing code. When we need to collaborate on a report, we can simply separate by a few chapters, and without much coordination, it is possible to just piece them together one day before the deadline and submit, hoping that the lecturer will overlook some inconsistencies, contradictions, or duplications. This is not the case for writing code. As we experienced many times in Assignment 1, improper communication led to wrong implementations of modules that does not play well with the rest of the code, as well as a completely missing functionality that just so happens to be a compulsory milestone -.- (and the rest of the team had to rush out the night before submission).

In the other assignments and final project, we made it a point to meet regularly to discuss the current progress and future direction. More importantly, beyond discussing “what needs to be done”, we iron out an implementation sketch where appropriate to prevent shocks when the PR comes in.

4. API changes, code breaks. (Learning APIs on the fly)

When I wrote this point in my first blog post, I had the Facebook API in mind, but honestly we simply used a Rails gem (omniauth-facebook) to handle the user authentication for free, and there was considerably less manual effort (still annoying as hell to debug, but less effort) in integrating other Graph API features such as open graph stories and the comments plugin. So that wasn’t too hard (:

However, in Assignment 3, it turns out that figuring out Rails’ ActionCable was worse than if we had to write the Facebook authentication from scratch. Facebook’s API is reasonably well-documented, and plenty of tutorials exist on the Internet. Meanwhile, ActionCable being a newly integrated feature in Rails, suffers from extremely sketchy documentation and half-baked functionality. While tutorials exist, they mostly teach the same thing – how to build a chat app (honestly, it seems like everyone just copied the same tutorial with unchallenging extensions). Not enough development using ActionCable has happened for the bugs to be ironed out and the core functionality improved to be able to support all use cases.

Yet, with a lot of Googling into weird corners of the Internet, as well as diving into the source code if all else fails, and hacky workarounds when we can’t figure out the right way to do what we want to do, we survived 😀

Week 12: We overengineered — October 30, 2016

Week 12: We overengineered

Previously, on Louie’s CS3216 Blog: Week 11: On engineers and overengineering.

We spent the week implementing (trying to implement) a timeslot system for teachers to specify their available timeslots for teaching, from which we will then remove the timeslots of lessons they are already teaching on our system. When students submit a request to enroll for a lesson, they will see the timeslots from the previous step, select a few, and then submit those selections in the request form.

Well, we somewhat got the timeslot back-end up, despite it not being very pretty (a sentient table that contains all the possible timeslots to be used as associations everywhere). The timeslot selector was pretty much hacked together with a large table with click-and-hold to select multiple timeslots and still contains some bugs. We were completely not in time to integrate this timeslot selector method with the request lesson form. More importantly, our subject listing and teacher listing still looks more or less the exact same horrid state it was last week, because we’ve been spending all our time implementing nice-to-have features and neglecting the most important component – UI/UX.

It has now been made painfully clear to us during this week’s meeting with Kok Wee that we were seriously behind time. The way forwards now is to simply scrape the idea of implementing fully the timeslot scheduler, and focus on turning whatever we have into something we can sell. The challenge is being able to pull this off in one week, as we have more or less wasted the last one week’s worth of efforts.

Week 11: On engineers and overengineering — October 23, 2016

Week 11: On engineers and overengineering

As back-end developers, we tend to place a lot of weight on functionality, and making sure that the architecture of our product is well equipped to handle all use cases. For instance, if there is even a remote chance that an association might one day be HABTM, we would typically design the schema with the association table in place, even if the most common use case is actually a simple belongs_to.

In the same way, we often set out to implement more than what we can achieve within a limited time frame, because we view the product as “unusable” without some set of core features. More often than not, these core features are not actually that core.

To put things in the context of PIVOTuition, our group internally disagrees on how much we should be implementing. As part of the process of the student registering for a lesson on our app, the student would have to pay up and schedule a lesson timeslot with the teacher. Kok Wee suggests that the payment system and timeslot scheduling be handled entirely offline by admin staff, which is what they are currently doing anyway. However, some of the group is intent on building a full-fledged lesson scheduler to allow a student to view a teacher’s dynamically-generated timeslot and select a particular time that he/she prefers – in addition to a virtual credits system to keep track of a student’s account balance and automatically deduct credits when lessons are attended.

My stand on this is that it is infeasible within the constraints of two weeks – this, together with the student/teacher/admin/lessons/classes management, seems to me like an entire CVWO project! I suggested to do the bare minimum, make it look beautiful (which would probably take up all of two weeks considering how our entire team are equally terrible at front-end), and if we actually have time, we can start thinking about which additional feature is the most nice-to-have. However, this opinion was shot down, under the argument that “without a timeslot scheduler our app is useless”. We will see how this pans out in a week… or two, in which case we will be royally screwed.

Week 10: Pivot — October 16, 2016

Week 10: Pivot

Yes, our new app is really named Pivot . Well it’s really a codename and probably will not be the actual name that the app will be released with, but you’ve gotta admit it does make for a pretty cool name, inside-joke part aside 😛

Pivot is an attempt to bring the private tuition industry online, beyond a simple directory listing or live broadcast (e.g. Hong Kong celebrity tutors who simply broadcast their lessons). Instead, students register for and attend the classes completely online using web conferencing.

This idea is more or less finalized, if not because we don’t have time to pivot one more time, because we finally settled for an idea that 1. is feasible in the span of 4 weeks (as far as we can tell), 2. is showy enough for STePS, and 3. does not have an insurmountable marketing problem. Also, what better external client to work with other than Kok Wee, an ex-CS3216 tutor? (: During our meetings, he often seems to be more of an educator than a client that we are working for.

One of the key things impressed upon us was to not reinvent the wheel. Web conferencing is certainly not new (obviously Skype and Google Hangouts come to mind here), but even in the context of live classes, NUS has been using Cisco WebEx to conduct remote iBLOC lessons. Given the complexity of working with the WebRTC API to implement webcam conferencing as well as a shared whiteboard, support for uploading pdfs or images to be annotated, etc., it is unlikely that we will be able to finish implementing a usable web conferencing product, let alone set up the registration server to keep track of lesson schedules and registrations. Apparently, this has happened previously to another group which intended to write from scratch a web conferencing whiteboard app + a whole service built around it, and ended up only managing the web conferencing part, which became QuickV. For Pivot, instead of going down that path, we have elected (well, more like been instructed to) make use of a pre-existing commercial API (BrainCert) that provides a web-conferencing + whiteboard sharing service for us to integrate into the main online tuition service that we are building. The entire service we are building is certainly flashy enough, and at the same time is not so complicated that we run the risk of having absolutely nothing to show for STePS.

Week 9: Ideas are not so cheap — October 9, 2016

Week 9: Ideas are not so cheap

We really should name our project “PivotApp” or something of the sort.

While in Week 7, our problem was in the way we clung too tight to an idea, we are now facing the issue of burning through too many external projects. To recap so far:

  1. TreatSure (food wastage). Problems were with the client, not the idea.
  2. HuntBot (web directory scraper). The project was too simple – the scraping part was done by us in half a day. The app also did not have much of a UI/UX aspect to it. There wasn’t much room to develop this idea further, and hence was unsuitable for a final project.
  3. Leads Marketplace (Carousell for marketing leads). While HuntBot was too small a project, this was possibly too large. In order for such a marketplace app to be usable, it needs a lot of features – a simple CRUD (like Carousell) would be insufficient. More importantly, as pointed out by Prof. Ben, for this app to grow, we need both service providers and service consumers. Without providers, consumers won’t come; without consumers, providers won’t come. There needs to be a strong plan to quickly inject some initial “seed users” so that more users will enter, and this is not very possible within the span of 4 weeks.

While I usually try to pen down the moral of the weekly story, in this case I am not even sure what we did wrong. Should we have seen right from the start that these project ideas were not feasible? Should we have simply stuck with one? Should we have simply explored many ideas concurrently?

Comments welcome.

Week 7: Ideas are cheap — September 26, 2016

Week 7: Ideas are cheap

(…we should not be)

So when our group first decided to take up an external pitch, we made the decision based on the idea alone. It seemed like the most intuitive thing to do. We will be putting in blood and soul for the next half of the semester into turning this idea into fruition, so the idea should be the strongest deciding factor. Hence, when we received an email from the external pitcher requesting us to sign a contract and bring it the next day (less than 24 hours), we were cautious about it and hesitant to immediately sign the contract, but didn’t put much thought into it.

However, as we started getting a flurry of concerned emails from TAs and Prof. Colin (and even M.M. Ben Leong), we began to realize that perhaps we really should be more worried for ourselves than we were. Among the concerns (TAs and ours) were:

  1. Remuneration was lowball. Honestly, when we first saw the number, we felt it was quite a tad low (using CVWO as a benchmark) but not sure exactly how low. The final project being a compulsory school project, the original remuneration sum may well have been the market rate because students would have been required to do a project anyway, which kinda reduces our bargaining power.
  2. Contract was one-sided. The contract went through a lot of pains to protect the external pitcher’s ideas and IP rights, and allowed the external pitcher to ambiguously define what a “quality product” means. Apparently, he wanted bug-free code as was made clear to us by our TA. There is no such thing in the world.
  3. Incompatible business timeline. Our project cycle needs to fit into a span of two months. Yet, the nature of the external pitcher’s idea is that it hinges on him accelerating his business plan to acquire merchant partners, before we can even have a workable app to release to the public. In addition, the external pitcher intends to partner with large companies with bureaucratic red-tape that cannot be snipped within a week.

The recurring suggestion is that we should simply seek out another external pitcher or come up with our own idea instead of continuing to push down this path. But initially, we did not even consider switching project because of how attached we were to the idea – we felt (and still feel) that it was a pretty solid and interesting idea.

I think the lesson to be learnt through this experience is that ideas are cheap, and not to cling too tightly to a good idea if the circumstances do not favor us. By trying too hard to salvage the idea (negotiating remuneration, requesting for amendments to the one-sided contract, asking if the business plan can be accelerated so we can have something to show for STePS), we were essentially shortchanging ourselves. Our efforts could have been spent on another idea which may turn out to be even more promising than the original idea.

Week 6: Half-stack is harder than full-stack — September 19, 2016

Week 6: Half-stack is harder than full-stack

…when it comes to Rails at least.

Maybe it was a bad choice to implement the backend API on Rails. The original decision to use Rails was that the backend API only needed to handle very simple authentication and CRUD methods on resources, which seemed like a very simple bundle exec rails generate scaffold. Authentication should have been a simple gem `devise` and for Facebook authentication, gem `omniauth-facebook`. In the context of our app, which has real-time updating features, we also wanted to use the new ActionCable in Rails 5, which brought native websocket support.

Ho ho. Were we ever so wrong. It turns out that Rails gems are mostly written to fit nicely into a full-stack Rails app. For instance, the gem that were relying on, Devise, would magically create the relevant view partials, controllers, and models (Devise columns) and handle everything for us. This magic completely disintegrates when you only have half a stack in Rails. When we set Rails to be api-only, Devise immediately broke because it relies on some cookie middleware which is disabled in api-only mode. Outside-in routing also had to be hacked to work, and at some point required the addition of a new gem to take care of session tokens, which we roundly hacked yet once more to fit into our front-end workflow.

In addition, Rails 5 ActionCable is some horribly undocumented shit which lives up to its status as an afterthought. A websocket connection is identified by a user, and has multiple channels (so the high-level model is that a channel belongs_to connection). From a channel, one can call an undocumented method to retrieve the connection, but there is no way (that we have found) to go in the opposite direction. We had to hack the channel initializer to add itself to a list in the connection. There is similarly no way to retrieve the connection identified by a user, and we had to write some hacky filtering method to filter all the connections and look for the one identified by a particular user.

In summary…

Rails 5 ActionCable.
Made to fit well around the nook in the ceiling.
Week 5: “Aim high, even if you fall short” — September 12, 2016

Week 5: “Aim high, even if you fall short”


Even when that high goal is a lot more risky than a more normal, boring one?

This catchphrase has been paraded around ad nauseam, but well it’s typically said by the ones who aimed high, took a risk, and succeeded. It sounds good and feels good to say it, but when it comes to reality, it’s probably not a good idea to aim high with wishful thinking without doing a thorough evaluation of the risks involved and potential contingency plans.

In the context of assignment 3, this is exactly what my group is facing. On one hand, we have an augmented reality idea that is very interesting and (in our opinion) damn cool. Yet, it relies on a bunch of web APIs for which mobile browser support is shaky, as well as this horribly undocumented new feature in Rails 5 (ActionCable) which no one has any experience with in getting to work. On the other hand, we had a rather basic CRUD idea for orientation game management which makes trivial use of device geolocation, etc. to satisfy a few milestones. We have no doubts that we are able to get it working, but… well… yeah.

How do we choose between the two ideas? Our team’s original consensus was to spend 4 days cramming out a proof of concept for the first idea, and failing which, to abandon the entire idea and fallback to the second idea (or the drawing board). I think that was the most sensible move we could have done.

However, now that we have been hacking at it for a while now, some serious compatibility issues are showing up. Most importantly, iOS Safari has zero support for the HTML5 getUserMedia API, which is used to hook the camera feed. Without this, there is no augmented reality to speak of, and the app will have to fallback to either simply rendering 3D markers in thin air without a camera feed (so there is no reality to augment), or simply scrape the 3D part and overlay 2D markers on a map.

My stand is that while augmented reality is indeed the main attraction of our app, the app can still serve its intended purpose without a camera feed – hence it is not completely unusable. In addition, since the API we are relying on is an official HTML5 specification, it should eventually be supported by most major browsers as a matter of time. Hence, our app is essentially an early adopter of a new API — since when has that ever been frowned upon? Regardless, we are in the process of seeking opinions on this idea. The possibility of us having to pivot in a few days is rather worrying.

Week 3.1: Application Critique (Photomath) — August 30, 2016

Week 3.1: Application Critique (Photomath)

Presentation summary

First off, a basic summary of Photomath. It is an app that is able to recognize math equations from a phone camera in real-time, decode it, and simplify / reduce the equations. It claims that it is able to show “detailed step-by-step solution[s]”, but quite frankly is unable to do so for all but the most trivial of algebraic manipulations.

The following points were brought up by the presenting team which I found interesting.

1. Disruptive to education

The presenting team mentioned that some reviews have criticized Photomath for feeding students with answers, resulting in them relying on Photomath for answers instead of figuring it out themselves or asking their teachers for help. By offering step-by-step solutions for problems, Photomath is allegedly able to ensure students learn how to arrive at the answer instead of simply copying the answer.

This criticism is definitely not new – it has been lobbed at WolframAlpha ad nauseam. Yet, is it really more educational for Photomath to provide detailed step-by-step solutions than just the final result? For most school assignments, a final correct answer with no working does not warrant any marks. Simply providing the final answer would allow students to check their own answer if it is correct, but a student who has not attempted the question will still have to try to reverse-engineer the answer, or at least somehow write some hand-waving nonsense that looks almost correct. A teacher worth his/her salt should be able to tell when a student is able to arrive at a correct answer with incoherent working and thus raise a red flag.

A possible balance between providing a student with full, submittable working and a final answer with absolutely no explanation would thus be to provide the final answer and step by step instructions without the actual working. E.g. “multiply both sides by 5” as opposed to displaying the working. This would force the student to minimally go through the process, at the same time allowing the student to check that the final answer is correct.

2. Educational expansion

At the heart of most of the team’s suggestions for Photomath is to develop some sort of “adaptive learning” algorithm for Photomath to be able to suggest / generate problems which are similar to a particular scanned problem. If this were possible, then it would do away with assessment books whose main selling points is essentially problem variations on a theme of some concept.

Is this actually feasible though? Probably, for problems that Photomath is able to produce step-by-step solutions. Being able to generate step-by-step solutions means that Photomath would be able to intelligently tweak some numbers and reorder some steps to produce a different problem that requires the same mathematical tricks to arrive at the answer.

Yet, we should note that Photomath is only able to produce step-by-step solutions for the most trivial of algebraic manipulations. The step-by-step solutions disappear on any simplification involving slightly more advanced operators, such as logarithms, and any form of calculus. The reason for this is that computers do mathematics very different from the way humans do. For example, JC-level integration typically involves tricks such as substitution and heuristic guessing (e.g. LIATE rule). Computers on the other hand make use of fairly systematic algorithms which bear little to no resemblance to what one would reasonably expect to be able to turn in for homework. Hence, while Photomath may be able to solve a more advanced problem using such deterministic algorithms, the steps taken would be so far off from a human solution that trying to generate similar problems using those steps would not make much sense.

In addition, as I will discuss below, educational apps are simply not MicroBlink’s forte. Choosing to continue down the educational path would diverge from their focus on computer vision algorithms.

Original thoughts

MicroBlink’s core business

MicroBlink’s main revenue stream is from selling industrial image recognition SDKs used in their other demo apps such as PhotoPay and BlinkBarcode. It’s core business thus lies in this image recognition technology. What then is the motivation behind Photomath?


The service that they are selling is an SDK, which is not very tangible. MicroBlink does provide a free trial of their SDK, but sampling an SDK is not as simple as sampling a packaged product – to thoroughly test it, a client would have to write demo code to get a feel of what the SDK can or cannot do, as well as how well the SDK does what it is supposed to do.

As such, the best way for MicroBlink to prove the quality of their SDK product is simply to use it themselves, and to build something beautiful with it.


From the point of view of prospective MicroBlink customers (developers who are interested in purchasing their SDK), the key criteria that governs their decision to purchase an SDK would be its technical potential. Now, MicroBlink’s technology has advanced to the point where they managed to achieve on-the-fly recognition of math equations. Cool! Let’s say they write an app that can overlay OCR-ed equations on some sort of augmented reality screen. It can even be connected to a PC by WiFi and output LaTeX equations from what is being scanned on the phone. That would be more than enough to convince prospective customers of their SDK’s quality.

Yet, what use is a demo app if no one uses it? If we take my example app above, releasing it to the App Store would likely attract a very small crowd of people who have such a use case of scanning equations into LaTeX form. For the majority of people out there (most of which do not even work with LaTeX), there is no real need for such an app.

Hence, MicroBlink seems to have made the strategic decision to invest significant resources into developing a math engine and math typesetter (which is damn ugly btw) such that their demo app targets a more general problem faced by people – solving math problems. Photomath is a large marketing stunt, which explains why the expenses have been sunk into a product that seemingly has no intention to be monetized (no ads, no in-app purchases).