Let’s build the future that we want to live in.
A Startup CTO’s Take on Early Technology Choices & Tradeoffs
Isaac Cambron is co-founder and CTO of Zensight.co, whose pre-launch product enables sales reps to find and use their best content to close more deals. Below, he answers questions about developing products from scratch, as well as the difficult technology choices and tradeoffs CTOs must make.
NextView Ventures: You just experienced something that most developers don’t ever see: zero code base at a company. On a high level, where do you even begin?
Isaac Cambron: It’s always daunting. I definitely spend a lot of time on paper first, making sure I understand what I’m really building and why. Mistakes you make on a whiteboard are a lot less expensive than ones you make coding, so maximum clarity is an important prerequisite to coding. You want to know the goals of your business, which will tell you what kind of product you should build, which will then allow you to form a plan about how you’re really going to build it. Then it’s time to break ground on actually building things.
NVV: When you’re starting from nothing, how far out do you try to scope your product before committing any code? And regardless of how far out you look, what do those first three months look like?
IC: It’s important to be milestone-oriented. The scope you want is “when will I have something that actually works?” That could be two weeks or six months, depending on what you’re actually building. You always want to be careful with how tightly you schedule things to make sure you stay agile and responsive to evolving business needs, but you also need to make sure your overall journey makes sense and that you’re building things in the right order, as well as taking on risks in a measured way.
The first three months of actually building things is really exciting: You go from a blank screen to a product that actually works. It’s challenging, though, because you’re materializing a lot of moving parts out of thin air and trying to weave them together while they change rapidly. I’ve found that the key is to integrate your parts early, even when they’re unfinished, so you can have a whole system that fits together. For example, if you’ve split the work up as a backend and a UI, it can be tempting to build them separately and then wire them together when they’re done, but that will just result in some “oh crap” moments way late in the process. Instead, tie them together early and just deal with the pain that comes from the interfaces changing every day. That lets you learn the flaws in your design much earlier.
NVV: When do you start thinking about technology choices and what you’ll use to build something? Does that inform everything from the start, or does it come in after you’ve identified a problem to solve with a product you’ll build? And how do you actually make that decision on the tech you’ll use?
IC: Technology choices are definitely dependent on what you’re trying to accomplish with your product, so you need to figure that out first. If you want to build a website that, say, keeps track of your favorite restaurants, you might think, “Ruby along with Rails are great choices here, so let’s do that.” On the other hand, if you’re building something that you realize will involve a machine learning system for large streams of data, that might be a poor choice, no matter how much you like Ruby.
But ultimately, in the end, you need to make tech choices that reflect the DNA of your team. For example, my team’s bias at Zensight is towards functional programming, and the tools we’d be using for almost anything are colored by that philosophy.
The reverse is true too: You want to figure out your technology choices as early as you can, because that will affect who wants to work with you. Tools, especially broader tools like programming languages, come with a lot of baggage, an attitude or even a philosophy on software development. For example, we picked Clojure for our development work. We did that for a lot of reasons. It’s got an ecosystem attached to it that fits nicely with what we’re building, and we really like the language. But we also picked it because we want to work with people who care about functional programming and design simplicity, and Clojure is the sort of language that attracts that kind of person. So your tool choices are a big part of the “what kind of team do we want to be?” decision.
NVV: Generally speaking, there are two schools of thought on building from scratch: (1) You could start scrappy and piece together something functional that you ship, and then bring in smart engineering discipline later to clean it up/set yourself up to scale, or (2) you can start with these smart principles from the very beginning and build with flexibility and scale in mind from the outset.
With that in mind: Which do you believe in and why? And regardless of your preference, how does the latter (smart principles early) fit with the need to ship fast, learn, and iterate?
IC: I definitely believe in and prefer the latter: smart principles from the beginning. I know there are some good businesses that have thrown something together and then rebuilt everything later, but it’s an expensive and painful endeavor. Build it right from the beginning with people who really know what they’re doing.
Then as your business grows, you’ve already established a culture of good engineering practices, you already have the senior staff up to speed, and you’ll find it easy to attract more talent. And your code already does what it’s supposed to do!
I also think a lot of people underestimate the tax that having a hacked-together solution levies on your product development, even in the short term. For example, not having good system monitoring doesn’t just make developers’ jobs hard when they try to figure out why the servers are down at 3 a.m., it could also cost your business real money at a crucial early moment in its life.
As for beginning with these principles and how that relates to shipping and learning quickly:
It’s important that “build it right” doesn’t mean “build the most general, abstractly correct implementation of your vision.” It means that you’ve followed good practices — simple things like building small, decoupled pieces of functionality or not distributing mutable state across your codebase. It means you’ve set up good tooling so that developers can attack problems quickly without a lot of grunt work. It means your code is organized in a way that makes it easy to find things. So it’s really, at the core, about removing friction from the process, and that actually gets you to shipping sooner.
What you don’t want to build are features you don’t need. Your product should do the bare minimum it can from the perspective of the user. That gives you a lot less surface area, which allows you to stay nimble. But the software itself should be well-crafted. One way to put all that is: build less, but build it better.
[Tweet “”Build less, but build it better” @icambron of @ZensightHQ”]
NVV: Startups are all about tradeoffs, and engineering is a great example. As a developer, how do you think about early tradeoffs and how they could affect the company longer term? How do you ensure they’re the right tradeoffs?
IC: In general, the decisions you make at the very beginning have outsized impacts on the future of your company, partially because they form the core of your technology architecture and partially because those decisions set the tone. Code has a way of living a lot longer than its authors intended, and bad software can poison development efforts for years to come. So making good decisions early is worth the extra effort.
Making good tradeoffs is a core skill of a senior engineer. What kinds of things don’t matter at all and will be a waste of time to fix, versus things that will bite me in the ass tomorrow and are worth a closer look? There are two questions that matter here:
- How much will it cost to do later versus doing now? The main driver for that is the degree to which it will impact how the rest of your software is written. Distributing work using job queues is cheap now and expensive later, because you’ll have to rethink how a lot of your code works. On the other hand, having a polyglot stack can be added later as easily as now, but would create maintenance friction in the meantime.
- What’s the probability you’ll need it? You’re definitely going to need ops automation, so just do it. Waiting is just increasing the probability you’ll have a horrible problem in production. On the other hand, maybe you won’t need that fancy Spark Streaming pipeline, so don’t waste precious cycles on it.