If you're thinking about building something in Rust, a good question to ask is, "what would I use if Rust didn't exist?"
If your answer is something like Go or Node.js, then Rust is probably not the right choice.
If your answer is C or C++ or something similar, then Rust is very likely the right choice.
Obv, there are always exceptions here, but this helps you work through things a bit more objectively. Rust can be a fantastic language for many purposes, but it has a very high development cost.
> If your answer is something like Go or Node.js, then Rust is probably not the right choice. If your answer is C or C++ or something similar, then Rust is very likely the right choice.
I've been saying that for a while. If you're building web backends, Rust is not a good choice. Go is so much easier. The green thread system gets rid of the thread/async distinction, garbage collection means you don't have to obsess over memory management, and the libraries for web backend stuff are the same things Google uses internally, so they're well-tested.
A big problem with Rust, long-term, is that the kind of programs that really need it are somewhat out of today's mainstream. It's not that useful for webcrap. It's not that useful for phone apps. The AI people use Jupyter notebooks and Python to drive code on GPUs.
Where do you really need Rust? Heavy-duty multi-threaded programming. Operating systems. Compilers. Routers and network infrastructure. Robotics, maybe. Hard real time. It ought to be used more for high-performance games, but the game infrastructure isn't there yet. Unreal Engine is C++ and Unity is C#. Rust has Bevy and Rend3, but they're not AAA title ready.
Perhaps Rust is fighting the last war - the mess inside C++.
> A big problem with Rust, long-term, is that the kind of programs that really need it are somewhat out of today's mainstream. It's not that useful for webcrap. It's not that useful for phone apps. The AI people use Jupyter notebooks and Python to drive code on GPUs.
One thing this is missing is that Rust is useful for libraries callable by many different languages. You may or may not want to use it to build an actual Web app (I personally think it's a solid choice, but reasonable people can disagree). But for building, say, the Python cryptography library [1], which is used as a part of "webcrap", Jupyter notebooks, and in many other domains, Rust is clearly an excellent option. Nobody is going to build core Python infrastructure in Go or Node, and without the plumbing libraries none of the higher-level applications can function.
Except that is the exact reason why I would pick C++ instead of Rust, the Java, .NET and JS ecosystems are written on top of C++, and the libraries I might want to write bindings for, are also written in C++.
Adding another language in the middle will only complicate our toolchain.
Regarding Python, with the pressure from Ruby, PHP, JS and Julia JIT compilers, they will eventually get more serious about JIT adoption, and then there is ctypes of OS APIs.
You mean to link against Rust binaries or can you make library files too? Compared to, say, SQLite as a single C file, I thought that Rust projects are not super easy to use as a dependency
Rust can output library files that use the C calling convention, either static or dynamic. Doing this entirely by hand is pretty annoying, because your API surface has to be C-compatible (so can't contain a lot of Rust's useful language features) and because you still have to do the other half of the FFI to use the library from the other language. However, it's possible to develop automated language-specific tooling to make this easier, with PyO3 being a particularly impressive example.
Depends on how you link rust, using PyO3 makes it arguably easier to do link python code to rust than any C construction I could think off.
Linking a single C file into python is quite difficult (if not using JIT like cppyy) because you need to make bindings & conversion often on both sides for each exported function.
> If you're building web backends, Rust is not a good choice
This heuristic wouldn't work for my department because we build web backends in C++. I keep telling the most senior devs here that nobody does this and for good reasons (velocity etc), and their response is "who cares what the rest of the world does, they're just bad at C++."
Another (maybe even more) important motivation was to have simple, statically-typed language so that new hires can contribute to the codebase faster and the code itself is more standardized and easier to maintain at large scale.
They basically got there with Java + some frameworks. It's not the best (I'd like NodeJS), but it works and has a huge ecosystem already, and anyone can use it. Some people complain that Golang is designed specifically for its original use case of specialized web backends and isn't great otherwise, or that its main design goal was being "not C++."
A few people at Google did, as far as I'm aware it didn't start as some officially sanctioned project at the company. golang has its own sets of challenges due to the limitations of the language and its error prone bare bones threading model.
These aren't high-volume, they're just web interfaces used internally by hundreds of people. Golang wasn't well-received either in our dept. Java would've saved us a lot of headache, a phrase I never thought I'd say; adjacent teams use it for similar things.
You're right. I think that it replaces C/C++ for many use cases. I'm a quant, and I use it to write fast algos for research. It won't be long until Rust has good high level SIMD primitives like the faster crate offered. I can't see myself using anything else thereafter for performant code.
You may be underestimating the amount of need there is for performant code though. Its everywhere.
>I've been saying that for a while. If you're building web backends, Rust is not a good choice. Go is so much easier. The green thread system gets rid of the thread/async distinction, garbage collection means you don't have to obsess over memory management, and the libraries for web backend stuff are the same things Google uses internally, so they're well-tested.
The thing here is that most web backends are basic CRUD bullshit, and you fundamentally will not hit the thread/async distinction, nor need to care about whether there's garbage collection or not. Microsoft has used actix-web in production as far as I know, it's not like the Rust web stack isn't battle tested.
>Where do you really need Rust? Heavy-duty multi-threaded programming. Operating systems. Compilers. Routers and network infrastructure. Robotics, maybe. Hard real time.
These are all the things that sit adjacent to a web framework, and once you step outside that CRUD happy path, Rust fits very well - and in this case just "bolts on".
>It's not that useful for phone apps.
This is more tangential but I know of more than a few companies who have written or are writing their cross-platform logic in Rust instead of C++. This is really akin to how some projects back Python modules with Rust: it's easy to have it backing things and it beats the hell out of dealing with C++.
And look, I'm not even saying don't use Go/Python/JS/<insert your preferred language here>. You do you, your startup will live or die by so many other things than choice of programming language.
They are out of the mainstream, but only because "systems people who have exchanged any hope of losing their virginity for the exciting opportunity to think about hex numbers and their relationships with the operating system, the hardware, and ancient blood rituals that Bjarne Stroustrup performed at Stonehenge" "SOLVE THE BEAR MENACE" [0].
There is probably a good space for Rust in writing the databases, caches and all sorts of proxies as well. I agree though, for most of the stuff I need for $DAYJOB the speed is nice but hardly required. It doesn't really matter if I can generate a HTTP response 50 microseconds quicker if the response then has to travel over the internet for 20+ milliseconds.
It does matter if you're using cloud autoscaling FaaS (previously known as CGI) and paying for those HTTP responses by the microsecond (and by RAM usage as well, which is also typically quite low in Rust).
Not really, the connection won't close until you are done sending it all and have received the relevant TCP ACK messages from the other sides. Being on autoscaling FAAS or not does not matter for that.
In any case, if you are trying to optimize microsecond usage in AWS lambda I hope you have a truly gargantuan amount of traffic and/or have incredibly cheap engineers or the money saved will barely match up to the cost of the engineering hours sunk into them.
I appreciate that there might be use cases where performance absolutely does matter, and log parsing is indeed one of the sweet spots for that. But offline analytics is something quite different than HTTP request generation, even if you sometimes do both in an AWS lambda.
Additionally for the case mentioned, the log parsing apparently already fit quite comfortably in the free tier of AWS lambda. Rubygems.org seems to get its developer time for free, so Andre can keep tuning this log parser as a hobby experiment (in the best sense of the word, nothing wrong with having fun). But TFA was about building a startup and most of those definitely don't manage to get their devs to work for free.
Rust has been around for so long these domains should have long since been covered. Quite telling they aren’t yet, particularly considering the momentum in publicity. I wonder why.
I’ve been writing data ETL pipelines in Rust and having a fantastic time.
Most of my data, cost and performance requirements aren’t suited to the likes of FiveTran/etc, and whilst I could theoretically use Python, it’s far too slow, and the propensity to crash unexpectedly (meaning I have to spend extra time debugging) means the development velocity is actually worse than just writing it in Rust. Plus, most of the libs and tooling I’d use from Python are available in Rust.
I’ve also written Rest and GRPC API’s in Rust (mostly for serving up data and being a query layer), and found it a far more pleasant experience than Python/Typescript/C#. Admittedly a somewhat ”smaller” use-case than a lot of what people would consider web-API’s but still.
How much of your ETL is rust vs SQL? I agree pandas for ETL isn’t the fastest but why not isn’t SQL faster still? Or don’t you find yourself in the situation where there is so little logic in the ETL that rust performance/safety isn’t that useful?
If you’re building a large complex app that needs to be shared across multiple platforms, C++ is a common choice. Not talking about games here, think Office, Facebook, Zoom, WebEx etc. It easy to see Rust replacing C++ in that stack.
But as Rust is so much nicer that C++, I could see it becoming popular for smaller projects that want to share common logic, with a native UI on top.
I think it's dismissive and overly simplistic to say that Rust is almost always a better option than C or C++. They're different languages with different strengths.
One strength of C++ is that it is far more established than rust - and that comes with a lot of advantages:
* It has a larger number of people who know how to work with it
* It has a huge catalog of established, fully functional libraries for everything you could imagine from UI to game development to embedded systems to simulation to anything else
* It has broad support in developer toolsets in general like editors and IDEs, static analysis tools, formatters, pre-commit hooks, etc
If I'm starting a new project with C++, I can immediately know that there's a huge landscape of programming already carved up and ready to work with. I can't do that as easily in Rust. The language, the libraries, the tools are all younger. Some of it isn't as fully featured, some of it isn't nearly as stable.
That will improve with time, but it's a huge advantage to C++ right now.
That's not the argument the GP is making. The GP is basically saying that if C/C++ aren't your second choice of language, then it's a sign your reasons for picking Rust are suspect.
They didn't say Rust is almost always better than C/C++.
There's perhaps the implication there, but it's certainly not explicit in the GP's comments.
> One strength of C++ is that it is far more established than Rust - and that comes with a lot of advantages:
I'm painfully aware of this. Typical Rust problem, from a reply I made to a posting on Reddit:
* WebGPU dev: WGPU updated to 0.15!
* Me: Might want to hold off on upgrading for a bit. See (bug report on related package)
* WebGPU dev: Good to know. I'll keep this in mind if someone has any issues when following my tutorial
* Me: I'm using Egui/rend3/wgpu/winit/vulkan cross platform on Linux and Windows, with cross-compiling. Getting all those crates to play well together is not easy. Every time something in that stack changes, it's days or weeks of trouble.
> That will improve with time, but it's a huge advantage to C++ right now.
Sadly, it's not really an advantage anywhere that hasn't already eaten the grief and doesn't already use C++.
Both C and C++ infrastructure are so horribly terrible that Zig is gaining traction simply by creating a better compiling infastructure totally indepdent of whether the language is better or not.
I love Rust but I am still looking for the perfect blend of the two camps.
One the one hand, Go/Node/Python/etc doesn't scratch my itch for the strong type system (sum types/tagged enums mostly) and on the other hand even though I like prototyping in Rust I really miss things like a REPL, more terse syntax, and a bit more expressiveness.
I think OCaml is closer to my ideal but the ecosystem isn't quite there. Maybe all it needs is time.
Pick a problem, not a tool first. Unless you're more interested in the tool than the problem, then it's fine. I don't love Rust, but I can get by. TS+NodeJS is okay. But I'm more interested in the problems that I'm solving so I just use whatever is the most suited.
I do that today, but I believe there is still a lot of opportunity for languages to approach my ideal, and I think I share my ideal with others. And if a language like that did exist, or could be made, I'd love to use it - changing languages every project is workable, but you'd probably agree (I hope?) that NOT changing languages every project would be even better.
Yes. I cringe a little getting emails from startup recruiters saying "join a Rust startup." As if the success of their business hinges on using Rust for something that probably doesn't need it.
I've found that the basic NodeJS or Python works for most problems I've chosen. Not even with strong typing.
its older than rust. its had plenty of time. what ocaml needs is a renaissance and new blood. sadly it doesn't have the momentum of being new but I agree its a compelling language. I see it as a better, typed alternative to go.
Have you looked at Node + TypeScript? I'm just starting to dig into TS, but its type system is one of the better ones I've seen. And Node is nice and mature with good async capabilities.
I've never really had a problem with it, but I isolate such resources behind a wrapper, which makes cleanup easy. I just create a little higher-order function:
> this drives me absolutely insane (console.log(["10", "10", "10"].map(parseInt) outputs [10, NaN, 2])
That's not really an issue with the type system, that's just coincidence and bad luck.
The signature of parseInt is:
parseInt(string: string, radix?: number | undefined): number
And Array<string>.map(fn) takes a function with the signature:
fn(element: string, index?: number | undefined, array?: string[] | undefined): any
So parseInt coincidentally matches the signature Array<string>.map() is looking for.
I'm not sure what you expect the type system to do here. It works just fine at catching an actual type error, such as this:
console.log([10, 10, 10].map(parseInt)
...which correctly complains:
Argument of type '(string: string, radix?: number | undefined) => number' is not assignable to parameter of type '(value: number, index: number, array: number[]) => number'.
Types of parameters 'string' and 'value' are incompatible.
Type 'number' is not assignable to type 'string'.
(As I'm sure you know, this is the correct code: `console.log(["10", "10", "10"].map(s => parseInt(s))` .)
Map’s second and third parameters are optional. Your functions aren’t required to implement them, which is good, because most of the time you don’t need them.
Again, this isn’t a type system issue. It’s both an API design issue and a poor programming hygiene issue. (Don’t pass bare functions if you don’t know what the parameters are.)
I mean, map always passes them in, so in that sense they aren't optional. Mixing that with functions that take in optional parameters, but aren't usually called with them, gives you a ticking time bomb, IMO. And double that danger when the language's type system allows you to call a function with more parameters than it could ever take.
> Don’t pass bare functions if you don’t know what the parameters are.
This is exactly the kind of thing I want my programming language's type system to catch for me, if I'm working in a language with a static type system like TS.
And even in dynamic languages, this is exactly the kind of thing I want my programming language to catch for me at runtime. Python does, for example.
Stuff like this - while it might fit JS and TS and make sense to some - makes absolutely no sense to me, and is why I simply look to other languages to fit my needs.
How would you change the Type System to fix this particular issue?
>> Don’t pass bare functions if you don’t know what the parameters are.
> This is exactly the kind of thing I want my programming language's type system to catch for me, if I'm working in a language with a static type system like TS.
Hows your compiler supposed to know you don't know what the parameters are?
> How would you change the Type System to fix this particular issue?
In TS you really can't (that's my point and why I prefer to avoid the language) because of JS and API baggage. But just about every other static language that I've worked in can complain for this kind of thing.
> Hows your compiler supposed to know you don't know what the parameters are?
Why does the compiler care about what I know? The compiler itself knows what the function's parameters are and it can tell me that something seems wrong because I'm asking it to call a function that maxes out at 2 parameters with 3 parameters.
TS does catch this kind of thing in a lot of places. It just intentionally decides not to do it for these kinds of callbacks because of the same JS and API baggage.
> But I'm not sure anything will help with the type system. For example, this drives me absolutely insane: https://www.typescriptlang.org/play#code/MYewdgziA2CmB00QHMA...
You just gave me CPTSD, thank you. This motivated me enough so that I will leave JavaScript and TypeScript for good now.
Scala is on my list of languages to try. I'm usually not a fan of large runtimes or too many abstractions from the OS, but I do want to give it a fair shake. F# too.
On the contrary. I’ve been recently writing a web service in Go… and omg what a terrible experience. Sure, I could prototype something very quickly, but now it’s almost impossible to refactor any of it without introducing subtle breakage. And it’s sooooo verbose and redundant and fragile.
I’m currently rewriting what I wrote in Rust to see how the prototypes compare and… I just feel so much at peace knowing that the type system and the borrow checker have my back and that I won’t encounter unexpected nil pointers or zero values. And I write this quickly as well.
(Yes, I do have experience with both languages, so none of these exercises were new to me. But I’ve been favoring Rust over the last couple of years.)
Quite the opposite here. Go is very easy to refactor if need be. What kind “breakages” are you talking about? Go being “verbose”? Or “fragile”? I doubt we’re talking about the same Go.
In Go you have a garbage collector, no need for the borrow checker or reference counting on your side. What unexpected nil pointers or zeros? It’s all easy and straightforward in Go. If you’re referring to the handling of materialized interfaces, which one may encounter in form of concrete error types, and which is one of Go’s idiosyncrasies, then it might help to look deeper into learning how to handle Go’s interfaces.
> Go being “verbose”? Or “fragile”? I doubt we’re talking about the same Go.
Maybe compared to C, Go is quite concise, but Go is nowhere near Rust's level of expressiveness, especially with poor generics support, much more verbose error handling etc.
> no need for the borrow checker or reference counting on your side.
I think that people that mention borrow checker in context of backend dev haven't done much backend dev in Rust. The nature of a web backend is to (most of the time) get data from the client, process, return a response. In this context you very rarely have to think about borrow checker and almost never use explicit lifetimes.
> What unexpected nil pointers or zeros? It’s all easy and straightforward in Go
If you forget to initialize a struct, you may end up with a nil pointer and you might not catch it until runtime.
NodeJS kind of muddies the waters. It ate a lot of use cases that would have previously been done in Java. That created conflict between backend teams that wanted statically typed code and a "boring" tech choice against "full stack" developers creating a backend service.
I think Rust will see a lot of adoption in web services that are glorified CRUD APIs. It would have been a poor choice to do many of these workloads in this in C or C++ (despite the data point of Amazon 1.0 LOLz).
I've really tried to give js/ts in backend a go. Both by nodejs and deno. And by kickstarting my own projects as well as diving into experienced nodejs developers' code.
I really don't see how anyone choses nodejs/deno to anything.
Java imo gives you much less trouble, is more stable, has a working (!!!) Unit testing setup and exceptional runtime.
Next on my list is to give rust a go, since I'm intrigued by its features, but if I was to go fast I'd go with java any day.
"I really don't see how anyone choses nodejs/deno to anything."
This is going to sound mean but I don't really know how to phrase it more nicely. People building backends in js/ts are doing so because either they, or a critical mass of the people they expect to code in it, don't know any better backend languages.
I don't mean for this to be judge-y. People have different skillsets. A nodejs backend can be the right choice if you're a full-stack dev or a solo dev and you mainly know js and you get a lot of agility and correctness by using what you know instead of trying to use a "better" choice but one that you yourself are less likely to use correctly or quickly in your own use case.
It can also be the right choice if you're a big backend java/etc guru but you know you want to set this thing up but then just monitor/oversee frontend/fullstack devs being the ones who do incremental modifications to it.
But yeah - without additional outside constraints and everything else being equal, it doesn't make a lot of sense to use nodejs as opposed to basically anything more boring - be it java, rails, etc.
The thing that surprises me the most about node based backends is that they forego both the platform maturity and static-safety of java AND the ridiculous amount of batteries included into django and rails, just to be able to use javascript, of all things. What you could rails-g in a minute you could instead spend a day looking for an npm package that won't be abandoned in a month or spend eternity rolling your own everything and then maintaining it.
This comment is presumptuous, dismissive, and also wrong. People who write application-like front ends in React (etc.) want back ends that can interoperate with those front ends.
They accomplish things like built-time code generation, static server-side rendering, and other kinds of code transformation that are difficult and flaky without a back end that can understand JS.
I have looked for non-tinkertoy solutions in Java and Go. There aren't any, and senior people in those communities are hostile to the very idea. (Maybe remembering Java Nashorn?) Maybe the only people friendly to the idea of interoperable back ends are Rust people (where you have libraries like Yew/Sycamore/Dioxus/Leptos that actively imitate JS frameworks).
But yes, your claim is that the only reason to write JS back ends is ignorance and enfeeblement is ignorant and repugnant.
> want back ends that can interoperate with those front ends.
You can ingest and emit JSON in any language. You can even compile backend-friendly code to run in JS on the frontend, via emscripten (and increasingly, Wasm), which will output very lean and JIT-friendly code. The usual "isomorphic" case for backend.js is no less 'presumptuous' or 'dismissive' than the comment you're pointing to and criticizing here.
How is this relevant? Serving a JS application to a client is not like serving a JSON API.
> You can even compile backend-friendly code to run in JS on the frontend, via emscripten (and increasingly, Wasm), which will output very lean and JIT-friendly code.
Not in my experience. Compared to front-to-back JS, shipping your applications as WASM ends up with downloads and memory footprints that are several times larger than the same application in ordinary JS, and this matters a lot for slower networks and mobile clients.
Edit: not to mention that Go has a very limited WASM story, so your "realistic" choices for shipping back end code to the front end are C++ and Rust.
> How is this relevant? Serving a JS application to a client is not like serving a JSON API.
In some JS applications, the way the frontend code communicates with the backend is via JSON API endpoints. I believe GP was just pointing out that you can write that JSON API in any language you want.
> not to mention that Go has a very limited WASM story, so your "realistic" choices for shipping back end code to the front end are C++ and Rust.
Can you elaborate on this? How is it limited in comparison to say, Rust.
My understanding is that to get reasonable WASM file sizes, one must use tinygo (a C reimplementation). tinygo is a WIP, although I wish I could find a better updated description of what's missing than this page on their site: https://tinygo.org/docs/reference/lang-support/
If you are referring to something similar to Blazor (client side), yeah no imo it's pretty awful for anything other than internal enterprise apps. I couldn't imagine running a public facing product on that.
By using Typescript you can share types on the backend and frontend. Java stacks tend to do the same thing but for backend and database by defining data at the ORM level. You can connect to your database in any language, but most people using Spring don't write plain SQL.
Your comments tells me you are in the group who doesn't know better. Data is passed in json which is a format other languages can read and send back. If that's your reason for using it you do have other choices.
Heh heh, well maybe in some cases but since TS/JS is kinda the lowest common denominator in web development, it's just the most convenient choice. We humans are limited in our capacity to learn and take time to get good at things. So it makes a lot of sense to pick a tool that can be used to build the whole app with.
And for all of its faults, NodeJS can be fun compared to something like Java which feels more like doing taxes. Maybe it's the danger. Maybe it's the fact there are so many packages and libraries out there - everyone can contribute! Who knows, but I won't waste my time learning say Rails just to use a "better" backend framework. It's good enough even though I know better. There are way more important things.
I love Rails and if it was continuing to grow even so slightly it will be my go to for sure. But unfortunately it has been slowly declining for a long time… Many moving to Go, Elixir, Rust, and elsewhere. It was by far the best dev experience with a framework I ever had. The last version still looks great. But realistically unless if you plan to do a rewrite, which is never a good idea, it may not be the best option out there. Even more with having to get people onboard for the next years ahead and the ecosystem too. I am looking for a framework to use and see grow a lot for at least the next 4 years with having hiring in mind.
Spring boot is great but it does have its quirks. Config and plumbing for instance compare to Nest or Rails doesn’t makes it the best and fastest dev experience. And all the Java extra stuff and it’s ecosystem makes it solid but also old compare to what you can see happening in other languages.
I have Quarkus in my mind though. It looks amazing in dev experience with lib like panache, resteasy etc… and performance are amazing too which comes as a bonus. But there is no dev out there. And I feel that in Java people want to work on Spring Boot because spending X years working on Spring Boot are more valuable in their career than X years on something else that is not really the de facto standard of the industry. So ya not great for hiring talented people…
But NestJS with the JS/TS ecosystem start to be very close to what Rails was in the past. Stuff like Prisma for instance makes everything a breeze. There is almost always a package for the thing you want. Great at websocket too. Can do GraphQL if it’s your thing. Same language as the front end, Nextjs, etc. One of the most performant dynamic languages. And interesting things happening like Deno or using Rust with it. So there are quite some perks to it.
Can’t speak about Django though. But I am wondering how is the dev experience like when we use it for real projects.
I am starting a new project/startup and wondering which one to start it with between all these technologies. And after looking for a long time I can see that they really all comes with their pros and cons.
> But unfortunately it has been slowly declining for a long time…
That could be a sign of “stability”.
I’m personally using Django since two years ago and have the same feeling as yours, there are nothing exciting happening in this area, but after two years of use I came to the conclusion that it’s features are too stable, so nothing new need to happen in the first place.
It’s a common myth that software should be always updating and introducing new features. No, it’s not, if it can solve the problem great it doesn’t need to change at all.
JS/TS/Rust are still in their exploration phase, new ideas, new exprimentations, new frameworks come and go everyday, and that’ the reason they look vibrant.
Before settle down with Django, for years I’ve used bleeding edge tech like Meteorjs/React/Nextjs/Vue/Nuxtjs/Svelte/SvelteKit/… in real world, or try to rewrite real world app with them, and the biggest problem of all of them is that they all have their quirks and things in JavaScript area are changing too often and too much, I’m so tired to chase all these fancy new ideas.
For 90% web apps Django+Htmx+AlpineJS can serve me good and do all the things that new tech can do easily, at the same time keep incredible stability.
I believe Rails or Laraval are same here, you don’t need to switch in 90% cases, just relex and appreciate the stability they bring.
Thank you for your feedbacks on Django. I agree Django is maybe a boring but solid framework. I never used it so I can’t speak about it’s dev experience but it looks great. I see Python kind of like Java but for dynamic languages. It’s not shiny it’s not the hype. But what can’t you do with it? Usually when a new tool comes out you have Java and Python as clients. Before you used to have Ruby too. Now not so much.
For Rails the thing is that it’s not just one lib among a huge ecosystem like Python but more or less Ruby = Ruby on Rails. Sure you have Sinatra which is the Flask of Ruby but that’s it. While in Python you can do so many other things from devops to ML to eBPF…
Ruby is growing (you can say "growing back") starting at least from 2020/2021 with a lot of things happening in 2022 and looking at a very exciting 2023.
Hotwire is an exciting technology coming out of Ruby/Rails ecosystem. Rails 7 was an important release bringing a lot of great features and Rails 7.1 looks even better.
Ruby has a lot of nice advances as language starting with 2.7 and continuing to the recent release of 3.2. Check the recent changes at https://rubyreferences.github.io
IMHO Ruby and its eco-system is the perfect mix of tech that works while trying to get right some of the most important modern approaches.
Specifically regarding the
> But realistically unless if you plan to do a rewrite, which is never a good idea, it may not be the best option out there
This is not directed to you but more a general rant :)
I hate with passion (and yes I am biased) this line of thinking because it is not true in maybe 90% of the cases. And it is not true when one says that about almost any established language that should be used where it fits (or where it is used the most).
What I write below applies to an average company mostly doing Saas/CRUD/web apps. If you are working at FAANG or FAANG-like companies maybe this does not apply to you.
Be sincere:
- Say that you want to pick something that will increase your hiring skills if you are a developer, or that you want to brag to your friends that you are using what Amazon/Google is using or that you want to speak to conferences about the latest big tech
- Or say that you don't like Ruby and just want to choose something else. That is fine.
- Or if you are a director of engineering/leader/manager say that you can hire JS developers cheaper or that offering a cool/hype technology is the only way to attract new people or that you want to feel safe in front of board members/GM/CEO by saying we failed to solve this even if we use everything that FAANG uses.
But please don't say that you don't choose Rails because you might grow so much that you will need to rewrite.
I don't know one single example where a company died because they choose Rails. Just the decision to rewrite a product on its own is a high risk of failing. It does not matter the from:, to: parameters.
And again I need to say to anyone thinking to start a project in Ruby/Rails but thinking they need to choose otherwise: You are not Google, nor Netflix, Amazon, .... You (probably) don't need anything from their tools or architecture that makes them offer concurrent services to hundred of millions of users.
Try to have 10k users first and then I think you will probably have the mindset + management experience to hire Ruby devs or to help a new hire to learn Ruby.
I agree like I said the last version of Rails is great. I have been doing Rails for almost a decade now so I’m quite familiar with all its new things. But there are also a lot of issues right now if you are planning to start a company.
The total number of job offers in Rails have been going down for quite a long time now.
If you look at the Stackoverflow surveys and compare the professional respondents for Ruby and RoR between 2021 and then 2022. It’s a 20% decrease. It’s a lot.
Critical contributors of Rails and its ecosystem left for Rust, Elixir, etc. For instance the guy that was behind Active Record went to Rust. Or the creator of Elixir itself and many other followed. On the other hand I don’t see prohiminent open source contributors coming to Ruby to at least replace them… I have been doing Rails myself for almost a decade now and I can tell you that many Rails devs want or already switched to Phoenix or other languages. It’s not going up.
Many gems are mature for sure and don’t really need anymore commits. But also many are abandoned with PRs and issues stacking up. The ecosystem is not really increasing anymore even more vibrant.
Now with all that said: is it impossible to find a job in Rails today? No. Is it impossible to find some devs? No. Is it going to disappear in 4 years? No. Are you going to make a big mistake using it today? No. But there are now so many other options out there without any of these cons and some other pros that it starts to be more and more difficult to chose Rails as a solution today to start a company. Unless you want to use Rails for a side project you can’t ignore these issues and all the other options we now have out there.
About rewrites. It’s not just about the technical part. It’s also the human part. Let’s say I hire you and we grow and there is also 3-10 more Rail devs. But a rewrite has to happen. Are you going to be so exited to jeopardize all your experience in Rails to switch to something new? Even if you are the other 2-9 devs may not. And let’s say more or less everybody agrees that a rewrite has to happen, now you still have to agree on which language and which framework you are going to use! Some may really want to do Go, some Elxir, some other TS…
Whatever the solution that will be chosen there will be a lot of frustrations. Plus there will be frustrations on the tech part of the rewrite and they have to start to be slowly getting more and more productive to the new tech where something that could have taken 1 day can take 5 now. All this, particularly the frustrations from switching to a tech where some won’t really like, will slow down a lot the company. When you check postmortems of startups that failed, so many times in the reasons why they failed there will be this “and we decided to do a rewrite…”. But I never saw a company failed and they will still say that the rewrite was a great idea.
With all that said: better pick the right solution today and look at all the options. Not the Google one, not the one that decrease but one that is at least solid to vibrant, not the last hyped one either, but the best one.
I truly love Rails. But I can’t just chose it because I love it. There are now better options out there for the long term future.
That’s an interesting comment. I chose Node not because I love it, but it’s the easiest to hire for as a startup.
I hate configuring typescript and having to deal with bundlers, package.json, esbuild, etc.
But Deno and Bun are just around the corner. What we need is to get rid of this a la carte mentality around tooling and just give everyone Typescript, batteries included, and make it fast.
While it doesn't have the batteries, typescript's gradual typing is much nicer than python's, so for some use cases it's a better language.
All languages come with tradeoffs in terms of performance, development/maintenance cost and ease of hiring. Most businesses only care superficially about performance, which leaves developer productivity and ease of hiring. Node/typescript isn't terrible in terms of developer productivity, and it's got the best hiring story of any language. Python is good in both those ways too, but since you already need a javascript hiring pipeline for the client it's easier just to use node and hire full stack devs.
Node runs circles around Django/Rails, and batteries included in Javascript tend to be pushed to either the frontend or the database. Node backend tends to be thinner, compared to Java/Django/Rails. Some people don't know any better, some have good reasons of doing this.
handlebars, terra, askama, and maud are examples I recognize from high up on that list.
Maud example: (chosen because it's the most "native Rust" in a sense and is designed for HTML specifically so I believe it's the closest to what you're asking for)
html! {
h1 { "Hello, world!" }
p.intro {
"This is an example of the "
a href="https://github.com/lambda-fairy/maud" { "Maud" }
" template language."
}
}
And the IDEs which practically write your code for you. I mean yeah Java is so verbose but most of that word vomit is me just tabbing through autocomplete
I went back and prototyped a slightly similar app in Python w/ a gui toolkit and I felt like I was driving through exception city. I have made my career writing in dynamic languages so I forgot just how pleasant it was to write in a static one!
Calibre, the ebook client, is a python GUI app. wxWidgets I think?
Theres another app that I use for renaming downloaded video files that uses a GUI toolkit.
I've written GUIs in pyGTK for industrial apps and it was a wonderful experience. The only reason I couldn't get it to work now because I can't get pygobject to compile on Windows (the offered solution of MSYS2... wasnt)
Unfortunately this project was working with Stable Diffusion, so I had to use something in Python
In any case I don't like this idea of a right or wrong answer here. LIke way too many people think Electron is a right answer and I think that's just dumb
I find typescript makes the most common things I do in business app software as straightforward as possible. That is, making copies of objects with slightly different structure to pass them to some other system. Typescript is just fantastic for plumbing.
To do the same in java means making a billion model files with a billion transformation functions on them
Your post is a great example why I wish Go lang was named something different. Because you use the lower cased versions java, rust, js, ts, nodejs, deno, etc. But all your 'go' refer to the verb, not the Go language.
Wouldn't you just use go/python/node for a simple crud API? fastapi for python is pretty performative if you use gunicorn as your runtime and time to iterate is must faster than it is in rust.
It depends exactly how simple that CRUD API is. If there's any business logic, I'd rather get all the cheap correctness guarantees that Rust provides. I don't find myself making many truly dumb CRUD APIs.
Time to iterate is also only much faster in certain situations, e.g. local development; if you have to e.g. build a container image, push to a registry, and redeploy to a k8s cluster somewhere, those savings become somewhere between less significant and nonexistent.
> Time to iterate is also only much faster in certain situations, e.g. local development; if you have to e.g. build a container image, push to a registry, and redeploy to a k8s cluster somewhere, those savings become somewhere between less significant and nonexistent.
Can you expand on what you mean here? I know you're not implying Rust is faster to move thru a CICD pipeline, so can you tell me what you do mean? I seem to be unable to make a different reading
I think the point being made here is that all CI/CD/SDLC stuff is effectively slowing down development, so the difference in iteration speed between Python and Rust is less explicit. But I dare to disagree, I just can't connect the dots here, moving code further down the CICD pipeline doesn't mean we can't work on the code itself or think about project improvement ideas.
Not your parent, but I have some ideas on this. I'm not sure how true they are. Maybe I'll write a longer version some day and see what people think. But the summary is this:
I suspect it has to do with how familiar you are with type systems, and the way that you use them. I find that Rust's constraints help guide me towards a solution more quickly, and I spend less time chasing down strange edge cases. Not eliminate! But reduce.
Most of the posts mentioning Rust not being the best choicce for a startup talk about iteration speed and prototyping. In that light I don't think this is the best heuristic. If you need to prototype quickly and search for a market fit, then by all means, choose whatever will make you go fastest (and I'd argue for a lot of use cases it would be Elixir with Phoenix's LiveView if you don't absolutely need an SPA or a mobile app), but if you're building sth that already has a market, Rust might be still a good choice even if it's not a C/C++ fit.
I don't agree with this. If Rust doesn't exist you might have a choice between the pain and endless bugs of using C++ or the ease, but much slower performance, of js. Maybe you end up choosing js.
But if Rust exists, suddenly you have a nicer-to-use high performance language, and you have a choice to use it.
Go is in a sweet spot where it is often used to compete with both groups: [Rust, C/C++] and [Node, Python, Ruby, etc]. The reason GP said it is probably because of Garbage collection.
I've done a bit of Rust in my job, and there are some basic things that Rust doesn't have going for it:
- steep learning curve (this means for the first 6 months, you or your colleagues are unproductive, write bad Rust which your company then builds upon over time).
- bad error messages (even though that was a focus for the rust team!)
- frustratingly complex for setting up test coverage
- Slow analyzer speed (*super laggy* on Clion, though this might be a jetbrains issue)
- Slow compilation times (I heard somewhere that "Go just goes". I've also written some Go in my free time, and compilation is fast. Well IMHO, "rust will rust" - it's very slow. Generics can make compilation event slower.)
- Verbose. I've seen a just few lines of JS get replaced with hundreds and thousands of Rust.
Rust lives in this interesting spot where, on paper, it should be superior to anything... but in practice, it's not a good choice in most cases.
It's very easy to ramp up someone in Go that's had a standard CS education and written C/C++ before. It's also simple enough syntax-wise for someone who knows python well enough to understand references, etc. Its stylistic restrictions and not being OOP-first also mean that codebases are generally readable. Compilation is also extremely straight forward.
With Rust, I've found even very experienced C++ folks have a long ramp-up period, the development toolchain is slow, and the ecosystem is limited.
Sure, for example there are projects to enable Rust usage with CUDA. But few are inclined to actually bother implementing a new BLAS and GPU accelerated tensor library with Rust.
I do think 10 years from now Rust will start getting more adoption as the ecosystem and tooling improve.
But it's hard to argue with Go where you'll typically get results that are faster or at worst comparable to Java without the OOP design pattern gobbledygook, simple concurrency model, and simple build process. It's "good enough" for 99% of use cases.
> With Rust, I've found even very experienced C++ folks have a long ramp-up period
I've found C++ folks especially have the hardest time with Rust, because they approach it using C++ idioms and habits, then get frustrated when they can't do things the way they're used to.
I've had better success teaching Java people Rust. They find it much easier to learn than C++, and I can get them writing idiomatic Rust code quickly, while C++ devs are still trying to get their coding habits past the borrow checker.
Go has bad interop with C/C++ and languages that use the C/C++ ABI (including Rust). You can use cgo as a workaround but it's clunky. So that makes an interesting case for other high level, novice-friendly languages like Nim, Crystal or Val/Vale/Vala.
Not the fault of Rust compiler per se but in my case the errors that mismatching trait impls from async libraries yield can be downright suicide-inducing.
esteban of course gave you an excellent response already, but just another bit of like, context here: while it may not be on rustc, the developers want to go beyond the norm here. rustc understands if you write async/await syntax like JavaScript, and then directly proposes that you switch to the Rust syntax:
pub async fn foo() -> i32 {
unimplemented();
}
pub async fn bar() {
let f = await foo();
}
gives
error: incorrect use of `await`
--> src/lib.rs:6:13
|
6 | let f = await foo();
| ^^^^^^^^^ help: `await` is a postfix operation: `foo().await`
It isn't on rustc to understand this either, but it helps a bunch of people, so the team does it anyway.
Check sibling reply. Sadly I never wrote those down. :(
I'll definitely do so going forward.
The problem is with that is the impostor syndrome: I legitimately can't tell if I am an idiot and skipped some basic Rust training, or the error messages are truly confusing and unproductive.
But your messages help. I'll just write those down and send them to GitHub's issue list.
I’m not working on Rust anymore, but the previous stated position on this, which as far as I know is still the case, is that if it’s confusing, you should file. Worst case scenario is “sort we can’t fix that” but it’s not an imposition to file issues. More is better. Because exactly as Esteban said, information is valuable. Even duplicates are valuable: they indicate that more than one person has run into this, and therefore it’s more valuable than an obscure issue only one person sees.
> I legitimately can't tell if I am an idiot and skipped some basic Rust training, or the error messages are truly confusing and unproductive.
It doesn't make a difference. The compiler can't assume any level of proficiency. If a topic requires you to read the docs, it should tell you so. There are some "basic" things it relies on, but for anyone with any level of experience programming should be able to read a diagnostic and either understand it outright or have enough clues about what to search for. So "this error is confusing because I didn't read chapter N of The Book" can be simplified to "this error is confusing."
Having examples of these is useful to see what we could get rustc to do. The general case might be impossible to deal with in a generic way, but we can target specific patterns libraries use and emit custom errors for them. The problem with these is we have to be reactive: if we don't see a problematic patter ourselves (or it isn't reported to us), we can't do anything about them.
Unfortunately last I tried these code snippets was months ago, was rushing like mad because it was a startup and I couldn't afford to just stop and write everything down and... yeah, priceless info was lost.
Just recently I am making a comeback to rewriting a tokio 0.1 library to the latest version so I'll likely have a few examples that I can post... where? In GitHub issues?
Even if it is an "it hurts when I do this" without more context it can be useful to bring the problem to our attention (but the more context you provide the higher the change we'll fix the problem).
The verbosity and complexity of `wasm_bindgen`/serialization between JS and Wasm (written in Rust) is primarily the thing I am frustrated at here when I see hundreds and thousands of Rust code. A concrete example: creating a Websocket client in Javascript/Typescript vs in Rust/Wasm.
In general though (outside of Wasm), Rust is less readable.
And with regards to Rust errors, I've found Rust errors related to Tonic and Diesel to be quite annoying/unreadable. The Diesel docs seem to blame Rust for this (can't find the docs for it right now).
Isn't this due to wasm having to access browser things mostly through browser JS interfaces?
eg Browsers provide JS functions that are intended for JS, which are not directly exposed to Wasm. So when your Wasm wants to access DOM things, access DOM functions, (etc) it needs to go through a JS shim layer instead of being able to call them directly.
If the browser dev's (or some W3C type of body?) introduced those same functions, but had them be directly accessible from wasm, then the JS shims wouldn't be needed.
The JS dev's for each of the browsers though would probably try and stop it ("security risk!" excuses, etc) though, as that would potentially cut into "their territory" and allow other languages to compete. :(
Expanding WASM to the DOM is definitely part of the roadmap. The problem at the moment, as I understand it, is that the DOM was designed with Javascript in mind, and figuring out how to translate that into something that works well for lower-level access is difficult, particularly in regards to getting garbage collection to work properly between WASM-land and JS-land. There are some alternative solutions that are being explored, but none of this has anything to do with security risks.
I hope you're right, and it does end up happening. That would very much enable many languages (LLVM based ones anyway) to become practical alternatives to JS for web dev, whereas now they're more like "can be sorta done with significant effort". ;)
Btw, my impression that it would be blocked by JS people involved in the process, was from a conversation some time ago with one of the JS people themselves.
They said (from their point of view) there's no need for WASM to directly access things instead of going through JS, and they'd block it themselves if things went that direction. Security was the lever they mentioned they'd probably be able to use.
For server binaries they're typically being dropped into Docker containers not scp-d to servers directly, and the moment you go there you can just use jib and get a JVM container easily so there's no difference in logistics.
For CLI tools whilst a single binary can be convenient, native-image lets you get those for JVM programs too these days. But it's not always the case that it's enough. In practice you will often hit the need for:
a. Cross platform / cross builds.
b. A way to easily update them for your users (that isn't "everyone mount this NFS/SMB drive")
c. Ability to ship other files e.g. third party libraries written in other languages, config files, data files, readmes ...
d. Possibly, avoiding virus scanners and Gatekeeper if you have users on Windows/macOS.
Conveyor [1] does support distributing CLI tools (in any language) that can then be updated via apt-get, the Windows package manager or Sparkle on macOS. If your language/runtime supports cross-building then it can do it all from your developer laptop, you don't need each OS to build for. The resulting artifacts are single files (deb, msix/exe, zip) and it supports both self-signing and regular signing if you want that.
It provides a few other neat features on Windows:
• One click install that immediately adds new tools to every single terminal session without needing restarts.
• If you want, silent background updates Chrome-style. If you don't, manually triggered updates.
• For JVM apps specifically it automatically configures the Windows terminal to support ANSI escapes, Unicode and other modern features so you can use all the same stuff as on UNIX without needing to futz around with win32 or wrappers.
Unfortunately the little default GUI that lets you trigger updates and add CLI tools to your path on macOS isn't officially launched yet, because it only works for JVM apps and not other types of program. But if anyone wants to try it just let me know, it's easy to activate.
If you don't need any such features then yes, a single binary can be a bit more convenient than a zip. But the number of situations where it breaks down is pretty high and it's not so hard to handle multiple files.
I want to be careful not to recapitulate every conversation I've ever had with a JVM person about this. I'm not claiming it's impossible to deploy JVM applications; obviously, tons of people do. I'm just saying people use Go and Rust because they work well in situations where you want to distribute and directly run a simple binary without additional tooling. That's not every situation; obviously, if you can use Docker, there's not much difference between a JVM app and any other kind.
Your comment is super interesting, don't let me sound like I'm trying to shoot it down. I'm being deliberately terse to avoid creating receptors for language war antigens to bind to.
Sure. Given the choice of one file or 50, one file is clearly better all other things being equal.
My feelings on this changed over time. About 10-15 years ago I thought single executable output was a critical feature for a language, because everywhere I went I saw people saying how important it was for them, how much simpler it made deployment. I figured, OK, people know what they want so that's what they should get.
Then Docker came along. Docker images aren't single files, they're the polar opposite. They aren't even things you directly manipulate using the filesystem at all. Yet people loved it and it took over the world. Clearly what all those people demanding single-file executables were actually wanting in 95% of cases was simpler deployment, and they were phrasing it as single executable because that was concrete and understandable whereas simpler deployment is a very vague concept so who knows what you'd get if you asked for it.
For people who are selecting Go or Rust or Graal native images primarily because of single-file output, I'd actually really appreciate a chance to ask a few questions or interview them quickly to learn more about the deployment context. Conveyor is all about deployment and it's good to understand more about how people are doing things and what could be better.
> I’d love to use C# without having to deal with distributing the runtime, so I’d like to hear more!
In the later versions of DotNet there are a couple of common ways to distribute (I'd suggest either DotNet 6 [LTS] or preferably DotNet 7 [current]).
You'd usually use the dotnet publish command, which ideally produces one of three things, all of which are self-contained and can be deployed to a clean server without any framework. Ordered by worst-first (in relation to your requirement):
1. The halfway house from dotnet publish is a folder with your app/site/api alongside all the dlls needed from the standard library and/or nuget. This is a standalone folder, though messy.
2. With an extra couple of options on the dotnet publish command you get it all as a single binary which is exactly what you say: a big executable.
3. There is another option available on the dotnet publish command which will use magic (probably tree-shaking but I can't remember) to produce a smaller single binary by removing unused code.
As an aside, it's also worth noting a couple of extra points:
* The dotnet publish command can cross-compile ready-to-deploy outputs for any supported platform (eg Mac or Linux, using x86, AMD64, or ARM64) just by specifying the combination of platform and CPU as command line options.
* Within C# you can mark your assets as embedded resources (like an embed FS in Go) and they will also be included in your output.
The final result varies in size depending upon what your code does (and hence included libraries), and some code (eg reflection) may interfere with the tree-shaking (or whatever) of option 3 - but it warns you whilst it generates the output, and you can either ignore it or use option 2.
Generally speaking the option 3 builds are between 1.5 and 2 times the size of a Go one, but you're looking about 20MB to 30MB for useful stuff. Not tiny, but still quite small these days. Option 2 builds probably double.
In use (and this is subjective) they consume a bit more memory than Go, but seem more consistent/stable in that usage.
Also note that within that 20MB-30MB build, for an api or a website you get a built-in web server that can sit behind nginx etc as usual, but is also good enough to expose directly.
Yes, "dotnet publish" is what I was thinking of. Wow, I didn't realize it could cross-compile!
I can't quite tell from the .NET SDK repository -- any idea if this stuff works on Linux (i.e. building on Linux, perhaps for Windows)? I see mention of MSBuild, so I'm guessing maybe not.
I love C#, but I abandoned it a while ago because I wanted to only rely on open source tools (just to ensure my code is usable in the future). Then, of course, they open-sourced a bunch of stuff (including the compiler). If I at least had the option to develop C# on Linux (with support for cross-compiling to Windows), that would be great (and honestly something I would have never expected 10 years ago).
> Actually, it does work from Linux ... cross-compiled from Linux to Windows.
Here's a link to the commands I use to generate my cross-platform builds [1]. They are easy enough to stick in a shell script or batch file so you get all the builds with one command. These produce single executables, trimmed for size.
Indeed (I mentioned reflection above). It only affects the trimming though - you still get (larger) standalone builds that need no framework installed.
Java, Go and C# (and node) have very similar performance, e.g. https://benchmarksgame-team.pages.debian.net/benchmarksgame/.... For all of them, the key to writing high performance code is avoiding allocations and boxing. Go and C# both do this slightly better than Java, but in most domains where these languages are used, this is not a big difference (and this is where you might use C/C++/Rust instead). I've found Go to be more verbose than Java, but I haven't used Go much since generics were released.
Not really, just do a rolling deployment like you should be doing anyway. No one cares if the new version takes 1 millisecond to start up or 3 seconds because they literally won't notice.
If your Java app takes half a minute to initialise it's the app's problem, not Java. Modern Java frameworks have moved from a dynamic deployment model to statically compiled and can start in milliseconds.
(for example, see the benchmarks on https://quarkus.io/blog/runtime-performance/)
Hardly, it's a fantastic guardrail when combined with health checks. You can say "you don't need it", but everyone makes mistakes sometimes. Make those mistakes not matter. You also take backups, right? Same idea.
It has a non-zero cost though, which is why I don't like it.
Things go wrong with the "roll" for example.
You have potentially two versions of your code running against the same DB for some time.
Stop -> deploy code -> start is simpler and less likely to go wrong.
JVM startup times make using it in Lambda or scaling container clusters awkward. Scaling can't happen fast enough for traffic spikes when the startup time and cold start performance is crap.
You exec a process expecting it to begin operating, providing some networked service, in a reasonable time. Instead it doesn't do that. It spends tens of seconds, sometimes minutes, running JIT and other sundry startup overhead.
You may not have seen this if you haven't used Scala...
Genuinely curious, what kind of application are you running? Which JVM are you using? Are you aggressively GC tuning? Very low on memory? I've used Scala from 2.8 up to 3.0, for microservice systems, monoliths, data pipelines, machine learning (way back), desktop apps for research using Swing, an Android app (worst idea ever), highly imperative to very functional, and I don't think I've ever seen anything remotely as bad as that even on genuinely big codebases. Hundreds of ms, sure, but minutes just getting the JVM up and running? I can see how that would be problematic.
Ok, so to expand: applications that I've been responsible for from the beginning have not had long start up times. Where I've seen it is with other folks applications where I was hired as a consultant to look at performance.
The most recent example was a Scala monolith. It had to use JVM 1.8 because <reasons> prevented migration to 11 (tried quite hard, but never succeeded). GC tuning doesn't really apply when considering start up delay, but yes it had been tuned over the years. Memory was not limited. The application, mainly due to Scala, had tens of thousands of classes. They all seemed to get JIT'ed on start up, which was the primary reason for the slow start up. People involved (who had come from heavy Scala shops like Twitter) seemed to think it was normal.
Yeah, Scala is absurdly bad for startup time because of poor modularization of the standard library. It's a decent language with a terrible standard library.
Whatever the absolute merits (or lack of them) of Go, the fact is that if it's a good (enough) option for you, then it's almost certain that some language will fit your problem better than Rust.
Precisely. If you like what you see in Rust but you don't need to worry about extremely strict hardware/memory/realtime constraints (i.e. you could use a memory-managed language), consider Haskell instead.
That really is a great way to think about it, and my previous experiences with the "wrong choice of Rust" seem so obvious when filtered through this lens.
Rust is a high development cost compared to node.js python or julia, but I'd say it is about the same as go or c#. Maybe a little better than all of those if you consider time getting test coverage. But if you are prototyping you probably aren't doing that. I'd say rust is a much lower development cost than c++ or java.
Golang absolutely has a faster development cycle than Rust. Unless you’re a Rust expert who never touches Go, but then it’s an issue of familiarity. Go devs hit the ground running and the ergonomics are streamlined, and the borrow checker and other rust restrictions don’t get in the way.
Given my downvotes you seem to be with the consensus on this one. I had 30 years of c++ development going into rust and I never found myself fighting the borrow checker. Golang seemed the same, just started coding and stuff worked mostly. But, the complexity of rust was familar coming from c++ with generics and macros but without some of the footguns, so it just seemed like power, not clutter.
I like go, but I wouldn't prototype in it, I'd pick julia or python. And if I'm familiar with the problem and want to code for production, rust really doesn't seem any slower to develop in than go to me and perhaps a bit less verbose. But in retrospect I think that is because of the direction I came at rust from means my habitual coding style lined up more closely with what rust expects. Its not a harder coding mindset, just a different one than someone who came from java would be used to.
30 years of C++ development experience means you aren't going to find any PL difficult and therefore your views on easy/difficult a PL is to learn and get going cannot be taken seriously. :)
While my overinflated ego enjoys your assessment, I want to reiterate that the patterns that minimize friction with the borrow checker aren't harder than standard patterns you'd see in garbage collected OOP or Functional focused languages, just different. Anecdotally here on HN it seems like people who came from ocaml or f# find rust even easier to adapt to than c++ people.
30 years of C++ can inoculate you to the idea of hideous amounts of boilerplate, or worrying about memory allocation timelines and such. I'm a 25 year C++ veteran myself.
I recently wrote an asynchronous microservice in C++, because it needed to use a C++ library I'd already written. Took about two weeks of effort, and clocked in at 1500 loc, not counting tests or the half-dozen external dependencies. I rewrote it in 100 lines of idiomatic Go using nothing except the standard library a few days ago. That's a 10x reduction in both lines of code and development time, although it's a bit unfair because I had already done the C++ version first. That is after giving up on a Rust version that was already weighing in at ~1000 LOC in an unfinished state.
After this experience, I don't think I'd ever use C++ or Rust again for a concurrent web service, unless there was hard real-time latency requirements. Golang is just so much better streamlined for that application, and the standard library is batteries included.
Go was designed from the ground up for that sort of thing, so that makes sense. And anecdotally asymc/await is a pain in rust. I've only used rust async through other libraries, and not that very often. I usually use plain threads.
Yeah Rust supports the same concurrency primitives as Go, but man are they a pain to use by comparison. With Go it is as trivial as using built-in keywords to spawn and merge lightweight threads, and the lightweight thread is the default mode of execution when main is invoked. Structs automatically serialize to JSON. The standard library’s HTTP server is fast, concurrent, and safe for use in production. Summed together that makes use case like mine a breeze to implement in Go.
But yeah, if I was writing an embedded firmware or something I would absolutely prefer Rust.
I use it for numeric heavy stuff and I'm going through tonic for any service connections. That abstracts me from any async wierdness and for the dsp code I don't care about lightweight threads. I don't want many/any more threads than I will have cores.
I feel like this is probably on the money, at least when it comes to building a startup. I often use Rust where before I would use Go/NodeJS/Python, but mostly because I like the type system and velocity on side-projects isn't as important.
If your answer is something like Go or Node.js, then Rust is probably not the right choice.
If your answer is C or C++ or something similar, then Rust is very likely the right choice.
Obv, there are always exceptions here, but this helps you work through things a bit more objectively. Rust can be a fantastic language for many purposes, but it has a very high development cost.