GPU style: do both, then throw away the one you don’t want.
Overarchitecting is overplanning for things you don’t know the system will need or planning for things you don’t understand that you think the system needs.
When will programmers realize that the over-emphasis (Java-style) on the use of classes, with every variable as a class-level variable, is just moar globals!! ?
* A class is just a mini program
* class-members in a large program with many classes are equivalent to globals in a smaller program (with a single class)
* you still have to use locals correctly
* just because it’s a class doesn’t mean overusing class members is ok
Being a programmer today is like being a diamond in a sea of diamonds. There are so many of us out there.
But finding a good programmer is like finding an IF diamond, where most of us are at least SI-2.
Image from here
Don’t forget to key a
std::map, you must overload
operator< Maps use binary search and insertion defaults to being in-order!
Friend classes in C++: In C++ a
friend is allowed to touch your
C++: public inheritance: everybody knows who your parents are. private inheritance: You are ashamed of your parents so nobody knows that you even have a parent class.
Oct 11 2012 12:49pm
Experimenting is the only way you know your assumptions are wrong.
Oct 15 2012 1:47pm
.push_back() into an STL vector is not necessarily slower than
.push_back() into an STL list. Even though you would think it should be ;).
Oct 16 2012 7:26pm
C preprocessor is the original duck typing
static is C’s private
Jan 4 2013
NEVER return references to entries (ie &theAddressOf) in a <vector> of value-types. return &vec and storing that value as a pointer is a no no. If you push_back into the vector, all the references you took earlier may become invalidated. Always use simple integer indices into a <vector>, or better yet use a vector of pointer types (where that makes sense to do).
Jan 26 2013
Overloading is overrated. (Not always, but sometimes). Is having 4 methods named intersects in your mesh class easier to read, or is naming them intersectsSphere, intersectsBounds, intersectsTri better?
Jan 26 2013
Marking a member function const is for when that member function call should have no change on the state of the object, neither now nor further down the line. If a const member function wants to return a pointer to a member inside the object, then that member function should not be labelled const, because that pointer is a key to making changes to the object further down the line.
constify member functions only when the member function being called is a prostitute and the code calling the “prostitute” is a married politician. Neither the caller nor the callee want the rest of society to know what went down in that function, so no record is kept. The prostitute agrees that the politician will have no lasting impact on her internal state (ie she will not talk about the affair). const on a member function means “this call never happened, and nothing changed inside the prostitute, nor will anything _ever_ change inside the prostitute anywhere down the line as a result of the politician’s call”
A bit of a long one, but hey, it involved prostitutes.
Feb 7 2013
If you delete the front node of a <list> while reverse iterating, list.rend() changes. list.rend() is not “one past the end” as list.end() would be.
Mar 3 2013
If I had a dollar every time I realized this. There are 6 cases to consider when doing ray sphere intersections: 1) Fall short 2) Entry 3) Impale 4) COMPLETE CONTAINMENT (which usually is mistakenly counted as a miss) 5) Exit wound 6) Past. Usually ppl only check for Entry,Impale and Exit, but CONTAINMENT must also be considered a “hit” (short ray inside large sphere))
Mar 21 2013
Never use M_2_PI from <math.h>. It is 2/PI, NOT 2*PI like you’d expect.
Mar 21 2013 11:28p
Crazy numbers like 8589934592 are almost certainly OOB problems.
Can you spot the potential OOB problem in the line below?
for( int i = 0 ; i < pts.size(); i++ )
nextPts.push_back( pts[i+i].pos + Matrix3f::rotation( alongLine, angle )*perpLine*r ) ;
The i+i was supposed to be i+1! Oops!
Mar 26 2013 11:58a
The ternary operator precedence level is VERY low!
int a = 5 + 1 ? 2 : 3 ;
The result for a is always 2. Why? because evaluation is happening as:
int a = (5 + 1) ? 2 : 3 ;
5+1=6 turns into TRUE, then the result is 2.
To make it evaluate properly, you would need
int a = 5 + (1 ? 2 : 3) ;
Mar 30 2013 11:32p
The Common Part Last rule
When naming multiple variables that have to do with the same thing, with similar names, such as playerVel for the player’s velocity and enemyVel for the enemy’s velocity, always put the different part first, not last. So never use a naming convention like velPlayer and velEnemy. It makes it far too easy to interchange the variables, especially when the similar string is long (for example, rollAccel and rollAccelRadar. I know of this rule and I just mistakenly used rollAccel where I wanted to use rollAccelRadar).
Another example: you’re more likely not to notice IconDashBaseship should be IconDashFighter than you would notice BaseshipIconDash is wrong and FighterIconDash should be there instead.
Apr 1 2013 3:26p
acos and asin on Mac are different than on PC.
acos( 1.0 + 1e-38 ) is nan on Mac because the arg is OOB strict domain of acos [-1,1]
This is not an April Fool’s joke.
Apr 10 2013 1:19a
Never use Google App Engine. Always use Amazon EC2 + RDS AWS instead.
Apr 24 2013 11:41p
Why encapsulate? It’s IMPOSSIBLE to remember all the implementation details of how a cohesive bunch of code works — even if you wrote it 3 weeks ago. THAT’S the reason for encapsulation. It says “Don’t fuck with this, it’s self managing”.
Apr 25 2013 1:19a
The factory pattern is most useful when an object type cannot and should not be used independently of some master managing class.
Fri May 3 2013 9:27p
std::vector. It is rat poison, not syntactic sugar.
Use the following idiom for removal from a std::vector instead
for( vector<TYPE>::iterator iter = vec.begin() ; iter != vec.end() ; )
if( iter->shouldRemove )
iter = vec.erase( iter ) ; // advances iter
++iter ; // don't remove
UI is 90% of a game.
Fri May 24 2013 11:30a
The best way to fast debugging is error checking and log messages for even the most outlandish cases. The condition that “shouldn’t happen” will always happen, at some point or another (usually do to programmer error!)
Great code has just the right amount of debug checks. No debug checks should be logically redundant or impossible (ie don’t set a flag=TRUE then immediately after check if that flag is still TRUE).
Mon May 27 2013 6:13
Exceptions are a retroactive way of handling error conditions. They kind of say “Yeah try this, if that doesn’t work, then do that.” Exceptions are too easily abused.
Sat Jun 1 2013 12:05p
Never use your extern variables inside a function that runs before main.
Tues Jun 4 2013 6:06a
I think I like writing stored procedures because the tables are like working with a couple of GB of global variables. Nothing better.
Fri Jun 7 2013 7:57p
There is a difference between brittle code and fragile code. Robust code survives all kinds of fail cases, at the extra overhead cost it takes to code that in. Brittle code breaks if something changes (for example, code that uses fixed value integer indexing for array access), but it might break in a safe way (check bounds before accessing). Fragile code is brittle code without the error checking.
Wed Jun 12 2013 3:14p
Betas are for suckers.
Thurs June 20 2013 5:31p
In good code, the author’s intentions clear.
If your intentions aren’t clear, use comments.
Sun June 30 2013 5:26p
The key to removing low area triangles (slivers AND small tris) is collapsing edges, not deleting triangles.
Tues July 1 2013 12:43p
Always clean up your mess in the kitchen before going to bed.
There is nothing, nothing worse than having to come back to your own mess.
Clean up your dirty code immediately (and by immediately I usually mean once the primary task the code is for is working correctly, clean it up).
Sun July 7 2013 6:32p
Calls to glVertexAttribPointer() MUST BE AFTER glBindBuffer().
Sun July 7 2013 6:33p
OpenGL is stupid.
Sun July 7 2013 6:33p
OpenGL is like a baby with OCD that cries inconsolably if you do something wrong. The biggest problem with OpenGL (unlike Direct3D’s detailed albeit hidden debug information) is that it doesn’t tell you what exactly you did wrong — just that it was an INVALID OPERATION. The order doesn’t always have logical reasoning — some state changes must be done just that way.
Thurs July 11 2013 3:16p
If you’re going to frustum cull, use SAT, but use a square based pyramid instead of a true frustum.
Sun July 14 2013 11:27a
The best way to develop is to “unit test” your code immediately as you produce it.
A “unit test” can be as simple as some specialized code that allows you to make sure your code is working by testing a wide variety of test cases all at once. For code such as raycasting, a good unit test is just draw a ray from the player’s forward vector and walk around the world, visually displaying the results.
Sun July 14 2013 7:56p
(int) for mathematical floor operation only if you’ve never heard of negative numbers.
Sat July 27 2013 12:58p
Journals are my answer to dead code.
Mon July 29 2013 11:19p
Don’t consider writing good or efficient code off the bat as just a “premature optimization”. To gracefully birth an efficient, well written program, you have to make good choices about the code you write at every step.
Fri Aug 2 2013 1:28p
Never let your program crash-fail on purpose, even for situations that should “never happen”. Emit an error message and fail gracefully.
Fri Aug 16 2013 12:42p
I hate NaN.
If you change your compiler optimization settings, be prepared for NaN bugs that didn’t appear before, to suddenly fuck everything up now. For this reason, whenever dividing floating point numbers don’t check for NaN; but Prevent NaN from ever occurring instead.
Tues Aug 27 2013 10:47p
Long live Globals.
(Tongue in cheek)
Wed Aug 28 2013 12:56p
If you can’t avoid having hardcoded constants in your program, at least confine them to a single loader or initialization function and put them in an array as soon as possible.
Sat Aug 31 2013 4:05p
Using a boolean variable to a constructor to indicate whether something is switched on or off isn’t very good. Use a 2-number enumeration instead. What I mean is, the code
MakeLine( EndCapStyle::Flat ) is much more readable than
MakeLine( 0 ).
Sat Aug 31 2013 4:12p
1 is much more readable than true, TRUE, and YES.
Thurs Sept 5 2013 6:15p
Initializer lists: they will bite you in the ass.
Fri Sept 6 2013 7:00p
Every bug is an OPPORTUNITY to uncover a mistake in the engine. A CLUE. If you paste over it and bury it, then that is the opposite of what you should be doing, and you will end up with a mudball.
Tues Sept 10 2013 2:40p
Every concept has a “burn-in” period. That is, anything you work on / paradigm you work in will seem foreign and strange and difficult for the first day, two days, month, whatever the burn in period is. After the burn in period, where you intensively work on a thing, then things start to become familiar things start to make sense. So you can’t get things right the first time for a new concept, because of the burn in period. Plan to iterate, or be happy with whatever the first result looks like.
Tues Sept 10 2013 2:41p
The correct abbreviation for Tuesday is Tues. Not Tue.
Wed Sept 18 2013 4:14p
Floating point subtractions in a squareroot where the values can be close together in value is just asking for the enemy
nanemesis to appear.
sqrtf( 1.f - valuePossiblyCloseTo_1 ) should have CLAMPED
valuePossiblyCloseTo_1 above by 1.f.
Wed Sept 18 2013 4:17p
nan is my enemy.
Mon Sept 23 2013 7:01p
Large amounts of boilerplate code mean something needs a redesign. Often, the API you’re working with is too primitive (doesn’t do enough with little code — e.g. WinAPI via C) or is just old and crufty (browsers ~ early 2000’s).
Large boilerplate means you should refactor the underlying API to do more with less code. Or, if you can’t do that, you should write an API on top of the base API so that the user can do more with less code.
Thurs Oct 3 2013 7:05p
Polling a datastructure for state is usually easier to maintain than changing state.
For example, say you have a UI element that displays the “mode” of a program, call it displayMode. Instead of having code that goes and updates the mode that will be displayed by displayMode, you should have displayMode look up the system mode when it needs to display. The reason this is easier to maintain is, if you don’t poll, then every place the system mode is changed, displayMode must also be updated.
This difficult to follow piece of advice brought to you by bobobobo
Thurs Oct 3 2013 11:31p
I think in computer programming you are continually learning about logic. When debugging, you are often finding a mistake in your logic. A bug is basically: there was a problem in your logic, or you forgot to take care of something.
Sun Oct 6 2013 12:13p
The fastest way to find a class or struct declaration is Xcode is not to cmd+click the class, rather do cmd+shift+F, then type ss classname or ct firstfewlettersofstructname, which will probably only turn up the correct class or struct declaration in search results.
Wed Oct 9 2013 2:55p
Developers or actual active software tech lead not being present at the interview is a red flag.
Thurs Oct 10 2013 8:28a
In software development, paranoia can save you a lot of time*.
* paranoid if statement and error checking means catching bugs early, as soon as they appear. Or, you could use unit tests.
Thurs Oct 10 2013 11:33a
ASSERT is bad. If your assert condition dissolves in release mode, you may have hidden bugs which only appear in release mode (usually uninitialized variable-type bugs).
Tues Oct 15 2013 2:21p
In polled environments (such as games) messages do not have to be passed via function calls. A message can be passed by setting a variable.
As long as the recipient of the message reads the variable frequently (and you have taken care of any threading issues), you can “send a message” by directly setting a variable that the recipient reads every frame.
Tues Oct 15 2013 6:11p
When writing a walkthrough or a tutorial, if you get stuck or end up not liking the progression, starting over, but drawing from the previous attempt, is a powerful way to do it. It clears your mind and relieves you of tension, but you can also draw from your previous work.
Sun Oct 20 2013 1:27p
Clean math==clean code
Tues Oct 22 2013 12:20p
Recruiters are like shoe sales-people, but they try to stuff random customers into random shoes. So you have to tell the recruiter if the shoe doesn’t fit. Otherwise, they’ll keep jamming away.
Tues Oct 22 2013 12:44p
Functors are a great way to customize object behavior per instance, where there isn’t a need to derive a custom class. onMove, onDie are two useful examples.
Fri Oct 25 2013 3:51p
Successful people have a grudge against unsuccessful people, where the successful try to keep the unsuccessful unsuccessful, believing success to only lie with the previously successful. Just a trend.
Fri Oct 25 2013 7:07p
Getting an inheritance hierarchy is a bitch to start out with, but it makes things unbelievably easy to extend and maintain later on if done right.
Sat Oct 26 2013 4:57p
Achievements are kind of like documentation for a game’s special features or hidden capabilities.
I think achievements done right, are like a list of “special” things you might not have known you could do in the gameworld. About discovering hidden things, or doing a task in a special but somehow preferred way (eg 50 x headshots). They shouldn’t be lame like the infamous Avatar 5x achievements you can get in one single place, and they shouldn’t feel like mind numbing work (e.g. “10 million kills”). They should just be like little tasks, akin to Quests from WOW or something similar.
Wed Nov 6 2013 9:09p
Using integer indices into a std::vector over iterators/std::list whenever reasonable (small array, not a lot of insertion into the middle).
Sat Nov 9 2013 12:03p
Meaningless loop counter names such as i, j, k are fine, as long as you are consistent with usage (eg I always use i as the outermost, j for inner loops, and k for triple-nested loops).
Don’t take the “variable names must be meaningful” bit of wisdom overboard. If you have a list of names and use i simply as the loop variable, then i is meaningless and doesn’t need a more meaningful name.
The context of the loop makes it completely clear that i will be the name-number in the list. Don’t use an extra long name like nameNo because you “think” you should.
Sat Nov 23 2013 3:49p
Say you had some branching code in a for loop
for( each checkersquare )
if( isRed ) color=Red ;
else color = Yellow ;
There are a number of ways to do this branchlessly.
The basic way to write branchless code is to write something like:
for( each checkersquare )
color = isRed * Red + (1-isRed) * Yellow
Or, for the specific case of red/yellow alternating patterns,
for( each checkersquare )
color = (1,0,0) + (1,1-isRed,0)
friend functions are just an admission by C++ that public members are sometimes desirable. Java will forever remain in denial.
Bobobobo’s links to non-bobobobo boboboboisms
8 things web designers should keep in mind
Jonathan Blow’s talk on How To Program Independent Games