Everyone has their ideal list of "best languages" you should be learning in 2020. I'm going to give you three lists, instead. Here are the programming languages you need to get the job.
Python. Accept no substitutes. Python is the single most popular programming language on the planet, it's ridiculously easy to learn, and it has more libraries and more utilities than just about any other. Python has more than enough application servers, database interfaces, and cloud APIs to make your career successful. Use black and don't argue with it.
- PHP: PHP is still around, and it's gotten better over the years. Lots of older shops still use it.
- Ruby: Ruby is in decline, but isn't nearly as dead as Perl. There are a lot of Ruby shops too, although do be aware that "Ruby on Rails" is actually a somewhat different language from Ruby proper; Ruby's exposed object model has allowed Rails to monkey-patch the language at a core level.
Go. Go is Python's compiled big brother; go is much faster than Python and much more secure. Go, like Python, is very easy to learn, and if you know Python, learning Go is trivial (and vice versa, if you chose to go the other way). Go has some powerful (and sometimes tricky) concurrency primitives that make basic multi-threading easy (and advanced multi-threading sometimes not so easy), but it also has all the application servers, database interfaces, and cloud APIs that you need. Kubernetes and Docker are both written in Go.
- C# or Java. Depending on your platform of choice (Windows vs MacOS/Linux), these languages can provide the same functionality as Go (and in the case of C#, some absolutely amazing data access methods), and with almost the same performance (although at times much larger memory demands). C# also comes with its own compiler/excutable bundler, making single-binary deployments of C# programs possible, and runs on Linux and MacOS now.
- C/C++. These are the "grandfather" languages of all system languages. Odds are your operating system is written in these. (In fact, the reason C/C++ programs are so much smaller than their equivalents in compiled C#, Go, or Rust is that C and C++ cheat by accessing their runtimes as compiled into your OS's core kernel; other languages don't have that, er, "privilege.") C and C++ are powerful, but they are also notoriously dangerous: they have no limitations on memory access or thread primitives at all, and it's easy to write programs with pathological behavior, or to write programs with such poor boundary checking that they are playgrounds for hackers to break into your system and wreak havoc.
- Rust. Rust is a successor to C/C++. It is as fast as those two, but it comes with a much more restrictive ruleset about allocating and accessing memory, as well as much more constrained primitives for generating threads. Learning Rust is therefore a fun and exciting challenge at the end of which you can write the most powerful programs of your career, using every cycle the CPU (and even the GPU) can give you, with the knowledge that what you've written will honor the restrictions and requirements you demand of it.
Bash. There are other shells, of course: Fish and Zsh are popular, and Csh and Shell are still around, but Bash is the common denominator, the one shell everyone is guaranteed to have that is also guaranteed to run older shell scripts. Just make sure you find a good guide to writing good Bash (erroring out on first failure, proper string interpolation, that sort of thing), and use the shellcheck program ruthlessly.
- Powershell, but only if you're on Windows. And only if you expect to ever be on Windows.
HTML, SASS, and Typescript. Once you learn how to use Typescript's type system to "describe what you mean" to the compiler, you'll have the most powerful tool available to help you clarify your thinking and organize your code, allowing you to get it right the first time. Sass is a wonderful extension of CSS that helps you nest your CSS, import it as needed, and organize it programatically. Use it lightly and learn how to use CSS variables to make your CSS truly re-usable.
- Native CSS, of course.
You should also constrain yourself from doing dumb stuff by using ESLint to double-check your code, Prettier to enforce formatting, Jest to run your unit tests, WDIO to run any in-the-browser tests, and a git hook like Husky to make sure that all of that is done before you send your code up for review.
SQL. SQL is a declarative language: you tell the database what you want and it figures out how to go fetch it. SQL is old and creaky, but it's really all we've got at the moment.
There are no good alternatives to knowing SQL. You can get a job if you know only MongoDB's OO-declarative or GraphQL's syntax, but both of those represent less than ten percent of all installations out there. If you want to talk to a database, the odds are good it'll be SQL, and nothing else.
What constitutes an 'advanced' programming language? An advanced programming language is one in which it is very easy to express ideas and concepts in ways that are impossible in any of the above languages. An advanced programming language is a struggle, an adventure, and a mountain to climb, and once you've reached the top you can journey back to the land of your professional languages with a huge toolkit of new skills that you can use.
There are two wildly different languages that I recommend everyone learn. Knowing them are superpowers. If you know even a small part of them, you will be ten times better than anyone who does not.
Haskell is a "pure" functional programming language with extremely strict types. That means that there are no variables (what!) and that all side effects (things like I/O or the passage of time) are safely walled off from the language itself. In fact, programming in Haskell is much more like writing one massive equation, the outcome of which is the running programming.
Haskell is infamous for bringing the monad into popular discourse, along with the notion that monads are impossible for mere mortals to understand. They're not, of course, but so many metaphors for them confuse or obscure the issue, and I'm not going to try. Let's just say this: Haskell is a language where, like SQL, you say what you want the program to do by describing the types you want to flow through the system, and Haskell will do its best to find the exact library of code that matches those types and use it. Only if it finds more than one will the compiler ask you for clarification. Side effects are unpredictable: since you don't know what a user could input or when an event could happen, monads isolate those and ensure that the behavior they cause (and when they cause it) is properly part of that massive equation, and any unpleasant erroneous or exceptional behaviors are fully documented and fully handled.
Haskell has no
for loop, no
while, nothing like that at all. Instead,
Haskell treats lists, arrays, streams, maps, and so forth as just another type,
and you work directly on the type. You have to explicitly say "A list of records
of type Person", and then every function you write that works on that list
starts with the assumption that it is a list. But even better, you don't have
to use all the features of a list, and the Haskell compiler will make excellent
decisions about how to allocate, access, and update that list depending upon how
few or how many features you use.
What you will learn from even a little Haskell is immense. Most importantly, you'll learn that collections like maps, lists, arrays, and records are just so much data, like numbers or strings, and that you should treat them the same way. Haskell's strict type system will let you work with gigantic collections, like whole JSON trees or entire diskfull databases, as if they were single items, and you'll be able to express your interest in all or part of your data, transformed exactly how you want it, as if you held a magic wand.
Scheme is at the opposite end of the world from Haskell: it has no types, and its syntax is absurdly simple. Scheme is the most malleable language in the world, its core is barely a dozen syntactical function calls, and its library in immense (and, to many, somewhat alien).
Because of this power, Scheme is frequently used to prototype other programming languages. That's one of its powers: you can define the source code analyzer, the intermediate representation, and the back end all in the same language, and all using the same tools.
What you will learn from Scheme: That code is just bits and data is just bits, that code is data and data is code. You'll learn to build functions on the fly and pass them around, treating them as if they were just another hunk of data until you need to run them and use their output, and you'll learn that you can run the function but delay accessing the value until later, or that you can partially run the function but the value won't be available until the environment, such as the rest of the program, or some outside effect like the network or a database or whatever, produces some value the function needs to finish.
It's all well and good to know one or more programming languages, and to be a full-stack developer you'll need at least one language in all five categories I listed, with a willingness to learn the others. But there's a lot more to learning how to program than just a language.
More importantly, you must learn to read source code and be able to make judgments about the professionalism and quality of the libraries you use. The code you write is going to be read by other human beings far more often than it will by a computer, if only because you have to go back to it more than once to repair, maintain, or extend it. If source code doesn't make any sense to you, you must have the tools to make a decision: that it's either poorly written, or there is some essential learning in which you need to engage in order to understand it. If it's the former, don't use it if you can avoid it; if it's the latter, decide for yourself if the investment in time to learn that code is worth the payoff.
Also, learn and max out your Integrated Development Environment, whatever it is. Modern IDEs integrate well with Language Server Protocol Servers (LSPs, and yes, that's a silly acronym) and can highlight bad code, poorly formatted code, spelling errors in prompts, as well as provide you with guidance on how and where functions and types are defined.
Learn your isolation tools, such as Docker or Podman, so you present as little attack surface as possible to malicious actors. Learn your continuous integration / continuous development systems, such as Jenkins or Dagger, so that someone else is constantly running your tests for you.
And finally, learn Git. Git is the industry standard version control tool; it lets you work fearlessly, knowing that if you screw up your original is safely tucked away in a safe repository. But understand that Github is not Git, and learn to use Git without Github.
I cannot emphasize this enough.
Learn how to organize a meeting, with an agenda, and pre-agreement, and a concrete set of goals and a solid understand of what you expect others who come to the meeting will learn or contribute.
Learn how to write documentation. Learn the four kinds of documentation: Introductory Tutorials, Advanced How-Tos, Internal Explanations, and Comprehensive References and Glossaries. Always write a great README. Understand that good programs don't need documentation, and that great programs are always well-documented, and that that is the single difference between those two categories. Learn how to effectively use visuals in your documentation; explaining a particularly tricky asynchronous process can suddenly get a hundred times easier with a well-drawn sequence diagram.
Learn how to learn, and learn how to meta-learn: Learn how to create a plan to learn something, and then execute on it. Learn how to identify the key things that you want to learn. Learn how to skim five books on the same topic at once, extracting the key ideas from the table of contents alone and then picking the best explanation from the five.
Learn how to handle your own distractions. Pomodoro, Getting Things Done, Inbox Zero, whatever it takes, figure out how to be productive, while understand that, no really, you probably have at most three productive hours a day as a software developer in you. Use them. Block them ruthlessly and let no one have them or interrupt them. Learn to negotiate hard for those hours.
Learn how to do a code review with kindness. Learn the difference between these three statements: "That's not going to work," "That's going to be unmaintainable in six months," and "That's not how I would do it, but it works and it's readable, so ship it." Learn how to be a mentor to those who know less than you.
Learn how to lead. Even if, like me, you never want to be a manager, eventually you'll become a leader: you'll be helping new devs understand how the code, the deployment, the build, and the company work, and what the business logic behind it all. When leadership goes awry, ask yourself what you aren't seeing, ask yourself if you're leading or in the way, ask yourself how to best serve the people who rely on you, and ask yourself if your actions are aligned with the mission.
Most importantly of all, learn to be honest. Say "I don't know," and say it a lot. Because it's true.
You can't know everything. I don't know everything. I know a lot about Typescript, CSS, HTML, and React, and I know a lot about Python and Go, and for those I use all the guardrail tools I mentioned. I've maxed out Emacs as my IDE (and my text editor, and my story writing environment). I've used Kubernetes, Docker, Django, Rails, Prometheus & Grafana a lot at various times, but at the moment that knowledge is rusty from disuse. At one point I was a Perl, C, and C++ master, but that's twenty years in the past. I use Git for everything.
At home, I use Rust and LIT-Html, and when I need to write a script, I force myself to use HyLang, a version of Scheme that runs on the Python VM, just to make it harder, just to make my brain work a little more than it has to.
But the fact is, I'm a 55 year old developer who just loves the hell out of this stuff, and I've never stopped learning, or wanting to learn more. Admittedly, at my age and with all my distractions it's a bit harder, but I'm re-teaching myself C++ this month for a "small" side project involving an obscure bit of hardware. Both because I want to, and because it'll fix one of those legendary "itches" of open source development.
Just never stop. Get enough sleep, eat well, take a walk and meditate every day, find good companions, and remember that it's a marathon, not a sprint. Learn how to take a day off and enjoy just loafing. But remember that you, too, contain multitudes, and that the master of yourself is you. If you want to give to the world, learn where the levers are and start pulling.
And then never, ever, stop.