Our team had the experience of hacking on several projects together before setting out to build Close.io sales communication software, but when starting on this app we took some time to carefully choose our tech stack (and the startups & services) to build upon.
We needed a very fast user interface (our #1 goal was to create happy users), and a scalable backend (our customers sometimes commonly import 10k or 100k new sales leads as they start using the system). Here’s how we’ve built it…
At its technical core, Close.io is a web app wrapped in Native Mac/Windows applications in order to provide a desktop experience and high quality calling functionality.
Probably the single best architectural decision we made early on is strictly enforcing that our internal app’s functionality will use the same public-facing RESTful API. This has a few benefits:
- The obvious. We ended up having an extremely robust public API as a result, which allows our customers to integrate with Close.io in a very deep way. It’s great to be able to answer most “can your API do X?” questions with “if it can be done in the UI, it can be done via the API”.
- Better abstraction. By creating a public-facing API for each new feature you need, you make better decisions about how something should work - both by itself, and the big picture of your application. It might be tempting to throw up a quick non-API view that you can AJAX post to for a new feature, but you can easily end up reinventing the wheel and have multiple not-quite-the-same conventions between different parts of your application.
- Rely on conventions. When working with a standardized API it’s easier to reuse code, auto-generate endpoint urls, etc. in the Backbone.js client and trust that standard REST principles apply everywhere.
- Investing in frameworks. Since we had to build so much complex functionality into our API, we invested in writing frameworks that have made our lives easier in the long-run and make for happier developers since there’s very little boilerplate code in creating new resources/endpoints. And we’ve gotten to be good net citizens by open sourcing them: Flask-MongoRest & cleancat.
Close.io is a single-page Backbone.js app with a few notable goals:
- Be really fast. No page reloads. Optimistic UI updates. Don’t wait for anything.
- Autosave nearly everything. We saw too many important call notes accidentally get lost in early versions, so all comments, call notes, email drafts, etc. are saved-as-typed.
- Intuitive UI/UX that looks good in a web browser, Mac app, and Windows app. Make the common tasks really simple to perform - try to halve (or better) the number of clicks from popular CRMs.
- Real-time. If Sally has some lead’s information open on her screen and then goes to lunch, when she comes back it’s important that she doesn’t make a call without first seeing that Joe, her overzealous coworker, already talked to that person while she was gone.
The UI frontend (even for our desktop apps) is written in HTML5. We use Handlebar.js for client-side templating, precompiled for optimal performance in production.
The visual design is sometimes done in Photoshop first (we Dribbble a little), though often is done directly in code.
We write LESS as a CSS preprocessor (using mixins provided by Bootstrap and CSSMixins to keep the code clean). We use Bootstrap as a foundation though we try to keep our style from looking too Bootstrap-ey.
Stay tuned for another post about how our Backbone.js app is structured, in detail, and the things we’ve learned.
The core of our application is built around search. We’ve invented a “lead search language” that helps sales people instantly build a lead list fitting almost any possible criteria. For example a search of:
status:cold called:never email_opened < “3 days ago”
will instantly show the user “cold” leads that have never been called, but that opened your email within the last 3 days. You can save a query as a “Smart View” to get back to it in 1 click.
We use MongoDB for its flexible schemas and quick performance. Mongoengine makes it nice to work with.
Our Python app is run by Gunicorn, gevent, and Supervisor. We chose Flask (even though we all had Django experience) because of its simplicity and light weight, and because with a client-heavy / API-only application built upon MongoDB, Django didn’t make as much sense.
We run Ubuntu on AWS. Multiple EC2 app servers run in different availability zones behind ELB.
Native Desktop Applications
On the Mac we use XCode to create the project, and a standard Cocoa WebView to render the UI. Sparkle is used for auto-updates. On Windows we use Visual Studio to build a mostly-shared codebase, but use chromiumembedded (CEF) to render the UI.
If you haven’t given Close.io a shot, check it out or send the link to someone you know who works in sales.
Tech stack sound interesting? We’re always looking for great designers & developers to join us.
Hit me up on Twitter with any questions/comments.
-by Phil Freo (@philfreo)