Stop Passing Everything: What Large Parameter Lists Are Trying to Tell You
Large parameter lists are a symptom, not the disease. Here we refactor data and behavior into explicit domain concepts that are easier to understand, evolve, and verify.
The main problem with many function arguments isn’t the number of arguments per se. Rather, it’s why a method needs all those arguments. As is usually the case, the problem is that it does too many things.
Consider this example:
public String sendShipmentNotice(
Shipment shipment,
AlertChannel alertChannel,
String recipientEmail, // used by EMAIL branch
String recipientPhone, // used by SMS branch
String webhookUrl, // used by WEBHOOK branch
String webhookToken // also WEBHOOK branch
) {
// shared context used by all branches:
String shipmentReference =
shipment.shipmentId() + "@" + shipment.warehouse();
String urgency = urgencyBand(
shipment.etaMinutes(),
shipment.delayedStops()
);
if (alertChannel == AlertChannel.EMAIL) {
return "EMAIL to " + recipientEmail
+ " | shipment=" + shipmentReference
+ " | eta_min=" + shipment.etaMinutes()
+ " | urgency=" + urgency;
}
if (alertChannel == AlertChannel.SMS) {
return "SMS to " + recipientPhone
+ " | shipment=" + shipmentReference
+ " | eta_min=" + shipment.etaMinutes()
+ " | urgency=" + urgency;
}
return "WEBHOOK " + webhookUrl
+ " | token=" + redact(webhookToken)
+ " | payload={shipment:" + shipmentReference
+ ",eta_min:" + shipment.etaMinutes()
+ ",urgency:" + urgency + "}";
}The code above is intentionally short. I don’t want to bother you with hundreds of lines that you won’t read anyway. But that’s how this problem would typically manifest in a real codebase.
The code has multiple issues:
Control coupling — where the caller controls the internal execution flow of this method — makes the code hard to mentally parse. You have several independent paths through the code that have to be pieced together during reasoning.
The caller is also forced to supply a bag of parameters that only make sense for some branches.
Adding insult to agentic injury: most of those parameters are strings.
Design smells combine
These design smells combine, and the resulting damage is obvious in the calling client code. With the last four arguments being String values, we could mistakenly swap them, and the code would compile just as happily.
Such bugs are subtle because nothing looks obviously broken. Also, type safety is an important safeguard for agents. The preceding code undermines that benefit, and any future edit can mix up same-typed values.


