Rust compiler error example illustrating lifetime issues
Rust compiler error example illustrating lifetime issues

Why We Initially Regretted Choosing Rust for Our Startup: A Retrospective

For nearly two years, Rust has been the backbone of our backend code at why.edu.vn, with just a touch of Python complementing it. Rust is undeniably a language I deeply admire. Its match feature is something I miss in almost every other language I use.

However, looking back, if I were to make the tech stack decision again for our early startup phase, Rust is not the language I would choose.

This advice is tailored for startups in their nascent stages – pre-product, pre-seed, or seed. To understand this perspective, it’s crucial to first explore the reasons that drew us to Rust in the first place.

Why Did We Initially Opt for Rust?

Unparalleled Safety. I firmly believe that even seasoned developers are susceptible to making unintentional errors. While type systems are essential for mitigating such mistakes, Rust elevates safety to a new level. Runtime issues become remarkably rare; you’d practically need to try to introduce memory leaks. Furthermore, crates like sqlx offer compile-time validation of SQL queries against your database schema. Rust and its ecosystem provide an extensive toolkit to prevent common coding pitfalls.

Expressive and Readable Syntax. Rust’s syntax is filled with features that enhance developer happiness. A prime example is the ? operator, a brilliant solution for error handling. It streamlines code by focusing on the successful execution path.

We frequently write concise and powerful code snippets like:

// fetch_user returns a Result
fetch_user()?;

This is incredibly succinct yet highly expressive. Combined with algebraic data types, pattern matching (match), and versatile type conversion traits (From, Into, TryFrom, etc.), Rust allows us to create code that is both remarkably readable and concise.

Why Wouldn’t We Choose Rust Again for an Early Startup?

Despite the compelling advantages, if we were starting our company anew, several critical factors would lead us to reconsider Rust, especially for the initial phases.

Slower Iteration Cycles. When embarking on your Rust journey, you will inevitably encounter a learning curve, battling the compiler. This is a natural part of the process and becomes smoother with experience. However, for a new startup, the paramount challenge is validating your product’s usefulness.

Rust compiler error example illustrating lifetime issuesRust compiler error example illustrating lifetime issues

(Example of a Rust compiler error related to lifetimes, a common challenge for newcomers, highlighting the complexities that can slow down development in early-stage startups.)

As illustrated in this example (https://users.rust-lang.org/t/error-with-lifetimes-on-impl-fn/58706), even seemingly simple tasks can become protracted debugging sessions due to Rust’s strict borrow checker and lifetime management. In the crucial early days of a startup, rapid iteration and validation are paramount. A quick Minimum Viable Product (MVP) can be invaluable in confirming your direction and avoiding wasted effort on features nobody needs. The time invested in crafting highly performant and elegant Rust code might be premature if the core product-market fit is still uncertain.

Furthermore, onboarding new team members unfamiliar with Rust introduces another layer of complexity. You’ll face the choice of prioritizing Rust expertise in hiring, which can limit your talent pool, or investing heavily in Rust training, which consumes valuable time and resources.

Performance is Less Critical with Cloud Credits. One of the primary motivations for choosing Rust is often its exceptional performance. However, early-stage startups have an intriguing alternative to consider when facing scaling challenges.

Instead of optimizing for performance at the code level from day one, startups can leverage the readily available resources and financial incentives offered by cloud infrastructure providers. AWS provides Activate, and GCP has a comprehensive startup program. A simple search for “startup cloud credits” will reveal a plethora of similar deals and programs, often bundled as perks with other startup-focused products and services.

These programs essentially provide “free money” in the form of cloud credits, allowing you to easily scale your infrastructure vertically or horizontally by deploying larger Kubernetes clusters or Auto Scaling Groups. This effectively postpones the immediate need to deeply optimize for performance in your codebase, freeing up your team to focus on more critical tasks like product development and market validation during the crucial early stages.

When Is Rust a Suitable Choice?

The core takeaway is that Rust excels as a language for building robust, high-performance production systems. However, during the prototyping, customer iteration, and product discovery phases of a startup, Rust might not be the most efficient choice. You risk expending valuable time wrestling with the language when that time could be better spent on validating your product and business model.

Rust becomes an excellent choice when you achieve clarity in your product direction and transition into phases focused on scaling, performance optimization, or building a solid, maintainable codebase to minimize long-term technical debt. In these scenarios, Rust’s strengths in safety, performance, and maintainability truly shine.

Are We Rewriting Our Backend Away From Rust?

It would be ironic if, after advising against Rust for early startups, we were to reverse course and rewrite our own Rust-based backend. However, that’s not the case.

Rust has proven to be an incredibly stable and reliable foundation for our platform. We’ve also made significant investments in our internal developer experience around Rust.

We’ve developed custom extractors to streamline API development for various user requirements. We’ve implemented middleware for request scoping on a per-customer basis. While these are standard practices in many languages, achieving them in Rust for our specific use case required navigating concepts like pinning.

Now that we have built these utilities, accumulated domain expertise, and established a solid Rust-based architecture, we can iterate quickly and confidently. But, reflecting on our initial technology choices, despite my personal fondness for Rust, I would advise against selecting it for a very early-stage startup environment.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *