github.com/NebulousLabs/Sia@v1.3.7/doc/Developers.md (about)

     1  Developer Environment
     2  =====================
     3  
     4  Sia is written in Go. To build and test Sia, you are going to need a working go
     5  environment, including having both `$GOROOT/bin` and `$GOPATH/bin` in your
     6  `$PATH`. For most Linux distributions, Go will be in the package manager,
     7  though it may be an old version that is incompatible with Sia. Once you have a
     8  working Go environment, you are set to build the project. If you plan on cross
     9  compiling Sia, you may need to install Go from source. You can find information
    10  on that [here](http://golang.org/doc/install/source).
    11  
    12  Sia has a development build, an automated testing build, and a release
    13  build. The release build is the only one that can synchronize to the full
    14  network. To get the release build, it is usually sufficient to run `go get -u
    15  github.com/NebulousLabs/Sia/...`. This will download Sia and its dependencies
    16  and install binaries in `$GOPATH/bin`.
    17  
    18  After downloading, you can find the Sia source code in
    19  `$GOPATH/src/github.com/NebulousLabs/Sia`. To build the release binary, run
    20  `make release-std` from this directory. To build the release binary with a
    21  (slow) race detector and an array of debugging asserts, run `make release`. To
    22  build the developer binary (which has a different genesis block, faster block
    23  times, and a few other tweaks), just run `make`.
    24  
    25  If you intend to contribute to Sia, you should start by forking the project on
    26  GitHub, and then adding your fork as a "remote" in the Sia git repository via
    27  `git remote add [fork name] [fork url]`. Now you can develop by pulling changes
    28  from `origin`, pushing your modifications to `[fork name]`, and then making a
    29  pull request on GitHub.
    30  
    31  If you see an error like the one below, it means that you either forgot to run
    32  `make dependencies`, or you cloned the project into a path that the go tool
    33  does not recognize (usually the wrong path, or symbolic links were somehow
    34  involved).
    35  
    36  ```
    37  consensus/fork.go:4:2: cannot find package "github.com/NebulousLabs/Sia/crypto" in any of:
    38      /usr/lib/go/src/github.com/NebulousLabs/Sia/crypto (from $GOROOT)
    39      /home/user/gopath/src/github.com/NebulousLabs/Sia/crypto (from $GOPATH)
    40  ```
    41  
    42  Developer Conventions
    43  =====================
    44  
    45  This file is meant to help a developer navigate the codebase and develop clean,
    46  maintainable code. Knowing all of these conventions will also make it easier to
    47  read and code review the Sia project.
    48  
    49  The primary purpose of the conventions within Sia is to keep the codebase
    50  simple. Simpler constructions means easier code reviews, greater accessibility
    51  to newcomers, and less potential for mistakes. It is also to keep things
    52  uniform, much in the spirit of `go fmt`. When everything looks the same,
    53  everyone has an easier time reading and reviewing code they did not write
    54  themselves.
    55  
    56  Documentation
    57  -------------
    58  
    59  All structs, functions, and interfaces must have a docstring.
    60  
    61  Anytime that something is left unfinished, place a comment containing the
    62  string 'TODO:'. This sends a clear message to other developers, and creates a
    63  greppable way to find unfinished parts of the codebase. 'TODO' statements are
    64  currently discouraged.  As the codebase matures, 'TODO' statements will become
    65  increasingly frowned upon. 'TODO' statements should not document feature
    66  requests, but instead document incompleteness where the incompleteness causes
    67  disruption to user experience or causes a security vulnerability.
    68  
    69  Documentation should give a sense of what each function does, but should also
    70  give a sense of the overall architecture of the code. Where useful, examples
    71  should be provided, and common pitfalls should be explained. Anything that
    72  breaks other conventions in any way needs to have a comment, even if it is
    73  obvious why the convention had to be broken.
    74  
    75  The goal of the codebase is to be accessible to newbies. Anything more advanced
    76  than what you would expect to remember from an 'Intro to Data Structures' class
    77  should have an explanation about what the concept it is and why it was picked
    78  over other potential choices.
    79  
    80  Code that exists purely to be compatible with previous versions of the
    81  software should be tagged with a `COMPATvX.X.X` comment. Examples below.
    82  
    83  ```go
    84  // Find and sort the outputs.
    85  outputs := getOutputs()
    86  // TODO: actually sort the outputs.
    87  ```
    88  
    89  ```go
    90  // Disallow unknown agents.
    91  //
    92  // COMPATv0.4.0: allow a blank agent to preserve compatibility with
    93  // 'siac' v0.4.0, which did not set an agent.
    94  if agent != "SiaAgent" && agent != "" {
    95  	return errors.New("unrecognized agent!")
    96  }
    97  ```
    98  
    99  Naming
   100  ------
   101  
   102  Names are used to give readers and reviewers a sense of what is happening in
   103  the code. When naming variables, you should assume that the person reading your
   104  code is unfamiliar with the codebase. Short names (like `cs` instead of
   105  `consensusSet`) should only be used when the context is immediately obvious.
   106  For example `cs := new(ConsensusSet)` is immediately obvious context for `cs`,
   107  and so `cs` is appropriate for the rest of the function.
   108  
   109  Data structures should never have shortened names. `FileContract.mr` is
   110  confusing to anyone who has not used the data structure extensively. The code
   111  should be accessible to people who are unfamiliar with the codebase. One
   112  exception is for the variable called `mu`, which is short for 'mutex'. This
   113  exception is made because `mu` appears in many data structures.
   114  
   115  When calling functions with obscure parameters, named variables should be used
   116  to indicate what the parameters do. For example, `m := NewMiner(1)` is
   117  confusing. Instead, use `threads := 1; m := NewMiner(threads)`. The name gives
   118  readers a sense of what the parameter within `NewMiner` does even when they are
   119  not familiar with the `NewMiner` function. Where possible, functions with
   120  obscure, untyped inputs should be avoided.
   121  
   122  The most important thing to remember when choosing names is to cater to people
   123  who are unfamiliar with the code. A reader should never have to ask 'What is
   124  `cs`?' on their first pass through the code, even though to experienced
   125  developers it is obvious that `cs` refers to a `consensus.ConsensusSet`.
   126  
   127  ### Function Prefixes
   128  
   129  Sia uses special prefixes for certain functions to hint about their usage to the
   130  caller.
   131  
   132  #### `threaded`
   133  
   134  Prefix functions with `threaded` (e.g., `threadedMine`) to indicate that callers
   135  should only call these functions within their own goroutine (e.g.,
   136  `go threadedMine()`). These functions must manage their own thread-safety.
   137  
   138  #### `managed`
   139  
   140  Prefix functions with `managed` (e.g. `managedUpdateWorkerPool`) if the function
   141  acquires any locks in its body.
   142  
   143  Control Flow
   144  ------------
   145  
   146  Where possible, control structures should be minimized or avoided. This
   147  includes avoiding nested if statements, and avoiding else statements where
   148  possible. Sometimes, complex control structures are necessary, but where
   149  possible use alternative code patterns and insert functions to break things up.
   150  
   151  Example:
   152  
   153  ```go
   154  // Do not do this:
   155  if err != nil {
   156  	return
   157  } else {
   158  	forkBlockchain(node)
   159  }
   160  
   161  // Instead to this:
   162  if err != nil {
   163  	return
   164  }
   165  forkBlockchain(node)
   166  ```
   167  
   168  Mutexes
   169  -------
   170  
   171  All exported functions from a package and/or object need to be thread safe.
   172  Usually, this means that the first lines of the function contain a `Lock();
   173  defer Unlock()`. Simple locking schemes should be preferred over performant
   174  locking schemes. As will everything else, anything unusual or convention
   175  breaking should have a comment.
   176  
   177  Non-exported functions should not do any locking unless they are named with the
   178  proper prefix (see [Function Prefixes](#function-prefixes)). The responsibility
   179  for thread-safety comes from the exported functions which call the non-exported
   180  functions. Maintaining this convention minimizes developer overhead when working
   181  with complex objects.
   182  
   183  Error Handling
   184  --------------
   185  
   186  All errors need to be checked as soon as they are received, even if they are
   187  known to not cause problems. The statement that checks the error needs to be
   188  `if err != nil`, and if there is a good reason to use an alternative statement
   189  (such as `err == nil`), it must be documented. The body of the if statement
   190  should be at most 4 lines, but usually only one. Anything requiring more lines
   191  needs to be its own function.
   192  
   193  Example:
   194  
   195  ```go
   196  block, err := s.AcceptBlock()
   197  if err != nil {
   198  	handleAcceptBlockErr(block, err)
   199  	return
   200  }
   201  ```
   202  
   203  Sanity Checks
   204  -------------
   205  
   206  Some functions make assumptions. For example, the `addTransaction` function
   207  assumes that the transaction being added is not in conflict with any other
   208  transactions. Where possible, these explicit assumptions should be validated.
   209  
   210  Example:
   211  
   212  ```go
   213  if build.DEBUG {
   214  	_, exists := tp.usedOutputs[input.OutputID]
   215  	if exists {
   216  		panic("incorrect use of addTransaction")
   217  	}
   218  }
   219  ```
   220  
   221  In the example, a panic is called for incorrect use of the function, but only
   222  in debug mode. This failure will be invisible in production code, but the code
   223  will have higher performance because the code should never fail anyway.
   224  
   225  If the code is continually checking items that should be universally true,
   226  mistakes are easier to catch during testing, and side effects are less likely
   227  to go unnoticed.
   228  
   229  Sanity checks and panics are purely to check for developer mistakes. A user
   230  should not be able to trigger a panic, and no set of network communications or
   231  real-world conditions should be able to trigger a panic.
   232  
   233  Testing
   234  -------
   235  
   236  The test suite code should be the same quality as the rest of the codebase.
   237  When writing new code in a pull request, the pull request should include test
   238  coverage for the code.
   239  
   240  Most modules have a tester object, which can be created by calling
   241  `createXXXTester`. Module testers typically have a consensus set, a miner, a
   242  wallet, and a few other relevant modules that can be used to build
   243  transactions, mine blocks, etc.
   244  
   245  In general, testing that uses exclusively exported functions to achieve full
   246  coverage is preferred. These types of tests seem to find more bugs and trigger
   247  more asserts.
   248  
   249  Any testing provided by a third party which is both maintainable and reasonably
   250  quick will be accepted. There is little downside to more testing, even when the
   251  testing is largely redundant.