views:

272

answers:

3

Where do you draw the line to stop making abstractions and to start writing sane code? There are tons of examples of 'enterprise code' such as the dozen-file "FizzBuzz" program... even something simple such as an RTS game can have something like:

class Player {} ;/// contains Weapons
class Weapons{} ;/// contains BulletTypes
class BulletType{} ;///contains descriptions of Bullets 
class Bullet{} ;///extends PlaceableObject and RenderableObject which can be placed/drawn respectively
class PlaceableObject{} ;///has x,y,z, coords
class RenderableObject{} ;///an object with a draw() command
class MovingObject{}; ///an object with a move() function

etc... and it can turn into a nightmare. This can be drawn to its logical extreme, much like functional programming can be drawn to the extreme where you can create a language with only variables, function application, and anonymous function definitions (although I must admit that is slightly more elegant)...

Any sane advice on this topic?

+16  A: 
  1. YAGNI (You Ain't Gotta Need It). Don't create abstractions you don't see immediate use for or a sensible reason. This way you have a simple thing that may become more complex, instead of a complicated things that you would strive to make simpler, but lose.
  2. Make sure the abstractions make sense. If they're too far from reality, too hard to justify... forget it.
  3. Let the solution feel natural. Work on it until it does. Then for an unfamiliar person the solution should seem so obvious, that he screams "how could you have done it differently?".
  4. Don't try to predict the future. You can't. If you try to cover all 10 possible cases, you will soon discover 11th and more, and it will be more difficult to implement it because of previous 10, not encountered in practice. Make it simple and easy to adapt. Software needs to be changed, but ease of adaptation (agility) is often much better strategy than trying to cover all maybe-possible cases up-front.
phjr
A: 

I believe that the criteria may be deduced from a clear definition of what abstraction is.

You are referring to abstraction within the Object-Oriented programing paradigm, where you have at your disposal the three principles: 'abstraction' - 'encapsulation' - 'information hiding or visibility'.

Abstraction is the process of choosing which attributes of the object are relevant to your system, and which must be completely ignored.

That means, the abstraction limit does not concern so much the number of concepts you define (Player, Weapons, Bullets, ...), but what you choose to put inside those concepts.

It is basically triage, where you will consider only from a concept what is useful to the services you need to define.

So a good criteria to start writing sane code might be the APIs, as the eclipse program suggest: API first.

Indeed, "Good APIs require design iteration", meaning the list of objects you mentioning in your question will be refined as the API needed is itself refined.

Plus, APIs mean to have well-defined component boundaries and dependencies (as in 'Core - Player - vs. UI - RenderableObject - '), meaning the very detailed list you mentioning can not be viewed as a long endless list of concepts, but must be clearly grouped into different functional perimeters (or functional components), from an applicative architecture.

Since APIs exist to serve the needs of clients, you will keep those objects only because they make sense for the client. The others objects should be in 'internal' packages and never be referred directly by any other parts of your application.

With that in mind, @phjr advices make perfect sense ;)

VonC
+2  A: 

Perhaps this question should be where to start abstracting.

The example you quote is a classic example of not enough thought about what the objects actually are, as they are all pretty much the same - and probably would be better expressed as a single "GameObject".

I also avoid sub classing by object properties. For StaticGameObject and DynamicGameObject may seem logica, but are probably better represented by container placement - i.e. two lists one for static objects and one for dynamic, thus allowing other logic to define the actions rather than the object itself being responsible for controlling something outside of it's scope.

Sometimes it is harder to work out what is shared by a group of things that you want to represent in a object - but it is worth doing.

Richard Harrison