Jump to content
  • Advertisement
Sign in to follow this  
ToohrVyk

Merciless postmortem

This topic is 4251 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

A year ago (may 2006), I examined my approach to development in an attempt to improve it. I designed a new approach at that time, inspiring myself from agile development in general, XP in particular, with much help from browsing the C2 wiki, and adapting it to my specific needs and documented human weaknesses. I have been using this new approach for the last year on four projects (a school project, a web site which landed me a job, my job itself, and a recently started video game), and I would like to look back on what this has accomplished. And, of course, share it with you [smile] My approach up until 2006 had been one of "design, program, debug", where I wrote up a detailed document describing what the program should ultimately do, along with possible extensions, then doodled up a class diagram on note paper, and then moved on to actually implementing the thing. The main issues I identified with this approach, and attempted to correct, were:
  • Analysis paralysis, when writing the design document or doodling out the classes was moving slower than my creativity, so the backlog kept on increasing.
  • Elegance in design: I always strived to design the program in the most elegant and precise way, finding simple yet creative means of achieving things, and always identifying and then using the best tool for every single job. The downside was rigidity, because the elegant solution relied on specific assumptions, and required a complete rewrite for every modification.
  • Write and forget: I used encapsulation to hide away the implementation of modules. This had the unwanted disadvantage of letting me get away with an ugly and badly commented implementation (because I would write it once, and then never read it again). This made changing the implementation extremely hard, even though the interface itself was squeaky clean.
And so, to correct these specific problems, I adapted agile programming methodologies to my particular psychology. I reused or made up the following rules for my development, and strived to follow them during development:
  • Do things, then do things right: this is the basic principle that I've decided to go with. Development is divided into feature-addition steps where new functionality is added to the program (do things), followed by refactoring steps where new and old functionality is rewritten in part to fit in a better design (do things right). The idea is that flaws in the reusability, maintainability or extensibility of code are most proeminent when trying to reuse, maintain or extend said code. By forcing myself to regularly run through older code in order to refactor it, I can notice rigidity before it sets in too hard—and since I'm in a refactoring phase, I can correct that on the spot. Another reason why I've decided to hold this principle is that you can only do something right after you've done it wrong once—meaning that getting things running on the first try requires too much work, so it's easier to prototype, diagnose, rewrite. The knowledge that a refactoring step will follow every modification is reassuring, and lets me get straight to the point (Do The Simplest Thing That Could Possibly Work) without regard for design rules.
  • Have something to show: the idea is that at the end of each development session (those sessions where features are added), the program should be doing something that it didn't before, and that something should be visible. For instance, a new module passes its corresponding unit test, or a new type of graphics effect appears on the screen. Adding code for a loader that will not be used until next week does not fall under this concept. In itself, this rule is a mix of YAGNI (You Ain't Gonna Need It) and test-driven development. The main objective is to prevent analysis paralysis, because new features are not designed or incorporated into the program unless they can be seen right away—which means they're already available for testing and judging if they stay. A secondary objective here is upholding morale (because the program does new things).
  • Conformism beats perfection: I must refrain from using the best tool for every particular job. The first reason is that deciding which tool is best is often a subjective opinion. The second reason is that deciding takes time, which would be better spend getting things to work using a good enough tool. The third reason is that the decision is either wrong from the outset, or becomes wrong the next time the code is modified. The fourth reason is that best tools tend to be unique and esoteric, which makes them a bad choice in situations where refactoring need to happen often. So, I settle for a small set of tools which I use in general situations. For instance, I have decided that all object creations must be performed through constructors, including factories, which lets me move from one implementation of creation to another (the constructor contents) without having to change the interface (constructor to function, function to constructor). Another such decision is global variables: while globals sometimes are the best tool for the job, deciding whether they are or not takes more time than giving them up and making the code fully parametric.
The result so far is that it works: code I write now is more easily modified than before, and follows a more flexible and reusable object-oriented structure than rigid code I used to write. I also write code faster, because I spend less time designing unneeded things, because my main objective is getting things done, and because time spent refactoring is smaller than the time I would have spent circumventing mistakes in a rigid and awkward design. It's not perfect, though. Constant refactoring does help the code become easier to modify, but frequent reading prevents me from noticing how badly documented it can be, and things get difficult when a module isn't refactored for a while. Also, motivation decreases greatly during the refactoring steps (because I'm not getting things done, I'm just rewriting working stuff), especially when they are long, which often bores me to death and makes me become sloppy. Overall, however, I'm pretty happy with how it turned out, because I churn out clearer and better code now than I did before.

Share this post


Link to post
Share on other sites
Advertisement
Great read. Basically what I do except sometimes I push off refactoring for a bit until I have a better idea of how the components will fit together.

Quote:
Original post by ToohrVyk
  • Have something to show: the idea is that at the end of each development session (those sessions where features are added), the program should be doing something that it didn't before, and that something should be visible. For instance, a new module passes its corresponding unit test, or a new type of graphics effect appears on the screen. Adding code for a loader that will not be used until next week does not fall under this concept.


  • In your loader example, do you mean the loader code would not be written until it is needed later next week?

    Share this post


    Link to post
    Share on other sites
    My comments...

    Quote:
    Original post by ToohrVyk
    • Analysis paralysis, when writing the design document or doodling out the classes was moving slower than my creativity, so the backlog kept on increasing.
    Having an ever-increasing backlog is not bad as long as it is prioritized and for each feature you ask yourself, "Is it worth delaying completion in order to make this change?"
    Quote:
    Original post by ToohrVyk
    • Elegance in design: ... The downside was rigidity, because the elegant solution relied on specific assumptions, and required a complete rewrite for every modification.
    You are confusing "elegance" with "optimization" and "cleverness". An "elegant" solution is simple and general, whether it is fast or slow or clever or brute force.
    Quote:
    Original post by ToohrVyk
    • Do things, then do things right: this is the basic principle that I've decided to go with. Development is divided into feature-addition steps where new functionality is added to the program (do things), followed by refactoring steps where new and old functionality is rewritten in part to fit in a better design (do things right).
    Definitely. An iterative development process is necessary in a project where the requirements can change frequently. However, I've seen people use that as a justification for doing no planning past the current iteration and that can be very inefficient.
    Quote:
    Original post by ToohrVyk
    • Have something to show: the idea is that at the end of each development session (those sessions where features are added), the program should be doing something that it didn't before, and that something should be visible.
    It's true. Something isn't really done unless you can see it working. However, "visible" can be taken to the extreme and people spend too much time on visible "progress" and not enough on actual progress.
    Quote:
    Original post by ToohrVyk
  • Conformism beats perfection: I must refrain from using the best tool for every particular job. ...
  • You listed a lot of good reasons, but to me it boils down to this: perfection is very expensive.

    Again, I think that iterative development and "designing for change" are very appropriate when the requirements are ambiguous or unspecified, or when they can change frequently, or when there are many unknowns. (Hey, that sounds like a description of game programming!) I think that agile development has many good features because it is based on those concepts, but I think it is less efficient when it is taken to the extreme.

    Share this post


    Link to post
    Share on other sites
    Sign in to follow this  

    • Advertisement
    ×

    Important Information

    By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

    GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

    Sign me up!