Hacker News new | ask | show | jobs
by cardanome 1301 days ago
Rust has brought so many great ideas into the programming mainstream. It is a shame that it has also attracted such a community around it that seems to project all sorts of hopes and wishes into the language.

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.

15 comments

I'm not sure that it's that cut and dry. Rust provides good tools for building high level abstractions and the developer tooling is comparable to something like typescript. Depending on the team, rust can be a perfectly reasonable choice for a CRUD application.

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.

Doesn’t Kotlin or Swift offer those things?

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.

Kotlin is probably also a good choice (but it ties you do the JVM, which does come with some operational headaches of it's own). Swift would be a fantastic language for this kind of work, but unfortunately it's library ecosystem isn't on nearly the same level as Rust's for backend web.
Rust is an interesting mix. OCaml gets pretty close and type inference offers better ergonomics. The fearless concurrency story is still much better in Rust than OCaml.
Yes, it's a completely clear cut.

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.

> automatic memory management enables a bunch of abstractions that the Rust developers gave up on long ago.

These claims should really come with sourcing. Rust devs have been raising the potential for abstraction in Rust since the initial 1.0 release, most recently with GAT's. What's always been quite hard is zero overhead abstraction, which GC languages simply have no equivalent for.

Sourcing for my "water is wet" claim? Just try writing a language parser in Rust and Haskell and you'll see the difference. Or, to be more on topic, write some database to HTML on Rust and note how you have to keep track of your templates' lifetimes.

The Rust developers are a bunch of very smart people working hard on creating a great language, but they can't do impossible things.

I have written HTML templates and never had to keep track of lifetimes. Do you have an example of how that happens?
Batch jobs seem like a good candidate for C++ because of how much faster a single instance will be. Multiplied across the size of the total job, that can represent enormous savings. On the other hand, using Rust for a web server with low QPS and atop a relatively novel web stack seems unnecessarily risky. The article does comment on Actix being a pain point.

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.

I worked at a company where a principal developer got tasked with building a CRUD app. He worked in a silo on it, coming back in 3 months with a CRUD app... written in Scala with heavy use of scalaz. It was a CRUD app that was scalaz features to defer the entire execution until runtime. Nobody could understand the code at all. The team ended up replacing the entire functionality in less than a week using Python+Flask.

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 worked with the same guy who made a CLI tool in Java + RxJava. Running everything reactively on hundreds of thread schedulers for something that needed basic collection of arguments and to post to an api.

I can't wait for reactive programming to die.

> He worked in a silo on it, coming back in 3 months with a CRUD app...The team ended up replacing the entire functionality in less than a week using Python+Flask.

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.

That’s just a noob dev.
Anecdotally I've been able to move faster with Rust on CRUD apps professionally than I've previously in other languages with GC built-in (e.g., C#, TypeScript/Node.js). The borrow checker isn't a problem after you get used to it.

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.

Rust has healthy friction and you learn how to avoid that friction. It might take you a bit longer to hash something out but chances are it will work first time, and will have better fundamentals in design.
I have a different experience with Rust these days. The errors that Rust throws are either the ones I had a vague hunch about or the ones I missed. It never feels like friction, but rather like helping guides. The error messages are informative and often very helpful in resolving problems.

The key, I believe is understanding the machine and memory model of low level computing. Rust errors immediately make sense in that context and it becomes easier to find a proper solution without having to work around it.

These days I feel much more comfortable with Rust than I'm with even Python. It feels like Rust does a lot of heavy lifting and thorough checking of a lot of semantics that's not possible in other languages. The worries about unforseen bugs are lesser (not zero, though) with Rust.

Edit: Phrasing

> It never feels like friction, but rather like helping guides.

That is exactly what I mean by "healthy friction." Friction can be used to guide users towards better habits. The fact that you encounter friction less often is evidence of having learned from friction in the past.

Have any of you actually written a CRUD app in Rust? I've written a couple that I also wrote in Node and Go. Using Tokio+Actix. It was a breeze, the LoC were actually similar to Node, and the built in observability was great.

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.

I think it comes down to how big/experienced the team is, how old the product is, and how many unfortunate decisions where made in the history of the project that are there to stay. To me the point of the article is that rust would not be a robust choice considering all these factors.

That said, the article is a sample of 1. I'm not aware of other similar experiences

> Have any of you actually written a CRUD app in Rust?

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.

crates.io’s backend is in Rust.
> I don't get how someone could think making a CRUD app in Rust could ever be a good idea

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.

> I don't get how someone could think making a CRUD app in Rust could ever be a good idea (beyond hobby projects).

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.

> With an IDE like Clion + Rust Plugin, the code writes itself.

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

My 2c: Rust + Actix + Diesel + Tera is the ultimate CRUD app stack, especially now that there is the excellent zero2prod[1] book to refer to for people who have not built a significant CRUD app before.

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.

[1]: https://www.zero2prod.com

IMO if you would forget about borrow checker, Rust is awesome language by itself.

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.

This is the kind of attitude that will send Rust the way of C++.

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.

Not only that, but the borrow checker also handles safety concerns. Rust's concurrency safety story ("fearless concurrency") is literally built on the back of ownership and borrowing.
Oh, wow, yes. I confess I skimmed the part about green threads.

I think OP doesn't understand that runtime features like GC and green threads have a cost, and Rust is designed around a making it safe to avoid that cost. Most of Rust's features don't make sense in the context of a managed runtime—what you would be left with is basically a subset of OCaml with C-style syntax and optional mutability.

> Most of Rust's features don't make sense in the context of a managed runtime

I don’t think that’s entirely true actually (which is why linearity is explored in languages like haskell).

For instance Go makes it easier to trigger data races, which undermine memory safety. This is a managed langage “built for concurrency” where using concurrency means memory safety is at risk.

And that’s not recent news, Russ Cox himself wrote about it back in 2010: https://research.swtch.com/gorace

True, but linearity/affine types applied carefully in the context of a managed runtime would look quite different from Rust's borrow checker. The reason why Rust's borrow checker is so infamous is because Rust has to prove everything at compile time. Bringing affine types to a GC language would most likely involve making them opt-in (or only triggered in concurrent situations), while making linearity optional in Rust would undermine its foundations.
Green threads have been totally superseded by current async support in Rust. That's why they're no longer part of the language itself.
Technically green threads were removed when rust was moved “down the stack” back before 1.0: green threads would mean requiring a runtime (scheduler & al) which is problematic when targeting foundational libraries and embedded programming, it makes integrating with other systems a lot harder.

Async being opt-in means the people who don’t need it can avoid it, though it’s not always great when e.g. the premier HTTP client of the ecosystem provides a “blocking” interface which iirc just starts a runtime and delegates to the async interface.

Ironically very early prerelease versions of Rust had a GC (and also Go-style fibers).

I think, however, a lot of people would love to see other GC languages take up the safety promises that Rust provides (especially concurrency).

A framework for "pluggable" and optional GC could be very helpful for dealing with the rare case of general graph-like data, where there really is no feasible alternative in terms of more explicit memory management. This will probably be done as a natural outcome of stable support for "local" allocators, which is already planned in Rust itself.
I feel like writing code that satisfies the borrow checker isn't that hard if you intuitively understand the lifetimes of the things you're dealing with. In C++ you have to do this anyway, so having the compiler help actually decreases the cognitive burden. I feel like desiring garbage collection is mostly a code smell, because it indicates that lifetimes and ownership are not obvious. Sometimes that'll legitimately be the case due to shared ownership, but there are facilities in both Rust and C++ for that.
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.

This is the basic win of Go. Go's "goroutines" are preemptable. So there's no need for an async/thread distinction.

> I don't get how someone could think making a CRUD app in Rust could ever be a good idea (beyond hobby projects).

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.

I've written web backends in Rust and it's fine for backend apps, especially APIs. For HTML rendering it's a bit lacking at the moment as it doesn't have the whole ecosystem that Rails for example has, but for APIs I haven't found a lot of missing stuff. I'd say for a Rust dev with some experience it's similar to Go, although more pleasant in my personal view.

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.

Rust is perfectly fine to write CRUD apps and the productivity between it and golang is identical. The only issue I would have with growing a rust app in 2022 is the pool of talent to hire from for it. I find the comments about using rust for different projects generally align with what people were saying 10 years ago about golang and with the rise of people being comfortable in golang it's now used in a massive array of projects beyond what outsiders were trying to peg the language to.

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.

If you want to use a hot new language, Nim seems like a safer default choice.
I am struggling to find any benefit of Rust for startups to be honest. It makes no economical sense to be bogged down by a language that is 3-10x slower to develop. The issues Rust is preventing will pop up earliest in production, likely rarely and at that point in time the company could be profitable, its product somewhat stabilized and actually have a case of using Rust for an internal rewrite.
> 3-10x slower to develop

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.

I'm only a Rust noob, and have importantly only used it for my own hobby projects. But can't you get a lot of the ergonomics from memory managed languages by using "managed" container structures like ARC and being slightly sloppy with your allocations?

For my hobby projects it hasen't felt more cumbersome than e.g C#.

Arc is not a convenience, since the type matters, the type is visible most places, almost no trait impls transparently work the same on T and Arc T and so on. For all its strengths, it must be said that it's not a language of transparent convenience, not when it comes to this central issue of ownership and sharing.
> If you CAN use a language with automatic garbage collection for your project, do that. Always.

Instruction unclear. App is now made in Haskell.

To be fair, https://ihp.digitallyinduced.com/ looks really tempting.