Best Practices

Best Practices

About

  • API Design: Thoughtful property exposure
  • Performance: Consider access patterns
  • Maintainability: Clear documentation
  • Consistency: Team conventions

Main Topics

  1. When to Use Getters/Setters

    • Definition: Appropriate use cases
    • Example:
      // Use when:
      // - Validation needed
      // - Derived values
      // - Change notification
  2. Performance Considerations

    • Definition: Cost of accessors
    • Example:
      // Simple getters may be inlined
      // Complex logic has overhead
  3. Read-only Design

    • Definition: Prefer immutable
    • Example:
      // Good:
      final _data = fetch();
      get data => _data;
  4. Documentation

    • Definition: Explain behavior
    • Example:
      /// The current temperature in Celsius
      /// Setting this will update both Celsius and Fahrenheit
      double get temperature => _celsius;
  5. Testing

    • Definition: Verify behavior
    • Example:
      test('setting negative balance throws', () {
        expect(() => account.balance = -1, throwsArgumentError);
      });

How to Use

  • Start Simple: Default accessors first
  • Add Logic: When requirements demand
  • Document: Public API thoroughly
  • Test: Both getters and setters

How It Works

  1. Design: Plan property exposure
  2. Implementation: Add logic gradually
  3. Verification: Tests ensure correctness
  4. Evolution: Can change internals safely

Example:

/// Represents a rational number
class Fraction {
  int _numerator;
  int _denominator;

  Fraction(this._numerator, this._denominator);

  /// Numerator part of fraction
  int get numerator => _numerator;

  /// Denominator (must not be zero)
  set denominator(int value) {
    if (value == 0) throw ArgumentError();
    _denominator = value;
  }

  /// Decimal value (numerator/denominator)
  double get value => _numerator / _denominator;
}

Conclusion

Well-designed getters and setters follow the principle of least surprise, providing predictable behavior while protecting class invariants. By adhering to best practices around immutability, documentation, and validation, Dart developers can create robust, maintainable classes with clear property contracts.