github.com/cloudfoundry-attic/garden-linux@v0.333.2-candidate/docs/DEVELOPING.md (about)

     1  # Development Setup and Workflow
     2  
     3  ## Environment and testing
     4  
     5  See our [Garden Linux Release](https://www.github.com/cloudfoundry-incubator/garden-linux-release) repository.
     6  
     7  ## Building CI Images
     8  
     9  See our [Packer README](../packer/README.markdown).
    10  
    11  ## Coding Conventions
    12  
    13  Thankfully Go defines a standard code format so we simply adhere to that.
    14  
    15  If you write Go code using some tool, like IntelliJ IDEA, which does not enforce
    16  the standard format, you should install a
    17  [pre-commit hook](https://golang.org/misc/git/pre-commit) to check the formatting.
    18  
    19  ### Error Handling
    20  
    21  We generally prefer Go idioms for error handling: the difficulty, particularly
    22  for newcomers, is knowing what those idioms are. So it would be more accurate to
    23  say that we _assert_ the following Go idioms. :-)
    24  
    25  [Effective Go](https://golang.org/doc/effective_go.html#errors) doesn't say a
    26  great deal on this subject, but its philosophy is to provide some indication of
    27  the _context_ in which the error occurred (typically the operation or package
    28  that generated the error) and any _symptoms_ the user might find helpful in
    29  correcting the error. The reader could be forgiven for assuming that whenever
    30  symptoms are to be included in an error, a specific type conforming to `error`
    31  should be provided, but this is often overkill (especially when the caller is
    32  unlikely to need programmatic access to the symptoms).
    33  
    34  In general it is better to recover from an error, possibly after logging it, and
    35  continue normally so the user doesn't see the error. Do not automatically "wrap,
    36  return and forget" an error without considering recovering from the error.
    37  
    38  ### Error Messages
    39  
    40  An error message should be crafted such that it clearly communicates to the
    41  user what was happening when the failure occured, and the nature of the
    42  failure. Include helpful information in the message, for example if a file
    43  cannot be opened list the filename in question.
    44  
    45  In general, we prefer the following format for error messages:
    46  
    47  ```
    48  {package where error occured}: {attempted behaviour and any additional helpful information}: {underlying error if applicable helpful}
    49  ```
    50  
    51  For example, the following error from the `link` package follows these
    52  guidelines:
    53  
    54  ```go
    55  fmt.Errorf("link: create link: invalid number of fds, need 3, got %d", len(fds))
    56  ```
    57  
    58  Sometimes the package name alone gives enough indication of the operation in
    59  question, in which case you can be more succinct:
    60  
    61  ```go
    62  fmt.Errorf("link: invalid number of fds, need 3, got %d", len(fds))
    63  ```
    64  
    65  ### Wrapping an Underlying Error with a New Message
    66  
    67  When wrapping an underlying error, place the underlying error message at the
    68  end, and add any additional context (including the wrapping package) which
    69  is helpful:
    70  
    71  ```go
    72  fmt.Errorf("devices: create bridge with name '%s': %v", name, err)
    73  ```
    74  
    75  Listing the activity being undertaken when the error occurred (as above) is
    76  often useful in cases where an error is being wrapped.
    77  
    78  Note that when wrapping an underlying error, the underlying error message will
    79  generally already have specified that it failed, so the error message will
    80  often read better if the wrapping message does not *also* begin with a phrase
    81  like 'failed to', for example compare "network: failed to set mtu: failed to
    82  find interface X" to "networking: setting mtu: failed to find interface X".
    83  
    84  It is sometimes appropriate to return the underlying error unmodified,
    85  where knowledge of the intermediate function or package does not add
    86  context that would help the user. In these cases it is important to log the
    87  error so that the call chain can be found in the log when debugging (see
    88  'Error Messages vs. Logging' below).
    89  
    90  Where a caller of a function may need to take action based on the specific
    91  error that occurred, a rich error type (a type implementing the Error
    92  interface) is helpful. The preferred message format is the same as
    93  above.
    94  
    95  ```go
    96  type MTUError struct {
    97  	Cause error
    98  	Intf  *net.Interface
    99  	MTU   int
   100  }
   101  
   102  func (err MTUError) Error() string {
   103  	return fmt.Spintf("network: set mtu on interface '%v' to %d: %v", err.Intf, err.MTU, err.Cause)
   104  }
   105  ```
   106  
   107  ### Logging Errors
   108  
   109  Try not to make error messages a substitute for logging:
   110  the point of an error message is to help the user. the point of logging is to
   111  help maintainers determine where in the code a problem occurred.
   112  
   113  Log important errors (along with helpful program state) when they
   114  occur so that unexpected errors can be quickly diagnosed and debugged.
   115  
   116  Hence, an error message should not read like
   117  a stack trace: if it does, consider using `panic` instead.
   118  
   119  ### Design Notes
   120  
   121  #### Container Creation
   122  
   123  ![Container creation](https://github.com/cloudfoundry-incubator/garden-linux/blob/master/docs/images/container%20creation.png)
   124  
   125  #### Process Structure
   126  
   127  ![Process structure](https://github.com/cloudfoundry-incubator/garden-linux/blob/master/docs/images/iodaemon%20process%20structure.png)