Skip to main content

Weighted Methods Per Class (WMC)

v1.3.0
short name: WMC
effort: 10m
default threshold: 45

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.

info

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​

analysis_options.yaml
dcm:
metrics:
weighted-methods-per-class:
threshold: 35

To set multiple threshold or other common config options, refer to the Configuring Metrics page.

Example​

info

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);
}
}
}