UNPKG

11.3 kBMarkdownView Raw
1# Contributing to Bitcore
2
3We're working hard to make *bitcore* the most powerful JavaScript library for working with bitcoin. Our goal is to have *bitcore* be a library that can be used by anyone interested in bitcoin, and to level expertise differences with great design and documentation.
4
5## Community
6
7If there are any questions, etc., please feel to ask in one of the community channels:
8
9- [Support Forum](https://labs.bitpay.com/c/bitcore)
10- [Development Chat](https://gitter.im/bitpay/bitcore)
11
12## Quick Checklist
13
14Ideally, please make sure to run:
15
16- `gulp test` passes all the tests (We run tests against Node.js v0.10, v0.12, io.js, and modern browsers)
17- `gulp coverage` covers 100% of the branches of your code (See `coverage/lcov-report/index.html` for details)
18- `gulp lint` doesn't complain about your changes
19
20## Design Guidelines
21
22These are some global design goals in bitcore that any change must adhere.
23
24### D1 - Naming Matters
25
26We take our time with picking names. Code is going to be written once, and read hundreds of times.
27
28We were inspired to name this rule first due to Uncle Bob's great work *Clean Code*, which has a whole chapter on this subject.
29
30In particular, you may notice that some names in this library are quite long for the average JavaScript user. That's because we prefer a long but comprehensible name than an abbreviation that might confuse new users.
31
32### D2 - Tests
33
34Write a test for all your code. We encourage Test Driven Development so we know when our code is right. We have increased test coverage from 80% to around 95% and are targeting 100% as we move towards our 1.0 release.
35
36### D3 - Robustness Principle
37
38*Be conservative in what you send, be liberal in what you accept.*
39
40Interfaces should accept as many types of arguments as possible, so there's no mental tax on using them: we want to avoid questions such as "should I use a string here or a buffer?", "what happens if I'm not sure if the type of this variable is an Address instance or a string with it encoded in base-58?" or "what kind of object will I receive after calling this function?".
41
42Accept a wide variety of use cases and arguments, always return an internal form of an object. For example, the class `PublicKey` can accept strings or buffers with a DER encoded public key (either compressed or uncompressed), another PublicKey, a PrivateKey, or a Point, an instance of the `elliptic.js` library with the point in bitcoin's elliptic curve that represents the public key.
43
44### D4 - Consistency Everywhere
45
46Consistency on the way classes are used is paramount to allow an easier understanding of the library.
47
48## Style Guidelines
49
50The design guidelines have quite a high abstraction level. These style guidelines are more concrete and easier to apply, and also more opinionated. The design guidelines mentioned above are the way we think about general software development and we believe they should be present in any software project.
51
52### General
53
54#### G0 - Default to Felixge's Style Guide
55
56Follow this Node.js Style Guide: https://github.com/felixge/node-style-guide#nodejs-style-guide
57
58#### G1 - No Magic Numbers
59
60Avoid constants in the code as much as possible. Magic strings are also magic numbers.
61
62#### G2 - Internal Objects Should be Instances
63
64If a class has a `publicKey` member, for instance, that should be a `PublicKey` instance.
65
66#### G3 - Internal Amounts Must be Integers Representing Satoshis
67
68Avoid representation errors by always dealing with satoshis. For conversion for frontends, use the `Unit` class.
69
70#### G4 - Internal Network References Must be Network Instances
71
72A special case for [G2](#g2---general-internal-objects-should-be-instances) all network references must be `Network` instances (see `lib/network.js`), but when returned to the user, its `.name` property should be used.
73
74#### G5 - Objects Should Display Nicely in the Console
75
76Write a `.inspect()` method so an instance can be easily debugged in the console.
77
78#### G6 - Naming Utility Namespaces
79
80Name them in UpperCamelCase, as they are namespaces.
81
82DO:
83
84```javascript
85var BufferUtil = require('./util/buffer');
86```
87
88DON'T:
89
90```javascript
91var bufferUtil = require('./util/buffer');
92```
93
94#### G7 - Standard Methods
95
96When possible, bitcore objects should have standard methods on an instance prototype:
97
98- `toObject/toJSON` - A plain JavaScript object that `JSON.stringify` can call
99- `toString` - A string representation of the instance
100- `toBuffer` - A hex Buffer
101
102These should have a matching static method that can be used for instantiation:
103
104- `fromObject` - Should be able to instantiate with the output from `toObject/toJSON`
105- `fromString` - Should be able to instantiate with output from `toString`
106- `fromBuffer` - Should likewise be able to instantiate from output from `toBuffer`
107
108`JSON.stringify` and `JSON.parse` are expected to be handled outside of the scope of Bitcore methods. For example, calling `JSON.stringify` on an Bitcore object will behave as expected and call `transaction.toJSON()` and then stringify it:
109
110```javascript
111var transactionString = JSON.stringify(transaction);
112```
113
114Likewise to instantiate a transaction from that string:
115
116```javascript
117var data = JSON.parse(transactionString);
118var tx = new Transaction(data);
119```
120
121### Errors
122
123#### E1 - Use bitcore.Errors
124
125We've designed a structure for Errors to follow and are slowly migrating to it.
126
127Usage:
128
129- Errors are generated in the file `lib/errors/index.js` by invoking `gulp errors`.
130- The specification for errors is written in the `lib/errors/spec.js` file.
131- Whenever a new class is created, add a generic error for that class in `lib/errors/spec.js`.
132- Specific errors for that class should subclass that error. Take a look at the structure in `lib/errors/spec.js`, it should be clear how subclasses are generated from that file.
133
134#### E2 - Provide a `getValidationError` Static Method for Classes
135
136### Interface
137
138#### I1 - Code that Fails Early
139
140In order to deal with JavaScript's weak typing and confusing errors, we ask our code to fail as soon as possible when an unexpected input was provided.
141
142There's a module called `util/preconditions`, loosely based on `preconditions.js`, based on `guava`, that we use for state and argument checking. It should be trivial to use. We recommend using it on all methods, in order to improve robustness and consistency.
143
144```javascript
145$.checkState(something === anotherthing, 'Expected something to be anotherthing');
146$.checkArgument(something < 100, 'something', 'must be less than 100');
147$.checkArgumentType(something, PrivateKey, 'something'); // The third argument is a helper to mention the name of the argument
148$.checkArgumentType(something, PrivateKey); // but it's optional (will show up as "(unknown argument)")
149```
150
151#### I2 - Permissive Constructors
152
153Most classes have static methods named `fromBuffer`, `fromString`, `fromJSON`. Whenever one of those methods is provided, the constructor for that class should also be able to detect the type of the arguments and call the appropriate method.
154
155#### I3 - Method Chaining
156
157For classes that have a mutable state, most of the methods that can be chained *SHOULD* be chained, allowing for interfaces that read well, like:
158
159```javascript
160var transaction = new Transaction()
161 .from(utxo)
162 .to(address, amount)
163 .change(address)
164 .sign(privkey);
165```
166
167#### I4 - Copy Constructors
168
169Constructors, when provided an instance of the same class, should:
170
171- Return the same object, if the instances of this class are immutable
172- Return a deep copy of the object, if the instances are mutable
173
174Examples:
175
176```javascript
177function MyMutableClass(arg) {
178 if (arg instanceof MyMutableClass) {
179 return MyMutableClass._deepCopy(arg);
180 }
181 // ...
182}
183function ImmutableClass(arg) {
184 if (arg instanceof ImmutableClass) {
185 return arg;
186 }
187 // ...
188}
189```
190
191#### I5 - No New Keyword for Constructors
192
193Constructors should not require to be called with `new`. This rule is not heavily enforced, but is a "nice to have".
194
195```javascript
196function NoNewRequired(args) {
197 if (!(this instanceof NoNewRequired)) {
198 return new NoNewRequired(args);
199 }
200 // ...
201}
202```
203
204### Testing
205
206#### T1 - Tests Must be Written Elegantly
207
208Style guidelines are not relaxed for tests. Tests are a good way to show how to use the library, and maintaining them is extremely necessary.
209
210Don't write long tests, write helper functions to make them be as short and concise as possible (they should take just a few lines each), and use good variable names.
211
212#### T2 - Tests Must not be Random
213
214Inputs for tests should not be generated randomly. Also, the type and structure of outputs should be checked.
215
216#### T3 - Require 'bitcore' and Look up Classes from There
217
218This helps to make tests more useful as examples, and more independent of where they are placed. This also helps prevent forgetting to include all submodules in the bitcore object.
219
220DO:
221
222```javascript
223var bitcore = require('../');
224var PublicKey = bitcore.PublicKey;
225```
226
227DON'T:
228
229```javascript
230var PublicKey = require('../lib/publickey');
231```
232
233#### T4 - Data for Tests Included in a JSON File
234
235If possible, data for tests should be included in a JSON file in the `test/data` directory. This improves interoperability with other libraries and keeps tests cleaner.
236
237### Documentation
238
239#### D1 - Guide and API Reference
240
241All modules should include a developer guide and API reference. The API reference documentation is generated using JSDOC. Each function that exposes a public API should include a description, @return and @param, as appropriate. The general documentation guide for the module should be located in the `docs/guide` directory and is written in GitHub Flavored Markdown.
242
243#### D2 - Proofread
244
245Please proofread documentation to avoid unintentional spelling and grammatical mistakes before submitting a pull request.
246
247## Pull Request Workflow
248
249Our workflow is based on GitHub's pull requests. We use feature branches, prepended with: `test`, `feature`, `fix`, `refactor`, or `remove` according to the change the branch introduces. Some examples for such branches are:
250
251```sh
252git checkout -b test/some-module
253git checkout -b feature/some-new-stuff
254git checkout -b fix/some-bug
255git checkout -b remove/some-file
256```
257
258We expect pull requests to be rebased to the master branch before merging:
259
260```sh
261git remote add bitpay git@github.com:bitpay/bitcore.git
262git pull --rebase bitpay master
263```
264
265Note that we require rebasing your branch instead of merging it, for commit readability reasons.
266
267After that, you can push the changes to your fork, by doing:
268
269```sh
270git push origin your_branch_name
271git push origin feature/some-new-stuff
272git push origin fix/some-bug
273```
274
275Finally go to [github.com/bitpay/bitcore](https://github.com/bitpay/bitcore) in your web browser and issue a new pull request.
276
277Main contributors will review your code and possibly ask for changes before your code is pulled in to the main repository. We'll check that all tests pass, review the coding style, and check for general code correctness. If everything is OK, we'll merge your pull request and your code will be part of bitcore.
278
279If you have any questions feel free to post them to
280[github.com/bitpay/bitcore/issues](https://github.com/bitpay/bitcore/issues).
281
282Thanks for your time and code!