1 | | * by Dave Loeser |
2 | | * Version 1. 12 |
3 | | * 10 February 2004 |
4 | | |
5 | | = Objective = |
6 | | |
7 | | The goal of this document is to provide a standardized coding methodology for the 0 A.D. programming team. With but a few guidelines such as Layout, Commenting and Naming conventions the team should feel as if they are reading their own code when reading someone else�s code. |
8 | | |
9 | | == Forewarning == |
10 | | |
11 | | Since this document was created after the start of preliminary coding, there may be source code that does not follow the guidelines as dictated by this document. |
12 | | |
13 | | The team will, as time permits, make an effort to update those sources. |
14 | | |
15 | | = Layout = |
16 | | |
17 | | == Formatting == |
18 | | |
19 | | Most editors allow for the conversion of tabs to spaces and most people prefer the use of tabs versus wearing the space-bar out. The size of the tabs is up to each programmer � just ensure that you are using tabs. |
20 | | |
21 | | Limit the length of a line of code to not more than 80 characters; not everyone has a 1600x1200 resolution. Functions that have many parameters and extend over 80 characters should be written: |
22 | | |
23 | | {{{ |
24 | | SomeFunction( |
25 | | HWND hWnd_, |
26 | | BITMAP bmDeviceBitmap_, |
27 | | long lAnimationFrame_); |
28 | | }}} |
29 | | |
30 | | as opposed to |
31 | | |
32 | | {{{ |
33 | | SomeFunction(HWND hWnd_, |
34 | | BITMAP bmDeviceBitmap_, |
35 | | long lAnimationFrame_); |
36 | | }}} |
37 | | |
38 | | Although the second method is commonly used, it is more difficult to maintain if the name of the function changed; you would need to re-align the parameters. |
39 | | |
40 | | == Brackets == |
41 | | |
42 | | Brackets should be aligned, here�s an example of valid bracket alignment: |
43 | | |
44 | | === Good Bracketing === |
45 | | |
46 | | {{{ |
47 | | void CGameObject::CleanUp() |
48 | | { |
49 | | if(NULL != m_ThisObject) |
50 | | { |
51 | | delete m_ThisObject; |
52 | | } |
53 | | } |
54 | | }}} |
55 | | |
56 | | === Bad Bracketing === |
57 | | |
58 | | {{{ |
59 | | void CGameObject::CleanUp(){ |
60 | | if(NULL != m_ThisObject){ |
61 | | delete m_ThisObject; |
62 | | } |
63 | | } |
64 | | }}} |
65 | | |
66 | | We�re not out to save vertical lines on the screen; it�s about being able to read the code; reading code is a visual experience if not visceral. |
67 | | |
68 | | = Commenting and Documentation = |
| 1 | == Objective == |
| 2 | |
| 3 | The goal of this document is to provide a standardized coding methodology for the 0 A.D. programming team. With but a few guidelines for layout, commenting and naming conventions, the team should feel as if they are reading their own code when reading someone else's code. |
| 4 | |
| 5 | == Layout == |
| 6 | |
| 7 | === Formatting === |
| 8 | |
| 9 | Most editors allow for the conversion of tabs to spaces and most people prefer the use of tabs versus wearing out the spacebar. The size of the tabs is up to each programmer -- just ensure that you are using tabs. |
| 10 | |
| 11 | Limit the length of a line of code to not more than 80 characters; not everyone has a 1600x1200 display. Functions that have many parameters and extend over 80 characters should be written as: |
| 12 | {{{ |
| 13 | SomeFunction( |
| 14 | HWND hWnd, |
| 15 | BITMAP bmDeviceBitmap, |
| 16 | long lAnimationFrame); |
| 17 | }}} |
| 18 | instead of: |
| 19 | {{{ |
| 20 | SomeFunction(HWND hWnd, |
| 21 | BITMAP bmDeviceBitmap, |
| 22 | long lAnimationFrame); |
| 23 | }}} |
| 24 | Although the second method is commonly used, it is more difficult to maintain (if the name of the function changed, you would need to re-align the parameters). |
| 25 | |
| 26 | === Brackets === |
| 27 | |
| 28 | Brackets should be aligned, here's an example of good bracket placement: |
| 29 | {{{ |
| 30 | void CGameObject::CleanUp() |
| 31 | { |
| 32 | if(NULL != m_ThisObject) |
| 33 | { |
| 34 | delete m_ThisObject; |
| 35 | } |
| 36 | } |
| 37 | }}} |
| 38 | Now we're not out to save vertical lines on the screen; it's about being able to read the code. Therefore, the following style should be avoided: |
| 39 | {{{ |
| 40 | void CGameObject::CleanUp() { |
| 41 | if(NULL != m_ThisObject) { |
| 42 | delete m_ThisObject; |
| 43 | } |
| 44 | } |
| 45 | }}} |
72 | | Commenting is a subject that is sure to cause debate. I prefer minimum comments and maximum expressiveness in the code. Examples of what is considered good and bad commenting style are shown below. |
73 | | |
74 | | === Bad Commenting Style === |
75 | | |
76 | | {{{ |
77 | | void CGameObject::SetModifiedFlag(bool flag) |
78 | | { |
79 | | // set the modified flag |
80 | | |
81 | | m_bModifiedFlag = flag; |
82 | | } |
83 | | }}} |
84 | | |
85 | | The above comments do not tell us anything that we don�t already know from reading the code, here�s a better approach. |
86 | | |
87 | | === Good Commenting Style === |
88 | | |
89 | | {{{ |
90 | | void CGameObject::SetModifiedFlag(bool flag) |
91 | | { |
92 | | // This sets the GameObjects modified |
| 49 | Commenting is a subject that is sure to cause debate, but minimal comments with maximum expressiveness are preferable. Bad commenting style is shown below: |
| 50 | {{{ |
| 51 | void CGameObject::SetModifiedFlag(bool flag) |
| 52 | { |
| 53 | m_ModifiedFlag = flag; // set the modified flag |
| 54 | } |
| 55 | }}} |
| 56 | The above comment does not tell us anything that we don't already know from reading the code; here's a better approach: |
| 57 | {{{ |
| 58 | void CGameObject::SetModifiedFlag(bool flag) |
| 59 | { |
| 60 | // This sets the CGameObject's modified |
95 | | |
96 | | m_bModifiedFlag = flag; |
97 | | } |
98 | | }}} |
| 63 | m_ModifiedFlag = flag; |
| 64 | } |
| 65 | }}} |
| 66 | |
| 67 | == Naming Conventions == |
| 68 | |
| 69 | === Filenames === |
| 70 | |
| 71 | Filenames can be freely chosen, but to avoid problems on Unix systems, they should not contain spaces or non-ASCII characters. If the file serves to define one class, e.g. `CEntity`, the file would usually be called `Entity.h`. |
| 72 | |
| 73 | === Namespaces === |
| 74 | |
| 75 | Namespaces are used as a mechanism to express logical grouping. |
| 76 | |
| 77 | ==== Global Scope ==== |
| 78 | |
| 79 | Symbols belonging to the global namespace should be prefixed with `::`. |
| 80 | Example: The Win32 function `::OutputDebugString()` resides in the global namespace and is written with the scope operator preceding the function name. |
| 81 | |
| 82 | === Classes === |
| 83 | |
| 84 | Classes should use concise, descriptive names that easily convey their use. |
| 85 | |
| 86 | Classes are named using !PascalCase - capitalizing each word within the name visually differentiates them. Example: A class named `CGameObject` is preferred over `gameObject` or `cGameObject`. |
| 87 | |
| 88 | === Functions === |
| 89 | |
| 90 | Functions should use concise, descriptive names that provide innate clues as to the functionality they provide. |
| 91 | |
| 92 | Global and member functions should be named using !PascalCase. Example: A function named `SetModifiedFlag()` is preferred over `SetFlag()` or `setFlag`. |
| 93 | |
| 94 | === Variables === |
| 95 | |
| 96 | Variable should use concise, descriptive names that provide innate clues as to the data that the variable represents. |
| 97 | |
| 98 | Member variables should be prefixed with `m_`, but both `m_camelCase` and `m_PascalCase` may be used according to personal preference (either way, the prefix ensures clarity). Example: `m_GameObject` is more descriptive than `gobj`. |
102 | | Each programmer is responsible for properly documenting their code. During code review the code reviewer will ensure that interfaces or API�s are properly documented. |
103 | | |
104 | | The suggested method of documenting a Class is: |
105 | | |
106 | | {{{ |
107 | | /* |
108 | | CLASS : CCivilian |
109 | | AUTHOR : Dave Loeser - daklozar@insightbb.com |
110 | | DESCRIPTION : An object that represents a civilian entity. |
111 | | |
112 | | NOTES : Notes regarding usage and possible problems etc... |
113 | | */ |
114 | | }}} |
115 | | |
116 | | Each method of a class should be documented as well and here is the suggested method of documenting a member function (continuing with CExample): |
117 | | |
118 | | {{{ |
119 | | class CExample |
120 | | { |
121 | | public: |
122 | | CExample(); |
123 | | ~CExample(): |
| 102 | Each programmer is responsible for properly documenting their code. During code review the code reviewer will ensure that interfaces or APIs are properly documented. |
| 103 | |
| 104 | If the comments are formatted in a certain way, they will automatically be extracted and added to the relevant documentation file. It suffices to write them as follows (sample comment for a class): |
| 105 | {{{ |
| 106 | /** |
| 107 | * An object that represents a civilian entity. |
| 108 | * |
| 109 | * (Notes regarding usage and possible problems etc...) |
| 110 | **/ |
| 111 | }}} |
| 112 | For single-line comments, `///` can be used as well. The comment text is inserted into the documentation, and can additionally be formatted by certain tags (e.g. `@param description` for function parameters). For more details, see the !CppDoc documentation. |
| 113 | |
| 114 | Each method of a class should be documented as well and here is the suggested method of documenting a member function (continuing with `CExample`): |
| 115 | {{{ |
| 116 | class CExample |
| 117 | { |
| 118 | public: |
| 119 | CExample(); |
| 120 | ~CExample(): |
| 121 | |
| 122 | /** |
| 123 | * This function does nothing, but is a good example of |
| 124 | * documenting a member function. |
| 125 | * @param dummy A dummy parameter. |
| 126 | **/ |
| 127 | void ShowExample(int dummy); |
| 128 | |
| 129 | private: |
| 130 | intptr_t m_ExampleData; // Holds the value of this example. |
| 131 | double m_FairlyLongVariableName; // Shows the lining up of comments |
| 132 | }; |
| 133 | }}} |
| 134 | The ctor and dtor need not be commented --- everyone knows what they are and what they do. `ShowExample()`, on the other hand, provides a brief comment as to its purpose. You may also want to provide an example of a method's usage. Member data is commented on the right side and it is generally good (when possible) to line up comments for easier reading. |
| 135 | |
| 136 | === Author and Modified By === |
| 137 | |
| 138 | To promote collective code ownership and encourage making necessary fixes to modules that happen to be written by others, we will avoid explicitly mentioning the author at the top of the file. Such a tag could (subconsciously) be interpreted as "his code only", a condition we want to avoid because "he" might get run over by a bus (thus losing the only source of knowledge and expertise on that piece of code). |
| 139 | |
| 140 | On a similar note, we will also avoid modified-by tags. The reasoning is as above, with the additional wrinkle of having to figure out when exactly to consider oneself to have modified the code. Is it after a quick typo fix, adding 2 lines, a function, ...? |
| 141 | |
| 142 | Note that the authors of course retain copyright; we can also reconstruct the file history and find out all contributors via SVN revision information. The purpose of this measure is simplicity and improved cooperation and does not deprive anyone of credit. |
| 143 | |
| 144 | |
| 145 | === Example === |
| 146 | |
| 147 | Here is a sample header file layout, `Example.h`: |
| 148 | {{{ |
| 149 | /** |
| 150 | * ========================================================================= |
| 151 | * File : Example.h |
| 152 | * Project : 0 A.D. |
| 153 | * Description : CExample interface file. |
| 154 | * ========================================================================= |
| 155 | **/ |
| 156 | |
| 157 | /* |
| 158 | This interface is difficult to write as it really |
| 159 | pertains to nothing and serves no purpose other than to |
| 160 | suggest a documentation scheme. |
| 161 | */ |
| 162 | |
| 163 | #ifndef INCLUDED_EXAMPLE |
| 164 | #define INCLUDED_EXAMPLE |
| 165 | |
| 166 | #include "utils.h" |
| 167 | |
| 168 | /** |
| 169 | * CExample |
| 170 | * This serves no purpose other than to |
| 171 | * provide an example of documenting a class. |
| 172 | * Notes regarding usage and possible problems etc... |
| 173 | **/ |
| 174 | class CExample |
| 175 | { |
| 176 | public: |
| 177 | CExample(); |
| 178 | ~CExample(): |
| 179 | |
| 180 | /** |
| 181 | * This function does nothing, but is a good example of |
| 182 | * documenting a member function. |
| 183 | * @param dummy A dummy parameter. |
| 184 | **/ |
| 185 | void ShowExample(int dummy); |
| 186 | |
| 187 | protected: |
| 188 | int m_UsefulForDerivedClasses; |
| 189 | |
| 190 | private: |
| 191 | uint8_t m_ExampleData; // Holds the value of this example. |
| 192 | int m_RatherLongVariableName; // Shows the lining up of comments |
| 193 | }; |
| 194 | |
| 195 | #endif // #ifndef INCLUDED_EXAMPLE |
| 196 | }}} |
| 197 | From the above we can see that header guards are utilized. Header file comment blocks show filename, project and author; a short overview follows. |
| 198 | |
| 199 | The order of declarations ought to be: public followed by protected and finally by private. |
125 | | // ShowExample() |
126 | | // This function does nothing, but is a good example of documenting |
127 | | // a member function. |
128 | | void ShowExample(); |
129 | | |
130 | | private: |
131 | | U8 m_ExampleData; // Holds the value of this example. |
132 | | U8 m_LongVariableName; // Shows the lining up of comments |
133 | | }; |
134 | | }}} |
135 | | |
136 | | Essentially, the CTOR and DTOR need not be commented � everyone knows what they are and what they do. !ShowExample(), on the other hand, provides a brief comment as to its purpose. You may also want to provide an example of a methods usage. Member data is commented on the right side and it is generally a good ideal (when possible) to line up comments for easier reading. |
137 | | |
138 | | = Naming and Coding Conventions = |
139 | | |
140 | | Naming and coding conventions cover two main areas: |
141 | | |
142 | | * Files and directory structures |
143 | | * Variables, functions and classes |
144 | | |
145 | | == Namespaces == |
146 | | |
147 | | Namespaces are used as a mechanism to express logical grouping. |
148 | | |
149 | | == Global Scope Functions == |
150 | | |
151 | | A function that is belongs to the global namespace should be prefixed with ::. |
152 | | |
153 | | ''Example:'' The Win32 function '''::!OutputDebugString()''' belongs to the global namespace and is written with the scope operator preceding the function name. |
154 | | |
155 | | == Variable Naming == |
156 | | |
157 | | Variables should use concise, descriptive names that provide innate clues as to the data that the variable represents. |
158 | | |
159 | | == Function Naming == |
160 | | |
161 | | Functions should use concise, descriptive names that provide innate clues as to the functionality they provide. |
162 | | |
163 | | ''Example:'' A function named '''!SetModifiedFlag()''' is preferred over '''!SetFlag()'''. |
164 | | |
165 | | Global and member functions should be named using ''Inclusive capitalisation.'' Inclusive capitalisation is a method that visually differentiates the words within a function name. |
166 | | |
167 | | ''Example:'' A function named '''!SetModifiedFlag()''' is preferred over '''setModifiedFlag()''' or '''setmodifiedflag()'''. |
168 | | |
169 | | == Class Naming == |
170 | | |
171 | | Classes should use concise, descriptive names that easily covey their use. Classes should be named using ''Inclusive capitalisation''. Inclusive capitalisation is a method that visually differentiates the words within a class name. |
172 | | |
173 | | ''Example:'' Every game has objects and '''CGameObject''' is more descriptive than '''cGObj''' or '''CGobj'''. |
174 | | |
175 | | == Header Files == |
176 | | |
177 | | Here is a sample header file layout. |
178 | | |
179 | | {{{ |
180 | | /* |
181 | | |
182 | | CExample interface file. |
183 | | |
184 | | AUTHOR : Joe Coder � joecoder@email.com |
185 | | MODIFIED BY : Coder Johnson - coder@email.com |
186 | | |
187 | | OVERVIEW : This interface is difficult to write as it really |
188 | | pertains to nothing and serves no purpose other than to |
189 | | suggest a documentation scheme. |
190 | | */ |
191 | | |
192 | | #ifndef __CEXAMPLE_H__ |
193 | | #define __CEXAMPLE_H__ |
194 | | |
195 | | // |
196 | | // INCLUDES and COMPILER DIRECTIVES |
197 | | // |
198 | | #include �utils.h� |
199 | | |
200 | | // |
201 | | // DECLARATIONS |
202 | | |
203 | | /* |
204 | | CLASS : CExample |
205 | | AUTHOR : Coder Johnson - coder@email.com |
206 | | DESCRIPTION : The CExample class serves no purpose other than to |
207 | | provide an example of documenting a class. |
208 | | NOTES : Notes regarding usage and possible problems etc... |
209 | | */ |
210 | | |
211 | | class CExample |
212 | | { |
213 | | public: |
214 | | |
215 | | CExample(); |
216 | | ~CExample(): |
217 | | |
218 | | // ShowExample() |
219 | | // This function does nothing, but is a good example of documenting |
220 | | // a member function. |
221 | | void ShowExample(); |
222 | | |
223 | | protected: |
224 | | |
225 | | private: |
226 | | |
227 | | U8 m_ExampleData; // Holds the value of this example. |
228 | | U8 m_LongVariableName; // Shows the lining up of comments |
229 | | }; |
230 | | |
231 | | #endif // __CEXAMPLE_H__ |
232 | | }}} |
233 | | |
234 | | From the above we can see that header guards are utilized. Header file comment blocks have been shortened to show the name of the module this file belongs to, the authors name and email address and a short overview. |
235 | | |
236 | | The order of declarations is public followed by protected and finally by private. See [http://code.wildfiregames.com/resources/development/CCivilian.h.html CCivilian.h] for an example. |
237 | | |
238 | | = Standard Template Library = |
| 201 | == Standard Template Library == |
242 | | Having said that I prefer to wrap up specific STL object in an effort to make the code more readable � see [http://code.wildfiregames.com/resources/development/CCivilian.h.html CCivilian.h] for an example. |
243 | | |
244 | | = Global variables or Singletons = |
245 | | |
246 | | Much debate regarding the use of global variables has been generated over the years so I will not re-enter that discussion. I will say that the Singleton design pattern does provide many benefits over that of a pure global variable. |
247 | | |
248 | | We will make use of the Automatic Singleton Utility as described by Scott Bilas in article 1.3 of the �Game Programming Gems�, volume I, �An Automatic Singleton Utility.� |
249 | | |
250 | | = Strings = |
251 | | |
252 | | A string class has been written, CStr, that should be used instead of directly using std::string or using C-style strings (i.e. char*). |
| 205 | Having said that, it may make sense to hide some uses of STL objects behind an interface. This can make the code more readable. |
| 206 | |
| 207 | == Singletons == |
| 208 | |
| 209 | Much debate regarding the use of global variables has been generated over the years so we will not re-enter that discussion. The Singleton design pattern does provide many benefits over that of a pure global variable. |
| 210 | |
| 211 | We will make use of the Automatic Singleton Utility as described by Scott Bilas in article 1.3 of the "Game Programming Gems", volume I, "An Automatic Singleton Utility". |
| 212 | |
| 213 | == Strings == |
| 214 | |
| 215 | A string class has been written, `CStr`, that should be used instead of directly using `std::string` or using C-style strings (i.e. `char*`). |