I talk to lots of people about software and programming: people who are trying to make a technical decision for a new project or who are interested in learning something new, and some form of the question "what programming language should I learn?" or "what's the best language for this new project?" comes up a lot.
These are awful questions, because there is no singular right answer, and in some senses all answers are wrong. This post will be an exploration of some decent answers to this question, and some useful ways to think about the differences between programming languages.
If you already build and maintain software in one programming language, build new components in the same language you already use. Adding new tools and technologies increases maintenance burden for all engineers, and software tends to stick around for a long time, so this cost can stick around for a long time.
The same basic ideas applies to selecting languages that will be used by teams: choose a tool that's complementary to what you're already doing, and that could provide value.
If you're more familiar with a few programming languages or don't feel you need to learn a new language for professional reasons pick something fun and off the wall: Ocaml! Common Lisp! Rust! Haskell! Scheme! Elixir! It doesn't matter and in these cases you probably can probably learn new languages when you need, the point is to learn something that's radically different and to help you think about computers and programming in radically different ways.
Choose the language that people working on similar projects are already using. For instance, if you're doing a lot of data science, using Python makes a lot of sense; if you're writing tools that you expect banks (say) to use, something that runs on the JVM is a good bet. The idea here is you may be able to find more well developed tools and resources relevant to the kinds of problems you encounter.
When starting a new project and there isn't a lot of prior art in the area that you're working, or you want to avoid recapitulating some flaw in the existing tools, you end up having a lot of freedom. In general:
- Think about concurrency and workload characteristics. Is the workload CPU, Network, or IO bound? Is the application multithreaded, or could take advantage of parallelism within processes? There are different kinds of concurrency, and different execution models, so this isn't always super cut-and-dry: theoretically languages that have "real threads" (C/C++, Java, Rust, Common Lisp, etc.) or a close enough approximation (Go,) are better, but for workloads that are network bound, event-driven systems (e.g. Python's Tornado and Node.J's) work admirably.
- How will you distribute and run the application? There are some languages that can provide static binaries that include all of their dependencies for distribution, which can simplify some aspects of distribution and execution process, but for software that you control the runtime (e.g. services deployed on some kind of container based-platform,) it might matter less.
- Are there strong real-time requirements? If so, and you're considering a garbage collected language, make sure that the GC pauses aren't going to be a problem. It's also the case that all GCsare not the same, so having a clear idea of what the tolerances
- Is this software going to be maintained by a team, and if so, what kind of tools will they need in order to succeed and be productive. Would static typing help? What's the developer tooling and experience like? Are there libraries that you'd expect to need that are conspicuously missing?
Have fun! Build cool things!