19 September 2009

A few words about debugging

Either your design is neat or messy, you will anyway put up with bugs.

Of course a neat design helps localizating bugs. But debugging will ever be the dark side of development, which will prove your smartness and fantasy, sometimes sorely.
There are many approaches and many books about debugging, ranging from breakpointing and logging to test oriented methodologies. I don't want here to go in depth but I wish you can do it yourself by reading about Agile and more specifically about eXtreme Programming.

Anyhow, I persuaded myself how important is preventing bugs, much before facing them.

Software development appears to be one of those things where less is more. Actually, the less code you write, the less probability you get to get into bugs. So be minimalist, achieve your functionalities with the least amount of code, avoiding redundancy and duplication. Don't Repeat Yourself and also Keep It Simple, Stupid.. All these recommendations, indeed, focus the Abstraction principle which is a minimalistic principle essential in designing software (and base of OOP).
Imagine that you have two parts in your engine where triangles are rendered. When you need to add a new rendering feature, you will have to modify both parts. Also if a bug about rendering incurs, you will have to check both parts again.

Have you ever heard about the Occam's razor principle? Well, if you still can't see how much a neat design has to do with minimalism, I think it can be worth to read some about it.

Regarding the finding bugs thing, I believe there is nothing better than a prototyping approach. Simply split in separate sessions your development. In each session changes are applied (say refactoring) to a bug-free version of your software in order to evolve it to a better yet bug-free version. This means that you need some kind of tool (say regression test) to verify that a certain version is still bug-free. When a new bug comes out, you will have certainly a better clue where it may resides.

The prototyping approach is OOP compliant and also brings more benefits such as:
  • There is always a working release to show (though prototypal)
  • You have a better vision of your design and can better address your efforts
As an example of bad prototyping, you can observe how many coders out there prefer to focus the last stunning effects of their 3D engines first instead of getting the game working as soon as possible and come back later to polish the details. They hardly have a clear vision of what is to be done, to be recycled, to be reinvented from scratch. In most of cases they don't even need to code a new 3D engine as there are already some others that can fit their requirements, perhaps open source (see devmaster.net).
A curious yet convincing lecture about this phenomenon is Write games not engines.

The prototyping approach also gives one more valuable benefit: you can get a prototypal version of your game working and sell it like it is the final version, even if not all intended requirements are accomplished (the above details to be polished). You make some money and can then keep on working for a new prototype, say a new chapter of the game.
It can be then worthwhile to split development in separate workflows, one for the making of a new game and others for the improvement of the engines in use. Which means that the game of today can be played with a better 3D engine, AI engine or Physics engine, developed in the future. This can be possible by means of a good software design.

13 September 2009

A few words about designing

The first time I read about Object Oriented Programming I didn't get it. I thought it was the next useless thing they wanted to sell me. So for a while I kept on avoiding it.

I think I was already a smart coder, experienced along a few years of hobbistic development. But I was used to think at software through a low-level and algorithm feasibility perspective. I was (and still I am) a greedy consumer of the Demoscene running in the 1990s, when on our desks were Amiga computers. And I was amazed by what could be brought to screen by tweaking hardware and well crafted low-level optimizations. Of course that was a starting era for the present-day computer graphics.
Above all, I think I was too proud of myself and wasn't used to think at feasibility under a resource basis. In front of the screen, I was the man with a vision in mind, the code at his fingers reach and no deadline for it.

It was by means of some professional experience that I could put up with more vast projects and evaluate feasibility in terms of men and time against deadlines.
Algorithm and performances typically were not a concern for that kind of applications and I could then focus the benefits of reusing code. By reusing you can effectively take advantage in a neat and rational manner of what has been done by you or others, accomplishing goals you wouldn't expect to do before under certain deadlines.

Along this experience I've been growing to like objects because the object way is a way to achieve reusability of code. And it can be applied to both huge and small projects, in team or one-man development.
OOP is shaped around the idea that each piece of code should always be intended to be reused and extended soon or later as requirements grow. For instance, I can start writing a basic Vector class for an exercise of 3D math now and some time later extend and reuse this class, under new requirements, in functionality and performances, for a more demanding project.

How to develop object oriented?

Using objects you won't probably get the philosophy behind until the day you start designing objects. Then you will be learning (and getting delighted) how parts of your software can be wisely isolated so that those parts can get their logical identity (as feature, issue, etc.) and thus be reused and evolved independently, by you or other programmers, for your current project or other projects.
You have to isolate a subset of your data and functions that work tightly to solve a specific concern of your application and put all in an object. So that that object will represent the part of your software that handles/solves that specific concern from a user perspective.
Now imagine that the user of this object may be an external system or another object of the same system. And also, following a Top-down approach, you can let a more abstract object to be itself user of more concrete objects (say lower level objects or more specialized objects). And those more concrete objects may actually not be completely concrete in their initial versions, fulfilling all intended functionality, but just be dummy objects to be perfected later.

This approach trains you to separate concerns since the beginning. Basically you have to sort out things considering their coupling degree per functionality and then put together what is tightly coupled and separate what is loosely coupled, minimizing the overlapping of functionality as much as possible.
Separating diligently you will be applying the so called Separation Of Concerns, which is one more thing prof. Dijkstra has been teaching me after his dead.

I guess that you have got that this is not intended to be the nth tutorial about OOP and probably what I've been saying can just sound well for those who already know exactly what I'm talking about. I just wanted you to see that: 3D engines shouldn't ever integrate hardware specific logic because that would mean to tie your software to a certain hardware configuration in a certain time. Graphic hardware APIs change along platforms and time. So if you want your software to survive, even if using a specific hardware API, you have to keep into account a painless port to other hardware APIs soon or later.
Same thing is for type of content. Imagine that your 3D engine takes advantage by specifically using BSP or Octrees, what happens if you start working with on-the-fly generated content or content which is loaded in memory piece by piece while the player proceeds? You know, BSP and Octrees come from static content.. You may then find yourself reinventing the wheel once again, which is right what OOP is made to avoid for.

However, sometimes 3D engines comes to be tightly integrated to their OpenGL/Direct3D layer and it may not be for a bad OOP design but for a matter of performances. In fact OOP abstraction requires a small overhead even for a plain Adapter Design Pattern, due to virtual calls indirection. So you may have a neat modular design but paying a toll in performances that can be undesirable when it comes up to real-time applications. And this is where integration come someway to a opposite role to separation.

Fortunately there are a few solutions to get rid of run-time virtual-table lookups, such as template-based static polymorphism (see the Curiously Recurring Template Pattern), that shows how C++ is still far beyond most of languages, enabling coders to write for performances yet following a great high-level design. And it's too bad that most of so called C++ programmers still consider template metaprogramming mysterious and confusing.

Designing software is really a process of creativity that requires some experience. I believe it is useful to know the best practices as well as the worst ones, for which I suggest to read about Anti-patterns.

10 September 2009

The ability to simplify

"The ability to simplify means to eliminate the unnecessary so that the necessary may speak."

Hans Hofmann, Introduction to the Bootstrap, 1993