The big three IMNSHO are OS Design, Compiler Design, and Computer Graphics, in that order of precedence.
OS Design teaches you about trade-offs. In many academic CS courses, the answers are cut-and-dried: here's how you write a binary search, here's how you implement a hashtable, etc. In OS design, every decision has a cost, because you have to balance time spent in the kernel vs. memory cost vs. speed of user programs, and the user programs will often have wildly different usage patterns. Should you copy-on-write pages? Which scheduling algorithm should you use? There are no right answers to these questions, but there're options, there are costs, there're benefits, and these depend a lot on how your OS gets used. Much like real software.
It'll also help you understand how to write performant programs, eg. if you know that the OS uses spare memory to cache file buffers but will page out memory (at the cost of millions of CPU cycles) if physical RAM is exceeded, you might look differently on rolling your own caching layer for file contents. I'm talking to you, Squid folks. ;-)
Compiler design is essential if you want to learn how to write code that writes code, which is essential if you don't want your job to be outsourced. It teaches you about complex data structures and how they're transformed into other complex data structures, which is useful for a lot more than just general-purpose programming languages. Chances are, you'll end up writing a "little language" - even if it's just the configuration system for a large product - at some point in your career, and you're stuck with a bunch of ad-hoc hacks if you've never taken compilers.
Computer graphics I included partially because it's cool and partially because it's one of the most mathematical courses you can take in college. You learn about fast matrix transformations, computational geometry, derivatives, and how to implement abstract mathematical operations on a computer. This ends up being useful in a lot of high-paying subfields (eg. finance, search, data-mining, operations research) and a few relatively low-paying ones (eg. computer games).
Honorable mentions: AI, theory of computation, concurrency, crypto. These will probably not be directly useful in your job (except concurrency, but you can pick up a lot of the important ideas of that on your own), but they're very cool and nifty to know.
I found Digital Image Processing to be the most fun and educational and the assignments were a major reason. The visual output acts as a pretty good motivator. The same probably goes for Computer Graphics.
I was never so thrilled looking that the output of a Prolog interpreter that i made. But maybe that's just me.
For OS, I'd like to add that it's probably the first time you'll have to consider concurrency. It's easier to handle parallel programming after you've dealt with concurrency at the operating system level.
OS Design teaches you about trade-offs. In many academic CS courses, the answers are cut-and-dried: here's how you write a binary search, here's how you implement a hashtable, etc. In OS design, every decision has a cost, because you have to balance time spent in the kernel vs. memory cost vs. speed of user programs, and the user programs will often have wildly different usage patterns. Should you copy-on-write pages? Which scheduling algorithm should you use? There are no right answers to these questions, but there're options, there are costs, there're benefits, and these depend a lot on how your OS gets used. Much like real software.
It'll also help you understand how to write performant programs, eg. if you know that the OS uses spare memory to cache file buffers but will page out memory (at the cost of millions of CPU cycles) if physical RAM is exceeded, you might look differently on rolling your own caching layer for file contents. I'm talking to you, Squid folks. ;-)
Compiler design is essential if you want to learn how to write code that writes code, which is essential if you don't want your job to be outsourced. It teaches you about complex data structures and how they're transformed into other complex data structures, which is useful for a lot more than just general-purpose programming languages. Chances are, you'll end up writing a "little language" - even if it's just the configuration system for a large product - at some point in your career, and you're stuck with a bunch of ad-hoc hacks if you've never taken compilers.
Computer graphics I included partially because it's cool and partially because it's one of the most mathematical courses you can take in college. You learn about fast matrix transformations, computational geometry, derivatives, and how to implement abstract mathematical operations on a computer. This ends up being useful in a lot of high-paying subfields (eg. finance, search, data-mining, operations research) and a few relatively low-paying ones (eg. computer games).
Honorable mentions: AI, theory of computation, concurrency, crypto. These will probably not be directly useful in your job (except concurrency, but you can pick up a lot of the important ideas of that on your own), but they're very cool and nifty to know.