Good design is achieved when a minimum number of distinct mechanisms accomplish a maximum number of goals.
Previous Entry
Strange way to wake up...
Next Entry
All my teh braens aer goan.
Comments
May 14, 2007 09:51 PM
Actually, I think that sentiment applies to a huge range of things; I've heard it echoed in fields from art to music to engineering. It seems to be fundamentally connected to the deep relationship between elegant design and aesthetically beautiful design.
Personally, I suspect it says some profound and interesting things about the way the human mind processes the world.
Personally, I suspect it says some profound and interesting things about the way the human mind processes the world.
May 14, 2007 11:54 PM
That's pretty strange but the sentence has two disting effects:
1) it gives a fair explaination of what good design is about (elegance, simplicity and behavior)
2) it's really confusing (what are goals? what are disting mechanisms?).
If these is the goal of the sentence, then I must agree that it's well designed [grin]
1) it gives a fair explaination of what good design is about (elegance, simplicity and behavior)
2) it's really confusing (what are goals? what are disting mechanisms?).
If these is the goal of the sentence, then I must agree that it's well designed [grin]
May 15, 2007 09:27 AM
A goal is anything you want to do; all software is designed for some purpose. That purpose includes one or more goals.
A "distinct mechanism" is admittedly somewhat harder to nail down. The basic idea I'm driving for is that there shouldn't be extremely similar structures in the code. For example, if you write a program that tracks restaurants and the dishes that each restaurant offers, you shouldn't have two different container classes (one class for holding restaurants and one for holding meals). A generic container that handles both is a more elegant design.
For another case, suppose you have a complex game, with modules for doing physics and AI. Each module needs to have a set of callbacks; when some critical event happens in the simulation, the AI is called back to react, or the physics is called back to handle the situation (a collision, for example).
It would be a less elegant design to have two separate callback systems for each. In this particular case, loose coupling is actually the wrong direction to take, because the operations are fundamentally tightly coupled. That is, both the AI and physics are integral parts of the game simulation; they are not fundamentally orthogonal processes, and therefore they are not best implemented as fully decoupled modules.
Instead, a single mechanism should dispatch both callbacks, and ideally allow for easy attachment of data payloads from the simulation itself. For instance, I should be able to callback the AI and pass it a list of the weapons a character is carrying; or, I should be able to call back the physics and tell it how much "strength" a car has, which the physics can then reduce based on collisions, leading to a damaged car.
The trick, of course, is that this consolidation doesn't always make sense. There are times when you really should have separate pieces of code that do extremely similar jobs. So it is not enough to just say "minimize the number of distinct mechanisms" because that may not in fact be the right thing to do. I think for an experienced designer it's fairly clear that in some cases, trying to excessively decouple things actually increases duplication, and is therefore a liability.
On the flip side, just saying "maximize the number of things your code does" is rather useless, and even outright dangerous. It'd be ridiculous to actually try and write software that way, because everything would be terribly bloated and probably pretty crap as a result.
Hence, the idea of finding a balance between the two. It's sort of like a highly abstract analogue of linear programming. There are two different curves here ("distinct mechanisms" and "things the program can do") and an optimal relationship has to be located. This is, strictly speaking, a very difficult thing to do, and relies a lot on experience and good design judgment in the first place.
[It's worth noting that this makes the statement basically useless as far as pithy aphorisms go. If you get why it is true, you already know enough that it won't teach you anything new. Such is the way of pithy aphorisms, though, I suppose.]
Taken to the logical extreme, this sentiment is (I believe) closely tied to why many people consider Lisps to be highly elegant: the language consists of purely one mechanism, lists and the associated construction/decomposition operations.
Of course, my personal feeling is that what makes a good language isn't necessarily maximal elegance - but that's a topic for another day [smile]
A "distinct mechanism" is admittedly somewhat harder to nail down. The basic idea I'm driving for is that there shouldn't be extremely similar structures in the code. For example, if you write a program that tracks restaurants and the dishes that each restaurant offers, you shouldn't have two different container classes (one class for holding restaurants and one for holding meals). A generic container that handles both is a more elegant design.
For another case, suppose you have a complex game, with modules for doing physics and AI. Each module needs to have a set of callbacks; when some critical event happens in the simulation, the AI is called back to react, or the physics is called back to handle the situation (a collision, for example).
It would be a less elegant design to have two separate callback systems for each. In this particular case, loose coupling is actually the wrong direction to take, because the operations are fundamentally tightly coupled. That is, both the AI and physics are integral parts of the game simulation; they are not fundamentally orthogonal processes, and therefore they are not best implemented as fully decoupled modules.
Instead, a single mechanism should dispatch both callbacks, and ideally allow for easy attachment of data payloads from the simulation itself. For instance, I should be able to callback the AI and pass it a list of the weapons a character is carrying; or, I should be able to call back the physics and tell it how much "strength" a car has, which the physics can then reduce based on collisions, leading to a damaged car.
The trick, of course, is that this consolidation doesn't always make sense. There are times when you really should have separate pieces of code that do extremely similar jobs. So it is not enough to just say "minimize the number of distinct mechanisms" because that may not in fact be the right thing to do. I think for an experienced designer it's fairly clear that in some cases, trying to excessively decouple things actually increases duplication, and is therefore a liability.
On the flip side, just saying "maximize the number of things your code does" is rather useless, and even outright dangerous. It'd be ridiculous to actually try and write software that way, because everything would be terribly bloated and probably pretty crap as a result.
Hence, the idea of finding a balance between the two. It's sort of like a highly abstract analogue of linear programming. There are two different curves here ("distinct mechanisms" and "things the program can do") and an optimal relationship has to be located. This is, strictly speaking, a very difficult thing to do, and relies a lot on experience and good design judgment in the first place.
[It's worth noting that this makes the statement basically useless as far as pithy aphorisms go. If you get why it is true, you already know enough that it won't teach you anything new. Such is the way of pithy aphorisms, though, I suppose.]
Taken to the logical extreme, this sentiment is (I believe) closely tied to why many people consider Lisps to be highly elegant: the language consists of purely one mechanism, lists and the associated construction/decomposition operations.
Of course, my personal feeling is that what makes a good language isn't necessarily maximal elegance - but that's a topic for another day [smile]
May 15, 2007 12:02 PM
Advertisement
Latest Entries
A Few Farewells
14900 views
Code Reuse In Actual Practice
16841 views
Source-Level Debugging For Epoch Programs
5320 views
Using Poison to Reverse Engineer Code
4006 views
Using Poison to Reverse Engineer Code
372895 views
Debugging Information Success
3215 views
Debugging Information Success
6045 views
Debugging Epoch Programs
3492 views
Debugging Epoch Programs
7812 views
Epoch 64-bit compiler progress
2900 views
Advertisement
I usually use it when referring to game design, but it works for software design as well [smile].