]> git.pond.sub.org Git - empserver/blob - doc/coding
New, more comprehensive guidelines. Compiled existing Empire
[empserver] / doc / coding
1                 Guidelines for Writing Empire Code
2
3              compiled and edited by Markus Armbruster
4
5 Preface
6 -------
7
8 Empire is an old program, and the age shows in places.  It took a lot
9 of people a lot of effort to write it.  Chances are that some of them
10 were smarter than you and me.  Treat the code with the respect it
11 deserves.
12
13 These guidelines are just that: guidelines.  Not law.  There's no
14 Empire Coding Police.  People hacked on Empire code long before I knew
15 it existed, and I hope they still will when I fade into Empire
16 history.  But there's substantial experience behind these guidelines,
17 so don't dismiss them cavalierly.
18
19 Here's our goal: algorithmic clarity.  All the rules and guidelines
20 are subservient to it.  If you'd have to obfuscate your code to
21 satisfy the letter of some guideline, don't!
22
23 Mind, I said `clarity', not `self-realization' or `expression of your
24 individuality'.  Dave Pare wrote:
25
26   Be invisible.  When you make a change, think not about marking your
27   place in history, or about showing off how much nicer your two-space
28   tabs are than those old, icky eight-space tabs that the stupid
29   empire hackers of old used, but think instead about the aesthetics
30   of the whole.  The resulting lines of code should flow smoothly from
31   the beginning of the procedure to the end.  Empire is 60,000 lines
32   of code.  If you're the general case, you're only changing fifty
33   lines, so be aware of that.
34
35 Some guidelines are more serious than others.  When I use words like
36 `is', `shall' or `must', I mean it.  When I write `should', it's a
37 recommendation.
38
39 Many guidelines concern style, i.e. they involve matters of taste.
40 That's how it has to be.  Uniformity of style is important for
41 clarity.
42
43 These guidelines don't attempt to be exhaustive.  More complete
44 guidelines that are mostly compatible with Empire can be found at
45 http://www.jetcafe.org/~jim/c-style.html
46
47
48 Source tree organization
49 ------------------------
50
51 FIXME
52
53
54 Code formatting
55 ---------------
56
57     In My Egotistical Opinion, most people's C programs should be
58     indented six feet downward and covered with dirt."
59         -- Blair P. Houghton
60
61 Over the years, enough Empire coders lacked the good taste to preserve
62 the style of the original Empire code in their changes, and thus
63 turned the source code into an unreadable mess.  In 2003, we fed it to
64 GNU indent.
65
66 We tried to restore things to the original style, mostly.  There is
67 one noteable change: basic indentation is now four spaces.  Restoring
68 the original eight spaces would have resulted in many more long lines,
69 which would have to be broken by indent.  Since indent isn't good at
70 breaking lines tastefully, we reluctantly chose four instead.
71
72 FIXME mention src/scripts/intend-emp, even better: convert it into an
73 indent profile and mention that.
74
75 If you use Emacs, `stroustrup' indentation style produces satisfactory
76 results.  The command `c-set-style', normally bound to `C-c .', lets
77 you set the style for the current buffer.  Set variable
78 `c-default-style' to "stroustrup" to switch to this style for all
79 buffers.
80
81 Tab character use
82
83 Whether you use tab characters or not doesn't really matter that much,
84 but tab stops are every eight characters, period.
85
86 Indentation, placement of braces, function name
87
88 Basic indentation is four spaces.  The opening brace goes on the same
89 line as `if', `struct', etc.  Put `else' and do loops' `while' one the
90 same line as the closing brace.  You are encouraged to leave out
91 syntactically optional braces.  Don't indent case labels.
92
93 Example:
94
95         if (is_fubar())
96             despair();
97         else {
98             do {
99                 char ch = getchar();
100                 switch (ch) {
101                 case EOF:
102                     return;
103                 case '\n':
104                     break;
105                 default:
106                     grind_along(ch);
107                 }
108             } while (happy());
109         }
110
111 In a function definition, the return type, function name and the
112 braces must all start on a new line, unindented, like this:
113
114         type
115         name(arguments)
116         {
117             body
118         }
119
120 This does not apply to function declarations.
121
122 Breaking long lines
123
124 Line length should not exceed 75 characters.  Break such lines at a
125 logical place, preferably before an operator with low precedence.
126 Line up the continuation line with the innermost unclosed parenthesis,
127 if there is one, else indent it four spaces.
128
129 Example:
130
131         FIXME
132
133 Bad example:
134
135         FIXME
136
137 Blank lines
138
139 Use blank lines to separate different things.  Functions must be
140 separated by a blank line.  You are encouraged to insert a blank line
141 between a block's declarations and statements.
142
143 Spaces
144
145 There is a space after `for', `if', and `while'.  If `for' and `while'
146 are followed by `;' (empty loop body) on the same line, there is a
147 space before the `;'.  There is no space between the function name and
148 the `(', but there is a space after each `,'.  There should be no
149 space between type cast operator and operand.  There is no extra space
150 after '(' and before ')'.
151
152 Example:
153
154         for (p = s; *p; ++p) ;
155         printf("%ld\n", (long)(p-s));
156
157 Comments
158
159 The function comment describing what a function does goes directly
160 above the definition.
161
162 Comments to the right of code should start in column 32 if possible
163 (counting from zero).
164
165 Comment lines should be indented exactly like the code the belong to.
166
167 You are encouraged to format multi-line comments like this:
168
169         /*
170          * Please use complete sentences, with proper grammer,
171          * capitalization and puntuation.  Use two spaces between
172          * sentences.
173          */
174
175 But please avoid elaborate boxes like this:
176
177         /***********************************************************
178          * Such decorations are a waste of time, hard to edit, and *
179          * ugly, too.                                              *
180          ***********************************************************/
181
182 Conditional compilation
183
184 Unless the conditional code is very short, please comment it like
185 this:
186
187         #ifdef FOO
188         ...
189         #endif /* FOO */
190
191         #ifdef BAR
192         ...
193         #else  /* !BAR */
194         ...
195         #endif /* !BAR */
196
197
198 Style
199 -----
200
201 Names
202
203 DoNotUseStudlyCaps!  Stick to lower_case and use underscores.  Upper
204 case is for macros and enumeration constants.
205
206 File names should not differ in case only, since not all file systems
207 distinguish case.  Best stick to lower case.  Avoid funny characters
208 in file names.  This includes space.
209
210 Preprocessor
211
212 Like many good things, the preprocessor is best used sparingly.
213 Especially conditional compilation.
214
215 Do not use the preprocessor to `improve' the syntax of C!
216
217 Macro names should be ALL_CAPS to make them stand out.  Otherwise,
218 they can be mistaken for objects or functions.  This is bad, because
219 `interesting' behavior can hide inside macros, like not evaluating
220 arguments, or changing them.  Exception: if a function-like macro
221 behaves exactly like a function, then you may use a lower case name.
222
223 Parameters that can take expression arguments must be parenthesized in
224 the expansion.  If the expansion is an expression, it should be
225 parenthesized as well.
226
227 You are encouraged to use enumeration constants instead of macros when
228 possible.  The existing code doesn't, but it makes sense all the same.
229
230 Comments
231
232 Every file should have a file comment FIXME
233
234 Every function should have a function comment that describes what it
235 does.  FIXME elaborate.  Writing such comments helps both future
236 maintainers and yourself: if it's too hard to write a concise function
237 comment, then your function is likely too complicated and could use a
238 redesign.
239
240 The existing code has very little useful comments, and it'll likely
241 take us years to fix it.  Please don't make it harder than it already
242 is.
243
244 Declarations
245
246 Do not declare system functions yourself; include the appropriate
247 system header.
248
249 Use prototypes, not old-style function declarations.
250
251 To get the best use of C's type checking, each function or variable
252 with external linkage should have exactly one declaration, in some
253 header file, and that declaration must be in scope at the definition.
254 No other declarations should exist.  In particular, please include the
255 appropriate header instead of just declaring stuff again.  The code
256 used to be full of this kind of junk, and it was quite some work to
257 clean it up.
258
259 Forward declarations of static functions should all go in one place
260 near the beginning of the file.
261
262 If you want a typedef name in addition to a structure or union tag,
263 give it the same name, like this:
264
265         typedef struct foo foo;
266
267 Yes, this is incompatble with C++.  Reducing the number of names for
268 the same thing is more useful than compatibility to a programming
269 language we don't use.
270
271 Please don't hide away pointers with typedefs, like this:
272
273        typedef struct foo *foop;
274
275 When I see `foo *', I *know* what it is.  When I see `foop', I have to
276 look it up.
277
278 Type casts
279
280 Casting pointers to and from `void *' clutters the code and serves no
281 purpose (repeat after me: C is not C++).  It is also unsafe, because
282 the cast suppresses type warnings.
283
284 Casting function values to void clutters the code and serves little
285 purpose (repeat after me: C is not Pascal).
286
287 Casting an argument to the type of the parameter clutters the code and
288 serves no purpose (repeat after me: ISO C is not K&R C).
289
290 Factor out common code
291
292 Do not gratuitiously duplicate code!  Ken Stevens said it well, and
293 it's as relevant as ever:
294
295   Cut-and-Paste coding is by far the biggest problem that the current
296   Empire suffers from.  This is how cut-and-paste coding happens.  Joe
297   Shmuck decides that he wants to add a new function to the server.
298   So he goes hunting through the server to find some already existing
299   code which does something similar to what he wants to do.  This is
300   good.  You should always write new code to imitate old code.  What
301   is bad is when Joe Shmuck decides to simply "copy" 200 lines of code
302   from the old function into his new function, and then just change a
303   couple of little things here and there to suit his needs.  This
304   method, known as Cut-and-Paste coding is the fastest and easiest way
305   to code.  However, it results in a server that is impossible to
306   maintain.  What Joe _should_ have done, is "move" the 200 lines of
307   code into a new _third_ function which the first two both call.
308   This is called writing a "general solution" to handle both cases.
309   Most of my work in the Empire2 project consisted in cleaning up
310   after a bunch of Joe Shmucks.
311
312
313 Portability
314 -----------
315
316 FIXME C89, POSIX
317
318 FIXME sizes, printf formats
319
320 FIXME reserved names
321
322 FIXME conditional compilation is a last resort
323
324 FIXME s_char
325
326
327 Robustness
328 ----------
329
330 Error checking
331
332 Check error conditions meticulously.  The existing code is bad enough
333 at this, please don't make it worse.
334
335 FIXME what to do on error
336
337 Buffer overruns
338
339 FIXME
340
341 Thread safety
342
343 Empire uses non-preemptive threads: a thread runs until it yields the
344 processor.  This simplifies programming, but there are still traps to
345 avoid.  Empire threads may yield the processor whenever they do I/O or
346 FIXME elaborate
347
348 Be careful with static storage.  Read-only data is fine.  More than
349 one thread writing static data is problematic, but there are safe
350 uses.  For instance, a static scratch buffer that is never used across
351 `yields' is safe.
352
353 Thread stacks cannot grow.  If you use too much automatic storage, you
354 can overrun the stack with disastrous consequences.  FIXME elaborate
355
356 Yielding the processor invalidates *all* the game state you copied
357 into variables.  You have to reread and possibly recheck.  See below.
358
359 Accessing game state
360
361 Game state consists of several sets of objects, e.g. sectors, ships,
362 bmaps, ...  Each set is fully held in memory and backed by a file in
363 the data directory.
364
365 There are several ways to access an object in set FOO:
366
367 * You can get a pointer to the object (not a copy!) with getFOOp().
368
369   This is inherently dangerous, because it allows you to update the
370   object in memory without updating the disk file.  It's used mostly
371   in update code, where it pays major performance dividends, but there
372   are uses in other places.  Whether they are wise is debatable.
373
374   Obviously, the object can change when you let another thread run.
375   This is not an issue in update code, because it never yields.
376
377 * You can get a copy with getFOO() and write it back with putFOO().
378
379   Yielding the processor invalidates the copy.  In particular, if you
380   yield the processor between get and put, and another thread changes
381   the game data, then put will clobber that change, possibly resulting
382   in a corrupted game.
383
384   Therefore, you have to re-get after a yield, and repeat any checks
385   you already made.  If you can afford to bail out when something
386   changed at all, use check_FOO_ok().
387
388   Putting updates both the object in memory and the disk file.
389
390   If you write a function that takes a pointer to an object, think
391   twice before you put it, and if you do, mention it in the function
392   comment.
393
394 * Bmaps have special access functions.
395
396   Each country has to bmaps: the working bmap and the true bmap.
397   Unfortunately, the bmap code called the former `bmap' and the latter
398   `map'.
399
400   You update bmaps with map_set().  This doesn't write through to the
401   file; instead, it returns non-zero when the update changed anything.
402   In that case, you must write bmaps to disk with writemap() before
403   you yield.  If you only updated the working bmap, then you can call
404   writebmap() instead.
405
406
407 CVS
408 ---
409
410 Commit related changes together, unrelated changes separately.
411
412 See chapter Change Logs in the GNU coding standards for guidelines on
413 log messages.  Try http://www.gnu.org/prep/standards_40.html#SEC40 or
414 search the web for `gnu coding standards change logs'.
415
416 Don't change whitespace gratuitiously, say just because your editor
417 screws up tabs.  Such changes make it much harder to figure out who
418 changed what and when.
419
420 \f
421 Historical guidelines, superseded by the above
422
423
424 Remarks from Dave Pare:
425
426 And now, a few editorial remarks on my views on Good Techniques for
427 Modifying Existing Software:
428
429 My safari through the hot and bug-ridden jungle that Empire has become
430 has given me some new insights on the modification of large software
431 packages.  My adventure has prompted me to propose some simple coding
432 guidelines for those dreaming of hacking on the code:
433
434 1) Be invisible.  When you make a change, think not about marking your
435 place in history, or about showing off how much nicer your two-space
436 tabs are than those old, icky eight-space tabs that the stupid empire
437 hackers of old used, but think instead about the asethetics of the whole.
438 The resulting lines of code should flow smoothly from the beginning of the
439 procedure to the end.  Empire is 60,000 lines of code.  If you're the
440 general case, you're only changing fifty lines, so be aware of that.
441
442 2) Procedurize.  If you find yourself in a triple-nested loop, or a five
443 hundred line procedure, perhaps it's because you need to split some of
444 that code off into a procedure.  In general, if you've got more than two
445 levels of tabs (or indentations), or more than one or two major loops in
446 a procedure, something may well be amiss.
447
448
449 Sasha Mikheev on indentation:
450
451 The empire indentation style can be achived by using 
452 indent -orig -i8 foo.c
453
454 or in old c-mode emacs (versions before 19.29):
455 ;add this to .emacs
456 (setq c-indent-level 8)
457 (setq c-continued-statement-offset 8)
458 (setq c-argdecl-indent 8)
459 (setq c-brace-offset -8)
460 (setq c-label-offset -8)
461
462
463 Further comments by Ken Stevens:
464
465 1) Global variables
466 The only variables which should be global are constants.  If you write
467 a routine which changes a global variable, then you will corrupt the
468 data when two different players run that routine at the same time.
469
470 2) Portability.
471 The following code:
472                 char    a;
473         #ifdef FOO
474                 unsigned char b;
475         #endif FOO
476 Should be rewritten as:
477                 s_char  a;
478         #ifdef FOO
479                 u_char  b;
480         #endif /* FOO */
481
482 AIX has different conventions for signed chars, and IRIX requires the
483 /* comments */ after #endif.
484
485 3) Cut-and-Paste
486 Cut-and-Paste coding is by far the biggest problem that the current
487 Empire suffers from.  This is how cut-and-paste coding happens.  Joe
488 Shmuck decides that he wants to add a new function to the server.  So
489 he goes hunting through the server to find some already existing code
490 which does something similar to what he wants to do.  This is good.
491 You should always write new code to imitate old code.  What is bad is
492 when Joe Shmuck decides to simply "copy" 200 lines of code from the old
493 function into his new function, and then just change a couple of
494 little things here and there to suit his needs.  This method, known as
495 Cut-and-Paste coding is the fastest and easiest way to code.  However,
496 it results in a server that is impossible to maintain.  What Joe
497 _should_ have done, is "move" the 200 lines of code into a new _third_
498 function which the first two both call.  This is called writing a
499 "general solution" to handle both cases.  Most of my work in the
500 Empire2 project consisted in cleaning up after a bonch of Joe Shmucks.
501 I took repeated code and "consolidated" it into general function
502 libraries.
503
504 4) Good style.
505 Just to add to Dave's "Be Invisible" motto, I'd like to give a little
506 example to illustrate some basic do's and don'ts for coding style:
507
508 The following function has bad style:
509
510 double att_combat_eff(com,own)
511 struct combat *com;
512 natid own;{
513   double str;
514   double eff=1.0;
515   if(com->type==EF_SECTOR)
516   {
517     eff=com->eff/100.0;
518     if(com->own==own){
519       str=com->sct_dcp->d_ostr;
520     }else{
521 str=com->sct_dcp->d_dstr;eff=2.0+(str-2.0)*eff;
522     }else if(com->type==EF_SHIP&&com->own!=own)
523       eff=(1.0+com->shp_mcp->m_armor/100.0);
524   return eff;}
525
526 Here is the same function written with "good" style:
527
528 double
529 att_combat_eff(com, own)
530         struct  combat *com;
531         natid   own;
532 {
533         double  eff = 1.0;
534         double  str;
535
536         if (com->type == EF_SECTOR) {
537                 eff = com->eff / 100.0;
538                 if (com->own == own)
539                         str = com->sct_dcp->d_ostr;
540                 else
541                         str = com->sct_dcp->d_dstr;
542                 eff = 2.0 + (str - 2.0) * eff;
543         } else if (com->type == EF_SHIP && com->own != own)
544                 eff = (1.0 + com->shp_mcp->m_armor / 100.0);
545
546         return eff;
547 }
548
549 These are all the things I fixed when changing the bad to the good:
550 - Function names should always start a new line (so you can search for them)
551 - There should always be a space after a ","
552 - Function arguments should be indented 8 spaces
553 - There should always be a tab after a type declaration
554 - Opening function bracket should be on a line by itself
555 - Indentation should be 8 spaces
556 - There should always be a space on both sides of every operator
557 - There should always be a space after if, for, while, switch
558 - The opening bracket should be on the same line as the if
559 - There should always be a space on either side of a {
560 - There should always be a new line after a ;
561 - The closing function bracket should be on a line by itself
562
563