XO Wallet Integration Part IV
This commit is contained in:
+58
-2
@@ -35,6 +35,62 @@ A table of common prefixes (conventions) is below:
|
||||
| revert | Reverts a previous commit |
|
||||
|
||||
|
||||
## Coding Guidelines
|
||||
|
||||
These guidelines represent best practices. While exceptions may occasionally be necessary as "the lesser evil," strive to adhere to these principles whenever possible.
|
||||
|
||||
1. Try to minimize state
|
||||
|
||||
State is a complexity multiplier. Keep mutable class members to an absolute minimum, as each stateful property exponentially increases cognitive load and potential for bugs. When designing classes or components, first attempt a stateless approach, adding mutable properties only when demonstrably necessary.
|
||||
|
||||
2. Try to avoid `any` types
|
||||
|
||||
Use `unknown` instead, as it provides better type safety while maintaining flexibility when needed.
|
||||
|
||||
3. Prefer immutable patterns
|
||||
|
||||
Use immutable data structures where possible to improve code predictability and testability.
|
||||
|
||||
For example:
|
||||
|
||||
```ts
|
||||
// GOOD:
|
||||
const mappedData = originalData.map((item) => item.field);
|
||||
|
||||
// AVOID:
|
||||
const mappedData = [];
|
||||
|
||||
for(let i = 0; i < originalData.length; i++) {
|
||||
mappedData.push(originalData[i].field);
|
||||
}
|
||||
```
|
||||
|
||||
Do note that there are some cases where it may make more sense to mutate data inline (e.g. as an optimization for very large data structures).
|
||||
|
||||
Use your best judgement, but treat immutability as the general rule.
|
||||
|
||||
4. Avoid Typescript, Linter and Formatter Directives
|
||||
|
||||
These exceptional cases should be minimized as they:
|
||||
- Create inconsistency in code standards
|
||||
- Make maintenance more difficult
|
||||
- Often mask underlying issues that should be properly resolved
|
||||
- Can lead to unintended side-effects throughout the codebase
|
||||
|
||||
4. Avoid additional dependencies.
|
||||
|
||||
Try to avoid pulling in additional packages. Not only can this bloat the project, but can also cause compatibility issues between environments (Web, Node, ESM, etc). We want `@xocash/stack` to "just work" without devs having to tailor build configurations.
|
||||
|
||||
Obviously this is an ideal: Sometimes it is simply not feasible or sensible to rewrite complex functionality that can be better done by a well-built package. However, please try to adhere to the following:
|
||||
|
||||
- Ensure the package is of high quality (well-written, well-tested).
|
||||
- Does not drag in additional dependencies itself (note that `devDependencies` are fine. These will not be installed when leveraged from our packages).
|
||||
- If the package being used **is heavy** and we have no other choice but to use it, consider whether we should package it separately to avoid problems. For example, if we build a `BlockchainBCHN` adapter, we will likely want to package this on its own under `@xocash/blockchain-bchn` as it only works in NodeJS environments.
|
||||
|
||||
5. "When in Rome..."
|
||||
|
||||
For conventions not explicitly mentioned, follow the "when in Rome" principle. Try to identify and use the patterns and conventions that are already established elsewhere in the codebase.
|
||||
|
||||
## Patterns
|
||||
|
||||
### Dependency Injection
|
||||
@@ -77,7 +133,7 @@ class SomeClass {
|
||||
|
||||
### Factory Patterns
|
||||
|
||||
When creating classes, create static `from(...)` (or `fromSpecificThing(...)`) methods.
|
||||
When creating classes, create static `from(...)` (or `fromSpecificThing(...)`) methods and place these at the top of the class (so that they appear first in the generated documentation).
|
||||
|
||||
In Javascript, a `constructor` cannot be asynchronous and we want to ensure that we can `await` class instantiation to mitigate against stateful errors.
|
||||
|
||||
@@ -223,7 +279,7 @@ Avoid revalidation at every code-path: This is not only inefficient, but a giant
|
||||
|
||||
```ts
|
||||
// You can accept other types (this is a nice convenience).
|
||||
broadcastTransaction(transaction: Transaction | Uint8Array): Transaction {
|
||||
broadcastTransaction(transaction: Transaction | Uint8Array | string): Transaction {
|
||||
// ... but always cast to the Primitive (to ensure correctness).
|
||||
if(!(transaction instanceof Transaction) {
|
||||
transaction = Transaction.from(transaction);
|
||||
|
||||
Reference in New Issue
Block a user