11 days ago - https://news.ycombinator.com/item?id=33714007
19 hours ago - https://news.ycombinator.com/item?id=33837803
I don't get how someone could think making a CRUD app in Rust could ever be a good idea (beyond hobby projects). That is just not playing to the strengths of the languages at all.
If you CAN use a language with automatic garbage collection for your project, do that. Always. If not, sure, Rust or whatever else language is in that space can be a good choice for embedded development or game dev or whatever. That should be common sense. No need for an article.
I hope for the sake of Rust that the hype around it will die soon so that it can become a pragmatic choice for certain projects.
I have a lot of experience writing microservices and batch jobs using C++. At first this seems outrageous, but with a reasonable set of high level utility libraries, C++ can be very expressive. And then you have the option to drop down to whichever level of abstraction is necessary to address performance or concurrency issues.
Beyond platform requirements (e.g. HTML, CSS and JS on the web or python for ML) I think language choice has more to do with business needs than high level problem domain. When you're building an MVP or have an urgent business need where you need to prioritize short term progress over long term flexibility, high level languages with GC are great. If you have an experienced team and you want to build something that will offer flexibility in the long term, Rust is a fine choice.
I agree Rust is a great language (and has many great things besides its safety protections) but I do think that putting it everywhere when it isn’t necessary is dangerous.
If one doesn’t exist already, someone should make a rust-like language with garbage collection.
EDIT: Thanks to reading other comments, I remembered Elixir, which offers a lot of the concurrency safety of rust without the memory risks.
If you want high level abstractions, well, automatic memory management enables a bunch of abstractions that the Rust developers gave up on long ago. There are languages with many more capabilities than the ones Rust gives you.
If you have a high level problem, you don't want to spend your focus on low level issues.
My current job doesn't use Rust at all, but we're experimenting with converting some CLI tools. There should be relatively little library dependence for the things we're targeting.
My conclusion from stories like this and the one in TFA - engineering management is important and hard, especially when you're dealing with smart engineers. You need someone who is technical enough to understand Rust/Scala vs Python, but also has the business sense to know that as cool as it might be, writing a CRUD app in Rust is not moving your business forward.
I can't wait for reactive programming to die.
This is a symptom of resume-driven development.
> writing a CRUD app in Rust is not moving your business forward.
Writing a CRUD app in a systems programming language might be a symptom of management failure.
There is still a steep learning curve, although the learning curve has improved significantly over the past couple years. Rust's type system, syntax, and standard library are major strengths compared to those in most GC-based languages, so I'd argue it can be a great fit for domains where GC-based languages have been used historically.
Suggesting that Rust isn't a good choice for a backend CRUD is... odd. With that said, one of the particular CRUDs described above: We ultimately went with Go. Only because Rust isn't an officially approved language at our shop yet though.
That said, the article is a sample of 1. I'm not aware of other similar experiences
I have, and Python from 10 years ago was a better platform.
Sure, it beats the Javascript ecosystem, but that's too low a bar.
It's the same people than have kept saying there is nothing wrong with writing a backend API server in C++.
Of course you can write a CRUD app in Rust. You can also write it in Brainfuck, such is the magic of Turing-complete languages. Is it a good idea? I'd argue there's languages that are much better suited to writing CRUD systems than either.
We're having a great time with Actix + sqlx. It feels like Go, but with less typing (physical).
With an IDE like Clion + Rust Plugin, the code writes itself. It feels like writing Java or Golang.
Every time someone says "oh no, borrow checker" for *single thread scoped CRUD apps*, I know they're not even writing Rust in this way and that their concerns are hypothetical imaginings. You can't possibly hit the borrow checker in HTTP handlers unless you're very new to the language or doing something incredibly advanced.
I never see the borrow checker for web apps unless I write threaded code that runs on singletons or other shared state - which is an awesome option to have, as it makes async jobs a part of your deployable artifact rather than some 3rd party job system like Sidekiq.
Bonus of using Rust: the person I hired to join me was also able to write a desktop application.
If there is any point to emphasize, it is this one. Writing Rust without a nicely tuned IDE is almost as slow as writing it using pen and paper.
Because abstractions are “zero-cost” in Rust and the type system is expressive, there are generally many more types involved and a lot of converting between them.
The IDE is very helpful in seeing what types are where, navigating to their definition, viewing their documentation, etc
When you're writing a CRUD app the only errors you should have to worry about are logic errors. The above mentioned Rust stack is the only one that I've been able to achieve that experience with in my whole career.
I'm not sure if it's even possible, but I think that if GC were introduced to Rust as an optional part, it would make Rust suitable for CRUD apps.
Like all low-level libraries are written with borrow checker and you can write your code with borrow-checker or GC, your choice. So you'll still get superior performance compared to any other GC languages, because your standard library is incredibly fast. And your code will use GC because your code does not matter from performance PoV. And if some function matters - you use borrow checker in that function, so it's fast.
Also green threads might be a good addition. It seems that modern computing reinvents it all over again. Golang, Java. Async/await is hard, people want to write blocking code and get good scalability at the same time.
We need a silver bullet programming language. Period. Suitable to write CRUD and MCU firmware at the same time. Until this silver bullet is not found, we will reinvent new languages.
Features cost, even optional features. No programming language can or should try to be everything to everyone: to attempt it is to serve no one very well at all, because you split the focus of the language development between too many use cases and you complicate the language so thoroughly that onboarding a new programmer becomes an exercise in re-education about which subsets are acceptable in the given organization.
Rust's niche is safely managing memory without a GC. If Rust adds a GC, even an optional one, it will have lost its soul.
This is the basic win of Go. Go's "goroutines" are preemptable. So there's no need for an async/thread distinction.
Me either, and I've said that before on HN. There is, however, a Rust lobby for CRUD apps. Those are the people who are pushing hard for "async". "Async" has its uses, but you don't really need it unless the load on your server has many thousands of concurrent connections, most of which are waiting. The OP here points out that his load is nowhere near that high. Python or node.js would work. Maybe even PHP.
If you need to write CRUD apps with high performance, use Go. That's what it's for. The libraries for what you need probably not only exist, but are running in production on warehouse-sized server farms.
I've been writing a metaverse client in Rust for two years, and I'm about 35,000 lines of safe Rust in. Separate threads are rendering, processing incoming messages from the network, updating the world state, fetching assets, and moving objects that are in motion, all in parallel. There's a lot of heavy machinery. Rust is good for this sort of highly concurrent problem. There have been no bugs in my code that required a debugger. (An early version of the rendering library I use, which is unsafe, caused trouble requiring using a debugger back in 2020. Took about 20 minutes to find the problem.) Rust is the right tool for the job for this sort of thing. I'd need a sizable team to do this in C++, and far more debugging.
As the original poster points out, and as some game devs have mentioned, the safety issues do slow development. You can paint yourself into a corner, where no easy fix will satisfy the ownership rules. It can take a week of rewriting to get out of that. Sometimes longer. Anything where an object needs a connection to its parent is unwieldy in Rust. You can do it, but soundness requires you do it through forward reference counted pointers and backwards weak pointers.
In the context of web apps you rarely have to deal with the borrow checker and the rest of the Rust code is rather high level.
For me the post is a bit weird, cause on the one hand he mentions a CRUD app and on the other hand he mentions complexity. If your CRUD app is complex it's either not a CRUD app or you screwed up along the way. I've seen dozens of Rails apps where development was painfully slow cause of a "big ball of mud effect": a bunch of "god models" having dependencies across the entire system, crossing all of the boundaries. So it doesn't have to necessarily be only related to Rust.
tl;dr rust is great for writing all kinds of apps and as the labor pool with rust grows so will it's usage in all aspects of computing.
Where do those numbers come from? Rust is not very beginner friendly and takes a while to learn, but nowadays I'm just as fast in it as in other languages, except maybe for Python.
That said I also don't think it makes sense for startups.
For my hobby projects it hasen't felt more cumbersome than e.g C#.
Instruction unclear. App is now made in Haskell.
Progamming languages, hosting platforms and non-standard databases aren't ideal places to spend such tokens.
For most apps what you want is JVM or .NET, PostgreSQL or MySQL or SQL Server, k8s or vanilla VMs/containers.
You almost never want different programming languages to these mature stacks, you might think you do, but you don't. Node.js/Python/Ruby etc all promise a fast start but in reality any perceptible velocity benefit is dead within months, usually before anything of value is shipped. Most of it has to with ecosystems (library quality etc, framework maturity) but those also being the 2 most advanced managed runtimes helps a ton.
For databases just standard RDBMS is almost always the way to go, unless you startup is intrinsically a data startup and you know ahead of time you require very special properties you just want one of these.
Keep hosting simple. Don't use any fangdangled "serverless" nonsense. It's not worth it, shipping a week or 2 later because you took the time to setup EKS/GKE/AKS will pay off in spades. k8s reputation for complexity isn't warranted and it's essentially standard now and will remain that way.
So now you have freed up your innovation tokens you can spend them on solutions to your actual business problems instead of on stuff that will only continue to eat your token budget and often yield negative real returns.
Databases, fully agreed. "Use Postgres unless you have a reason not to." When you need a key-value store for caching or whatever...consider Postgres hstore first, and then spin up a Redis only when you need to.
Hosting...depends. With my product hat on instead of my infra hat, I think there's real value in managed serverless options. The various Heroku descendants--I work at Render, but I'm friends with the Fly folks and they're great too--can, if you are in a low-devops environment, provide some real benefits. Or, for a more stripped-down option, AWS Fargate/GCP Cloud Run, but to bootstrap that you're going to be doing somewhere between the work necessary between a Heroku++ option and "run a server somewhere and keep it patched".
Why would you even bother as an early stage startup? Ship your code on a PaaS like fly.io/Render/Vercel/Heroku/etc until cost/scale is an actual issue. Same for using managed DB solutions. Your time (=money) would be much better spent elsewhere.
As for language, I would optimize for what's easy to hire for.
Generally speaking if it's the platform you have you will shoehorn the shape of your code into a serverless shape bucket even if it has no business looking like that. These architectural shortcomings will inevitably come back to haunt you.
Also most of these platforms amount to cgi-bin v2, meaning things like memory leaks and requests that hang get swept under the rug. Meaning you already have very difficult to diagnose failures and when you do eventually go to migrate you will find your code is full of these smells making it harder to reform into something reasonable.
That is also putting aside the spaghetti nature of intertwined functions of any serverless codebase of scale, the huge IaC overhead if you go with something like AWS Lambda and the massive amount of incidental complexity that serverless advocates try to make you look the other way for (hello API Gateway).
Expressive GC languages within the major ecosystems exist, no need to reach for a systems language for a web app just because you want the modern, high level features.
Yeah, that's not the kind of thing you use low level stuff for. Ruby on Rails or Node or Elixir, or whatever Java thing is going to let you iterate faster than a lower level language.
But if the choice is between Elixir and Rust for that same CRUD app, it doesn’t seem strange; Elixir would be a far better choice.
I would presume the commenter is more familiar with ecosystems like Elixir, even though it wouldn’t be the most optimal choice. But certainly more optimal than Rust in that case.
Creating a CRUD module, with schema, migration, controller, view, template and data validation is literally one command away with `mix phx.gen.html/phx.gen.json`
If you haven’t tried it, I 100% recommend.
With C++, lifetime and ownership are just about as important but unfortunately no one's got your back. You can ignore lifetimes and ownership but you do so at your own peril. And the compiler won't tell you you're doing it wrong because the language wasn't designed for it to do so.
If you want a taste of rust's "mindset" (with respect to limitations imposed by some types) without jumping ship to a new language, try C++'s Guidelines Support Library [1]. It introduces some of the same benefits/friction as switching to rust but without a new language. Opting-in to some of these guidelines might be a gentler way to get some of the benefits of Rust. But it comes with a similarly higher bar.
When I first heard about Rust I really thought it would be the language to end all languages, but even after just a few days using it I realized that's not the case. Maybe someday someone will come up with that perfect language for everything, but given recent progress in AI I think the more likely long term outcome is that neural nets will start writing all our code for us. I wouldn't start work on a new programming language today given the changes that are clearly coming in the next 20 years or so. At least, not one designed for humans. Maybe there's an opportunity for someone to make the first programming language designed for neural nets to use.
Maybe that neural net language would look like Rust. The downside of lower programmer productivity may not matter when the programmer is a neural net. You can just run more neural nets! And neural nets are anything but perfect so they will still benefit from the safety guarantees Rust provides. Rust is the language that I don't want to write, but I want the software I use to be written in it.
The main problem i encountered (beyond the usual learning curve for stdlib and other common libraries) is all the gotchas and rough edges around async
Hmm... in some ways. I feel like one probably shouldn't be using C++ for anything network facing or security critical, whereas Rust is ideal for those situations.
The web frameworks are still immature, and rapidly changing.
I still use Rust for CLI, lambdas, and/or backend web services.
Ruby on Rails tickles the cheap and easy CRUD + RAD paradigm pretty well. I don't see Rust doing that anytime soon.
However rust string handling is barely a step above c’s, there are a variety of datastructures c engineers dislike simply because of the memory management constraints. Getting 2x better performance than Java is a marginal gain for many environments.
I really hope rust takes a bent towards ease of use. Stabilizing a rust gc arena would be hugely impactful, or simply revisiting the string api.
> However rust string handling is barely a step above c’s
How so? Personally I've found it very good.
For beginners, it’s impossible to write a common program for doing some basic string manipulation without reading 3/4 of the Rust book and waiting through dozens of compilation failures.
I have used Rust at a startup, and it worked out extremely well. But we used it for CLI tools (where it shines), and performance critical code, and for specialized, high performance servers.
Very unsurprising. Rust is a bad choice to use when building a typical CRUD app especially when you are not making any money. So when I saw this about immature libraries:
> Rust, by comparison, has long felt like a work in progress. The docs for a lot of popular libraries are pretty sparse, and one often needs to read the source code of a given library to understand how to use it. This is bad.
I just couldn't help but say that someone has finally cut through the hype, and experienced the reality of the immature state of the library ecosystem in Rust rather than pretending that it is fine; especially for a startup which can result in the failure of feature delivery and of itself.
This cargo culting of programming languages promised by a fan club or hype squad of any new language needs to stop.
Maybe an oversight, C++ is misplaced in that list. C++ without knowing about ownership and lifetimes is a recipe for disaster.
There's so much code in Go that is documented like "while this object takes a file handle, it does not close it itself even though there is a close function, you will need to close it" that in Rust is just a lifetime annotation.
As a result, expect some churn in your codebase. Your team will have to discover and iterate upon best practices. Avoid the impulse to spend too much time code golf refactoring because “oh I can use a proc macro to decrease boilerplate while avoiding the orphan rule and having nice traits!” Rust can definitely nerd snipe you by making you worry about some very small edge case like oh no I’m copying a few too many times.
Basically unless you’re pretty damn sure you have product market fit (PMF) and you’re sure that rust offers an appreciable benefit to said PMF, I would not use it.
This, to me, is a bizarro opinion. Compared to c++, rustc's error messages are (by and large) incredibly helpful and clear, oftentimes showing how the code should have been written.
The classic silver-bullet story, same old, same old.
dang - scribe.rip is an alternative front end to medium.com. That's why this wasn't caught by the dupe detection.
Selecting more than one language sometimes works, in my experience you can have various microservices that talk to each other, then it doesn't matter what language each is implemented in.
However, it isn't optimal to have to master more than one language (most good people do, but we also want to cater to weaker team members; in football, not everyone is a Ronaldo, Pele or Messi either). I don't see why C++ or Rust shouldn't have opt-in garbage collection offered for parts of the codebase where this makes sense (where productivity is worth more than runtime speed), which is probably most part of most projects if we are honest.
As some of you know Rust actually _had_ GC in an earlier version, and some readers may complain saying "but C++ can do GC if you want" (of course you can add a Boehm-style GC in your project). But what I'm referring to is that there should be a "batteries included" GC-enabled part of systems programming languages by default (as a technical and cultural preferred setting), unless you mark up a library/crate/class as performance-relevant. This could be done with a mechanism similar to marking up "unsafe", e.g. "uncritical" (= runtime matters less in this section compared to productivity). Then strings and other objects could be garbage-collected and programmers could focus on solving the actual problem instead of managing memory. Critical sections could be marked as such, and there'd be the much-coveted "zero overhead" abstractions for these. The advantage is you would not need to stay up to date in two languages, and you could avoid FFI-type integration, which tends to be brittle (JNI? shudder!).
An entirely separate point is the availability of programmers that master a language. I totally agree with the poster that you should use a mainstream language to avoid being hit by a talent shortage.
Go lang is suggested rather than Rust, but the standard way of using Go is lower-level and less productive (unless you care about performance) than the Rails of 10 years ago (and I am not a fan of Rails).
Haskell can be a great option here- all the high level benefits of Rust and more in a language with a GC and plenty of good frameworks and libraries for CRUD. Unfortunately its one of the only languages that has a greater learning curve than Rust.
If you are starting a new project, ask yourself:
1. Would I be writing this in C++? Then Rust is a great alternative.
2. Would I be using C? Then may be Rust or Zig would make a good alternatives
3. Would I be writing it in Ruby or Python? Then Go or Elixir can be considered
Then they are bad engineers and should be fired. Maybe it's just my general rage at so-called developers being incapable of understanding undergraduate level recursive functions, but the quality of developer is on the floor in my opinion.
If you are a software engineer and not a code monkey in a web shop, you should have no problem at least trying to expand your knowledge. I worked with people who're afraid of changing a line in k8s manifest file even after you tell them what and where.
There are some languages that look alien to the typical engineer and hard to understand without at least a minor prior knowledge, but Rust isn't one of them.
Also GC doesn't remove all resource management... ironically I find most GC-based languages to be more mentally taxing when managing manual resources (file handles, mutex locks, etc).
> Rust, though, one needs to learn entirely new ideas — things like lifetimes, ownership, and the borrow checker. These are not familiar concepts to most people working in other common languages, and there is a pretty steep learning curve, even for experienced programmers.
Rust's borrow checker system doesn't exist in isolation. It's designed to avoid problems that can occur with computing and memory model of programming - things like call stack frames (esp constant size), heap memory and other resource management, concurrency paradigms, etc. These are just the tip of low level computing models. There are things like cache coherence that Rust doesn't address directly. These are concepts that programmers must know if they want to do: a) Low level programming b) High performance programming. The problem raised by author may partially belong to the second category. Even if it is not, programmers should probably learn these, because they are likely to face such problems at some point and may gain from that knowledge.
There are two ways to learn the borrow checker rules. The first is to start with the rules itself. It's going to appear rather convoluted. The other approach is to understand the machine/memory model that I mentioned above first. Once you do, the rules are going to make much more sense - especially in the context of specific error messages during coding. These days, I'm able to connect every single error message that I see to some potential memory or concurrency problem, even though they are the result of some seemingly convoluted but simple borrow checker rule.
> Despite being some of the smartest and most experienced developers I had worked with, many people on the team (myself included) struggled to understand the canonical ways to do certain things in Rust, how to grok the often arcane error messages from the compiler, or how to understand how key libraries worked (more on this below).
There were dozens of errors that I made today that were easily understood just by a glance at Rust's error messages. The help messages that accompany these error messages are often the solution that I needed. Even otherwise, the error messages point out potential low-level bugs as I mentioned above - allowing me to make proper corrections. This may just be anecdotal. What is not anecdotal is that the Rust team reworked the error messaging early in the project's life to make it that way. It's generally accepted that Rust's error messaging is top-notch. I find it disrespectful to all those early endeavors to call it arcane. Perhaps it's a good idea to try to learn those error messages. There is an entire index of errors with detailed explanations [1].
> We started having weekly “learn Rust” sessions for the team to help share knowledge and expertise. This was all a significant drain on the team’s productivity and morale as everyone felt the slow rate of development.
Perhaps this is the wrong way to approach the problem. The thing that may need learning is type theory. Type theory is often too esoteric with a theoretical mathematical approach. Perhaps we need an introduction to it that encourages people to see a bunch of bits as a storage for data with a particular meaning (the type). Next step would be to how to track types using software (type system) and then extend the idea all the way to include constant-size stack frames, generics, polymorphism and lifetime tracking.
> Libraries and documentation are immature
Library ecosystem is still growing - especially async programming. But documentation support is a first-class feature of Rust's language ecosystem. I find myself writing documentation much more often in Rust than with other languages. It's also equally easy to browse the documentation of the language, stdlib and other libraries. Sections are marked out clearly and navigation is well thought-out. Every search of a feature or API takes me through half a dozen links to the final target in a matter of minutes, if not less. It's a good investment to learn browsing technique for documentation in any language.
> Rust makes roughing out new features very hard
Somehow, my experience doesn't match here either. I use the same technique for trying out new features in both Python and Rust. Create a scratch project for each experiment. A single project may take up to a dozen such scratch projects. It's marginally easier in Rust than in Python, mainly because project management is another first-class feature of Rust tooling.
But what's really remarkable about Rust compared to most other languages I've encountered is that Rust's discipline gently nudges the scratch project to a proper design. By the end of the scratch project, the experimental code is often in a good enough state to be directly integrated into the main project. It's amazingly friction-less to integrate integrate external code into the main project.
I wouldn't blame the author for having a very different experience as mine. But I sure would like to know what makes Rust 'click' for some, but remain a tough nut to crack for others.