CMSI 281: Coding Standards Page

Up to now, as far as your code projects at LMU are concerned, you have probably been responsible for some sort of a file header, and a descriptive set of comments in all the code that you turn in. However, since this course is supposed to give you an idea of real-world software engineering and development projects, there will be fairly stringent coding standards imposed, and which you will be expected to follow as a matter of course in your project development. As stated in the syllabus, you will be graded on the coding standards you are expected to use at all times.

Now, I know what you're thinking. . . #@$!!** coding standards!!! I'm going to write code that works! I'll come back later and put in the comments and make it all pretty so I can get a good grade.

WRONG!!! . . . . . (Thanks for playing)

. . . . . for several reasons:

In the first place, you are highly unlikely to go back to your code at the end of the term to insert comments, even to improve your grade. Even with the best of intentions, it just doesn't happen. You will be just too flippin' busy at the end to have time to go back to revisit every module. There are at least 50 notebooks upstairs in the archives from past completed projects that bear witness to this fact.

In the second place, starting out with the comments, instead of the code, will help you stay on track with what the module or block is supposed to do.

Finally, people will be looking at your code during the semester, not just at the end of the term, and your grade will suffer or benefit accordingly.

Believe me, though, when you go to work for Electronic Arts or Google or Amazon and your first job is to make some addition or a bug fix to somebody else's code, and you discover they didn't follow any sort of standard (and didn't put in any comments) you'll soon see the logic behind this. (Take a look at the bottom of this page to get an idea of what I mean!)

There are standard rules for this course that will apply to source files for all languages used in a project, whether it be SQL, Java, Javascript, PHP, Tcl/TK, Objective-C, Ada, Swift, GO, ML, PL/I, or FORTRAN:

Javadocs

All Java source code must be commented in Javadocs style. If you are not familiar with this excellent documentation tool, you can visit the link at Sun's java documentation web site. Also, here is a link to the Javadoc 6.0 tool main page. From there you can get to the pages that show all the @ tags and how to use them by clicking on the appropriate link under Javadoc Tool Reference Page.

All Java source files must have a file header. All classes, fields, constructors, and methods must also be documented in good Javadocs style. There are examples available on the pages at the links listed above.

File headers must have the following information:

You may want to include a version number constituting the module version, like 1.4.2, but this is optional. If your configuration management tool handles this for you, it's OK to leave the internal number out of the file header, since it becomes redundant.

Note that with Javadocs there will be order dependency with several of the tags required for these items. See the links above for details. Also, there is some good information in the Java In A Nutshell book.

Here is a trivial file that illustrates Javadocs basics:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
   /** @(#)Whatever.java   1.0.0   20-May-2006   (NOTE: This line may be omitted if using CVS)
    *  Purpose    : Provide a simple class file Javadoc comment example
    *  Author     : Homer Simpson
    *  Description: This file provides a simple class file comment description which illustrates the
    *      formatting of the code for the CMSI 401/402 "senior project" coding standards.  It is expected
    *      that all students supply this information in all code file headers.
    */

   /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    *  Revision History:
    *  -----------------
    *
    *   Ver      Date      Modified by:  Description of change/modification
    *  -----  -----------  ------------  -----------------------------------------------------------------
    *  1.0.0  20-May-2006  H. Simpson    Initial version/release
    *  1.0.1  21-May-2006  H. Simpson    Added comments to class definition
    *  1.1.0  02-Jun-2006  H. Simpson    Fixed bug in method whatever
    *
    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
    import java.awt.Image;
    import java.net.MalformedURLException;
    import java.net.URL;

   /**
    * This is the Whatever class that will just show a "\/\/" on the CRT
    *
    * @author   Homer Simpson
    */
    public class Whatever  {

     /**
      * Class constructor.
      */
      public Whatever()   {
         int i = 5;
      }

     /**
      * Class constructor specifying number of objects to create.
      * @param  nudnik  a dummy parameter for illustration
      */
      public Whatever( int n )   {
         int i = n;
      }

     /**
      * Returns an Image object that can then be painted on the screen.  The url argument must specify
      * an absolute {@link URL}. The name argument is a specifier that is relative to the url argument.
      *
      * @param  url  an absolute URL giving the base location of the image
      * @param  name the location of the image, relative to the url argument
      * @return      the image at the specified URL or null if none exists
      * @exception   none
      */
      public Image getImage( URL url, String name )   {
         try {
            return getImage( new URL( "127.0.0.1" ), name );
         } catch( MalformedURLException mfe )   {
            return null;
         }
      }
   }
      

The Javadocs output of this class file can be seen with this link.

Doxygen

Source code in other languages like 'C' and C++ can still be documented using an automated tool. One such tool which I have used in the past onseveral projects is called Doxygen. It is free, just like Javadocs, and can be found at this URL. There are binary distributions for Linux and Windows, and there is a handy configuration GUI that helps maintain the configuration file that builds the html output. It will do Java code, too.

Just like in the Java section above, all non-Java source files must have a file header. All classes, fields, constructors, and methods must also be documented. Doxygen is really easy to use; the GUI makes it simple to configure, build, and maintain the documentation. There is no dependence on tag order, either.

File headers must still have the following information:

Here is another trivial file that illustrates the use of Doxygen for a code module in 'C'.

Here is another trivial file that illustrates Doxygen basics:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
   /**
    * \file    rptgen_version.c
    * \brief   Report Generator Server (RGS) version
    *           function source code
    * \author  Original author ~ B.J. Johnson
    * \date    Original date   ~ 10-Mar-2004
    * \version 1.0   Initial release
    * \version 1.0.1 Updated comments to reflect better Doxygen format
    *
    * Project:
    * \par
    * Readiness Tester Project
    *
    * Functional Subsystem:
    * \par
    * All
    *
    * Description:
    * \par
    * This module contains the functions needed to properly format a string containing the program name
    * and the version and build information for return to the Mobius test executive for display.  This
    * is usually done at startup, but there is a service provided for the purpose so that it can be done
    * from the Mobius command line.
    *
    */

   /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    *  INCLUDE FILES (All other include-type stuff is in these files)
    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
    #include "rptgenHeader.h"
    #include "rptgenMsgTokens.h"
    #include "rptgenPrototypes.h"

   /**
    * \fn        getProgramName()
    * \brief     Function to get name of program in string format
    * \return    String formatted server program name
    * \exception None
    *
    * Description:
    * \par
    * This routine is a no-brainer, returning a "#define"ed constant
    *
    *Side effects:
    * \par
    * None
    *
    */
    char * getProgramName() { return( PROGRAM_NAME ); }

   /**
    * \fn        getVersionInformation( char * version )
    * \brief     Function to get version of program in string format
    * \param     version character pointer to formatted version string
    * \exception None
    *
    * Description:
    * \par
    * This is also a no-brainer, except that the version number needs
    *  some explanation.  Version numbers include a major, a minor, and
    *  a "patch" number, according to the CM ladies.  The major and minor
    *  numbers are self-explanatory, but the patch number is a bit
    *  confusing.  The usage is similar to what other software packages
    *  frequently call the "build" number or "release" number.  However,
    *  in the BSS case, if the patch number is zero, it will not appear.
    *  In other words, if the patch is zero, the version string will be
    *  "1.2", not "1.2.0".
    *
    *Side effects:
    * \par
    * The version string argument is modified.
    *
    */
    void getVersionInformation( char * version )
    {
       if( 0 == PATCH_VERSION )
       {
          sprintf( version, "Revision %s.%d, built on %s, %s",
                   MAJOR_VERSION, MINOR_VERSION, BUILD_DATE, BUILD_TIME );
       }
       else
       {
          sprintf( version, "Revision %s.%d-%d, built on %s",
                   MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION,
                   BUILD_DATE, BUILD_TIME );
       }
    }

   /**
    * \fn        getVersion( RsmpCmdHandle handle, RsmpUserData * data, char * userCmd, char * response )
    * \brief     Function to get the debug level value
    * \param     handle   RsmpCmdHandle struct pointer to RSMP commmand
    * \param     data     RsmpUserData struct pointer to RSMP data
    * \param     userCmd  Character pointer to something
    * \param     response Character pointer to something else
    * \return    integer status value
    * \exception None
    *
    * Description:
    * \par
    * This is the function that acutally makes the uptime string for display.  It checks to ensure that
    * there is only one argument (which is really not used, but might have a "?" in it), then if it's
    * cool, proceeds to call the "getVersionInformation()" to get the program's build information, then
    * coupled with a call to the "getProgramName()" function, assembles the string and puts it in the
    * "response" string argument.  That's that.
    *
    * Side effects:
    * \par
    * The response string is modified on success, and both the response and errMsg strings are modified
    * on failure.
    */
    int getVersion( RsmpCmdHandle handle, RsmpUserData * data, char * userCmd, char * response )
    {
       char            versionInformation[VERSION_STRING_SIZE];
       int             status = NO_ERROR;

       getVersionInformation( versionInformation );
       sprintf( response, "%s: %s",
                          getProgramName(), versionInformation );
       return( status );
    }

The Doxygen output of this source file can be seen with this link.

Don't let this happen to you!

Here is an example file from a real project. This is the epitome of the bad example so you can see what you're up against. Notice that the indenting is not consistent, there are almost NO comments, the variable names aren't descriptive, the stars are misaligned on the header block, and on and on.

The project that we had to do was to translate this code from 'C' language into Tcl/TK language, and make it work the same as the original. This is just one module, which I have presented as an example. There were over 100 modules of code to be ported for this project, and all of them looked like this! Obviously, this original code is so bad that you can tell the task was extraordinarily difficult.

Here is an example of some of the worst errors in coding standards:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
   /************************************************************************/
   /* File Name:  R93.c                                                 *
   /* Project: CTCU/RTCU                                         *
   /* Language:   Borland C++ Compiler  (version 3.0)                     *
   /* Disclosure:    Copyright (C) 1995 Hughes Aircraft Co.                  *
   /*                      ALL RIGHTS RESERVED                             *
   /*                         *
   /* The contents of this medium may not be reproduced in whole      *
   /*      or in part without the written consent of the Hughes Aircraft   *
   /*      Company except as authorized by section 117 of the U.S.   *
   /* Copyright Law.                                           *
   /*                                                                      *
   /* Description:   This is the source code for test(s) corresponding to  *
   /*    the section(s) in the Test Specification (TS80346-110):  *
   /*    ***   TLM Unconditioned Analog Functional test   ***  *
   /*    Refer to the file specref.h for specific paragraphs   *
   /*    in the test specification.          *
   /************************************************************************/

   /************************************************************************/
   /* Revision Change History:                                             *
   /*                                                                      *
   /* Rev    Date     PTR# S/W Engineer  Comments                          *
   /* _____  ________ ____ _____________ ____________________________      *
   /*   11/09/95  L. Onishi     Refer to TS by mnemonic
         Refer to spec by mnemonic since paragraph #'s for the
         CTCU portion of the spec keep changing.
   /*   05/03/96  L. Onishi     Check failsafe
         Abort if return status from begin_test fails because we
         have to check FAILSAFE tp and abort if it is invalid if
         testing a CTCU.
   /*   11/7/96   L. Onishi     Reduce test time
   /*   11/12/96           Production test vs. troubleshooting
         We were checking all tlm channels to verify uniqueness.
         Test Spec indicates we only have to check the channel
         that is uniquely loaded.  We have to remember that this
         is only a production test, and not for diagnostic purposes.
         We had setup the test to check all telemetry channels so
         that we could identify which channels had problems in the
         event of a failure.  That is fine for troubleshooting,
         but we have to remember that this is only a production
         test, and troubleshooting features are optional.  The
         test now matches the verbage in the test spec and we
         only check the channel that has the unique voltage.
   /************************************************************************/

   /************************************************************************/
   /* ***  NOTES  ***
   /*  * see testnote.txt
   /************************************************************************/

   #define  TLM_AN_TEST 0


   #include "..\abc_test.c"

   /*#define ACTIVE_CH 0xAF00          /* expected data on active channel */
   /*#define OTHER_CH  0x9600          /* expected data on other channels */

   double   dac_vlt[] =       {1.025,  1.505,  1.985,  2.465,  2.945,  3.425};
   unsigned int exp_avlt[] = {0x3300, 0x4b00, 0x6300, 0x7b00, 0x9300, 0xab00};
   int max_loads;

   double active_vlt, other_vlt;


   void clr_active_ch(int ch)
   {
     char msg[20];

     sprintf(msg, "%dl-ch,%d,0", (ch/64)+1, ch%64);
     exec(msg);
   }


   void set_active_channel(int ch)
   {
     char msg[80];

     sprintf(msg, "%dl-ch,%d,1", (ch/64)+1, ch%64); /* configure active channel */
     exec(msg);
   }


   void main(int argc, char *argv[])
   {
     int channel;                         /* tlm load card channel number */
     unsigned exp_data;                   /* expected serial data */
     char msg[80];                        /* temp string */
     int n1, n2, n3, n4;
     char prefix[20];
     char strx[100];       /* [0] = "is" spur signals */
     char sbx[100];
     char data_word[8], exp_word[8];
     char   pattern[3][100];              /* for special header   */
     char   *pat[3];                /* for special header   */
     int num = 8;
     int errix;

     initTest(testName, argc, argv[1], argv[2]);

   /*======================================================================*/
   /* begin_test
   /* apply bus (MIN bus, unit ON, tlm ON)
   /*======================================================================*/
     if (ux_begin_test(UX_MINBUS, ON, ON) != 0) {
       exitTest(ABORT);
     }


   /******************************************************************
      1.3a Unconditional analog uniqueness test.
   ******************************************************************/
     printSubHeader("Unconditioned Analog channel uniqueness (1.3a) ");

     exec("l-adj,on");
     max_loads = ux_valid_tlm_ch/64;
     for(n1=1; n1<=max_loads; n1++) {
       sprintf(msg, "%dl-ld,0,dac1", n1);    /* direct load 1 to DAC 0 */
       exec(msg);
       sprintf(msg, "%dl-dac,1,%f",n1,dac_vlt[0]); /* set DAC for load card */
       exec(msg);
       sprintf(msg, "%dl-ld,1,dac0", n1);
       exec(msg);
       sprintf(msg, "%dl-dac,0,%f", n1, dac_vlt[n1]);
       exec(msg);
     }

     for(n1=1; n1<=(ux_valid_tlm_ch/64); n1++) {
       for (n2 = 0; n2 < 4; n2++) {
         sprintf(msg, "%dl-set,%d,0", n1, n2);
         exec(msg);
       }
     }
     ux_twait(100);

     for (n1 = 0; n1 < 3; n1++) {
       for (n2 = 0; n2 < 82; n2++) {
         pattern[n1][n2] = 0;
       }
     }


     for (n1 = 0; n1 < 3; n1++) {
         for (n2 = 0; n2 < 82; n2++) {
      pattern[n1][n2] = 0;
         }
     }
     sprintf(pattern[0], "%-21s\0","(starting chan)");
     sprintf(pattern[1], "%-21s\0","---------------");
     num = 8;
     for (n1 = 0; n1 < num; n1++) {
         sprintf(msg, "+%03d  \0", n1);
         strcat(pattern[0], msg);
         sprintf(msg, "%-6s\0", "-----");
         strcat(pattern[1], msg);
     }
     *pattern[2] = '\0';

     n1 = 0;
     while(n1 < 3)
         pat[n1] = pattern[n1++];
     setSpecialHeader(ON, pat);

     channel = 0;
     while(channel < ux_valid_tlm_ch) {
       if (channel%64 == 0) {
         sprintf(msg, " - Testing ch %03d-%03d", channel, channel+63);
         ux_section_hdr(msg, 0);
         sprintf(msg, "i-load,an%d_u.fp2", channel/64);
         exec(msg);
       }
   /******************************************************************
      Configure 1553 data word to request current active channel.
   ******************************************************************/
       n3 = 0;
       n1 = 0;
       while (n1 < 8) {
         errix = 0;
         sprintf(prefix, "%03d", channel);
         sprintf(strx, "%03d   (AN) ch%03d    ", channel, channel);
         sprintf(sbx,  "%03d     should be:  ", channel);
         n4 = 0;
         while (n4 < 8) {
      set_active_channel(channel);       /* set active telemetry channel */
      exec("i-run,bc,5,1");
      ux_twait(200);
      n2 = channel%64;
      n3 = 0;
      if ((channel >= 0)   && (channel < 4))    /* exclude ch 0-3 */
            n3--;
      if ((channel >= 64)  && (channel < 68))      /* exclude ch 64-67  */
            n3--;
      if ((channel >= 192) && (channel < 212))  /* exclude ch 192-211   */
            n3--;
      if (n3 >= 0) {
        sprintf(msg, "i-data,view,%d", (n2*2)+6);
        exec(msg);
        ux_chk1553Rsp(prefix, msg, 0);
        exp_data = exp_avlt[(channel/64)+1];
        if (ts->testdata[0] == 0) {       /* check 1553 status, no error */
         sprintf(data_word, " %04x ", ts->testdata[3] & ux_rt_ad_mask);
         if ((ts->testdata[3] & ux_rt_ad_mcmp) != (exp_data & ux_rt_ad_mcmp)) {
           data_word[5] = '*';
           sprintf(exp_word, " %04x*", exp_data);
           errix++;
         }
         else {
           sprintf(exp_word, "%-6.6s", " ");
         }
        }
        else {
         sprintf(data_word, " *****");
         sprintf(exp_word, " %04x*", exp_data);
         errix++;
        }
      }
      else {
            sprintf(data_word, " n/a  ");
            sprintf(exp_word, " n/a  ");
      }
      strcat(strx, data_word);
      strcat(sbx, exp_word);
      clr_active_ch(channel);
      channel++;
      n4++;
         }
         if (errix != 0) {          /*  if an error occurred */
          sprintf(msg, "%-82.82s *FAIL*", strx);   /*   space out to the error column */
          strcpy(strx, msg);
         }                                   /*  end if */
         prtSpecial(PDATA, errix, strx);        /*  output the results  */
         if (errix != 0) {
          prt(PERROR, sbx);
         }
         n1++;
       }
     }
     setSpecialHeader(OFF, pat);

     ux_end_test();
     exitTest(NORMAL);
   }

   /************************************************************************/
   /* END OF TEST
   /************************************************************************/