Programmers are by and large lucky for having the luxury of practicing what they enjoy virtually anywhere. Compare that to most engineering disciplines and you’ll see that you can’t go far in your garage. May be electrical engineering comes in next, but that’s about the closest you get. Programmers on the other hand can code anything. I mean, anything. The only costs are the hardware (dirt cheap, by the way) and the time to do it. Want to create your game, no problem. Try an OS! Crazy, but doable. And the thing that really tops it all, is that you don’t need to move from your chair, or bed!
This is not a tiny advantage. I’d argue it is the number one reason behind the boom that the field experienced. It’s still going strong. There was a time though when things weren’t any different from rocket science. But that was before the 80’s and the affordable generation of PCs.
So since anything is possible, let’s see what are the top problems any serious programmer should solve at least once (in many cases a dozen!). Here is my list of the top 5 problems that I think give the maximum benefit when solved per unit time spent solving them. These have the benefits of being limited in scope, touch on many areas and sub-issues and are potentially useful. Also, they require only the most basic knowledge and tools to solve. You can solve any and all of them in text mode. Even the games may be simulated with text-based interfaces (although that way you won’t learn about graphics).
This is really simple. Just write a program that would do the 4 basic math operations: add, subtract, multiply and divide. Then add some more. The point of the exercise is of course parsing and operator precedence. You are exposed to the world of parser design, expression trees and possibly symbol tables (if you add variables or unknowns to the mix). What I like about this problem is that it’s very easy to get a basic version running and then add complexity. Also, you get to define the rules (such as precedence) and complexity (whether there are parens and variables or not). It pays off real quick.
2) Arcade Games
I’d say Tetris, but I don’t think it’s the only one that qualifies. There are so many games one can write that have the same basic features: Pacman, Arkanoid, Snakes and Sokoban just to name a few. The main benefit is to design a state-machine, real-time processing, AI, Graphics, collision-detection and much more. Yet another problem that may start with very limited features and extended as much as necessary. 3D worlds not being an exception. Besides being fun, games are so multi-faceted that you have to touch upon so many domains and problems that they are very educational. The experience is just unparalleled.
3) Maps and Trees
You can’t go far without arrays and list and queues and the numerous data structures. Most programmers have to write similar structures indirectly and unintentionally. Still, many try to dodge writing them by using standard libraries or 3rd party code. There is nothing like writing an abstract map based on a hash-table and another based on a binary search tree and put them head-to-head in performance comparison. Try programming a map that would beat your best alternative in both speed and space. Balancing trees is yet another complex problem. Many algorithms with many trade offs. The benefits of this problem is to learn more about the basic tools of the trade while learning all about complexity and efficiency along the way. Did I mention that you will use lists and arrays in maps and trees? Writing highly efficient maps and trees is one challenging task that is not even apparent until you start thinking about it.
There are multi-million dollar databases out there. But can you create your home-grown version that has any number of the features the big guys have? Try something that is as flexible as storing any data type. Then add efficient searching features. Then try adding relations, hierarchies, indexing, even a query language! You’ll learn all about file formats, on-the-wire data types, serialization, complex data structures, sorting and searching, data manipulation and data mining to name a few. Furthermore, you’ll appreciate what it takes to create efficient and scalable data structures on and off the disk.
This is one of the most complex problems of the programming world. I’m of course talking about compilers and language design. Try writing an interpreter for a popular language or a dialect of one. Say Basic or Pascal. Try Lisp. Why not even go as far as inventing your own. You’ll learn about language design, parsing, symbol tables, optimization, simulation, automata and many, many more. This is not only fun, but it’s also a very challenging task. I can’t promise that it would become the next big thing, in fact, it probably will only be used by you. But this is one of the more challenging problems that may be limited in scope and extended as needed. And if you feel crazy, write a debugger for your interpreter.
I’m sure one may add other problems, replace some in my list or simply say there is no such list. Anyway, here you have it. This is what I’d recommend for practice.