> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nearplay.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Best Practices

> Tips for efficient smart contract development

Tips to write better NEAR smart contracts.

## Code Organization

### Use Clear Naming

```rust theme={null}
// Good
pub fn transfer_tokens(&mut self, recipient: AccountId, amount: u128) { ... }

// Bad
pub fn tt(&mut self, r: AccountId, a: u128) { ... }
```

### Group Related Methods

```rust theme={null}
#[near]
impl MyContract {
    // === View Methods ===
    pub fn get_balance(&self) -> u128 { ... }
    pub fn get_owner(&self) -> AccountId { ... }

    // === Mutating Methods ===
    pub fn transfer(&mut self, ...) { ... }
    pub fn withdraw(&mut self, ...) { ... }

    // === Admin Methods ===
    pub fn set_owner(&mut self, ...) { ... }
}
```

### Keep Methods Small

Each method should do one thing. If a method is getting long, break it into smaller private functions.

## Gas Optimization

### Minimize Storage Writes

Storage operations are expensive. Batch updates when possible.

```rust theme={null}
// Good - one write
self.balances.insert(&account, &new_balance);

// Bad - multiple writes in a loop
for item in items {
    self.data.insert(&item.id, &item);
}
```

### Use Efficient Data Structures

| Use Case            | Recommended  |
| ------------------- | ------------ |
| Key-value lookup    | `LookupMap`  |
| Iterable collection | `Vector`     |
| Unique set          | `LookupSet`  |
| Small fixed data    | `LazyOption` |

### Avoid Large Return Values

Returning large amounts of data costs gas. Use pagination for lists.

```rust theme={null}
// Good - paginated
pub fn get_items(&self, from: u64, limit: u64) -> Vec<Item> {
    self.items.iter().skip(from).take(limit).collect()
}

// Bad - returns everything
pub fn get_all_items(&self) -> Vec<Item> {
    self.items.to_vec()
}
```

## Security

### Validate Inputs

Always check user inputs before processing.

```rust theme={null}
pub fn transfer(&mut self, amount: u128) {
    require!(amount > 0, "Amount must be positive");
    require!(amount <= self.balance, "Insufficient balance");
    // ...
}
```

### Check Caller Identity

For admin functions, verify the caller.

```rust theme={null}
pub fn admin_action(&mut self) {
    require!(
        env::predecessor_account_id() == self.owner,
        "Only owner can call this"
    );
    // ...
}
```

### Handle Errors Gracefully

Use `require!` for expected failures, `panic!` for unexpected ones.

```rust theme={null}
// Expected failure - user error
require!(self.balances.contains_key(&account), "Account not found");

// Unexpected failure - bug
let value = self.data.get(&key).expect("Data should exist");
```

### Be Careful with Cross-Contract Calls

Cross-contract calls can fail. Always handle the callback.

```rust theme={null}
#[private]
pub fn on_transfer_complete(&mut self, #[callback_result] result: Result<(), PromiseError>) {
    match result {
        Ok(_) => { /* success */ }
        Err(_) => { /* rollback changes */ }
    }
}
```

## Testing

### Test Happy Path and Edge Cases

```rust theme={null}
#[test]
fn test_transfer_success() { ... }

#[test]
fn test_transfer_zero_fails() { ... }

#[test]
fn test_transfer_insufficient_balance() { ... }
```

### Use Descriptive Test Names

```rust theme={null}
// Good
#[test]
fn test_withdraw_fails_when_balance_is_zero() { ... }

// Bad
#[test]
fn test_withdraw() { ... }
```

## Quick Reference

<CardGroup cols={2}>
  <Card title="Do" icon="check">
    * Validate all inputs
    * Use efficient data structures
    * Write tests
    * Keep methods focused
  </Card>

  <Card title="Don't" icon="xmark">
    * Store unnecessary data
    * Return large datasets
    * Skip error handling
    * Trust user input blindly
  </Card>
</CardGroup>
