This is the second instalment of “Tech stacks in Asia” with up and coming Asian tech startups. In this blog we hear from Singapore based Klinify.
Describe Klinify in 2-3 sentences.
Klinify is a VC backed startup based in Singapore. We help doctors and hospitals go digital without changing their workflow. Our product combines everything healthcare professionals love about paper with none of the inconvenience of the typical EMR system. You can learn more about us here: www.klinify.com
What are your primary programming languages?
We run a pretty mixed shop over here. We primarily use python, java (android), shell script, coffeescript (backbonejs), couchdb.
Since Klinify is a full clinic system we’ve got a lot of components: the main product is an Android app that runs on the Samsung Note series of tablets, but it links with a full system that includes a webapp, a light desktop app, and a light API.
We use Jenkins and Docker to do continuous integration and deploy our server side code, and CouchDB ties all our data together.
Generally we’ve aimed for tools that increase developer happiness. We’re big on the idea that things that are easier to do will get done more often, so we’ve put a lot of effort into automating our deployment and release systems. We’ve also tried hard to get rid of boilerplate and tedious repetitive coding. Most of our choices are aimed at making our developers maximally productive.
We’ve got multiple frontends, one for doctors and one for nursing and admin staff. The doctors use a straight up native Android app. The two unusual choices in the Android app are that we use CouchDB (via the Couchbase Android libraries) for our data storage and the use of the Samsung Galaxy Note series.
One of our biggest selling points is that doctors can continue to use the same approach they’re used to with their paper based notes, and having a tablet that lets them write in the same way that they’ve always done has made it a lot easier for doctors to adopt our system.
This approach is nice because it’s the best of both worlds for us. We:
- get the simplicity of coffeescript (no more time wasted because of a missing )or })
- and browserify allows us to keep our files structured and modularized, while browserify’s sourcemap support makes debugging from Chrome as seamless as if we’d used vanilla js.
Backbone has also been nice because there are multiple libraries available to sync Backbone’s models and collection with CouchDB, rather than having to do that stuff manually (something we abhor 🙂 ).
We also have a “half frontend” (our desktop app) that the admin staff uses. We found that nurses and other admin staff frequently had paper documents that they needed to scan into the system, so we built a light desktop app that watches the scanner directory and uploads any images that are placed in that directory to our API.
We wanted to reuse our existing backend code for processing and uploading images and we didn’t want to be tied to any particular platform, so we built the desktop frontend in Python and PyQt, and use py2app and py2exe respectively to build the app into OS X and Windows executables.
Our backend consists of a Python based API built around the lovely Flask framework. We deal with a lot of large images, so we have a flexible configuration driven storage backend that allows uploads to be stored in Amazon S3, the local filesystem or both. The API interacts with CouchDB as well to make sure that all the data stays in sync.
Since we spin up a lot of different copies of our backend, each with their own database and API, we set up our own Docker registry and some shell scripts to simplify their use so that we can have a new instance ready to run in just a couple of minutes. We use this both for our local instances for in-house development and for our production servers.
This took some work to get set up, but has the advantage that each installation’s data is separate from the backend code, so we can upgrade (or even downgrade!) our entire backend in just a couple seconds without causing any noticeable changes to the client.
What went differently than expected?
For the most part the tools we’ve chosen have allowed us to get more done with less, but we have run into our fair share of difficulties!
CouchDB is rather different from most NoSQL databases, and there were the usual growing pains involved with learning a new database. This was to be expected though, and overall was well worth the trouble.
Coming to terms with the ecosystem itself was a bit of an adventure though. While CouchDB is a mature and well-documented project, the same cannot be said for the library we chose for the Android portion (couchbase). Understanding the CouchDB/couchbase ecosystem took some time.
CouchDB has been around forever, but most of the new activity in the Couch ecosystem seems to revolve around a company called Couchbase, which was founded by one of the original founders of CouchDB.
Despite the similar names and founders, Couchbase’s products are all intended to use Couchbase’s own database server (which is in some ways similar too, but with a very different API) but provide a compatibility layer that allows them to interact with vanilla CouchDB servers.
The CouchbaseLite Android Library is a pretty young project – and the documentation is still sparse. This led to a lot of head scratching in the early days, especially since we didn’t have a lot of Android experience on the team for the first few months.
We also ran into some of the usual issues with building a cross platform desktop app. PyQT is great and allowed us to get something up and running quickly and easily, but also caused lots of small inconsistencies between the OS X and Windows apps.
py2exe and py2app, the tools we used to pack our python code into single executables, all have their own quirks as well and it took some trial and error to get this up and running.
What are your primary databases
We had a rather unusual set of requirements: we needed something that:
- would enable offline access on mobile,
- had excellent data retention and a proven track record (since we’re dealing with medical records it’s important that every single change to every document is preserved), and
- easily allowed us to sync multiple devices, all of whom may or may not have had internet access at the times changes were made.
- On top of that, we wanted the ease of use that NoSQL databases provided.
Given our requirements, CouchDB was a bit of a no brainer. The Couchbase libraries, whilst intended to be used with Couchbase’s own database, are also fully compatible with traditional CouchDB installations, and provided us with the offline and mobile capabilities we needed. On top of which, the syncing features are just magical: delete a patient or edit a note on the tablet, the tablet saves the change to it’s local database, and simultaneously pushes the change up to remote instance. Our webapp and other tablets then immediately pull the change down to their local databases and you end up with seamless syncing functionality for the user with very little extra work from our end.
CouchDB even handles conflicts in a flexible and safe way. If tablet ‘A’ modifies a document at the same time that tablet ‘B’ does, CouchDB will automatically pick one to as the authoritative copy and notify us via it’s changes feed that there was a conflict. This fires up our custom conflict resolution process, and we can then merge or discard the conflicted data as we see fit.
The most beautiful part is that CouchDB is ‘append-only’. It’s literally impossible to delete something from a CouchDB database. When you ‘delete’ a document, the document is simply marked as deleted and not exposed to queries by default, but the document (and every change that was ever made to it) is still there if you need to go back for it.
CouchDB does have it’s own set of headaches, the whole concept of views and the inability to “query” it in the sense most of us are used to from other databases takes some time to get used to, but its syncing features and solid data retention have made it a good choice for us.
Which DevOps tools do you use?
Most of our cloud infrastructure runs in AWS. Our choices there are quite standard, S3 for storage, and EC2 for our virtual servers.
For our devops work we rely on Jenkins, Gitlab, Docker, and some shell scripts to glue the pieces together. Gitlab is configured so that whenever we push code it fires off webhooks which notify our Jenkins server to start a new build of all three components of the Klinify system (the Android app, the API and the webapp). These all get packaged together, tagged as a docker image, and uploaded to our docker registry as a new docker image. They’re then tagged with the jenkins build number and any applicable version/release numbers for easy access.
When we want to bring up an instance of the Klinify system, we just call our deploy scripts and pass the build tag or release name as a parameter. This gets us whichever version of Klinify we need up and running almost instantly, and makes upgrading and downgrading dead-simple.
Since our deployments are Docker based this has the added advantage that our application’s data and configuration is all stored outside of the Docker container itself. This means that cloning deployments or getting a deployment into a reproducible state when testing a bug is easy since we can just copy our data directory in and out.
Which part of your stack are you most excited about?
Docker is the most exciting portion of our stack right now! The pace at which Docker development is proceeding and the Docker community is growing is pretty amazing.
New Docker based tools are being released constantly, and the Docker team itself is fixing bugs and pushing new features at an amazing rate. This means that the limits of what’s possible keep getting pushed.
CoreOS is an amazing new development, and now even Amazon is getting involved with their new EC2 Container Service.
How have you found recruiting staff for your stack?
Let’s break this into three parts: Android, webapp and backend.
Recruiting for Android was quite difficult. Android is still a relatively new platform, and since our core product is an Android tablet app we needed someone with a lot of experience.
The Android API is massive, and as a result it takes a long time to become proficient in it. We needed someone who could scaffold and architect the product, and we found that this required a deeper understanding of Android than a dev could get with just a year or two of experience.
For the other parts of our stack generalists with a year or two of experience in the area worked well, but we needed a true specialist for the Android side. Since there is so much demand for good mobile developers it took us a full six months to find our guy!
Our webapp stack was based on coffeescript, backbone.js, and browserify. All three of these are less popular than their main alternatives (vanilla js, angular.js, and require.js), so this narrowed the pool a bit, but not that much. Everyone we’ve hired at Klinify has been able to pick up our web stack quickly enough.
Each of the pieces have their own pros and cons:
- Coffeescript and browserify are simpler once you understand them, but take some getting used to initially.
- Angular seems to be a more clearly defined and more idiot-proof framework than backbone.js, which makes it easier when working with outsourcers and more junior devs.
- Backbone on the other hand is lighter, and while this makes it more flexible, it makes having devs who fully understand how all the pieces work together critical.
Overall our choices here were a net positive because they made our coding easier and more efficient, but they did slow us down on the recruiting front a bit.
Recruiting for the backend was the easiest. Our backend started off quite simple since our focus was on the UX of the frontend product, and our choice of tools for the backend (Python + Flask) were both pleasant to code in and popular. The challenge here was more in finding smart people with the right combination of aptitude and attitude for Klinify. Finding experienced candidates wasn’t a problem.
Do you hire locally or import staff? Do you remote work hires?
We didn’t make any remote full-time hires, but did experiment with outsourcing. Our experience was that it was cheaper, but incurred a lot of management overhead and only worked well for self-contained tasks.
So where did you find hires?
We got a lot of good leads from Angellist. Startupjobs and Workable also helped a lot, and we also received good applications from the hiring page on our own website.
Do you find new languages a selling point or a hindrance?
In terms of recruiting they were a hindrance. While they were a net-benefit to us overall in terms of ease of coding, they definitely limited the pool of applicants.
Did you pick the stack first based on idealisation, or what staff you had on hand?
A mix of both. We looked for the overlap between what our staff already knew and what seemed to be the best tool for the job. Most of us at Klinify enjoy learning new languages and tools, so we wouldn’t rule out tools just because no one on staff currently knows them.
On the other hand, we’re a startup, and for startups speed is king, so we were obviously looking to leverage the experience of the team to move quickly.
Overall, the only piece of technology that nobody on the team had had prior experience with was CouchDB, and while we did hit some rocky stretches there, it was worth it in the end for the extra flexibility it gave us.