]> git.pond.sub.org Git - empserver/blob - doc/coding
Import of Empire 4.2.12
[empserver] / doc / coding
1                 Guidelines for writing Empire code
2
3
4 Remarks from Dave Pare:
5
6 And now, a few editorial remarks on my views on Good Techniques for
7 Modifying Existing Software:
8
9 My safari through the hot and bug-ridden jungle that Empire has become
10 has given me some new insights on the modification of large software
11 packages.  My adventure has prompted me to propose some simple coding
12 guidelines for those dreaming of hacking on the code:
13
14 1) Be invisible.  When you make a change, think not about marking your
15 place in history, or about showing off how much nicer your two-space
16 tabs are than those old, icky eight-space tabs that the stupid empire
17 hackers of old used, but think instead about the asethetics of the whole.
18 The resulting lines of code should flow smoothly from the beginning of the
19 procedure to the end.  Empire is 60,000 lines of code.  If you're the
20 general case, you're only changing fifty lines, so be aware of that.
21
22 2) Procedurize.  If you find yourself in a triple-nested loop, or a five
23 hundred line procedure, perhaps it's because you need to split some of
24 that code off into a procedure.  In general, if you've got more than two
25 levels of tabs (or indentations), or more than one or two major loops in
26 a procedure, something may well be amiss.
27
28
29 Sasha Mikheev on indentation:
30
31 The empire indentation style can be achived by using 
32 indent -orig -i8 foo.c
33
34 or in old c-mode emacs (versions before 19.29):
35 ;add this to .emacs
36 (setq c-indent-level 8)
37 (setq c-continued-statement-offset 8)
38 (setq c-argdecl-indent 8)
39 (setq c-brace-offset -8)
40 (setq c-label-offset -8)
41
42
43 Further comments by Ken Stevens:
44
45 1) Global variables
46 The only variables which should be global are constants.  If you write
47 a routine which changes a global variable, then you will corrupt the
48 data when two different players run that routine at the same time.
49
50 2) Portability.
51 The following code:
52                 char    a;
53         #ifdef FOO
54                 unsigned char b;
55         #endif FOO
56 Should be rewritten as:
57                 s_char  a;
58         #ifdef FOO
59                 u_char  b;
60         #endif /* FOO */
61
62 AIX has different conventions for signed chars, and IRIX requires the
63 /* comments */ after #endif.
64
65 3) Cut-and-Paste
66 Cut-and-Paste coding is by far the biggest problem that the current
67 Empire suffers from.  This is how cut-and-paste coding happens.  Joe
68 Shmuck decides that he wants to add a new function to the server.  So
69 he goes hunting through the server to find some already existing code
70 which does something similar to what he wants to do.  This is good.
71 You should always write new code to imitate old code.  What is bad is
72 when Joe Shmuck decides to simply "copy" 200 lines of code from the old
73 function into his new function, and then just change a couple of
74 little things here and there to suit his needs.  This method, known as
75 Cut-and-Paste coding is the fastest and easiest way to code.  However,
76 it results in a server that is impossible to maintain.  What Joe
77 _should_ have done, is "move" the 200 lines of code into a new _third_
78 function which the first two both call.  This is called writing a
79 "general solution" to handle both cases.  Most of my work in the
80 Empire2 project consisted in cleaning up after a bonch of Joe Shmucks.
81 I took repeated code and "consolidated" it into general function
82 libraries.
83
84 4) Good style.
85 Just to add to Dave's "Be Invisible" motto, I'd like to give a little
86 example to illustrate some basic do's and don'ts for coding style:
87
88 The following function has bad style:
89
90 double att_combat_eff(com,own)
91 struct combat *com;
92 natid own;{
93   double str;
94   double eff=1.0;
95   if(com->type==EF_SECTOR)
96   {
97     eff=com->eff/100.0;
98     if(com->own==own){
99       str=com->sct_dcp->d_ostr;
100     }else{
101 str=com->sct_dcp->d_dstr;eff=2.0+(str-2.0)*eff;
102     }else if(com->type==EF_SHIP&&com->own!=own)
103       eff=(1.0+com->shp_mcp->m_armor/100.0);
104   return eff;}
105
106 Here is the same function written with "good" style:
107
108 double
109 att_combat_eff(com, own)
110         struct  combat *com;
111         natid   own;
112 {
113         double  eff = 1.0;
114         double  str;
115
116         if (com->type == EF_SECTOR) {
117                 eff = com->eff / 100.0;
118                 if (com->own == own)
119                         str = com->sct_dcp->d_ostr;
120                 else
121                         str = com->sct_dcp->d_dstr;
122                 eff = 2.0 + (str - 2.0) * eff;
123         } else if (com->type == EF_SHIP && com->own != own)
124                 eff = (1.0 + com->shp_mcp->m_armor / 100.0);
125
126         return eff;
127 }
128
129 These are all the things I fixed when changing the bad to the good:
130 - Function names should always start a new line (so you can search for them)
131 - There should always be a space after a ","
132 - Function arguments should be indented 8 spaces
133 - There should always be a tab after a type declaration
134 - Opening function bracket should be on a line by itself
135 - Indentation should be 8 spaces
136 - There should always be a space on both sides of every operator
137 - There should always be a space after if, for, while, switch
138 - The opening bracket should be on the same line as the if
139 - There should always be a space on either side of a {
140 - There should always be a new line after a ;
141 - The closing function bracket should be on a line by itself
142
143