I was talking with some of my fellow students today and the discussion turned to academic projects. Which academic projects had us learn the most?
Most of the examples that I heard were projects that were overly easy. Very little thought process was put in place for these. The student was able to complete it way ahead of the deadline by applying an established design principle or design pattern. Basically, a problem was given to a student who already knew the answer.
This isn't learning. This is merely practice.
Problems like these definitely have their place in a college curriculum. Practice is essential to hone any skill and keep it sharp. Major League ballplayers don't stop hitting balls in batting practice once they've learned the exact technique their hitting coaches want them to learn. Likewise, programmers shouldn't stop applying existing design patterns to new problems that merit the pattern once they've learned it.
Practicing skills was not the topic of the original question. We asked which project had us learn the most. My answer was a project that I came very close to failing. Some of the guys in the conversation had the same class and the same project, and they shuddered at the thought of it. Many of them had failed that project in at least one requirement of the assignment.
What was the project? It was in a class called Game Console Development and involved writing a working video game in the XNA 4.0 framework that would run on both a PC and an X-Box 360. The course itself was six weeks long, with five weeks given to the project, full of all the standard reading and assignments given in any college course.
This project was not a greenfield project. A greenfield project, for those not familiar with the term, is a code project created from scratch. Those projects tend to be easier for college undergrads because that individual has no questions about the framework because he or she wrote all of it. This project used the XNA 4.0 framework, which is vast and documented (quite well) over at the MSDN web-site. Not only did we have to contend with this framework that was brand new to most of us, but we were also given another framework inside of that one to build around.
Because of the length of the course, our instructor wanted us to spend most of our time on programming game logic and not setting up an infrastructure to display menus and options and load the game assets. At first, this was a welcome blessing. The menu system seemed easy enough to understand with the example code at first glance.
Then we were asked to change it. Because we couldn't leave the default settings for these menus in place since they had nothing to do with our game. The blessing quickly became a curse.
If you would like to check out the code in question, titled Game State Management Example, it is available for everyone here.
Now, looking at this production quality code, written by some great software developers who are loads smarter than I am, made me feel inferior. Not only had I never written anything close to this elegant, beautiful sample framework, but at first I couldn't tell you what many of the lines actually did. It was all Greek to me. I got the overall picture, but instead of using this framework as a black box, I was expected to open it up and tinker with the fragile components. What does this do? I had no idea where to start. Changing some of the code often left me with a bunch of code that no longer compiled.
Now, compare this to the projects discussed earlier, where the students had a clear idea of what was needed and knew every line of code by heart because they authored it. Those projects were practice, and this was learning.
I knew what the results of the sample were. I had run the code on both my PC and X-Box 360. There was an abstract data type that defined what a screen was, and then there were classes that used these defined screen properties to define specific types of screens. That much was clear. I could also find the one screen that proudly displayed the message, "Game code goes here..." So, my game would be coded there, but for the rest of it...I had no idea.
I wanted to be angry with my instructor for working up the assignment this way. Why would he give us code that was so advanced compared to our study of .NET and C# that we would have no idea how to work with it? I tried to bring this up to him as politely as I could, and he gave me an answer. His answer was so important to how things actually worked, and I felt like an idiot for not realizing it.
My instructor, Andy Dunn, formerly of Microsoft and now senior game programmer extraordinaire at Exato Game Studios, told me that rarely in the real world would I be implementing code from scratch. More likely, I will debug, maintain, and add to existing code much like we were doing in this assignment. I was floored, like a boxer who is staring at the stadium lights and can't find the will or energy to stand back up for another round. I was ready to tell myself that if I couldn't understand this, then I shouldn't be in software development.
Good thing I didn't listen to myself about quitting.
There was a lot of trial and error. There was a lot of back-and-forth discussion about the fine details of the framework with Andy. And there was a lot of frustration. But, I ended the course with a passing project. I had not been able to implement all of the features that I wanted to, but I was able to implement all of the features required for the assignment and then some. I was also able to secure some positive feedback from Andy, who told me it looked very polished, you know, for a student project.
I came very close to failing this project because I was ready to quit. I was frustrated with not knowing how all of this code worked. To me, it was pure voodoo. The Microsoft team that wrote it was using arcane PC wizardry to get XNA and .NET to do things I had never been exposed to. I saw little value in using this framework as a foundation for my game, until my mentor stepped in and got me to do it. I forced myself to continue failing at this project until I got it working.
And then I no longer felt like a failure, but rather like a ragged and tattered survivalist who was lost at sea. The design patterns and challenges about sorting small arrays and comparing drop-down list items and writing classes to do binary arithmetic were simply the kiddie-pool. I now saw the actual danger of the open sea and how easy it was to get swept away and drown. To avoid drowning, I would need to be able to dive into huge waves and swim for my life by picking through unfamiliar code and somehow making it work.
Microsoft Research published a paper on some of the skills that fresh graduates lack upon obtaining their first software developer position. Not surprisingly, working on a team with a large established code base was one of the top issues highlighted in the paper. I still feel inferior when comparing myself to some of the best that Microsoft has to offer, but I feel a bit better after reading that new hires in that company experienced some of the same problems that I did on my academic project.
What did I learn during this course? I learned that existing codebases take a lot of time to get familiar with when they are new to you. I learned that trial and error does not mean I'm a total idiot. I learned that three years of study lets me get out of the kiddie pool and see firsthand how much knowledge is actually present in the software development industry. But, the most important lesson of all, I learned that there is a fine line between learning and failure.