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  124 125 #### Process Structure 126 127 