The objective was to develop an HTML embedable widget to facilitate the purchase of voucher codes. The number of screens was under ten with pretty simple interactions. CouchDB was to be used as a UI settings and copy store, to be easily edited.
Server-side rendering and just jQuery like old times
I’m a proponent of separating frontend and backend, ridding the server from any UI concerns and obtaining a simpler and more solid service model. I’ve been completely avoiding server-side rendering since I moved away from Rails some years ago. However in this particular case I actually found server-side rendering to be simpler, for these reasons:
- CouchDB needed be consulted often for UI settings
- Very small amount of content overall
- No complex UI interactions
- Highly unlikely that any server API would ever be reused
With such simple UI flows it also seemed to me that using any MV* would be silly.
I think for a brief moment it felt like being back in 2009 or something except a-ha now using javascript and being free from OOP-everywhere mentality which meant much faster development and much less bloated code.
Express
For a server framework I decided to go with express. One strong reason was the server-side rendering decision. But I think I’d still chose express otherwise, not because I particularly like express but because I find more stuff wrong with other usual alternatives. I find restify to be frequently missing too much stuff, and I sometimes feel that hapi wants to take all the fun, simplicity and flexibility from node just to indulge people in suits. Express was a good choice.
Development setup
If you know me you know how much I think maitaining short feedback loops is important. This makes me want to have some tools running:
- Web page reload on file changes using Live Reload
- nodemon -q server.js for the running the service locally, and have it restart on any change to the code
- nodemon -q -w couch/ couch/setup running the couch setup with the initial values — fast way to change what’s in Couch
- gulp watch to instantly update built assets
Deployment to SmartOS on Joyent
We were in charge of deployment to the dev environment only, where everything ran locally. The app ran behind one nginx and accessed both couch and postgres locally.
The service was setup using Service Management Facility (SMF) which is nice if you don’t mind that the service configurations are XML.
Installing software packages with pkgin is very easy, but I had mostly two problems with it:
- Not many available packages
- It wasn’t very clear to me how to update the package sources
Deploys were done with a post-receive git hook on a git bare repo on the dev server. This script would:
- Create a new folder under /deploys with a unix timestamp
- Checkout the code to this folder
- Substitute the /deploys/current symlink to point to this new folder
- Run setup tasks (gulp, postgres setup, couch setup)
- Restart the SMF service
Load testing
We used blitz.io to test and mesure how much load the app could take. Unsurprisingly, we weren’t satisfied with the initial results, so we took some steps:
Caching Couch
Couch was being consulted in every request to fetch settings and content. We started caching couch documents, using changes feed for invalidation.
Postgres stored procedures
To minimize postgres accesses per request. On some cases, to perform validations, a single request would cause several queries to Postgres. We decided to move the logic over to postgres and have a single stored procedure for every interaction scenario. This meant we had to deal with PL/pgSQL, but it also meant these requests with multiple validations were now much faster.
Varnish
Varnish was the best improvement of all. Because the application was session-free, a huge percentage of the load could be dealt by varnish, both alleviating the pressure on node and greatly increasing the final load capacity.
End result
I believe that the best results come from simplicity and that the best software is made as simple as the requirements allow it.
Instead of blindingly following popular best-practices, structuring for a future an eventually large codebase, planning for extensibility, going for a swiss-army overlord framework when a tiny library will perfectly do, focusing more on “design-patterns” than on the actual problem you’re trying to solve, worrying about defining a “proper” well-defined interface when all you need is one implementation, it’s better to kept it real, don’t be the “future programmer”, accept that that day when all the extra effort you put into having as much loose coupling as you can possibly imagine is going to pay off is actually never going to come, keep it small and simple.
By focusing on simplicity first and only worrying about performance when actually needed the codebase was kept to a minimum, and so possible future changes are easier, even if much code can’t be easily reused out of the box without slight changes. Less is more.
Make it as simple as you can, and no simpler.