Skip to content

avoid_long_functions

v1.0.0WarningConfigurableCode Quality

This rule flags a function body longer than the configured line budget.

A long function is not wrong, but it is where several responsibilities usually end up sharing one scope and one set of locals. Enforcing a budget in the analyzer puts the signal at the point of writing, where splitting is cheap, rather than in a CI script that reports it after the fact — which is what makes it a genuine replacement for a check_file_length.sh-style gate.

Lines are counted from the body’s braces, so the signature and any doc comment do not count against it.

This rule is in the pedantic preset. A budget is a house style, and the default of 50 is stricter than many codebases run: measured against a production Flutter app it reported 187 functions, median 98 lines — all genuinely long, none of them a bug. Override the budget when your project needs a different limit.

A test main() legitimately runs to hundreds of lines, since every test(...) is one more statement in the same body. Scope the rule rather than raising the budget for everything:

rules:
avoid_long_functions:
exclude:
- test/**

The examples below use a small budget so the difference fits on a page. The default is 50.

With max_lines: 10, this body is 16 lines, and it validates, prices, persists and notifies in one scope:

void handleOrder(Order order) {
if (order.lines.isEmpty) {
throw ArgumentError.value(order, 'order', 'has no lines');
}
if (order.customerId.isEmpty) {
throw ArgumentError.value(order, 'order', 'has no customer');
}
var total = 0;
for (final line in order.lines) {
total += line.unitPrice * line.quantity;
}
order.total = total - order.discount;
orders[order.id] = order;
outbox.add('order-placed:${order.id}');
outbox.add('invoice-due:${order.id}');
}

Each step is named, and each can be read and tested on its own:

void handleOrder(Order order) {
_validate(order);
order.total = _priceOf(order);
_persist(order);
_notify(order);
}
void _validate(Order order) {
if (order.lines.isEmpty) {
throw ArgumentError.value(order, 'order', 'has no lines');
}
if (order.customerId.isEmpty) {
throw ArgumentError.value(order, 'order', 'has no customer');
}
}
int _priceOf(Order order) {
var total = 0;
for (final line in order.lines) {
total += line.unitPrice * line.quantity;
}
return total - order.discount;
}
void _persist(Order order) => orders[order.id] = order;
void _notify(Order order) {
outbox.add('order-placed:${order.id}');
outbox.add('invoice-due:${order.id}');
}

This rule is in the pedantic preset, so it is enabled by preset: pedantic or by name:

many_lints.yaml
rules:
avoid_long_functions:
enabled: true
analysis_options.yaml
many_lints:
rules:
avoid_long_functions:
max_lines: 80
Option Type Default Description
max_lines int 50 The longest body allowed, counted between the braces

To disable this rule:

many_lints.yaml
rules:
avoid_long_functions: false

To keep the rule on but skip certain paths, use per-rule exclude.