| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
My own personal simple coding style for C++, but most of them can be apply to many languages.
This is the style I used for all my personal repositories. And also for other people to reference if needed.
The intention of this coding style is just to keep things simple and natural.
No cryptic prefixes, suffixes and underscores that are specific to different languages.
|
This style just utilizes different case types and English grammar to differentiate different entities and intentions.
Here are the cases that are used in this coding style:
This section applies to most languages, not just c++
Things are always changing, new deadlines, new features, new requirements.
Instead of spending time over-engineering and designing something that you don't know how it will work out (and you never will, unless you can predict the future), get it working first. After that you can do whatever you want, refactor it, clean it, etc.
Nothing is future proof and don't waste your time trying to pretend you will design something future proof. Something "good enough" is often the right balance between how much time is spent on designing the architecture and implementation to allow changes if needed.
This of course is different per context/scenarios, but generally languages are fast enough under most use-cases, and performance often only matters under certain part of a program (i.e. a hot loop).
Sacrificing readability and iterability (i.e. using an array/struct for better CPU caching over (linked) list strurcture that reads better) on non performance critical part isn't worth it.
That is not to say you should make it inefficient, small habits like adding const and using reference is generally good to do and doesn't hurt readability.
A good rule of thumb is "Make it easy to read first, then make it run faster"
The mainstream really endorse OOP. Schools, corporates, books are all praising it because it is "Battle Tested" and is the industry de facto, not knowing how painfully confusing to navigate and difficult to add features to these codebase. Not to mention it is slower as well, see "Clean" Code, Horrible Performance by Casey Muratori.
Here by OOP I mean object inheritance and interfaces, not functions that are binded to a data structure, not RAII.
OOP sounds great on paper, you re-use things with hierarchical design, isolation of concerns and allow easy testing. But in practice it often falls short in terms of readability and iterability.
Trying to follow through a flow on what a function does? Too bad you will have to go to 20 different files to understand which concrete functions can be called, not to mention there can be more than 1 concrete functions can be called if it is a multi-layer inheritance.
Using interfaces to make it easier for testing? Good luck diving through many layers and wrappers when you are trying to debug or read the code, only to find out the logic is a dynamic delegate/function object that is spawned and configured somewhere else and you now have to find where that is. Also good luck adding new features since the moment you change the interface, you are forced to update 20 other classes (and tests) that are dependent on that interface.
Of course "Clean Code" and "SOLID" says none of these are an issue if you follow their rules. This will be true if we live in a perfect world where there are no deadlines, no change of requirements, no unique new features, no special use cases from the customer, etc.
But we don't live in a perfect world, this is just a lie so that people can sell books and host talks and the only people can do this are big corporations which can afford to this and the rest of us are wasting time trying to perfect something that is always imperfect.
I have been to this path (Using OOP) and DEEPLY regretted it.
Just implement the damn thing.
Instead of OOP and all those shit, just use composition, good ol' if statements and switch statements when you need to generalize something. Not only it is easier to read since now each function in the generalization shows EXACTLY what concrete functions it will call, it is easier to debug as well since you can can access all the concrete data just by poking into the member data structure.
TODO...
Identifiers or names should require minimum context to understand their purpose or what they store. Therefore, abbreviations should be avoided as it requires context to understand what it stands for.
Try to be simple and explicit (and sometimes long) rather than cryptic and short.
//Example
float NormalizedSum(int* vec, size_t count, int min, int max)
{
int sum = 0;
for(int i = 0; i < count; i++)
sum += vec[i]
float normalizeRange = max - min;
return (float)(sum - min) / normalizeRange;
} //Example
#ifndef HUMANOID_ENEMY_HPP
#define HUMANOID_ENEMY_HPP
namespace MyGame
{
class HumanoidEnemy
{
private:
bool Initialized;
ModulesManager CurrentModulesManager;
bool StatusChecked;
static const int NUM_OF_LEGS_FOR_HUMANOID = 2;
public:
HumanoidEnemy();
~HumanoidEnemy();
void Initialize();
void CreateModule(std::string moduleName);
void RemoveModule(std::string moduleName);
void CheckStatus();
bool IsStatusChecked();
};
}
#endif if( HasSomethingHappened() ||
HasSomethingElseHappened() ||
HasSomeOtherThingsHappened())
{
DoSomethingUrgent(a, b);
DoSomethingNext();
}
else
{
DoSomethingNotUrgent(a, b);
DoSomethingElseNext();
}
//Instead of
if( HasSomethingHappened() ||
HasSomethingElseHappened() ||
HasSomeOtherThingsHappened()) {
DoSomethingUrgent(a, b);
DoSomethingNext();
} else {
DoSomethingNotUrgent(a, b);
DoSomethingElseNext();
}
if(condition())
{
//Many statements here
}
//Can be commented out to skip the condition easily like this
//if(condition())
{
//Many statements here
}
//Or to temporary disable a block but still have it being compiled
//if(condition())
if(false)
{
//Many statements here
} void SomeFunction()
{
auto someLambda = []()
{
//...
}
//Or move the [...](...) to its own line if it gets too long, but indented
auto someLongLambda =
[&MyVar, &MyVar2, &MyVar3, ...](int myParam, int myParam2, int myParam3, ...)
{
}
//Or like this (See Multilines section)
auto someLongLambda =
[
&MyVar,
&MyVar2,
&MyVar3,
...
]
(
int myParam,
int myParam2,
int myParam3,
...
)
{
...
}
}
MyClass myVariable =
someVariable.FirstFunction(mySuperDuperLongArgName, mySuperDuperLongArgName2);
//Or
MyClass myVariable = someVariable.FirstFunction(mySuperDuperLongArgName,
mySuperDuperLongArgName2); //Align variables to the nearest tab width
void FunctionWithLotsOfParameters( int a,
bool b,
std::string c,
std::vector& someVector,
//A few more parameters...
uint32_t finalParameter)
{
//...
} //Align to nearest tab width
if( (ConditionFunction(var1, var2, var3) &&
conditionVariable &&
conditionVariable2) ||
conditionVariable3)
{
DoSomething();
} auto someLongLambda =
[
&MyVar,
&MyVar2,
&MyVar3,
...
]
(
int myParam,
int myParam2,
int myParam3,
...
)
{
...
} //Normal case
//Align to nearest tab width
runcpp2::NodeRequirement::NodeRequirement( const std::string& name,
ryml::NodeType nodeType,
bool required,
bool nullable) : Name(name),
NodeType(nodeType),
Required(required),
Nullable(nullable)
{
...
}
//Extreme case
//Align to nearest tab width
HumanoidEnemy::HumanoidEnemy( int myParam1,
const std::unordered_map<std::string, int>& myParam2,
std::unordered_map< std::string,
std::vector<MyObject>>& myParam3,
const std::unordered_map
<
std::string,
std::vector<const MyObject&>
>& myParam4,
std::vector<std::pair<int, bool>> myParam5) :
//Move to indented newline since there is no space after :
MyMember1(myParam1),
MyMember2(myParam2),
MyMember3(myParam3),
MyMember4(myParam4),
MyMember5(myParam5)
{
...
} //Align to nearest tab width
SomeFunctionCall( MyArgWithLongName1,
MyArgWithLongName2,
MyArgWithLongName3,
MyArgWithLongName4);
//Or in a very nested indented situation
bool MyFunction(...)
{
for(...)
{
if(...)
{
for(...)
{
MY_MACRO_FOR_HANDLING_ERROR
(
SomeFunctionCall
(
MyArgWithLongName1,
MyArgWithLongName2,
MyArgWithLongName3,
MyArgWithLongName4
)
);
}
}
}
...
} //Align to nearest tab width
someVariable.FirstFunction()
.SecondFunction()
.ThirdFunction(); //Align to nearest tab width
FunctionInSameScope (var1, var2, var3, var4, var5, ...)
.SecondFunction()
.ThirdFunction(var1, var2, ...); if(!IsWaterBoiled())
BoilWater();
if(!HasChocolatePowder())
GetTeaBag();
else
GetChocolatePowder();
CreateBeverage();| Back | FazBrowse Home | New Git URL |