Working on any project at all is barely an undertaking that is immune to chaos. Split up a file that grew beyond a point, naming of objects and functions, files ... "chaos awaits". In this article I'm going to introduce you to a few concepts of not losing the mind within growing projects... as inspiration to improve your coding - to help wherever it may.
In the beginning we have an ambition, a goal, a demand - be as logical, clean and efficient as it gets, but nobody is free of making mistakes. Mistakes come in many ways and design errors are amongst the worse mistakes that can happen. Once having settled on a pool of code that is supposed to function to the desired end it may happen that the entire project becomes useless; That dependend on the amount of people working on the project. The key term is: When it grows beyond the 'local brain-capacity' a deligently established structure upon the structure is a must have.
It is of course in the responsibility of the projects leader to get the group organized and the more organized a venture does get, the less important is all of this to the individual because he/she will mostly work on a select portion of the whole. There are no grey areas to the one who is designated a certain job and minor clinches here and there will possibly always be a part to anything ever.
The bigger the venture is, the less space there is for going out of the way to experiment on a certain idea and that is mostly up to the captain to decide who in turn has other tools and ways, like first of all the blackboard and most importantly the many people sitting around providing active feedback - where nothing happens until it can be set into stone.
"You take note, sit down and write your code" - vidi, veni, vici. But while the code director of a large group has many minds to rely upon, that is a luxury not all can efford. Here structural errors are more dangerous, but not the inevitable failure.
Bugs are an example to cast some more light into this scenario. Bugs mostly are either just programming errors - those don't matter to us here - or they are the quirks of 'brave code' that hasn't been thought through as strong as possibly intended. The problem resides within human reason. To the human mind string + string is a legitimate thing, so is number + number and whatever solution is required to solve the problem is the goal. But while the immediate difference isn't large to our brain, it is large to the work-flow of a program. Parsing through text may be a neat example or implementing a sorting algorithm while the little man knows or would think that it may also work without. Trying to get complex operations done in one go and the first time writing it requires preparation, and to be really precise this preparation has to be done in consideration of all the things that are influenced.
If the one day you produced a value through a formula that you needed somewhere, then re-arranged the formula and the value got forgotten - then we got what we might call 'broken code' or: Find the needle in the hay-stack. In such cases it is often a nice idea not to look for the problem in the code, but within the concept, the approach, the development attitude - well - all what is not 'in code'.
Rules, no matter how many hate them, provide order, order provides structure - nothing new. Thus every project "should" begin with that on mind, or else the lack of structure will become the structure - and if someone wants to do it for the kick or whatever ... well.
This is what things could look like in the start. Here we have two locations - one is the private library called commons and the other is the newly setup project - old school. What matters for a good commons pool is not different to what matters for a good external library like lets say OpenGL: Structure.
Structure in this case is to be relied upon. Everything that can be relied upon is great. Everything that is currently under construction can't be relied upon, but, that means that it is bad - and that isn't good - and that ... is obvious.
In order to really begin with anything solid and complex one has to setup rules, something to rely upon, but here is where the issue within development begins. The target is clear: Make everything that is new as reliable as possible. That way the project may grow more and more complicated - it won't matter if everything does what it is supposed to do.
Easier said than done, sometimes however, where here once again the problems reside within the gap between human mind and virtual reality. In essence the provided structure wherein "the thing" is to be worked out depends on the human grasp and furthermore intention/ambition. One can begin simple, most simple, most essential, bare-bones and basic, or one can right away proceed to laying everything out. Like there is a corelation between mass and energy, there is a corelation between quality and quantity. If you write a complex structure you are most likely lacking behind in content, while if you write simple structures you are most likely lacking in applicable wealth. Bridging the gap towards the respective pit is the challenge - especially once you stumble upon that one extra feature that offers itself to be implemented while you basically should take care of stuffing some holes.
But here its not all the meats fault. One must though admire those brave men of old that had to resort to monochrome text-mode editors to get their s*t together.
I can't tell you though how well you would handle such situations, we humans sometimes do in general lack in depth information how much other people fail - not for our entertainment but for allowing us to be a little bit more hostile towards our inner coward. That is one reason why we like to stick to rules - unwritten ones maybe - things however that we know are 'real'. We always get to hear that making mistakes is normal, but when we look into our past I'm sure that most of us see how those that actually made them for others to see yielded flak for it - rather than respect. And I know that I should keep my ego out of an objective article, but [finding some excuse].
A nice workaround is to convert weaknesses into strengths, or, covering flaws within styles. Its pretty much like baking bread. There is dough, theres the oven, then there is bread. One doesn't sort the baked bread back to the dough, or the fresh dough under the baked bread.
Saying, something like:
(Or however you like it be) - which may not provide itself very useful in a lot of cases but it does add one thing though: You don't have to remove old code while it is still somehow used here and there. This proves itself helpful because when really wanting to dig the greater possible outcome you can barely get along without helper classes or temporary constructs of a feeble human intellect trying desperately to justify an existence that is without meaning or purpose ... until ... you get the magic going.
Naturally every project grows into an individual systematic layout. Even if for the beginning one file would do, soon it isn't just the files that matter but the synopsis. Multiple elements need to be grouped, then includes and definition hierarchy must be regarded, class definition and function body have to be organized - and it is critical to understand that the different components within a project can follow individual ideas of structure.
I for instance like to picture things as they take hold within Memory/RAM, which yields that there are three different types of classes:
Abstract to this organization is the approach of looking at the memory-'operations' hierarchy. Here one begins with the 'base class' at all, therein most likely one will have everything that produces the rest.
In example of a Map Generator
Map Generator, Map Virtual Structure and Map File Data Structure go together. This taps into the Map File Data Components, definitions and advanced feats (if any). This again will base into the 'main class' at some point, next to sub-classes, map-components that are engine driven, etc.. At first it is easy to:
"Quick Start" - which is best to get started to work on the idea. Components are created when needed. But now we would realize that our Map Generator might work better if sorted into its own class - thus holding potential to be operated as independent unit; Yielding greater flexibility on utilizing buffer memory, holding generation-specific data within the class and not littering the "main class"; Or we may find that File Data and Generator work much better in tandem than this. What now matters is that we would realize these changes within whatever form of organization we got started with. Soon all will be contained and included within 'map.h' or something and once having not thought everything through properly enough all sorts of crap will float around within folders of "anonymous meaning" like 'core' or 'engine'.
core may be anything that is required to initialize before the engine can just make use of things ... any idea a potential mistake. But mistakes are what we wanted.
Once we see how the thing takes shape and we want to 'finally' use it, we would begin to re-write it. This is complicated 'Zen' stuff - philosophy about when what is ready - but it's best to say that when you know it's ready, it's ready.
Thereby I much prefer to put files into folders. Hereby the rule is that all folders that are located within the base folder are visible at first glance, no confusing nesting, if done properly. So I try to wrap the thing up within an identifier that is comprehensive to me within the filesystem as it is within code, so:
So that I know: "Uhu, _MAP_!!!" and therein needs to be all that I need 'for' it, or more specifically, all that flows into the 'Integration Class' (If I called it: _MAP_MEMORY_HANDLE_ to work on _MAP_, then I call the file '_MAP_.MemoryHandle.H' or something). I locate it within the Base Folder because at this point it sticks out.
The less people and the more complex the code the more 'Zen' is required by the coder because when laxing back the one or the other thing 'more' comes to mind, while otherwise the one or the other more 'tedious' thing is ignored - temporarily or infinitely. Quickly hacking some working code together is a skill, having the peace to know what to hack together is a virtue.
I hope that this odysee yielded some useful info for you - things that have not much to do with the valuable coding 1x1 and maybe therefore elude our attention from time to time.
19 Septh 2014: General Overhaul 1
12 Sept 2014: Initial Draft
To Grow or Not to Grow
The Yielding of Error
In the beginning we have an ambition, a goal, a demand - be as logical, clean and efficient as it gets, but nobody is free of making mistakes. Mistakes come in many ways and design errors are amongst the worse mistakes that can happen. Once having settled on a pool of code that is supposed to function to the desired end it may happen that the entire project becomes useless; That dependend on the amount of people working on the project. The key term is: When it grows beyond the 'local brain-capacity' a deligently established structure upon the structure is a must have.
It is of course in the responsibility of the projects leader to get the group organized and the more organized a venture does get, the less important is all of this to the individual because he/she will mostly work on a select portion of the whole. There are no grey areas to the one who is designated a certain job and minor clinches here and there will possibly always be a part to anything ever.
The bigger the venture is, the less space there is for going out of the way to experiment on a certain idea and that is mostly up to the captain to decide who in turn has other tools and ways, like first of all the blackboard and most importantly the many people sitting around providing active feedback - where nothing happens until it can be set into stone.
"You take note, sit down and write your code" - vidi, veni, vici. But while the code director of a large group has many minds to rely upon, that is a luxury not all can efford. Here structural errors are more dangerous, but not the inevitable failure.
Bugs are an example to cast some more light into this scenario. Bugs mostly are either just programming errors - those don't matter to us here - or they are the quirks of 'brave code' that hasn't been thought through as strong as possibly intended. The problem resides within human reason. To the human mind string + string is a legitimate thing, so is number + number and whatever solution is required to solve the problem is the goal. But while the immediate difference isn't large to our brain, it is large to the work-flow of a program. Parsing through text may be a neat example or implementing a sorting algorithm while the little man knows or would think that it may also work without. Trying to get complex operations done in one go and the first time writing it requires preparation, and to be really precise this preparation has to be done in consideration of all the things that are influenced.
If the one day you produced a value through a formula that you needed somewhere, then re-arranged the formula and the value got forgotten - then we got what we might call 'broken code' or: Find the needle in the hay-stack. In such cases it is often a nice idea not to look for the problem in the code, but within the concept, the approach, the development attitude - well - all what is not 'in code'.
//mainfile.cpp #include "dafuq.h" //#include "DaFuq.h" #include "DaFinFuq.h" #include "da_fuzk.h" #include "da_definite_one.h" #include "fuzz2.h"
The Yielding of Rules
Rules, no matter how many hate them, provide order, order provides structure - nothing new. Thus every project "should" begin with that on mind, or else the lack of structure will become the structure - and if someone wants to do it for the kick or whatever ... well.
+- Base Dir base.cpp ... +- MyCommons Directory commons.h + units.h ...
This is what things could look like in the start. Here we have two locations - one is the private library called commons and the other is the newly setup project - old school. What matters for a good commons pool is not different to what matters for a good external library like lets say OpenGL: Structure.
Structure in this case is to be relied upon. Everything that can be relied upon is great. Everything that is currently under construction can't be relied upon, but, that means that it is bad - and that isn't good - and that ... is obvious.
In order to really begin with anything solid and complex one has to setup rules, something to rely upon, but here is where the issue within development begins. The target is clear: Make everything that is new as reliable as possible. That way the project may grow more and more complicated - it won't matter if everything does what it is supposed to do.
Easier said than done, sometimes however, where here once again the problems reside within the gap between human mind and virtual reality. In essence the provided structure wherein "the thing" is to be worked out depends on the human grasp and furthermore intention/ambition. One can begin simple, most simple, most essential, bare-bones and basic, or one can right away proceed to laying everything out. Like there is a corelation between mass and energy, there is a corelation between quality and quantity. If you write a complex structure you are most likely lacking behind in content, while if you write simple structures you are most likely lacking in applicable wealth. Bridging the gap towards the respective pit is the challenge - especially once you stumble upon that one extra feature that offers itself to be implemented while you basically should take care of stuffing some holes.
But here its not all the meats fault. One must though admire those brave men of old that had to resort to monochrome text-mode editors to get their s*t together.
I can't tell you though how well you would handle such situations, we humans sometimes do in general lack in depth information how much other people fail - not for our entertainment but for allowing us to be a little bit more hostile towards our inner coward. That is one reason why we like to stick to rules - unwritten ones maybe - things however that we know are 'real'. We always get to hear that making mistakes is normal, but when we look into our past I'm sure that most of us see how those that actually made them for others to see yielded flak for it - rather than respect. And I know that I should keep my ego out of an objective article, but [finding some excuse].
A nice workaround is to convert weaknesses into strengths, or, covering flaws within styles. Its pretty much like baking bread. There is dough, theres the oven, then there is bread. One doesn't sort the baked bread back to the dough, or the fresh dough under the baked bread.
Saying, something like:
- All sophisticated classes have practical, bold, capital names (i.e. VERTEX_3D)
- All project specific 'finite' classes begin and end with one Underscore and are capsed
- All project specific 'finite' namespaces begin and end with two underscores and are capsed
(Or however you like it be) - which may not provide itself very useful in a lot of cases but it does add one thing though: You don't have to remove old code while it is still somehow used here and there. This proves itself helpful because when really wanting to dig the greater possible outcome you can barely get along without helper classes or temporary constructs of a feeble human intellect trying desperately to justify an existence that is without meaning or purpose ... until ... you get the magic going.
Inside and Outside in Harmony - the Yin and Yang of code Layout
Naturally every project grows into an individual systematic layout. Even if for the beginning one file would do, soon it isn't just the files that matter but the synopsis. Multiple elements need to be grouped, then includes and definition hierarchy must be regarded, class definition and function body have to be organized - and it is critical to understand that the different components within a project can follow individual ideas of structure.
I for instance like to picture things as they take hold within Memory/RAM, which yields that there are three different types of classes:
- 'Memory Units' (main class, primary cells, ...)
- '"Sub-Memory" Units' (memory handles, buffer operation classes, 'Handy structs', ...)
- 'Component Units' (Everything else that is basically in use by the upper)
Abstract to this organization is the approach of looking at the memory-'operations' hierarchy. Here one begins with the 'base class' at all, therein most likely one will have everything that produces the rest.
In example of a Map Generator
Map Generator, Map Virtual Structure and Map File Data Structure go together. This taps into the Map File Data Components, definitions and advanced feats (if any). This again will base into the 'main class' at some point, next to sub-classes, map-components that are engine driven, etc.. At first it is easy to:
#include "Map.FileData.h" class MapVirtualClass { public: ... bool GenerateDefault (int default_value); };
"Quick Start" - which is best to get started to work on the idea. Components are created when needed. But now we would realize that our Map Generator might work better if sorted into its own class - thus holding potential to be operated as independent unit; Yielding greater flexibility on utilizing buffer memory, holding generation-specific data within the class and not littering the "main class"; Or we may find that File Data and Generator work much better in tandem than this. What now matters is that we would realize these changes within whatever form of organization we got started with. Soon all will be contained and included within 'map.h' or something and once having not thought everything through properly enough all sorts of crap will float around within folders of "anonymous meaning" like 'core' or 'engine'.
core may be anything that is required to initialize before the engine can just make use of things ... any idea a potential mistake. But mistakes are what we wanted.
Once we see how the thing takes shape and we want to 'finally' use it, we would begin to re-write it. This is complicated 'Zen' stuff - philosophy about when what is ready - but it's best to say that when you know it's ready, it's ready.
Thereby I much prefer to put files into folders. Hereby the rule is that all folders that are located within the base folder are visible at first glance, no confusing nesting, if done properly. So I try to wrap the thing up within an identifier that is comprehensive to me within the filesystem as it is within code, so:
base_dir/zen/MapVirtualClass.cpp base_dir/_MAP_/... base_dir/_MAP_.IntegrationClass.H base_dir/main.cpp
So that I know: "Uhu, _MAP_!!!" and therein needs to be all that I need 'for' it, or more specifically, all that flows into the 'Integration Class' (If I called it: _MAP_MEMORY_HANDLE_ to work on _MAP_, then I call the file '_MAP_.MemoryHandle.H' or something). I locate it within the Base Folder because at this point it sticks out.
Conclusion
The less people and the more complex the code the more 'Zen' is required by the coder because when laxing back the one or the other thing 'more' comes to mind, while otherwise the one or the other more 'tedious' thing is ignored - temporarily or infinitely. Quickly hacking some working code together is a skill, having the peace to know what to hack together is a virtue.
I hope that this odysee yielded some useful info for you - things that have not much to do with the valuable coding 1x1 and maybe therefore elude our attention from time to time.
Article Update Log
19 Septh 2014: General Overhaul 1
12 Sept 2014: Initial Draft