I recently wrote the same UNIX PAM module in Go, Python, and Rust. I started with Go because I enjoy writing Go and the Go compiler can generate shared libraries. Go didn't work out because Go's use of threads resulted difficult-to-debug conflicts with the use of fork(2) in sshd - after realizing that the issue was related to threading, I found that you can write PAM modules using the excellent pam-python [1] package. The code I wrote in Python worked great, but I really wanted to generate a module as a stand-alone shared object binary, so I re-wrote the code using Rust, which worked great.
Footnote:
Different technologies might all be able to get you to your destination, but some are going to be more suited than others. This depends heavily or a wide variety of different factors. Large team or small team? High throughput or low throughout? Simple or complex?
The variables are too diverse to offer a meaningful answer. Use Rust when performance and safety are paramount. Use Go when you need to write a thin network-aware app or API. Use Node when you have an excess of JavaScript talent…
Where I find node shines is when it comes down to time to market, or orchestrating disparate platforms together. Node works great as a glue layer. Not that Go doesn't, but the amount of developer time to do it is quite a bit lower in Node imho, with a more agile approach. I'm a pretty big fan of web-facing applications talking to a service written with Node that will in turn talk to other systems behind it. It's probably the easiest place to transport that weirdly bound WS* service to something easier to consume in a different language. If/when performance is an issue, you have a working prototype for a Go rewrite.
Most of the same network scaling issues apply to all of the above. And as an aside, all service authors should have to write a client in a static and dynamic language.
1. This is based on my experience, so YMMV and there are many cases where more than one way can work well!
2. I appreciate pragmatism. Try to use an appropriate tool for the job.
3. I identify as a polyglot, and have used Go and node.js extensively for 8+ years (and other languages for many more years than this).
4. Of the three languages listed, Rust is my weakest. That said, I always enjoy reading about it and learning about the design philosophy and choices.
---
Rust: If/when I had the luxury of enough time to actually learn rust :) ..and one or more of the following were true:
- Cases requiring eeking out max performance and guarantees about program safety / correctness.
- Real-time or soft (near) real-time is a serious requirement.
- targeting embedded applications or other highly resource-constrained runtime environments.
Node.js: Great for frontend work and single page apps. Also a goto when I know there's already a decent library written that will do what is required.
Go: Shines for a few classes of problems:
- Command-line apps and systems work - it can be a very quick way to a working solution, and also reasonable to create reliable and robust applications compared to many other languages.
- Situations where ease of deployment is important. Distributing a single binary can eliminate drastic amounts of complexity.
- Problems where it's useful to trivially spin up many concurrent processes.
Then, for most other things there's Python, bash, Java / Groovy / JVM, and C.
---
grin
No matter what, have fun!
Rust is often a good choice in place of "large project in C/C++".
The safety features of Rust helps you maintain correctness as the project grows.
At 500 lines Rust may be somewhat inconvenient and C seems fine (at least for someone new to Rust).
As the size grows most C/C++ projects tend to go out of control (unless they are really strict and serious) with a continuous repetitive stream of "oops null pointer over here" ... "oops forgot to free over here". As the size grows the inconvenience of Rust fades and it starts to provide more value.
This is great if memory managment and high performance are a big concern for you, if they are not you might want to choose a language like Go or Node which allow you to gloss over such details until they really become an issue.
Do not fix problems you do not have by throwing Rust at them, but feel free make the climb of learning it to expand you horizon. :)
If you wanted to run one codebase across Desktop(Win32, OSX, Linux), Mobile(Android, iOS) and Web(Asm.js/WASM) you'd usually have to resort to a scripting(perf-impact) or C/C++(compiler differences, poor dependency management).
With Rust I can do all that one from one Cargo.toml and a codebase that just works for all my platforms(modulo any forking inside libs that use "target(win32)", etc).
For someone who's done that most of their career it was amazing to see how solid and straightforward that is with Rust.
I would not write that specific code in Node.
Thank you. I write mostly Node & wanted to try Go for a long time because of performance & then I heard that Rust is even faster. So I thought I would learn that.
But you are right, I don't have any problem with Node. Its working great for me. :)
My knowledge of Go limits itself to "Hello, world", so I can't speak for or against that technology.
Easy things are easy, but sometimes hard things are almost impossible with the wrong tool.
When I need something to go faster, or have bulletproof reliability, I use Rust. The type system requires more work up front, but then it guarantees you won't chase unexpected `nil`/`undefined`. It has fast and incredibly convenient de/serialization with Serde. Fearless multicore computation with Rayon. It's good at number crunching, and gives enough low-level control to manipulate large data structures with little memory overhead.
In the end, I find Rust to strike the right balance between expressiveness and correctness. Unlike C/C++ where you can shoot yourself in the foot, with Rust you're forced to write thread and memory-leak safe code. And in the end, Rust code often look much cleaner AND safer than the C++ equivalent.. what's not to like.
go -> fast, easy to deploy services talking to other services.
node.js -> full-stack developers rapidly developing a product.
rust -> safer language than C/C++ but with the same performance.Oh Jesus, here we go again.
They are catering to different domains! Node is intended for doing backend programming for supporting web applications. And there are many better alternatives IMO.
Rust is intended for systems programming manly (not limited to that, of course). It also would be good for certain high-performance backends.
As for Go, I'll let Rob Pike (Go creator) explain the reason for Go:
The key point here is our programmers are Googlers, they’re not researchers. They’re typically, fairly young, fresh out of school, probably learned Java, maybe learned C or C++, probably learned Python. They’re not capable of understanding a brilliant language but we want to use them to build good software. So, the language that we give them has to be easy for them to understand and easy to adopt.
Because what he's saying here is, in my opinion at least, anathema to company line about who they hire.
I know things have changed, but in the early '00s good luck getting hired to Google without a PhD, masters minimum.
4.0 dual major in CS and psychology from Georgia Tech, graduated in 4 years with both of those degrees. Yeah, no thanks. [Not me, a friend of mine who wanted to work for them]
They always insisted, at every hiring event I attended through around 2008, that they only hired the "best of the best" and things like that. If that's true, then this:
> They’re not capable of understanding a brilliant language
Isn't true.
So Rob has it right and Google is hiring really mediocre people. Or Rob has it wrong but only saw the mediocre hires.
EDIT: Cleaned up the grammar a bit.
I've lost count of the number of engineers I've pissed off by implying that they or their coworkers might in fact be human beings and thus prone to errors.
White knuckling (as the term is applied - as a pejorative - in Alcoholics Anonymous) is rampant in software. If you make a mistake it's because you're bad and you should TRY HARDER LOSER. Not because our architecture or tools are error prone/obtuse.
You could say the pressure cooker interviewer process is looking for people who don't cave under pressure, but I don't think that just because you don't crumble doesn't mean you aren't incapacitated. I suspect it ends up selecting for people who think working under intense pressure is normal and there's no point in trying to relieve that pressure, ie working smarter.
They’re not [in]capable of understanding a brilliant language, but we want to use them to build good software.
i.e. they're smart people, but we don't want them to focus those smarts on the language itself, but on writing software with the language...
That’s bullshit too, and they know it, but it’s the best they have and works well enough when they have a limitless pipeline of people willing to try.
I’d like to see google recycle their current employees through their interview pipeline and see what happened.
All big corporations start hiring mediocre people sooner or later. Nothing wrong with that. It's just the way it is.
Still too stupid for anything more complex than go.
IMO about smalltalk, it's not just because of dynamic typing but also because of the builtin IDE, VM and DB.
Negative work is when someone does work so badly that it takes more time to correct their errors than it would have for them not to do the work at all.
For a given task, random programmers are quicker at achieving the goal with dynamic programming languages. That's why scripting languages are popular. They are also easier to learn.
You don’t have to dig through the codebase to figure out that a function should have only accepted a number, because the interpreter/compiler would have screamed at you the moment you try something else.
Scripting languages may be easier to learn, but they aren’t as scalable and efficient. In requiring less scaffolding and structure, they’re not as well suited at creating correct code in large codebases. They’re still great for prototyping, though.
I've softened a little bit about scripting languages. They are great for small functions like AWS lambdas and "scripting" like the UserData portion when you're setting up a VM in AWS.
What I have in mind is a language able to convert functions calls from dynamic to static (and the opposite). If the compiler can infer the type, the call is static else dynamic (with multidispatch for function overload).
My experience is Javascript and even PHP scale better than C++. I do a lot of type checking and I don't use OOP features.
But as far as using C++ and not using OOP, as thevold saying goes, you can write FORTRAN in any language.
I think Smalltalk is the most productive language because of its VM (builtin IDE, DB...) and not because of OOP.