Stardock coding practices

By on July 31, 2009 11:49:52 AM from Elemental Forums Elemental Forums

CariElf

Join Date 08/2001
+54

We've got a new coder starting on Monday and in order to help him out, my co-workers and I have been compiling a list of guidelines about our coding practices.  Up until now, I've just sat down with new coders and given them a tour of our codebase and tried to convey our coding practices at that point, but new people always have a lot to remember and having a document to refer to might help.  I thought that I'd share our list with you and see if you have any suggestions to add.

                                          Stardock Dev Guidelines

Read Effective C++ 3rd Edition (More Effective C++ is redundant as it's older than the 3rd edition, which compiled the earlier edition of Effective C++ and More Effective C++) and Effective STL.  You'll recognize some of Scott Meyer's tips in the list below, and it will help you write better code. 

1) Make Get functions (functions that just return a variable) const, unless it's returning a pointer or reference to a class that needs to be modified. Also use const correctness when passing variables.

2) Name variables so that they tell something about the variable.

Don't use single letter variables. Even if it's x y and z for coordinates, use the prefix to indicate what type it is.

Try to avoid generic variable names; instead of ulIndex, use ulShipIndex when iterating through a list of ships.

Class names should have a C in front of them unless they're functor, e.g. CBasicGameObject

Basic types should have a prefix before the variable name:

- b for BOOL,

- n for INT,

- l for LONG,

- ul for ULONG,

- f for FLOAT,

- d for DOUBLE,

- sz for null terminated strings,

- str for STL strings,

- c for CHAR (or TCHAR),

- by for BYTE (unsigned char)

Class member variables should have m_ as a prefix, e.g. BOOL m_bInitialized;

Pointers should have a p in the name, e.g. CMapData * m_pMapData;

References can have an r in the name, e.g. CMapData & rMapData;

Global variables should have g_ as a prefix, e.g. CResourceManager * g_pResourceManager;

3) Use the typedefs for the basic types; if we have to port our code to another platform, it will be easier to add in a header with the #defines. Try to avoid using ints as the size of ints can vary based on the OS, use LONGs instead. Use BOOL instead of bool when possible.

4) Game objects, data classes, and graphic resources should be ref counted. So derive them from CCoreRefCount.

5) STL algorithms make your life easier and can be faster than doing the same work manually. It's faster to call std::for_each on a vector and pass it a functor than to loop through the vector yourself. If you do need to loop through a vector yourself, use iterators instead of accessing the elements with the [] operator, particularly if you're going to delete items.

6) #include "Kumquat3D.h" in every header file.

Try to avoid using #include for other files in your header file. Use forward declarations if possible in the .h, then use #include in the .cpp. It helps with compile times.

7) Check for existing code before you re-invent the wheel, and ask about code you're not familiar with before changing it.

8) Use Skype + IRC. If you don't need an immediate answer to a question, this is less disruptive. It takes at least 15 minutes to get back in the zone once you get out of it. Also, you can seach chat logs for conversations that happened over IM and you can't for verbal conversations.

9) Get a Google e-mail for Google docs, and a Windows Live ID for Mesh.

10) When designing your code, think about if this is code that may be used again. If so, it may belong in Kumquat3D rather than the game project, or write a base class in Kumquat3D and inherit it in the game project so that you can use app specific code.

11) Write detailed change log entries. A text file to be used for the change log is saved with each project.

12) Commit the entire module at once so that there's less chance of code being left out, and so that people who are trying to update while you're comitting your changes won't get partial changes and have to update again when you're done.

13) Don't hard-code strings, use the string file for screens and data files for strings. Also try to avoid hardcoding filenames.

14) Use TCHAR types and their functions, and use _T() for literal strings. Not all of our code uses TCHARs, but we're converting it as we go.

15) Write wrapper functions instead of accessing screen code directly from game code, if it's absolutely necessary that the code be done in the screen code rather than game code.

16) Use this-> when calling member functions.

17) It's often useful to create typedefs for container classes, so that if you change from using a vector to a deque, you don't have to search and replace in your code, and even if you don't, it makes the code more readable.

e.g. typedef std::vector<CBasicGameObject*> BasicGameObjectArray;

18) Try to remember to get someone to update to grab your changes after you've commited them so that you can make sure that you've checked everything in and that everything works on someone else's computer. Or check it out yourself on your testbox and make sure that it compiles.

19) Function names should indicate what the function does. Get means that it's returning a value; if you're calculating the variable, use Calculate or Convert or something of that sort in the title. If you're doing more than one thing in the function, consider whether you should be breaking it up into smaller functions, particularly if you find yourself copying and pasting code in the same function. Breaking the functions into smaller functions may also help you make the task more efficient.

Locked Post 100 Replies +1
Search this post
Subscription Options


Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 12:02:44 PM from Elemental Forums Elemental Forums

The scary thing is that with about a year to go on my education (if all goes as planned, I graduate this spring) I only understand about half of that (Okay, closer to 2/3s...)

And even more annoyingly, several parts of what I do understand I only understand because a teacher tossed it out as an unimportant, but amusing, tidbit (const, for example... though I think that's because they want to deal with it in 144 instead of 41 for some reason).


Most annoyingly, is the reference to STL.  I HATE STL.  Why?  Because I wasn't allowed to use it way back in 40 and 41, so I need lots and lots of practice to make it as easy as defining my own classes, much less easier (as it should be).

 

 

Oh well, at least this gives me something to 'shoot' for in my coding practices...  (Edit:  Oh, and some stuff to research...  like the different 'types' of C++ isn't something they mentioned in class, but sounds like it's important!)

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 12:13:22 PM from Stardock Forums Stardock Forums

Thank you for posting these guidelines. I was very curious about them and appreciate it.

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 12:28:29 PM from Elemental Forums Elemental Forums

That was neat, thanks.

edit - Ron, I'm graduated and I didn't understand all of it either. Don't worry about that, if you start working a lot in C++ you'll pick it up.

(I've got a significantly different set of guidelines to work with, this being a .net shop.)

edit 2 - fixed the name, too many people with similar avatars is confusing. (Well, that and I'm dizzy from blowing up baloons all day.)

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 12:30:02 PM from Demigod Forums Demigod Forums

a teacher tossed it out as an unimportant, but amusing, tidbit (const, for example

Funny, my prof always advised using const args by default unless you had some reason not to.

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 12:44:19 PM from Elemental Forums Elemental Forums

Good stuff. Well, aside from hungarian notation. Ack, eww, yuck.

http://www.joelonsoftware.com/articles/Wrong.html

The whole article is about creating good code, but nearer the bottom Joel talks specifically about Hugarian notation, it's original intent versus how it typically ends up being used. The original intent looks pretty good.

 

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 12:45:59 PM from Elemental Forums Elemental Forums

Ron, don't feel too bad.  You'll always learn more once you get some practical experience than you did at school.  A lot of the issue is just scale; the kind of scale you can get in a school project doesn't usually compare to the kind of scale you work with in a professional environment.  Some colleges and universities offer a class called something like "Senior Project" where you have to spend at least a semester working on a large project, sometimes sponsored by a local business.  This is a great opportunity that I saw a lot of my classmates blow off by undertaking too small of a project.  I probably spent at least 30 hours a week on my Senior Project.  Of course, I'd gotten permission to use my project at Stardock as my Senior Project so I was getting paid for that time. (If you're interested, check out LightWeight Ninja.)

The other problem with school projects is that you never have to touch them again after you've done them.  A lot of our code guidelines are for making it easier to go back to a project that you haven't worked on for awhile to fix a bug or start a sequel for.   Or if you bring a new person on to the project, it makes it easier for them to figure it out.

The third problem is that school projects don't necessarily require working with other people, at least not on a regular basis.  That's bad because you learn a lot by working with other people, besides not learning how to code when you're one of a team.

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 12:58:59 PM from Elemental Forums Elemental Forums

The whole article is about creating good code, but nearer the bottom Joel talks specifically about Hugarian notation, it's original intent versus how it typically ends up being used. The original intent looks pretty good.

We don't go overboard on Hungarian notation.  One of the programmers who used to work at Stardock before my time was seriously into it so that if he had a class named classEditFieldsFrame, he used name variables classEditFieldsFrame * pceffEditFieldsFrame.  It was bad.  Now, what we'd do would be call the class CEditFieldsFrame and then delcare the variable like this: CEditFieldsFrame * pPlanetViewFrame; or something like that.

The primary reason that we use the prefixes for type is that it makes it easier to search for variables. It's a lot easier to seach for ulPlanet instead of planet, which will have more hits.  Plus, then you don't have to go and find where the variable is declared in order to know what type it is so that you can use the same type in your for loop.

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 1:14:51 PM from Demigod Forums Demigod Forums

Uhmmmm (mind boggles...)...Can i get ya'll some coffee...a donut perhaps??? Since i did'nt understand i sentance of any of the above, i'll just keep enjoying the end product.

And Lightweight ninja is very cool Cari...it's one of my young son's fav games to mess with atm....

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 1:15:57 PM from Elemental Forums Elemental Forums

The primary reason that we use the prefixes for type is that it makes it easier to search for variables. It's a lot easier to seach for ulPlanet instead of planet, which will have more hits.  Plus, then you don't have to go and find where the variable is declared in order to know what type it is so that you can use the same type in your for loop.

That makes sense. I've worked in Java for 12+ years, which is a different world in some ways. And the 5 years before that of C/C++ was on Solaris which doesn't have the same sort of DWORD, NEAR and FAR pointers and such stuff that Windows has. I know distinguishing between a pointer to something and the thing itself is a big deal, where as in Java everything except primitives is effectively an immutable pointer (ie. everything except primitives is pass by reference).

I'm so used to just hovering over a variable to see it's type in my IDE. Or using "find usages" that's smart enough to search given the context of the variable rather than just searching on it's name. Java code doesn't have globals (well, you can, but they almost never get used). And there aren't the equivalent of .h versus .c files so the declaration of something is always in the same file as it's implementation. Well, ok, there are exceptions, but they're uncommon.

I'm sure Stardock has it well under control , but the Joel Spolsky article certainly made me rethink about Hungarian differently, in a good way.

God I'd love to work on a project like Elemental, but that's just never going to happen. Maybe when I retire, I can join a team as a cheap hobbyist freelancer as a way to have fun and keep busy.

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 1:19:13 PM from Elemental Forums Elemental Forums

Quoting ckessel,

I'm sure Stardock has it well under control , but the Joel Spolsky article certainly made me rethink about Hungarian differently, in a good way.

yeah, me too. Thanks for posting that!

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 1:25:25 PM from Elemental Forums Elemental Forums

I thought of applying for that dev position, but I didn't want to relocate to the midwest, I personally enjoy being on a coast more.

 

Very nice article and while most of it is common sense its overloocks waay too often by developers.  I have the 2nd edition of Effective C++ at home good book.  But I would like also recomment The Mythical Man-Month  as reading for any new employee coming in, Im sure you've read it and is an excellent book on large scale development cycles, if I recall it even has a chapter on bringing new people in midway through a dev cylce.

 

 

Currently Im doing a lot of PHP dev work, but also JAVA, SQL, C/C++ and PERL scripting at the same time.  Writing backend and front end software for routers, but I would love to get into the game development scene someday.  Good luck to your new dev and I can't wait to try out the beta.

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 1:36:51 PM from Elemental Forums Elemental Forums

But I would like also recomment The Mythical Man-Month  as reading for any new employee coming in, Im sure you've read it and is an excellent book on large scale development cycles, if I recall it even has a chapter on bringing new people in midway through a dev cylce.

Classic book . There's a whole bunch I could recommend, but I'll stick with Peopleware as one of my favorites. Construx, founded by Steve McConnell of Code Complete fame (required read if you haven't read it) as well as other books, has a neat list of books here in his "professional development" tracks they use at Construx:

Edit: bleh, forgot the page requires registration (though it's free). Here's a snippet of some of the books.

  • Code Complete, Steve McConnell
  • Programming Pearls 2nd Edition, Jon Bentley
  • Applying UML & Patterns 2nd Ed, Craig Larman
  • Conceptual Blockbusting, James Adams
  • Software Creativity, Robert Glass
  • Rapid Development, Steve McConnell
  • Software Project Survival Guide, Steve McConnell
  • UML Distilled, Martin Fowler et all
  • Writing Solid Code, Steve Maquire
  • Software Implementation, Michael Marcotty
  • More Programming Pearls, John Bentley
  • The Art of Software Testing, Glenford Myers
  • Mastering the Requirements Process, Robertson and Robertson
  • Software Requirements, Karl Wiegers
  • "Manager's Handbook for Software Development", NASA Goddard Space Flight Center
  • Antipatterns and Patterns in Software Configuration Management, William Brown et al
Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 1:44:31 PM from Elemental Forums Elemental Forums

Quoting ckessel,

But I would like also recomment The Mythical Man-Month  as reading for any new employee coming in, Im sure you've read it and is an excellent book on large scale development cycles, if I recall it even has a chapter on bringing new people in midway through a dev cylce.
Classic book . There's a whole bunch I could recommend, but I'll stick with Peopleware as one of my favorites. Construx, founded by Steve McConnell of Code Complete fame (required read if you haven't read it) as well as other books, has a neat list of books here in his "professional development" tracks they use at Construx:

Edit: bleh, forgot the page requires registration (though it's free). Here's a snippet of some of the books.


Code Complete, Steve McConnell
Programming Pearls 2nd Edition, Jon Bentley
Applying UML & Patterns 2nd Ed, Craig Larman
Conceptual Blockbusting, James Adams
Software Creativity, Robert Glass
Rapid Development, Steve McConnell
Software Project Survival Guide, Steve McConnell
UML Distilled, Martin Fowler et all
Writing Solid Code, Steve Maquire
Software Implementation, Michael Marcotty
More Programming Pearls, John Bentley
The Art of Software Testing, Glenford Myers
Mastering the Requirements Process, Robertson and Robertson
Software Requirements, Karl Wiegers
"Manager's Handbook for Software Development", NASA Goddard Space Flight Center
Antipatterns and Patterns in Software Configuration Management, William Brown et al

 

I have a book somewhere at home thats title "Microsoft's guide to writing bug free code."  Still haven't read it.

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 1:51:09 PM from Demigod Forums Demigod Forums

Does Stardock use any scripting languages?

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 2:00:39 PM from Elemental Forums Elemental Forums

Quoting DeadMG,
Does Stardock use any scripting languages?

 

Can you be more specific?  Technically makefiles are scripting and Im sure they have at least those.

 

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 2:09:49 PM from Elemental Forums Elemental Forums

Wow. I love how nothing of that made any sense whatsoever to me.

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 2:11:29 PM from Elemental Forums Elemental Forums

good stuff.  I like how this was put in the elemental journals with what I assume to be Galactic Civilization variables, classes, and functions.  I mean ulShipIndex isn't a variable in Elemental, right?   how similar is the elemental and GalCiv2 code?

I was always frustrated by not hardcoding strings.  I guess I don't like keeping track of several files at once, though I can see how it would be easier to track down problems with strings later.

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 2:17:00 PM from Elemental Forums Elemental Forums

Quoting landisaurus,
I was always frustrated by not hardcoding strings.  I guess I don't like keeping track of several files at once, though I can see how it would be easier to track down problems with strings later.

Translation is where it really shines. We write bilingual (English/French) software where I work. I only speak English. So, when I write the software, I'm writing in English. At some point later on in the development cycle, when the strings are put into a strings file of some type (I'm using .net resource files, but I've also used a formatted text file in other cases), I can just send that file to the translation department.

When it comes back, I drop it in, and poof, the french version exists. To do that with hardcoded strings means you have to *find* all the strings to send them for translation, which is itself a PITA.

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 2:28:03 PM from Elemental Forums Elemental Forums

Does Stardock use any scripting languages?

We're integrating support for Python in the Elemental engine.  The marketing dev uses Javascript, but I'm not sure if any of the webdevs do.

good stuff. I like how this was put in the elemental journals with what I assume to be Galactic Civilization variables, classes, and functions. I mean ulShipIndex isn't a variable in Elemental, right? how similar is the elemental and GalCiv2 code?

Yeah, I used GalCiv names because they're a bit more recognizeable.   The Elemental engine is a cleaned up and updated version of the GalCiv2 engine.  Before a new major project we tend to go through and do an overhaul on the engine because we learn a lot over the course of a project, and technology updates.

I was always frustrated by not hardcoding strings.  I guess I don't like keeping track of several files at once, though I can see how it would be easier to track down problems with strings later.

That, and you can't localize hardcoded strings. Also, hardcoding filenames means that modders can only replace files with those filenames, not add new ones. And again with the searching.  Some of our coders who are no longer here hardcoded strings in GalCiv2: Dread Lords because they wanted to get the work done quickly, and they figured that they could change it later.  Then came the time to localize GalCiv2 and I had to do a search for quote marks to find all the hardcoded strings.  It was not fun. 

The goals of our guidelines are to make the code readable, make it easier to maintain, make it reusable, make it stable and make it efficient.

 

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 2:38:24 PM from Elemental Forums Elemental Forums

This is completely unintelligible. But I love it anyway.

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 2:39:02 PM from Elemental Forums Elemental Forums

We usually use IClassName for interfaces (pure abstract classes).

Also, never use a bool as argument to change the behavior of a function call. Make two functions, or pass an enum with a descriptive name.

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 2:50:07 PM from Elemental Forums Elemental Forums

I have a few suggestions.

 

First type the stack contents in every line of code as a comment.  This helps immensely when troubleshooting random errors, and helps you from developing memory leaks.

 

Second, don't calculate anything in the main program.  Have all calculations done with functions.  Also, make sure each function is short and don't calculate more than one thing in each.  Splitting up the functions like this helps organize the program as you go along, but the most beneficial part of this is that it allows very easy modification of the program.  Need to add a few features? Just adjust a few functions to call out additional functions that your new features will use.  It also makes sure you understand the interrelationships between the functions, so changing one thing won't adversely affect other things in your program.

 

Also, The C Programming Language (Ansi C) by Kenigan and Ritchie is one of the best reference books to have around.  It is a very good book for anyone in the industry. (Even if you aren't just a beginner)

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 2:54:59 PM from Elemental Forums Elemental Forums

Consistent indentation

Every now and then I have to fix up some old script from programmers long past, and the indentation is often completely chaotic.  I just have to go through the file and reformat everything before I can even begin to make sense of it.

 

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 3:03:16 PM from Elemental Forums Elemental Forums

Read Effective C++ 3rd Edition (More Effective C++ is redundant as it's older than the 3rd edition, which compiled the earlier edition of Effective C++ and More Effective C++) and Effective STL. You'll recognize some of Scott Meyer's tips in the list below, and it will help you write better code.

Just for hilarity, here's something that took me a quick websearch to understand...

You weren't reffering to being able to read / work in a specific version of C++ (something that didn't make much sense), you were reffering to two books that I will now have to buy once my financial aid paycheck comes in.

Ron, don't feel too bad.  You'll always learn more once you get some practical experience than you did at school.  A lot of the issue is just scale; the kind of scale you can get in a school project doesn't usually compare to the kind of scale you work with in a professional environment.  Some colleges and universities offer a class called something like "Senior Project" where you have to spend at least a semester working on a large project, sometimes sponsored by a local business.  This is a great opportunity that I saw a lot of my classmates blow off by undertaking too small of a project.  I probably spent at least 30 hours a week on my Senior Project.  Of course, I'd gotten permission to use my project at Stardock as my Senior Project so I was getting paid for that time. (If you're interested, check out LightWeight Ninja.)

Yeah, my school requires either a senior project (3 credit class) or take two of the 'chain' courses.  Probably for much the reasons you're outlining.


Naturally, I went with the latter, and am taking both the video and AI chains -- mainly because I want to take both of those anyway.  Guess it's time to change my mind!  (Basically, there are a bunch of classes that are 'too big' to fit into one semester so they're split into two and called chanis... you're required to take one, two if you want to skip the senior project).

 

Well, at least you confirmed my gradually sinking suspicion that my graduation will not mark the end of my educational career.

 

<<EXPLITIVE STRING DELETED>>

Reason for Karma (Optional)
Successfully updated karma reason!
July 31, 2009 3:14:48 PM from Elemental Forums Elemental Forums

Quoting CariElf,

We don't go overboard on Hungarian notation.  One of the programmers who used to work at Stardock before my time was seriously into it so that if he had a class named classEditFieldsFrame, he used name variables classEditFieldsFrame * pceffEditFieldsFrame.  It was bad.  Now, what we'd do would be call the class CEditFieldsFrame and then delcare the variable like this: CEditFieldsFrame * pPlanetViewFrame; or something like that.

It depends on the type of Hungarian used, too. I agree that the example you sited was a bit overboard. The place I currently work at would call the class EDITFIELDSFRAME and the variable declaration would be "EDITFIELDSFRAME * peffPlanet;" or similar. This scheme has grown on me.

It's interesting to see the style guidlines used at Stardock, thanks for this post.

Reason for Karma (Optional)
Successfully updated karma reason!
Stardock Forums v1.0.0.0    #108433  walnut3   Server Load Time: 00:00:00.0000890   Page Render Time: