The hard balance
One of a founder’s toughest logistic challenges is balancing drinking the coolaid of one’s own vision against the iron skepticism that is required for making healthy data-driven decisions.
With the vision, we’re in the land of dreams: Ok, I convinced myself, the team, the people investing in us, the people paying for our services and the people using them that the world is one day going to work according to our bold vision. I claimed that this is how it’s going to be, it’s inevitable, it’s coming and we might as well be the ones executing on it. I claimed that you are all going to behave the way we predict for the foreseeable future.
In the real world on the other hand, a realm of estimates, percentages, decision-making through empirical means, nothing ever goes according to plan. You make a prediction, you test it, most of the time you discover missing a subtle but fatal nuance: one of your assumptions was wrong and you now need to try again with a different set of variables. Rinse and repeat. Maybe you overcome a local maximum, then you run into the next one which turns out to invalidate everything you had done up until that point. Oops, months wasted, time to go all the way back and try again. You just discovered one more way something couldn’t work.
The trick is that you need to convince everybody else of being right, yet at the same time you have to relentlessly try to prove yourself wrong: you most likely missed something and the plan won’t work until all the kinks are ironed out. It’s a very hard line to walk, it’s working every day through cognitive dissonance, getting used to it and not letting it stop you from making progress.
2013 - a retrospective
The kind of fast-paced, “just get it done now” work we do tends to be very day-to-day. You toil the days away, immediately switching to the next task, and never feel like you’ve learned anything. In a healthy Agile tradition, I would like to reflect on the past year and acknowledge the learnings, keeping things in perspective for those moments where I feel I’ve accomplished nothing. Here are some of them for posterity:
- First MVC JS app in Backbone.js. Since then iterated for close to a year on our existing teacher dashboard. Now using Backbone + LayoutManager to implement the student MVC app for Chromebooks, directly replicating the iOS experience. Really fortunate to be able to chat with folks of the caliber of Tim Branyen and Samuel Reed when it comes to getting some Backbone coaching.
- Got a lot more intimate with JS, CoffeeScript and functional programming in the process. Interesting foray into the require.js / AMD territory with hand-rolled build scripts etc. Dropped that in our latest app, but will eventually slowly build back up a very simple minimalistic pipeline with grunt.js.
- Lots of time spent on CSS and layout work. Good chunk of time working with boostrap 2.3.2 and bootstrap 3.0.x on both responsive sites.
- Wrote first unit test suite in JS thanks to buster.js. Actually extremely pleasurable, somewhat close to the testing experience in Clojure.
- Started working with Clojure half-way through the year. Still very much of an ongoing project, S. Halloway claims it takes at least 18 months for alien superpowers, so I still have plenty of room. Migrated Parse.com-based backend to our Ring app, rewrote all of our clients to use the new REST api instead of Parse’s libraries. Lots of tests on all levels of granularity. App is continuously being refactored as I discover new simpler and more elegant techniques. Infinitely grateful to the folks in #clojure, especially bitemyapp (Chris Allen) for the torrent of tips.
- Finally got some time re-visit the Dragon Book and put some of that to use for our tentative math interpreter with Clojure + instaparse.
- Lots of ops work. Never touched a “datacenter” previous to this year, was always hiding behind something like Heroku. Started with AWS EC2, not using any of their convenience services, feeling pretty comfortable with it now. Initially started CM with Puppet, didn’t like it. Switched on Ansible, no headaches whatsoever now. Switched traditional EC2 to a VPC. The system was all Internet-facing for a while, I had to figure out how to setup a VPN for the first time, which was fun. Now all office machines are on VPN and have direct safe access to the datacenter.
- Lots of Postgres work. Anything from deployment, to administration, to fine-tuning for performance for the given machine. That one was a BIG book, which I still reference every time.
- Good progress in my understanding of computer networks, still a work in progress. Recently had to setup a DNS server at the office for our Chromebook to be able to reach the sites hosted on my dev machine. Networks is such a good skillset to have when doing ops work, debugging connectivity in various locations such as our school networks.
- Plenty of Linux administration work. Again, still very much a work in progress. Lots of time spent on bash and Linux/UNIX tools and utilities. Running Ubuntu full time on all of my machines now, including home. Got very comfortable using tmux, and recently switched from Unity to xmonad so that the mouse is halfway useless. Tiling window managers are awesome, but do require some configuration effort.
- Lots of practice of XP and other Agile practices with a small team. Good experience with cherrypicking which practices to follow and when. Right now the engineering efforts at Front Row are still very manageable, but we’ll need to step things up a bit once more people hop on board and chaos ramps up.
Looking back this has been a pretty fruitful year. Here’s what I hope to work on in 2014:
- Would be interesting to pursue the interpreter-building route a bit more, see where that goes. Still very interested in getting more practice with building languages.
- More Clojure work, of course. The language and the ecosystem are like chess: the pieces are very simple, but I can see this taking many years to master.
- Would love to experiment with Haskell for some internal low-pressure tools, build some experience before considering it for production.
- More work with scaling out the system. Right now our load is very humble, partially thanks to how the API was designed. If we do our job well at Front Row, then it will be time to start engineering for a more interesting load.
- More depth with anything infrastructure-related such as Linux, network administration etc.
- More opportunities to release some of our tools as open-source. I recently put out an early alpha of a Mixpanel client library for Clojure, so I’m hoping to release more of these tiny helpers as I get more experience with designing quality libraries that others actually want to use.
There aren’t too many examples of Clojure’s instaparse use out there, so if you’re working on parsing a little language of your own, I hope this might come in handy.
I’ve been working on a little interpreter for some internal stuff part of the Front Row stack, mainly for validating student answers in the more complex middle school math domains. The interpreting the answer becomes pretty much mandatory for validating things like equivalence of two polynomials. This is what came out from the early efforts.
The EBNF grammar itself can be found here, the implementation of the parser is here (still blows my mind it’s under 50 lines), and the tests are all here. Wouldn’t have touched this with a ten foot pole without testing every single incremental addition.
A couple of resources I found useful, in addition to instaparse’s official docs:
The author of instaparse himself was also generous with a few tips on the library’s Google Groups.
Another great little guide on understanding differences between traditional Regular Expression engines. Greg’s wiki is generally considered a real goldmine.
List of great Clojure libraries for reference
By Mr. bitemyapp's recommendation, the following libraries are a great way to advance one's Clojure style chops. Dumping the list here for my own reference.
Got my homework cut out for me :)
Correct Content-Type of static assets in Ring apps
If you’re thinking of serving assets from a Clojure Ring app, then you should be aware of an interesting quirk of one of the core pieces of Ring middleware: wrap-file-info. This middleware is used to automatically detect the file type based on extension and inject the corresponding Content-Type header into the HTTP response.
Now, when developing with it enabled, you might run into an interesting and somewhat hard situation to debug. In development mode the files will be served with the correct MIME type. In production, when the app is packaged together into a single uberjar, IF your resources were being served from within the resources/ folder, then wrap-file-info will fail to correctly identify the file type.
Why? In development ring will be working with real files on disk, in a .jar situation you simply don’t get file extensions. See the following thread where Weavejester clarifies the situation.
Solution? Use wrap-content-type middleware instead. It only cares about the extension specified in the URL and should work correctly in most of the basic cases. I imagine you could have Ring fetch resources outside of the .jar itself, in which case the problem above would not reproduce. I believe you could get the best of both worlds by moving your assets outside of the uberjar and by using wrap-content-type regardless.
As a sidenote, cURL seems to infer MIME type based off of the URL, a behavior that’s inconsistent with the current versions of Firefox and Chrome. If you try to debug the issue above with cURL, you will be deeply puzzled. cURL will consistently correctly guess the MIME type, while the browser pointing at the file will print out a console message saying it’s getting a resource with text/plain, instead a different Content-Type value. The browser still correctly tries to use the resource, as they’re wrapped in a <script> or <link> tag with a specified content type. What makes this a tad extra frustrating is that Firefox allows you to generate cURL requests from the debug panel, and the requests are actually inconsistent with the browser that output that command.
If someone knows how to turn off Content-Type inference in cURL, do let me know :)
Apparently I’m not the only one who experiences those feelings towards ObjC block syntax.
[git] How many lines have I written today?
Neat one-liner that might be interesting to folks. Say you’ve been working in a separate branch for a few hours and you want to know how many new lines of code you cranked out. There you go:
$ git diff parent-branch...topic-branch | grep '^+' | wc -l 390
Pretty neat given how small the command is.
Front Row Classroom has been out for less than a week and already the visionaries at FCPS are experiencing the power of adaptive math practice and teacher analytics to improve teacher effectiveness and quality of education.
Very satisfying to see the hard work paying off when students across the country have a much better time with math.
Back to work now!