I’m back in school studying computer science (with a concentration in software engineering), but plan on being a competent programmer by the time I graduate, so I figure I need to learn lots of secondary and tertiary skills in addition to those that are actually part of the coursework. In parallel to my class subjects, I plan on learning HTML/CSS, SQL, Linux, and Git. What else should be on this list?
Preliminaries: Make sure you can touch type, being able to hit 50+ wpm without sweat makes it a lot easier to whip up a quick single-screen test program to check up something. Learn a text editor with good macro capabilities, like Vim or Emacs, so you can do repetitive structural editing of text files without having to do every step by hand. Get into the general habit of thinking that whenever you find yourself doing several repetitive steps by hand, something is wrong and you should look into ways to automate the loop.
Working with large, established code bases, like Vladimir_Nesov suggested, is what you’ll probably end up doing a lot as a working programmer. Better get used to it. There are many big open-source projects you can try to contribute to.
Unit tests, test-driven development. You want the computer to test as much of the program as possible. Also look into the major unit testing frameworks for whatever language you’re working on.
Build systems, rigging up a complex project to build with a single command line command. Also look into build servers, nightly builds and the works. A real-world software project will want a server that automatically builds the latest version of the software every night and makes noise to the people responsible if it won’t build, or if an unit test fails.
Oh, and you’ll want to know a proper command line for that. So when learning Linux, try to do your stuff in the command line instead of sticking to the GUI. Figure out where the plaintext configuration files driving whatever programs you use live and how to edit them. Become suspicious about software that doesn’t provide plaintext config files. Learn about shell scripting and onliners, and what the big deal in Unix about piping output from one program to the next is.
Git is awesome. After you’ve figured out how to use it on your own projects, look into how teams use it. Know what people are talking about when they talk about a Git workflow. Maybe check out Gerrit for a collaborative environment for developing with Git. Also check out how bug tracking systems and how those can tie into the version control.
Know some full stack of web development. If you want a web domain running a neat webapp, how would you go about getting the domain, arranging for the hosting, installing the necessary software on the computer, setting up the web framework and generating the pages that do the neat thing? Can you do this by rolling your own minimal web server instead of Apache and your own minimal web framework instead of whatever out of the box solution you’d use? Then learn a bit about the out of the box web server and web framework solutions.
Have a basic idea about the JavaScript ecosystem for frontend web development.
Look into cloud computing. It’s new enough not to have made it into many curricula yet. It’s probably not going to go away anytime soon. How would you use it, why would you want to use it, when would you not want to use it? Find out why map-reduce is cool.
Learn how the Internet works. Learn why people say that the Internet was made by pros and the web was made by amateurs. Learn how to answer the interview question “What happens between typing an URL in the address field and the web page showing up in the browser” in as much detail as you can.
Look into the low-level stuff. Learn some assembly. Figure out why Forth is cool by working through the JonesForth tutorial. Get an idea how computers work below the OS level. The Elements of Computing Systems describes this for a toy computer. Read up on how people programmed a Commodore 64, it’s a lot easier to understand than a modern PC.
Learn about the difference between userland and kernel space in Linux, and how programs written (in assembly) right on top of the kernel work. See how the kernel is put together. See if you can find something interesting to develop in the kernel-side code.
Learn out how to answer the interview question “What happens between pressing a key on the keyboard and a letter showing up on the monitor” in as much detail as you can.
Write a simple ray-tracer and a simple graphics program that does something neat with modern OpenGL and shaders. If you want to get really crazy with this, try writing a demoscene demo with lots of graphical effects and a synthesized techno soundtrack. If you want even crazier, try to make it a 4k intro.
Come up with a toy programming language and write a compiler for it.
Write a toy operating system. Figure out how to make a thing that makes a PC boot off the bare iron, prints “Hello world” on the screen and doesn’t do anything beyond that. Then see how far you can get in making the thing do other things.
not having to pay attention to the keyboard, your fingers should know what do without taking up mindspace
Yes, this is a critical skill. Especially when someone is learning programming, it is so sad to see their thinking interrupted all the time by things like: “when do I find the ‘&’ key on my keyboard?”, and when the key is finally found, they already forgot what they wanted to write.
your typing being able to keep up with your thinking
This part is already helped by many development environments, where you just write a few symbols and press Ctrl+space or something, and it completes the phrase. But this helps only with long words, not with symbols.
It’s not the top speed, it’s the overhead. It is incredibly irritating to type slowly or make typos when you’re working with a REPL or shell and are tweaking and retrying multiple times: you want to be thinking about your code and all the tiny niggling details, and not about your typing or typos.
It’s a good start, but I notice a lack of actual programming languages on that list. This is a very common mistake. A typical CS degree will try to make sure that you have at least basic familiarity with one language, usually Java, and will maybe touch a bit on a few others. You will gain some superpowers if you become familiar with all or most of the following:
A decent scripting language, like Python or Ruby. The usual recommendation is Python, since it has good learning materials and an easy learning curve, and it’s becoming increasingly useful for scientific computing.
A lisp. Reading Structure and Interpretation of Computer Programs will teach you this, and a dizzying variety of other things. It may also help you achieve enlightenment, which is nice. Seriously, read this book.
Something low-level, usually C.
Something super-low-level: an assembly language. You don’t have to be good at writing in it, but you should have basic familiarity with the concepts. Fun fact: if you know C, you can get the compiler to show you the corresponding assembly.
You should take the time to go above-and-beyond in studying data structures, since it’s a really vital subject and most CS graduates’ intuitive understanding of it is inadequate. Reading through an algorithms textbook in earnest is a good way to do this, and the wikipedia pages are almost all surprisingly good.
When you’re learning git, get a GitHub account, and use it for hosting miscellaneous projects. Class projects, side projects, whatever; this will make acquiring git experience easier and more natural.
I’m sure there’s more good advice to give, but none of it is coming to mind right now. Good luck!
Sorry if I wasn’t clear. I intended the list to include only skills that make you a more valuable programmer that aren’t explicitly taught as part of the degree. Two Java courses (one object-oriented) are required as is a Programming Languages class that teaches (at least the basics of) C/C++, Scheme, and Prolog. Also, we must take a Computer Organization course that includes Assembly (although, I’m not sure what kind). Thanks for the advice.
In school you are typically taught making small projects. Make a small algorithm, or a small demonstration that you can display an information in an interactive user interface.
In real life (at least in my experience), the applications are typically big. Not too deep, but very wide. You don’t need complex algorithms; you just have dozens of dialogs, hundreds of variables and input boxes, and must create some structure to prevent all this falling apart (especially when the requirements keep changing while you code). Also you have a lot of supporting functionality in a project (for example: database connection, locking, transactions, user authentification, user roles and permissions, printing, backup, export to pdf, import from excel, etc.). Again, unless you have structure, it falls apart. And you must take good care of many things that may go wrong (such as: if the user’s web browser crashes, so the user cannot explicitly log out of the system, the edited item should not remain locked forever).
To be efficient at this, you also need to know some tools for managing projects. Some of those tools are Java-specific, so your knowledge of Java should include them; they are parts of the Java ecosystem. You should use javadoc syntax to write comments; JUnit to write unit tests; Maven to create and manage projects, some tools to check your code quality, and perhaps even Jenkins for continuous integration. Also the things you already have on your list (HTML, CSS, SQL, git) will be needed.
To understand creating web applications in Java, you should be able to write your own servlet, and perhaps even write your own JSP tag. Then all the frameworks are essentially libraries built on this, so you will be able to learn them as needed.
As an exercise, you could try to write a LessWrong-like forum in Java (with all its functionality; of course use third-party libraries where possible); with javadoc and unit tests. If you can do that, you are 100% ready for the industry (the next important skill you will need is leading a team of people who don’t have all of these skills yet, and then you are ready for the senior position). But that can take a few months of work.
There is another aspect of working on big projects that seems equally important. What you are talking about I’d call “design”, the skill of organizing the code (and more generally, the development process) so that it remains intelligible and easy to teach new tricks as the project grows. It’s the kind of thing reading SICP and writing big things from scratch would teach.
The other skill is “integration”, ability to open up an unfamiliar project that’s too big to understand well in a reasonable time, and figure out enough about it to change what you need, in a way that fits well into the existing system. This requires careful observation, acting against your habits, to conform to local customs, and calibration of the sense of how well you understand something, so that you can judge when you’ve learned just enough to do your thing right, but no less and not much more. Other than on a job, this could be learned by working a bit (not too much on each one, lest you become comfortable) on medium/large open source projects (implementing new features, not just fixing trivial bugs), possibly discarding the results of the first few exercises.
I’ve TAed a class like the Programming Languages class you described. It was half Haskell, half Prolog. By the end of the semester, most of my students were functionally literate in both languages, but I did not get the impression that the students I later encountered in other classes had internalized the functional or logical/declarative paradigms particularly well—e.g., I would expect most of them to struggle with Clojure. I’d strongly recommend following up on that class with SICP, as sketerpot suggested, and maybe broadening your experience with Prolog. In a decade of professional software engineering I’ve only run into a handful of situations where logic programming was the best tool for the job, but knowing how to work in that paradigm made a huge difference, and it’s getting more common.
I’m back in school studying computer science (with a concentration in software engineering), but plan on being a competent programmer by the time I graduate, so I figure I need to learn lots of secondary and tertiary skills in addition to those that are actually part of the coursework. In parallel to my class subjects, I plan on learning HTML/CSS, SQL, Linux, and Git. What else should be on this list?
Preliminaries: Make sure you can touch type, being able to hit 50+ wpm without sweat makes it a lot easier to whip up a quick single-screen test program to check up something. Learn a text editor with good macro capabilities, like Vim or Emacs, so you can do repetitive structural editing of text files without having to do every step by hand. Get into the general habit of thinking that whenever you find yourself doing several repetitive steps by hand, something is wrong and you should look into ways to automate the loop.
Working with large, established code bases, like Vladimir_Nesov suggested, is what you’ll probably end up doing a lot as a working programmer. Better get used to it. There are many big open-source projects you can try to contribute to.
Unit tests, test-driven development. You want the computer to test as much of the program as possible. Also look into the major unit testing frameworks for whatever language you’re working on.
Build systems, rigging up a complex project to build with a single command line command. Also look into build servers, nightly builds and the works. A real-world software project will want a server that automatically builds the latest version of the software every night and makes noise to the people responsible if it won’t build, or if an unit test fails.
Oh, and you’ll want to know a proper command line for that. So when learning Linux, try to do your stuff in the command line instead of sticking to the GUI. Figure out where the plaintext configuration files driving whatever programs you use live and how to edit them. Become suspicious about software that doesn’t provide plaintext config files. Learn about shell scripting and onliners, and what the big deal in Unix about piping output from one program to the next is.
Git is awesome. After you’ve figured out how to use it on your own projects, look into how teams use it. Know what people are talking about when they talk about a Git workflow. Maybe check out Gerrit for a collaborative environment for developing with Git. Also check out how bug tracking systems and how those can tie into the version control.
For the social side of software development, Peopleware is the classic book. Producing Open Source Software is also good.
Know some full stack of web development. If you want a web domain running a neat webapp, how would you go about getting the domain, arranging for the hosting, installing the necessary software on the computer, setting up the web framework and generating the pages that do the neat thing? Can you do this by rolling your own minimal web server instead of Apache and your own minimal web framework instead of whatever out of the box solution you’d use? Then learn a bit about the out of the box web server and web framework solutions.
Have a basic idea about the JavaScript ecosystem for frontend web development.
Look into cloud computing. It’s new enough not to have made it into many curricula yet. It’s probably not going to go away anytime soon. How would you use it, why would you want to use it, when would you not want to use it? Find out why map-reduce is cool.
Learn how the Internet works. Learn why people say that the Internet was made by pros and the web was made by amateurs. Learn how to answer the interview question “What happens between typing an URL in the address field and the web page showing up in the browser” in as much detail as you can.
Look into the low-level stuff. Learn some assembly. Figure out why Forth is cool by working through the JonesForth tutorial. Get an idea how computers work below the OS level. The Elements of Computing Systems describes this for a toy computer. Read up on how people programmed a Commodore 64, it’s a lot easier to understand than a modern PC.
Learn about the difference between userland and kernel space in Linux, and how programs written (in assembly) right on top of the kernel work. See how the kernel is put together. See if you can find something interesting to develop in the kernel-side code.
Learn out how to answer the interview question “What happens between pressing a key on the keyboard and a letter showing up on the monitor” in as much detail as you can.
Write a simple ray-tracer and a simple graphics program that does something neat with modern OpenGL and shaders. If you want to get really crazy with this, try writing a demoscene demo with lots of graphical effects and a synthesized techno soundtrack. If you want even crazier, try to make it a 4k intro.
Come up with a toy programming language and write a compiler for it.
Write a toy operating system. Figure out how to make a thing that makes a PC boot off the bare iron, prints “Hello world” on the screen and doesn’t do anything beyond that. Then see how far you can get in making the thing do other things.
Also this list looks pretty good.
Regarding touch-typing, do you find yourself reaching ‘top speed’ often while programming?
It’s not really about typing large amounts of text quickly, it’s basically about
(1) not having to pay attention to the keyboard, your fingers should know what do without taking up mindspace; and
(2) your typing being able to keep up with your thinking—the less your brain has to stop and wait for fingers to catch up, the better.
Yes, this is a critical skill. Especially when someone is learning programming, it is so sad to see their thinking interrupted all the time by things like: “when do I find the ‘&’ key on my keyboard?”, and when the key is finally found, they already forgot what they wanted to write.
This part is already helped by many development environments, where you just write a few symbols and press Ctrl+space or something, and it completes the phrase. But this helps only with long words, not with symbols.
It’s not the top speed, it’s the overhead. It is incredibly irritating to type slowly or make typos when you’re working with a REPL or shell and are tweaking and retrying multiple times: you want to be thinking about your code and all the tiny niggling details, and not about your typing or typos.
For a decent summary, here’s a pretty well-written survey paper on cloud computing.. It’s three years old now, but not outdated.
It’s a good start, but I notice a lack of actual programming languages on that list. This is a very common mistake. A typical CS degree will try to make sure that you have at least basic familiarity with one language, usually Java, and will maybe touch a bit on a few others. You will gain some superpowers if you become familiar with all or most of the following:
A decent scripting language, like Python or Ruby. The usual recommendation is Python, since it has good learning materials and an easy learning curve, and it’s becoming increasingly useful for scientific computing.
A lisp. Reading Structure and Interpretation of Computer Programs will teach you this, and a dizzying variety of other things. It may also help you achieve enlightenment, which is nice. Seriously, read this book.
Something low-level, usually C.
Something super-low-level: an assembly language. You don’t have to be good at writing in it, but you should have basic familiarity with the concepts. Fun fact: if you know C, you can get the compiler to show you the corresponding assembly.
You should take the time to go above-and-beyond in studying data structures, since it’s a really vital subject and most CS graduates’ intuitive understanding of it is inadequate. Reading through an algorithms textbook in earnest is a good way to do this, and the wikipedia pages are almost all surprisingly good.
When you’re learning git, get a GitHub account, and use it for hosting miscellaneous projects. Class projects, side projects, whatever; this will make acquiring git experience easier and more natural.
I’m sure there’s more good advice to give, but none of it is coming to mind right now. Good luck!
Sorry if I wasn’t clear. I intended the list to include only skills that make you a more valuable programmer that aren’t explicitly taught as part of the degree. Two Java courses (one object-oriented) are required as is a Programming Languages class that teaches (at least the basics of) C/C++, Scheme, and Prolog. Also, we must take a Computer Organization course that includes Assembly (although, I’m not sure what kind). Thanks for the advice.
In school you are typically taught making small projects. Make a small algorithm, or a small demonstration that you can display an information in an interactive user interface.
In real life (at least in my experience), the applications are typically big. Not too deep, but very wide. You don’t need complex algorithms; you just have dozens of dialogs, hundreds of variables and input boxes, and must create some structure to prevent all this falling apart (especially when the requirements keep changing while you code). Also you have a lot of supporting functionality in a project (for example: database connection, locking, transactions, user authentification, user roles and permissions, printing, backup, export to pdf, import from excel, etc.). Again, unless you have structure, it falls apart. And you must take good care of many things that may go wrong (such as: if the user’s web browser crashes, so the user cannot explicitly log out of the system, the edited item should not remain locked forever).
To be efficient at this, you also need to know some tools for managing projects. Some of those tools are Java-specific, so your knowledge of Java should include them; they are parts of the Java ecosystem. You should use javadoc syntax to write comments; JUnit to write unit tests; Maven to create and manage projects, some tools to check your code quality, and perhaps even Jenkins for continuous integration. Also the things you already have on your list (HTML, CSS, SQL, git) will be needed.
To understand creating web applications in Java, you should be able to write your own servlet, and perhaps even write your own JSP tag. Then all the frameworks are essentially libraries built on this, so you will be able to learn them as needed.
As an exercise, you could try to write a LessWrong-like forum in Java (with all its functionality; of course use third-party libraries where possible); with javadoc and unit tests. If you can do that, you are 100% ready for the industry (the next important skill you will need is leading a team of people who don’t have all of these skills yet, and then you are ready for the senior position). But that can take a few months of work.
There is another aspect of working on big projects that seems equally important. What you are talking about I’d call “design”, the skill of organizing the code (and more generally, the development process) so that it remains intelligible and easy to teach new tricks as the project grows. It’s the kind of thing reading SICP and writing big things from scratch would teach.
The other skill is “integration”, ability to open up an unfamiliar project that’s too big to understand well in a reasonable time, and figure out enough about it to change what you need, in a way that fits well into the existing system. This requires careful observation, acting against your habits, to conform to local customs, and calibration of the sense of how well you understand something, so that you can judge when you’ve learned just enough to do your thing right, but no less and not much more. Other than on a job, this could be learned by working a bit (not too much on each one, lest you become comfortable) on medium/large open source projects (implementing new features, not just fixing trivial bugs), possibly discarding the results of the first few exercises.
I’ve TAed a class like the Programming Languages class you described. It was half Haskell, half Prolog. By the end of the semester, most of my students were functionally literate in both languages, but I did not get the impression that the students I later encountered in other classes had internalized the functional or logical/declarative paradigms particularly well—e.g., I would expect most of them to struggle with Clojure. I’d strongly recommend following up on that class with SICP, as sketerpot suggested, and maybe broadening your experience with Prolog. In a decade of professional software engineering I’ve only run into a handful of situations where logic programming was the best tool for the job, but knowing how to work in that paradigm made a huge difference, and it’s getting more common.