Three Secrets of Great Programmers
Occasionally, I ask myself what professional advice I wish I’d been given earlier in my career. You know, like the kinds of things your grandmother would have told you, if only your grandmother had been a software engineer instead of an English teacher, and you’d been listening?
Strap yourself in. Here comes another link bait-headlined episode of ramblings on software engineering.
Assuming you work in software, you’ve no doubt noticed how engineers vary widely in intellectual style and capabilities. Some are good — they know stuff, they get things done, and people respect them. Some are are really good — they move faster, are more reliable, know even more, or can solve the toughest problems. And a few are great: They do everything the good ones do, but somehow they make a whole team more productive.
The funny thing is, if you ask some of these great software engineers how you can become stronger, you’ll get lots of different answers. Some will suggest you try programming competitions. Some will suggest you hack low-level code first so you really understand hardware. Others will say it doesn’t matter what you do, as long as you write a lot of code. Or maybe they’ll insist on starting with strong foundations in algorithms and computer science. A few will secretly believe you have no hope if you didn’t start hacking disk drive controllers at six years old, like they did.
Instead of specific recommendations, I think it’s interesting to consider some more philosophical points. These three points are not direct advice, but they are somewhat counter-intuitive observations that seem to be second nature to some of the great engineers I’ve been lucky enough to work with.
Code is for humans, not for computers.
As you begin programming, the challenge is simply to get a computer to do what you want it to do. You might think of it as communicating with the computer, and it can even be fun to do this in as direct a way as possible, such as in C or assembly language. But the novelty wears off. Most programmers realize that in a lot of situations, this can be difficult and an inefficient use of their time. So whenever possible, they use higher-level languages and frameworks that are easier to write in.
But there is a more subtle point even some experienced programmers forget: As systems evolve, more time will be spent reading, debugging, and changing the code than writing it. Really, in software engineering, the true goal of writing code is not to give the computer (or more generally, the distributed system) commands, but to communicate to yourself and to other engineers what the whole system should do. Now — and in the future as you change it. As a side effect, you produce code that works (and, if you’re good at it, also runs efficiently). So when picking or building languages and frameworks, think what will best support communication with people. While deep or clever hacks are impressive and fun, becoming a better software engineer is often really about finding ways for code to convey its own meaning in a clean, maintainable, and understandable way.
You never “don’t need to know that.”
On the other hand, don’t misconstrue the previous point as saying you should only program at a high level and not worry about lower-level parts of a system. As you begin using complex tools and working on larger teams, you can often do a lot without understanding some details, because the system supports you, or because someone else is handling that other part of the system. If you use an ArrayList in Java, you don’t have to do anything to resize or to free the memory. If you use a remote filesystem like NFS, you can treat a file on another server just like a local file. If you use a library from someone, you don’t need to read its source code.
This is both convenient and necessary much of the time. But never forget (or neglect learning) what’s really going on. You do need to worry about that stuff. You might be writing in Python, but have you ever looked at the source code for Python’s libraries or the interpreter? If you build an API that has 200ms latency, do you know how much is network, how much is disk, how much is CPU? When Firefox makes an HTTP request, how many sockets does it use, and which headers does it send and why? When you run “top” in Linux, do you know what every number on the screen means? In any real engineering situation, these details will come up. Maybe not right away, but eventually. Be lazy about how much code you write, but never be lazy about knowing what’s going on under the hood. Become a sponge for technical information. Prod yourself into learning new programming languages or working on new kinds of projects on a regular basis. This tendency to absorb information is one of the most important characteristics of great engineers.
Technologies don’t matter.
As programmers, we love to talk about technology. Is Ruby better than Python, or is Node now the obvious choice? Which RPC layer is faster? Should certain data be stored in Cassandra or MySQL? This is great, and you should know and have opinions about those topics (especially if you’ve followed the advice in the previous point). But quite surprisingly, if you look at successful and unsuccessful engineering efforts, there is essentially no correlation between success and the exact types of technologies that are used. What matters is who is working on a team, how they use the technologies, and how they work together to build, ship, and improve a product. Good software engineering is done by good software engineers. It’s rarely done with the perfect programming language, or using the most hyped new technology. A lot of the hardest challenges in software development concern the way people communicate and manage complex code, systems, and processes, not in raw technology.
There are many important corollaries to this: Pick programming languages you or your team use well, or are aligned with the market, or are popular enough you can hire folks. Be pragmatic, not religious about how you solve problems. Learn by working with great engineers of all types, and seeing how they solve problems. Realize that having a strong team with a good engineering culture is more important than any particular technology.
If you’re not already suffering pontification overload, check out the previous episode.