Weighted Methods Per Class (WMC)
Weighted methods per class is a quantitative metric that measures the sum of the cyclomatic complexity of all methods in a class/extension/mixin/enum/extension type.
High WMC values indicate classes that are hard to understand, maintain and test.
Additional resources: Chidamber-Kemerer metrics paper.
This metric uses Cyclomatic Complexity metric results for calculating the weight of each method.
Why Be Cautious
High weighted methods per class values can lead to:
- Increased Complexity: More complex classes are harder to read and understand.
- Testing and Maintainability Challenges: Complex classes require more effort to test and maintain.
- Error-Proneness: Complex methods tend to be more error-prone, especially when inherited.
How to Address High Weighted Methods Per Class?
First, understand the responsibility of the class. If the class is doing to many things, consider splitting it into several classes, each with a limited responsibility.
Additionally, check if all methods need to be in that particular class and consider extracting those that do not depend on state as helpers or utilities.
Config Example
dcm:
metrics:
weighted-methods-per-class:
threshold: 35
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: High Weighted Methods Per Class
// WMC: 11
class OrderProcessor {
// CYCLO: 5
void processOrder(Order order) {
if (order.hasDiscount()) {
if (order.total > 100) {
applyDiscount(order);
} else {
addLoyaltyPoints(order.customer);
}
}
if (order.total > 200) {
scheduleShipping(order);
}
if (order.isGift) {
sendGiftNotification(order);
}
}
// CYCLO: 2
void applyDiscount(Order order) {
if (order.customer.isVIP) {
order.total *= 0.8;
} else {
order.total *= 0.9;
}
}
// CYCLO: 2
void addLoyaltyPoints(Customer customer) {
int points = customer.isVIP ? 50 : 20;
customer.loyaltyPoints += points;
}
// CYCLO: 2
void scheduleShipping(Order order) {
if (order.isInternational) {
scheduleInternationalShipping(order);
} else {
scheduleLocalShipping(order);
}
}
}
✅ Good: Low Weighted Methods Per Class
// WMC: 2
class OrderProcessor {
final DiscountService discountService;
final ShippingService shippingService;
const OrderProcessor(this.discountService, this.shippingService);
// CYCLO: 2
void processOrder(Order order) {
discountService.handleDiscount(order);
shippingService.handleShipping(order);
if (order.isGift) {
sendGiftNotification(order);
}
}
}
// WMC: 7
class DiscountService {
// CYCLO: 3
void handleDiscount(Order order) {
if (order.hasDiscount() && order.total > 100) {
applyDiscount(order);
} else if (order.hasDiscount()) {
addLoyaltyPoints(order.customer);
}
}
// CYCLO: 2
void applyDiscount(Order order) {
order.total *= order.customer.isVIP ? 0.8 : 0.9;
}
// CYCLO: 2
void addLoyaltyPoints(Customer customer) {
customer.loyaltyPoints += customer.isVIP ? 50 : 20;
}
}
// WMC: 4
class ShippingService {
// CYCLO: 2
void handleShipping(Order order) {
if (order.total > 200) {
scheduleShipping(order);
}
}
// CYCLO: 2
void scheduleShipping(Order order) {
if (order.isInternational) {
scheduleInternationalShipping(order);
} else {
scheduleLocalShipping(order);
}
}
}