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.


Post a Comment