Weight of a Class (WOC)
Weight of a class is a quantitative metric that measures whether a class reveals more data than behavior.
Calculated as the ratio of functional public methods to the total number of public members (formula: WOC = Functional Public Methods / (Public Members (Methods + Fields + Accessors))).
Low WOC indicates a data class (with little or no behavior).
Edge Cases and Clarifications
- Methods without the implementation, operators, boilerplate methods (e.g.
toString) are excluded from functional methods. - All types of widgets (and states) are excluded.
- Any class with
externalmembers is excluded.
Why Be Cautious
Low weight of a class can lead to:
- Weak Encapsulation: Any part of your app can access/change a field without the class validating if that change is allowed. You lose the ability to guarantee that the object is in a "valid state."
How to Address Low Weight of a Class?
First, understand the purpose of the class. If it's supposed to be a data class or DTO, exclude it from the calculation as having low WOC for such classes is normal.
For cases when there are other classes that access the fields, consider moving that logic to the target class as a public method(s).
For cases when some of the fields can be made private, consider making them private, as private fields are excluded from the WOC denominator. This immediately "lightens" the class's public interface, focusing it on behavior.
Config Example
dcm:
metrics:
weight-of-class:
threshold: 0.33
To set multiple threshold or other common config options, refer to the Configuring Metrics page.
Example
To view what contributes to the metric value, generate an HTML report.
❌ Bad: Low Weight of a Class
// WOC: 0
class BankAccount {
String accountId;
double balance;
String status;
DateTime lastUpdated;
BankAccount(this.accountId, this.balance, this.status, this.lastUpdated);
bool get isOverdrawn => balance < 0;
}
// Business logic "leaks" into external services
class AccountService {
void withdraw(BankAccount account, double amount) {
if (account.status == 'active' && account.balance >= amount) {
account.balance -= amount;
account.lastUpdated = DateTime.now();
}
}
}
✅ Good: High Weight of a Class
// WOC: 0.5
class BankAccount {
final String _accountId;
double _balance;
String _status;
BankAccount(this._accountId, this._balance, this._status);
void withdraw(double amount) {
if (_status != 'active') throw Exception("Account frozen");
if (_balance < amount) throw Exception("Insufficient funds");
_balance -= amount;
}
double get currentBalance => _balance;
}