~ubuntu-branches/ubuntu/utopic/gridengine/utopic

« back to all changes in this revision

Viewing changes to doc/devel/style_guide.txt

  • Committer: Bazaar Package Importer
  • Author(s): Mark Hymers
  • Date: 2008-06-25 22:36:13 UTC
  • Revision ID: james.westby@ubuntu.com-20080625223613-tvd9xlhuoct9kyhm
Tags: upstream-6.2~beta2
ImportĀ upstreamĀ versionĀ 6.2~beta2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
DRAFT of a Coding Styleguide
 
2
============================
 
3
 
 
4
 
 
5
1 Introduction
 
6
==============
 
7
 
 
8
   1.1 Target group
 
9
   ----------------
 
10
 
 
11
      Each developer providing code for SGE followes the rules of this 
 
12
      styleguide.
 
13
 
 
14
   1.2 Conventions
 
15
   ---------------
 
16
 
 
17
      Each rule in this style guide is part of one of the following categories:
 
18
 
 
19
      Category    Description
 
20
      ----------- -----------
 
21
 
 
22
      A           ABSOLUTE MUST
 
23
 
 
24
                  It is abolutely not allowed to break one of the rules being
 
25
                  part of this category. 
 
26
                  Only those rules are part of the A category which have
 
27
                  a direct impact on stability or security of a software
 
28
                  component.
 
29
 
 
30
      M           MUST
 
31
 
 
32
                  Each developer has to stick to such rules. A violation
 
33
                  against one of these rules has to be discussed on
 
34
                  'dev@gridengine.sunsource.net'.
 
35
 
 
36
      S           SHOULD
 
37
 
 
38
                  Rules of this group should only be violated with an
 
39
                  important reason.
 
40
 
 
41
      R           RECOMMENTATION
 
42
 
 
43
                  Rules part of this category are recomendations.
 
44
 
 
45
   1.3 Usage
 
46
   ---------
 
47
      (M)   All Grid Engine developers respect the rules defined in
 
48
            this styleguide. All new code developed conformes to this 
 
49
            styleguide.
 
50
 
 
51
      (R)   The Grid Engine source code base contains a high amount of code
 
52
            not yet conforming to the style guide.
 
53
            Whenever existing code pieces are changed, they are made
 
54
            conformant to the style guide.
 
55
 
 
56
      (M)   This styleguide will be maintained by all developers of SGE. Each
 
57
            developer can suggest the addition/modification/removal of
 
58
            rules in this styleguide. All modifications of this guide are
 
59
            discussed on 'dev@gridengine.sunsource.net'.
 
60
 
 
61
   1.4 Version
 
62
   -----------
 
63
      
 
64
      Version  Date        Developer      Changes
 
65
      -------- ----------- -------------- ------------------------------------
 
66
      
 
67
      0.1      ?           E. Bablick     Initial version
 
68
                           J. Gabler
 
69
      0.2      11/13/2002  J. Gabler      Review. Added a cull programming rule 
 
70
                                          suggested by A. Haas.
 
71
                                          
 
72
 
 
73
2 C language
 
74
============
 
75
 
 
76
   2.1 Security
 
77
   ------------
 
78
 
 
79
      Buffer Overflow
 
80
 
 
81
         (A)   No more additional static buffers are added to the source code to
 
82
               store strings, exchange error messages, concatenate collected
 
83
               information, etc.
 
84
               Instead dynamic strings and the provided access functions are 
 
85
               used (dstring, libs/uti/sge_dstring.h).
 
86
 
 
87
      Memory Leaks
 
88
 
 
89
         (S)   If functions return strings, make the caller pass a
 
90
               dstring as parameter and use this string as buffer.
 
91
               The alternative - writing to a local buffer and returning a 
 
92
               duplicate (strdup) - often leads to memory leaks.
 
93
               As a side effect this method can show better performance, as the
 
94
               buffer can be reused for multiple calls of a function requiring 
 
95
               a buffer.
 
96
               
 
97
         (M)   If memory is allocated for use in an automatic pointer variable,
 
98
               this is done on demand (as late as possible).
 
99
               No memory is allocated for the initialization of the variable.
 
100
               Initializing with NULL in most cases is the better choice.
 
101
               Thereby memory leaks can be avoided, esp. when the function
 
102
               has multiple exit points, e.g. in error handling.
 
103
               
 
104
 
 
105
#if TODO
 
106
      Untrusted data
 
107
 
 
108
         ...
 
109
#endif
 
110
      
 
111
 
 
112
   2.2 Programming style
 
113
   ---------------------
 
114
      
 
115
      2.2.1 Naming Conventions
 
116
      - - - - - - - - - - - - - 
 
117
 
 
118
         General
 
119
 
 
120
         (M)   All names are build up with english words.
 
121
         
 
122
         (M)   Names are built up of letters, digits and the underscore 
 
123
               sign ('_').
 
124
 
 
125
         (M)   If a name consists of more than a word, all words are separated
 
126
               by an underscore sign ('_').
 
127
 
 
128
         (S)   The maximum length for name is 35 characters.
 
129
 
 
130
         (M)   All names (of datatypes, constants, functions ...) which have
 
131
               global character and which may not be associated to an object or
 
132
               a whole module begin with with the prefix "sge_" or a 
 
133
               module specific prefix.
 
134
               Examples: 
 
135
                  - cull_pack_descr() 
 
136
                  - sge_peopen()
 
137
 
 
138
         (M)   All names (of datatypes, constants, functions ...) that can be
 
139
               associated to an object begin with the objects name.
 
140
               Examples:
 
141
                  - job_search_task()
 
142
                  - range_parse_from_string()
 
143
                  - range_is_empty()
 
144
                  - queue_initial_state())
 
145
 
 
146
         (M)   Names that can be associated to lists of objects contain the 
 
147
               phrase "_list_" in between the object name and the end part of 
 
148
               the name.
 
149
               Examples:
 
150
                  - range_list_calculate_union_set()
 
151
                  - job_list_add_job()
 
152
 
 
153
         Object names
 
154
 
 
155
         (M)   Object names contain only letters and the underscore sign ('_').
 
156
 
 
157
         (S)   They are short.
 
158
 
 
159
         (M)   Following list shows some of the objects and their corresponding
 
160
               names within SGE.
 
161
 
 
162
               Prefix         Object
 
163
               -----------    ---------------------------
 
164
               answer         Answer object
 
165
               cal            Calendar object
 
166
               ckpt           Checkpointing object
 
167
               cmplx          Complex object
 
168
               cmplx_attr     Complex Attribute object
 
169
               ja_task        Job array task object 
 
170
               job            Job object
 
171
               pe             Parallel Environment object
 
172
               pe_task        PE task object
 
173
               queue          Queue object
 
174
               range          Id range object
 
175
               schedd_conf    Scheduler Configuration object
 
176
               var            Variable object
 
177
 
 
178
         Preprocessor Definitions
 
179
         
 
180
         (M)   Names interpreted by the prepocessor contain only capital letters
 
181
               and the underscore sign ('_'). 
 
182
 
 
183
         (M)   Names preventing the preprocessor from including header files
 
184
               twice or multiple times begin with "__" and  end with "_H".
 
185
               Example:
 
186
                  #ifndef __SGE_RANGE_H
 
187
                  #define __SGE_RANGE_H
 
188
                  ...
 
189
                  #endif /* __SGE_RANGE_H */
 
190
 
 
191
         Datatypes
 
192
 
 
193
         (M)   Type definitions contain only lower case letters and the 
 
194
               underscore sign ('_'). 
 
195
 
 
196
         (S)   They end with "_t".
 
197
 
 
198
         Constants/Enums
 
199
 
 
200
         (M)   Names of constants or enum values contain only capital letters 
 
201
               and the underscore sign ('_').
 
202
 
 
203
         Variables
 
204
 
 
205
         (M)   Names of variables contain only letters and the underscore sign 
 
206
               ('_').
 
207
 
 
208
         (S)   Global variables begin with the prefix "GLOBAL_"
 
209
 
 
210
         (S)   Names of global variables are expressive.
 
211
 
 
212
         (R)   Names of local variables are short.
 
213
 
 
214
#if TODO
 
215
         Functions
 
216
 
 
217
         ...
 
218
#endif
 
219
 
 
220
         Functions which might be interpreted as 'methods'
 
221
 
 
222
         (M)   Function pairs which primarily read or write an attribute
 
223
               of an object begin with "get_" or "set_" in its
 
224
               main name.
 
225
               Examples:
 
226
                  - var_list_get_string()
 
227
                  - var_list_set_string()
 
228
 
 
229
         (M)   Functions which primarily check a certain state and upon
 
230
               the state return true or false contain the phrase
 
231
               "is_" or "has_" in their name.
 
232
               Examples:
 
233
                  - job_is_array()
 
234
                  - job_has_tasks()
 
235
      
 
236
         Modules
 
237
 
 
238
         (M)   Filenames of modules and their corresponding headerfiles
 
239
               are be build up of lower case letters and the underscore sign 
 
240
               ('_').
 
241
 
 
242
         (S)   All sourcefiles have the prefix "sge_".
 
243
 
 
244
         (M)   The basename of a source file and its corresponding header file
 
245
               are equivalent.
 
246
               Examples:
 
247
                  - sge_job.h, sge_job.c
 
248
                  - sge_queue.h, sge_queue.c
 
249
 
 
250
         (M)   The extension of C source and header files is ".c" and ".h"
 
251
 
 
252
      2.2.2 Module Design
 
253
      - - - - - - - - - -
 
254
 
 
255
         (M)   Functions, global variables are declared in a header file 
 
256
               whereas the implementation part is put into a source file. 
 
257
               There are following exceptions:
 
258
                  a) Test applications can be put completely into a sourcefile.
 
259
                  b) The main() function does not need a declaration. 
 
260
                  c) Functions that will only be called locally in a module are
 
261
                     declared locally in the sourcefile.
 
262
 
 
263
         (S)   Structure of header files:
 
264
 
 
265
                  1) #ifdef - to prevent multiple interpretation of declararion
 
266
                  2) Copyright Comment
 
267
                  3) Inludes
 
268
                  4) an ADOC header that gives an introduction
 
269
                     to the modules purpose and contents
 
270
                  5) Preprocessor definitions with ADOC comments
 
271
                  6) Enum and type definitions with ADOC comments
 
272
                  7) Declaration of global variables
 
273
                  8) Declaration of functions
 
274
                  9) #endif (see 1)
 
275
 
 
276
         (S)   Structure of source files:
 
277
 
 
278
                  1) Copyright Comment
 
279
                  2) Inludes
 
280
                     a) System includes
 
281
                     b) includes of Grid Engine library modules
 
282
                     c) includes local to the component (directory)
 
283
                     d) include of message catalog headers
 
284
                     e) include of headerfile for this source file
 
285
                  3) Global ADOC comments
 
286
                  4) Private preprocessor definitions with ADOC comments
 
287
                  5) Private type definitions with ADOC comments
 
288
                  6) Private enum definitions with ADOC comments 
 
289
                  8) Definition of global variables with ADOC comment
 
290
                  7) Static (module global) variables with ADOC comment
 
291
                  8) Declaration of static functions with ADOC comment
 
292
                  9) Definition of functions, each function has an individual
 
293
                     ADOC comment
 
294
               
 
295
         Copyright Comment
 
296
      
 
297
         (M)   Each file (sourcefile, headerfile, makefile) begins
 
298
               with a copyright comment. (find an example of a copyright 
 
299
               comment in "source/libs/gdi/version.c")
 
300
 
 
301
         (M)   Each "Sun Microsystems" copyright comment is
 
302
               introduced by the comment "/*___INFO__MARK_BEGIN__*/" and 
 
303
               finished with following comment "/*___INFO__MARK_END__*/".
 
304
 
 
305
         Includes
 
306
 
 
307
         (S)   Headerfiles are included in the following order:
 
308
 
 
309
               1) System inludes
 
310
               2) 3rd party includes
 
311
               3) SGE includes (Grid Engine libraries)
 
312
               4) includes local to the component (directory)
 
313
               5) Includes of the own module
 
314
 
 
315
               For technical reasons the order might be different but then
 
316
               the reason has to be explained explicitely with a
 
317
               "special comment"
 
318
 
 
319
      2.2.3 Programming Techniques
 
320
      - - - - - - - - - - - - - - -
 
321
 
 
322
         Constants
 
323
 
 
324
         (S)   enums are used instead of defines where possible.
 
325
 
 
326
         (S)   typedefs are used where possible, e.g. for enums.
 
327
               This allows the compiler to do type checks, many errors
 
328
               can already be found at compile time.
 
329
 
 
330
         CULL objects
 
331
 
 
332
         (M)   CULL lists are created "on demand" (as late as possible, 
 
333
               see also the section about Memory Leaks).
 
334
               There is a set of functions that faciliates this policy:
 
335
               lSetElemStr, lSetSubStr, lSetElemUlong, ...
 
336
         
 
337
         (S)   CULL object types are defined in separate header files.
 
338
               These header fieles are named "sge_<type>L.h".
 
339
               Object type specific enums, typedefs and access functions are 
 
340
               declared in a module "sge_<type>.h", the corresponding function 
 
341
               definitions are in a source module "sge_<type>.c".
 
342
               Examples:
 
343
                  - sge_jobL.h, sge_job.h, sge_job.c
 
344
                  - sge_queueL.h, sge_queue.h, sge_queue.c
 
345
 
 
346
         Data types
 
347
 
 
348
         (R)   Data types are strictly distinguished.
 
349
               NULL is explicitly tested.
 
350
               Conditions have the type boolean.
 
351
               Examples:
 
352
                  /* "traditional" C */   |  /* preferred style */
 
353
                                          |
 
354
                  lListElem queue;        |  lListElem *queue;
 
355
                  queue = ...             |  queue = ...
 
356
                  if(!queue) {            |  if(queue == NULL) {
 
357
                     ...                  |     ...
 
358
                  }                       |  }
 
359
                                          |
 
360
                  if(!strcmp(a, b) {      |  if(strcmp(a, b) == 0) {
 
361
                     ...                  |     ...
 
362
                  }                       |  }
 
363
                                          |
 
364
               Reasons:
 
365
                  - This policy makes transitions of code to other programming 
 
366
                    languages much easier. 
 
367
                    Example: According to the c++ standard, NULL is not 
 
368
                    necessarily defined to have the value 0.
 
369
                  - Modern programming languages like Java explicitly require
 
370
                    this coding style.
 
371
                  - It makes code more readable.
 
372
 
 
373
         Error handling
 
374
 
 
375
         (M)   Library functions do not do any error output to stderr (using 
 
376
               macros like ERROR or WARNING).
 
377
               
 
378
               Functions in libuti can have a dstring as parameter that will be 
 
379
               used to return error messages. The dstring is the first parameter
 
380
               of a function.
 
381
 
 
382
               Functions in all libs depending on gdilib (and gdilib itself) 
 
383
               take an answer list as parameter that can be populated by the 
 
384
               function as errors or warnings occur, or to return informational 
 
385
               messages.
 
386
               For object specific functions (having a "this-pointer" as first 
 
387
               parameter, the answer list is the second parameter, else the 
 
388
               first one).
 
389
               In libs/gdi/sge_answer.h functions are declared that allow for an
 
390
               easy creation of answers.
 
391
 
 
392
         I18N
 
393
 
 
394
         (M)   All messages that can be output by Grid Engine (except debug 
 
395
               messages, DPRINTF), are defined in special header files.
 
396
               Each component (directory) has its own messages file, its name is
 
397
               built as "msg_<component>.h", e.g. "msg_utilib.h" or 
 
398
               "msg_qmaster.h".
 
399
 
 
400
         (S)   There is one global messages file ("common/msg_common.h"), that 
 
401
               contains general error messages like "out of memory", "cannot 
 
402
               write to file" etc., that would otherwise be duplicated for each 
 
403
               component.
 
404
 
 
405
         (S)   Each module only includes the common messages file and the one of
 
406
               its component (directory).
 
407
 
 
408
         System calls and standard C library functions
 
409
         
 
410
         (S)   For a high number of system calls and C library functions there 
 
411
               exist Grid Engine equivalents in libuti, that do additional error
 
412
               checking and hide operating system specific behaviour. 
 
413
               These functions are always prefered over the original functions.
 
414
 
 
415
#if TODO
 
416
         - Tabelle der bisherigen answer return werte
 
417
 
 
418
         Initialisation
 
419
 
 
420
         ? operator
 
421
 
 
422
         Zusammengesetze Befehle
 
423
   
 
424
         Debug Output
 
425
         - DENTER/DEXIT/Varaibleninitialisierung
 
426
 
 
427
 
 
428
         Static Buffers
 
429
 
 
430
         Thread safety
 
431
         - global variables
 
432
         - static variables 
 
433
 
 
434
         Environment Variables 
 
435
 
 
436
         Comments
 
437
         - auskommentierung von code
 
438
 
 
439
#endif
 
440
 
 
441
   2.3 Format
 
442
   ----------
 
443
      General
 
444
      
 
445
         (M)   Tabs are not used within source and header files.
 
446
 
 
447
         (M)   3 spaces are used to indent source code.
 
448
 
 
449
         (M)   Lines have to be wrapped after the 79th character.
 
450
 
 
451
         (R)   The script "gridengine/source/scripts/format.sh" is used to 
 
452
               format the C source code automatically. 
 
453
               Automated sourcecode reformating can be disabled for short code 
 
454
               pieces with the comment "/* *INDENT-OFF* */".  
 
455
               "/* *INDENT-ON* */" reenables the format mechanism.
 
456
 
 
457
      Preprocessor elements
 
458
        
 
459
         Here are some examples:
 
460
 
 
461
            #if SOLARIS64
 
462
            #  include <sys/some_special_header.h>
 
463
            #endif
 
464
 
 
465
            #define SGE_MIN_USAGE 1.0
 
466
      
 
467
            #define REF_SET_TYPE(ref, cull_attr, ref_attr, value, function) \
 
468
            { \
 
469
               if ((ref)->ja_task) { \
 
470
                  (function)((ref)->ja_task, cull_attr, (value)); \
 
471
               } else { \
 
472
                  (ref_attr) = (value); \
 
473
               } \
 
474
            } 
 
475
 
 
476
         (M)   "#" of a preprocessor tag is put in column 0 (ANSI C).
 
477
               The keyword of the tag is indented.
 
478
 
 
479
         (M)   Constant names and their value are put into one line.
 
480
 
 
481
         (M)   Macro definitions are formatted similar to function definitions.  
 
482
 
 
483
      Functions
 
484
 
 
485
         Functions have following format:
 
486
 
 
487
            static int 
 
488
            queue_weakclean(lListElem *qep, lList **answer, 
 
489
                            u_long32 force, char *user,
 
490
                            char *host, int isoperator, 
 
491
                            int isowner) 
 
492
            { 
 
493
               ...
 
494
            }
 
495
 
 
496
         (M)   Functions start with qualifier and return type. 
 
497
 
 
498
         (M)   There is no space between the function name and the 
 
499
               open paraentheses.
 
500
 
 
501
         (M)   If the arguments do not fit into one line, the arguments are 
 
502
               continued in a new line under the first argument of the previous 
 
503
               line.
 
504
 
 
505
         (M)   Functions which do not accept parameters contain the keyword 
 
506
               "void" in its declatation and definition.
 
507
 
 
508
         (M)   The brace in the function definition, is in column zero again. 
 
509
               Statements inside the function body are idented like statements 
 
510
               inside a compound statement. 
 
511
 
 
512
      Statements
 
513
   
 
514
         Statements have following format:
 
515
 
 
516
            for (i = 0; i < MAX; i++) {
 
517
               while (1) {
 
518
                  do {
 
519
                     if (i == 1) {
 
520
                        switch (i) {
 
521
                        case 1, 2:
 
522
                           ...
 
523
                           break;
 
524
                        case 3:
 
525
                           ...
 
526
                           break;
 
527
                        default:
 
528
                           ...
 
529
                        }
 
530
                     } else if (i == -5) {
 
531
                        ...
 
532
                     } else {
 
533
                        only_one_function_call();
 
534
                     }
 
535
                  } while (!found);
 
536
               }
 
537
            }
 
538
 
 
539
         (M)   In contrast to functions, the opening left brace of a
 
540
               compound statement is at the end of the line beginning
 
541
               the compound statement and the closing right brace stands
 
542
               alone on a line.
 
543
 
 
544
         (M)   There is one space between the keyword and the open
 
545
               parentheses. 
 
546
 
 
547
         (M)   Braces are in the same line as the keywords.
 
548
 
 
549
         (S)   All blocks are enclosed in braces, even if the block only 
 
550
               consists of a single line.
 
551
 
 
552
         (M)   Function calls do not contain spaces between the function 
 
553
               name and the parentheses. 
 
554
 
 
555
         (S)   The format of a function prototype is equivalent with
 
556
               the function definition.
 
557
 
 
558
      Declarations
 
559
 
 
560
         Declarartions have following format:
 
561
 
 
562
            static int sge_set_ls_fds(lListElem *this_ls, fd_set *fds)
 
563
            {
 
564
               int i, k, l;
 
565
               int ret = -1;                               /* return value */
 
566
               int name[3] = { LS_out, LS_in, LS_err };
 
567
               FILE *file = NULL;                          /* load sensor fd */
 
568
   
 
569
               first_statement();
 
570
               ...
 
571
 
 
572
         (M)   Multiple variables of same type are declared in one line. 
 
573
 
 
574
         (M)   Each pre-initialized variable has its own line. 
 
575
 
 
576
         (M)   The asterik of a pointer declaration is part of the 
 
577
               variable name. 
 
578
 
 
579
         (M)   One space is put in between the type name and the asterisk of
 
580
               a pointer declaration.
 
581
 
 
582
         (M)   Function parameters are commented in the functions ADOC comment.
 
583
 
 
584
         (R)   Local variable declarations are commented at the end of the 
 
585
               declaration. 
 
586
           
 
587
         (R)   Variable declarations are done as local as possible.
 
588
               Example:
 
589
                  lListElem *queue;                      /* local in function */
 
590
 
 
591
                  for_each(queue, Master_Queue_List) {
 
592
                     const char *queue_name;             /* local in block */
 
593
 
 
594
                     queue_name = lGetString(QU_qname);
 
595
                     ...
 
596
                  }   
 
597
 
 
598
      Comments
 
599
 
 
600
         (M)   Comments are inserted in front of the code block which they 
 
601
               describe or behind the code but starting in the same line.
 
602
               Example:
 
603
                  /* 
 
604
                   * comment for the following compound element
 
605
                   */
 
606
                  {
 
607
                     int name;      /* description of name */
 
608
                     char *pattern; /*
 
609
                                     * more detailed description of 
 
610
                                     * the variable pattern.
 
611
                                     */
 
612
                  }
 
613
         
 
614
         (M)   Line comments like this: /* line comment */
 
615
 
 
616
         (M)   Block comments look like this:
 
617
 
 
618
               /*
 
619
                * block comment block comment block comment
 
620
                * block comment block comment block comment
 
621
                */
 
622
 
 
623
         Special Comments
 
624
            
 
625
            (M)   Special comments are used within the sourcecode
 
626
                  to mark certain code sections. 
 
627
 
 
628
                  SpecialComment := "/*" Initials ":" Keyword 
 
629
                                    [ " (" IssueNumber ")" ] ":"
 
630
                                    Text "*/" .
 
631
 
 
632
                  Initials := '2 character initials, same as in Changelog' .
 
633
         
 
634
                  Keyword := "TODO" | "DEBUG" .
 
635
 
 
636
                  IssueNumber := 'Issuezilla id'
 
637
 
 
638
                  Text := 'Descriptional text'.
 
639
 
 
640
                  Examples:
 
641
                     - during the development phase of a certain feature, 
 
642
                       one might want to mark tasks still to be finished:
 
643
                           /* JG: TODO: improve error handling */
 
644
                     - during development a code section is detected, that can
 
645
                       cause problems or can be improved, but the change has 
 
646
                       nothing to do with the current development and the change
 
647
                       and esp. testing is non trivial: 
 
648
                           /* JG: TODO: args should be dynamically allocated */
 
649
                     - a bug or enhancement request is filed in issuezilla and
 
650
                       the corresponding code section shall be marked for later 
 
651
                       use:
 
652
                           /* JG: TODO (254): use function creating path */
 
653
   
 
654
         ADOC Comments 
 
655
 
 
656
            (M)   ADOC comments are used to describe language elements.
 
657
                  These type of comments are extracted from the sourcecode
 
658
                  using the adoc tool to generate pdf/html/GNU Info ...
 
659
                  documentation.
 
660
                  "doc/devel/adoc.html" describes more details about ADOC tool
 
661
                  and the format of ADOC comments to be used. 
 
662
 
 
663
3 Software Development
 
664
======================
 
665
 
 
666
   3.1 Process
 
667
   -----------
 
668
 
 
669
#if TODO
 
670
      IssueZilla
 
671
      Review
 
672
      Quality Assurance
 
673
      Test suite
 
674
      use dbx and/or insure
 
675
      ...
 
676
#endif