When working on a project, any project really, but especially one of this magnitude, it's important to have a solid strategy and paradigm for development. Too often people pencil out a rough design for their project and then eagerly jump into coding, only to find out that their earlier assumptions were incorrect. What should happen at this point is that small changes are made here and there, which allows the developer to get back on track. Unfortunately, the reality is often quite different. Due to their eagerness to get coding quickly, they fail to design enough flexibility into their project, and so must now either scrap a large percentage of it, or trudge along with a less than desirable interface and framework with which to work with. This often leads to a failed or incomplete project.
During the course of this little experiment I will be relying on my education both from practical experience as well as from schooling to help keep things running smoothly. First, lets take a look at the phases of development. Most projects/applications are divided up into four parts: Analysis, Design, Implementation, and Testing.
During the analysis phase a software engineer gathers the requirements from end users or superiors in order to determine what exactly it is s/he's developing. For the sake of this little experiment, the analysis so far is mostly my previous journal entry. It, roughly speaking, is a list of features and expected behavior for the application. In general, the analysis should be entirely complete even before design begins. Otherwise, your parameters for design are already flawed, which guarantees that you will have to make design changes at a later date. So what's the moral of the story? I still need to go back and describe, in fuller detail, what the features and behaviors of the application will be. Now, this isn't a technical thing, but rather an 'experience' thing. Analysis should always be done from the perspective of the end-user.
Once a complete analysis of the program being developed has been made, the technical design begins. Ironically, when I used to work for Liquid Entertainment we would have weekly code reviews on Fridays. The goal of this is still a mystery to me, but the outcome was that every Friday we would waste an afternoon in order to look over the code and systems that had ALREADY been written, in order to make sure it was designed correctly, the code was elegant, and the overall implementation met with company style guidelines, etc...Now, I say 'ironically' because at this point the systems had already been written. It was, as implied by the meeting title, a review of what had just been accomplished. Now, I don't claim to be a genius, but had they been following strategic development paradigms, they might have realized that a "Code Preview" might have been more effective. In this way, the developers could have met on Monday mornings, and taken a look at how their systems were going to interact throughout the week, come up with appropriate interfaces, etc...so that when Friday came they were confident that they had engineered, together or in small groups, a design for the systems which was as elegant and modular as possible.
So what's the moral of the story? Before even a line of code is written, a full systems design should be written up which details what systems will exist, when they will be introduced, what their interfaces will look like, and what other systems they are expected to interact with. Will this design be perfect - no. There are, by and large, always mistakes or oversights which must be rectified during actual implementation. But having an awareness of the application as a whole and it's various systems means that from the beginning there will be an understanding of the relationships between systems and can thus be engineered with as little coupling as possible - allowing for maximum flexibility when (not if) the time comes that a modification to the design is required.
I will come back to this after I discuss the last stage of development. Primarily because I've developed my own paradigm to implementation which I feel deserves a bit of extra attention, and I don't want to dwarf its importance by following up with the final stage of development. That just seems anticlimactic.
The final stage of development is testing. Wait, that doesn't make any sense. In modern practice testing is done throughout the implementation cycle, and thus makes little sense as a final phase. Now, one could argue that this phase is really just an extension of the implementation phase, and that it means after each compile, tests should be performed, but if that's the case, I don't believe it deserves its own phase. Most developers now agree that testing is an integral part of implementation, to the point where programming paradigms such as eXtreme Programming (XP) have even made strong cases for testing even BEFORE implementation. Now, I'm not quite that masochistic (yeah right, prove it!), but I do believe that unit testing as well as integration testing should be key aspects to anyone's development cycle. So what do we do with the final phase of development? Optimize it! That's right. Borrowing from eXtreme Programming we will always...optimize last! This means that although performance should always be a consideration when developing algorithms, etc...performance should not be the primary concern during implementation. Instead, we'll make a second pass over a system after it's complete and meets all unit tests, in order to increase performance and make it more efficient. So, what's the moral of the story? We need to use a unit testing framework such as nUnit during development to make sure our systems always run as expected. And then, and only then, we'll make sure everything is optimized and runs as efficiently as possible.
Implementation Part 2 (The Rope Bridge Philosophy)
While I was working as the tools lead at Pandemic Studios I adopted what I call the "Rope Bridge" analogy, and used it to describe to my juniors the best way to proceed with implementation. Sit back, relax, and clear your mind as I illuminate for you an ancient and mystic method for implementing your projects.
A project is broken up into systems, systems are broken up into classes, and classes are broken up into methods and properties. Any time you are given a task, you are being asked to implement either a system, class, or some sub-component within a class. Understandably, your first instinct is to figure out where you are now, and where you need to be in order to call your task 'complete.' Now, there are two ways to do this. One is to begin coding from where you are, adding new functionality, building out your classes and systems, etc...until you eventually end up at your destination. This is, metaphorically speaking, the equivalent to standing on one side of a large chasm and beginning to build a large concrete bridge as you walk across. As most civil engineers will tell you, this is a very daunting task, and requires hair-line precision. An inch off in either direction can send your bridge off to one side or another or drive it into the side of the cliff. At the same time, concrete bridges are known for being sturdy, immovable, and well...just plain not very flexible. With programming it's no different. Trying to get completely from point A to point B requires a good deal of foresight, which is made even more difficult when attempting to develop a system which is flexible. This leads us to the alternative...The Rope Bridge.
Imagine you are standing on the same chasm, and have been given the task of getting to the other side. Instead of working from beginning to end, developing a cement bridge, instead, build a rope bridge. A rope bridge is the smallest, most fragile form of passage from one side to the other. It doesn't hold a lot of weight, doesn't allow many paths from one side to the other, tends to be a bit low hanging, but damn it's flexible.
From a programming standpoint, this means take the easiest route from point A to point B, with the least amount of code necessary to accomplish the minimum specification required. In other words..."Just barely get it working." Once you've accomplished this, you've successfully built your rope bridge. This makes testing possible, allows for immediate user feedback, and gives you an idea of what you may be able to expect from your bridge (and the chasm) in the near future. Once the rope bridge has been built, your job becomes clearer. It's time to add some suspension (stability) to it. This means making it safer. This can include assertions, or other debugging tools which helps to guarantee your code will be more secure.
Next, you must make the bridge wider. It's great that you've got this little suspension bridge, but if it only allows the "Diamond in The Rough" to cross the bridge it wont prove very useful. This comes in the form over method/operator overloading, properties, conversion classes, and anything else which allows more methods of accomplishing the goal you've already completed. Why do this? Ease of use, and flexibility. Always design your systems to be just a bit more flexible than you think is necessary.
Finally, pave your bridge and make it solid. I'm not sure how this applies to the coding paradigm exactly, but the best I can guess, it means prepare the code/system you've created for higher volume of invocations, and make sure its stable enough to accept the most unexpected circumstances. How you go about doing this seems to be more case-by-case and depends on the type of system you're implementing. In general though, this involves a bit of refactoring and cleanup. Always make sure your code is precise and concise.
So what's the moral of the story? BUILD A ROPE BRIDGE!!
Well folks, that just about wraps it up for this entry. Hopefully, by taking all of the above into considering, along with abstraction, divide and conquer, and other proven software engineering techniques I should be able to move forward with MiniMORPG with as few hiccups as possible. Let me know your thoughts, and as always, check back soon as I continue the battle of "Man vs. The MMORPG!"