Differences between revisions 11 and 12
Revision 11 as of 2014-02-26 17:46:53
Size: 4642
Editor: 192
Comment:
Revision 12 as of 2014-02-26 18:07:49
Size: 6834
Editor: 192
Comment:
Deletions are marked like this. Additions are marked like this.
Line 152: Line 152:


== Code ==

Remember, when you write code, you are not primarily communicating to the computer. You are communicating an algorithm specification to the next engineer who will be looking at your code.

 * Line length
   Forget about 80, 120, etc character line lengths. Modern, widescreen monitors are much longer than they are tall. Put at least one statement on each line. And in extremely rare cases you might put 2 statements on one line if they form a conceptual unit.
 * Comment your code!
   Expect that the reader knows c++ so do not explain what something does.
   Answer the question "Why".
   Example:
    {{{#!highlight cpp
  class Buffer
  {
    uint32_t refAndLen; // 8 bits (highest) reference count and 24 bits length combined into one.
    char data[1]; // Not really length 1, this structure will be malloced and placed on a much larger buffer so data is actually len() long
  };

  ...

const Buffer& SAFplus::Checkpoint::read (const char* key) const
{
  size_t len = strlen(key)+1; // +1 b/c I'm going to take the /0 so Buffers can be manipulated as strings
  char data[sizeof(Buffer)-1+len]; // -1 because inside Buffer the data field is already length one.
  Buffer* b = new(data) Buffer(len);
  *b = key;
  return read(*b);
}
  
}}}

  Also note in the buffer allocation case I did not hand-optimize the +1 and -1, by removing them. With a 2.4Ghz machine, this is a useless optimization and obfuscates the code.

 * Do not use goto
    Better to not malloc/free dynamically (allocations are expensive) but if you must do so use scope objects to handle automatic allocation and deallocation.
 * line up your { vertically, except for single line stuff.
    '''''YES'''''
    {{{#!highlight cpp
    if (foo)
      {
      a++;
      b--;
      }

    if (foo) { a++; b--; }
}}}

    '''''NO'''''
    {{{#!highlight cpp
    if (foo) {
      a++;
      b--;
      }
}}}

 * Parenthesize rather then rely on order of operations.
    '''''YES'''''
    {{{#!highlight cpp
    if ((foo && ((a == 1) || (b==2))) & !a)
}}}

    '''''NO'''''
    {{{#!highlight cpp
    if (foo && a == 1 || b==2 & !a) {
}}}

Directories

Library only

  • Put library files in
    • ../components/<library name>

  • Put unit test files in
    • ../components/<library name>/test

  • Generate libcl<library name>.so and .a

  • Put ALL AND ONLY ALL library .o files in $(MWOBJ_DIR) for eventual link into libmw.so & libmw.a

  • Put non-library .o files in $(OBJ_DIR)

Client/Server

  • Put client library files in
    • ../components/<library name>

  • Put unit test files in
    • ../components/<library name>/test

  • Put server files in
    • ../components/<library name>/server

  • Put files common to client library and server in
    • ../components/<library name>/common But common files still get linked into libcl<library name>.so and .a

  • Generate libcl<library name>.so and .a

  • Put all and ONLY ALL library .o files in $(MWOBJ_DIR) for eventual link into libmw.so & libmw.a

  • Put non-library .o files in $(OBJ_DIR)

Files

  • Use .hxx and .cxx and prefix all header files with "cl".
    • example: clTransaction.hxx, transaction.cxx

  • Use bumpyCase for file names, with first character lowercase.
  • Name major functional blocks cl<FN>Api.hxx

    • examples: clLogApi.hxx, clCkptApi.hxx

      An application only needs to include these files. These files must include any other required header files.

  • Other files can be named based on the primary class defined inside
    • examples: clTransaction.hxx

      An application MAY include these files if it wants that specific functionality.

  • Internal APIs should be named cl<something>Ipi.hxx

    • examples: clCkptIpi.hxx

      These files may get pulled into application builds due to object containment. However, it must not be necessary for the application program to ever use symbols defined in the Ipi files.

Definitions

  • All application-level APIs must be defined under the SAFplus namespace:

    •    1 namespace SAFplus
         2   {
         3   class Checkpoint  // Class
         4     {
         5     ...
         6     }; 
         7 
         8   typedef enum  // Enum
         9     {
        10     LOG_SEV_EMERGENCY = 0x1,
        11     ...
        12     };
        13 
        14   Logger* logInitialize(void);  // A function
        15 
        16   int logSeverity;  // A Variable
        17   };
      
  • All internal APIs must be defined under the SAFplusI namespace (I for internal):

    •    1 namespace SAFplusI
         2   {
         3 
         4   };
      
  • Do not hide implementation using handles.
    • Expose them via pointers or containment. This makes debugging much simpler and its easy enough just to skip over tracing through the implementation if needed. Also, prefer containment; do not use pointers rather than containment just to hide implementation.

      Example: clSvcIpi.hxx

         1   namespace SAFplusI
         2   {
         3     class InternalObject
         4       {
         5       ...
         6       };
         7   };
      
      clSvcApi.hxx
         1   #include <clSvcIpi.hxx>
         2   namespace SAFplus
         3   {
         4     class Svc
         5       {
         6       ...
         7       InternalObject& getIo(char* key);  // WRONG: InternalObject is exposed to the application so should be in the API, not IPI.
         8 
         9       protected:
        10       InternalObject array[20];
        11       };
        12   };
      
      Note that in this case, the application will end up including the Ipi file. This is ok, it is clear by the namespace what is API and what is internal.

      Example: With pointers, predeclarations are preferred

         1 namespace SAFplusI
         2   {
         3     class InternalObject;  // Predeclaration
         4   };
         5 
         6 namespaces SAFplus
         7   {
         8     class Svc
         9       {
        10       ...
        11       protected: 
        12       InternalObject* array;
        13       };
        14   };
      
  • Do not use "cl" prefix for class or variable declarations.
    • A prefix is unnecessary because we are under the SAFplus namespace.
  • Classes should be defined using bumpy case, with a leading Capitalization.
  • Prefer enums over #defines
    • Enums are under the SAFplus namespace, macros are not.
  • Prefer inline functions over macros
    • The only exception to this is when you need FILE and LINE macros

  • Constants should be all caps with underscores
    • Example: LOG_SEV_EMERGENCY Constants can be actual enum constants, or other items that you want to be considered constant even if they are not.

      Example: const WellKnownHandle APP_LOG(2,0);

  • Do not use "using namespace xxxx;" inside a header file.
    • Doing so forces every cxx file that includes this header to be 'using' that namespace and therefore defeats the purpose of having 2 namespaces.

Code

Remember, when you write code, you are not primarily communicating to the computer. You are communicating an algorithm specification to the next engineer who will be looking at your code.

  • Line length
    • Forget about 80, 120, etc character line lengths. Modern, widescreen monitors are much longer than they are tall. Put at least one statement on each line. And in extremely rare cases you might put 2 statements on one line if they form a conceptual unit.
  • Comment your code!
    • Expect that the reader knows c++ so do not explain what something does. Answer the question "Why". Example:
      •    1   class Buffer
           2   {
           3     uint32_t refAndLen; // 8 bits (highest) reference count and 24 bits length combined into one.
           4     char data[1];  // Not really length 1, this structure will be malloced and placed on a much larger buffer so data is actually len() long
           5   };
           6 
           7   ...
           8 
           9 const Buffer& SAFplus::Checkpoint::read (const char* key) const
          10 {
          11   size_t len = strlen(key)+1;  // +1 b/c I'm going to take the /0 so Buffers can be manipulated as strings
          12   char data[sizeof(Buffer)-1+len]; // -1 because inside Buffer the data field is already length one.
          13   Buffer* b = new(data) Buffer(len);
          14   *b = key;
          15   return read(*b);
          16 }
        
    • Also note in the buffer allocation case I did not hand-optimize the +1 and -1, by removing them. With a 2.4Ghz machine, this is a useless optimization and obfuscates the code.
  • Do not use goto
    • Better to not malloc/free dynamically (allocations are expensive) but if you must do so use scope objects to handle automatic allocation and deallocation.
  • line up your { vertically, except for single line stuff.
    • YES

         1     if (foo)
         2       {
         3       a++;
         4       b--;
         5       }
         6 
         7     if (foo) { a++; b--; }
      

      NO

         1     if (foo) {
         2       a++;
         3       b--;
         4       }
      
  • Parenthesize rather then rely on order of operations.
    • YES

         1     if ((foo && ((a == 1) || (b==2))) & !a)
      

      NO

         1     if (foo && a == 1 || b==2 & !a) {
      

SAFplus: Programming Style Requirements (last edited 2015-04-23 16:42:04 by AndrewStone)