methods with too many parameters

R

Roedy Green

Let us say you invent a generic method to create the header on a
webpage. Let's say it has a whacking huge number of parameters.

Now along comes a new heading that needs a wrinkle, one extra parm
passed. You could create a new method with N+1 parms, and have the old
N-parm method call it with a default.

Let's say this process continues. You end up with mess, and no way of
keeping track of what parameter is what.

So instead you do a textual search an replace of all calls in the
universe to add a default parameter to a N+1 parm method.

Now the calls get pretty ugly, lots of null, false, "". So when you
come to maintain them, you can't tell which parm is which.

How might such a problem be tackled? I had five ideas:

1. with keyword parameters. They can go in any order. Ones left out
get as standard default. The problem with that is, it requires a
major addition to Java syntax, and you can't proofread. You may
inadvertently leave out a crucial keyword, and you won't notice.
Further you code will get out of canonical order making it harder to
read and compare.

2. With an SCID/IDE that inserts temporary comments between positional
parameters to identify them. You can further click to see the full
javadoc on a parm.

3. With an SCID/IDE that has hoverhelp for a positional parameter.

4. With a SCID/IDE with a gather feature. It temporarily pulls
together all method calls in the universe into one page. You can then
more easily cross-compare them. It is like a lot of tiny scrolling
windows so you can see each call in context. The calls are labelled
with the class/method where they came from.

5. You do the call with a number of aux set up calls then a master
call. The master call would contain all the mandatory parms, and the
aux calls would be for various groups of related optional parms. This
is like a poor-man's keyword scheme.

What do you think? Any other approaches?
 
A

Andrew McDonagh

Roedy said:
Let us say you invent a generic method to create the header on a
webpage. Let's say it has a whacking huge number of parameters.

Now along comes a new heading that needs a wrinkle, one extra parm
passed. You could create a new method with N+1 parms, and have the old
N-parm method call it with a default.

snipped

What do you think? Any other approaches?

sounds like a normal case of unrefactored code...

So, the only valid approach to this messy code is to change your design,
not the language or IDEs.
 
S

Stefan Schulz

Roedy said:
Let us say you invent a generic method to create the header on a
webpage. Let's say it has a whacking huge number of parameters.

Now along comes a new heading that needs a wrinkle, one extra parm
passed. You could create a new method with N+1 parms, and have the old
N-parm method call it with a default.

Let's say this process continues. You end up with mess, and no way of
keeping track of what parameter is what.

So instead you do a textual search an replace of all calls in the
universe to add a default parameter to a N+1 parm method.

Now the calls get pretty ugly, lots of null, false, "". So when you
come to maintain them, you can't tell which parm is which.

How might such a problem be tackled? I had five ideas:

[5 Ideas]

None of the above. If the number of parameters gets overwhelming,
clearly it is time to throw them together and build a new class which
encapsulates them all, neatly grouping them together.

This has the added benefit of not adding two-thousand overloaded
versions of the method, of allowing defaults on all parameters, and not
just the ones added later, and generally improve both clarity and
readability.
 
S

Stefan Ram

Roedy Green said:
5. You do the call with a number of aux set up calls then a master
call. The master call would contain all the mandatory parms, and the
aux calls would be for various groups of related optional parms. This
is like a poor-man's keyword scheme.

operation.setParameterA( 2 ).setParameterB( 3 ).execute();

or

OperationAParameterRecord record =
new OperationAParameterRecordVersion2();
record.setA( 2 );
record.setB( 3 );
object.operationA( record );
 
S

Suresh

message
[snip]
What do you think? Any other approaches?

pass the parameters as a property object. This way you could also have
default values for missing parameters.
 
T

Thomas Hawtin

Roedy said:
Let us say you invent a generic method to create the header on a
webpage. Let's say it has a whacking huge number of parameters.

Now along comes a new heading that needs a wrinkle, one extra parm
passed. You could create a new method with N+1 parms, and have the old
N-parm method call it with a default.

Let's say this process continues. You end up with mess, and no way of
keeping track of what parameter is what.
[...]
1. with keyword parameters. They can go in any order. Ones left out
get as standard default. The problem with that is, it requires a
major addition to Java syntax, and you can't proofread. You may
inadvertently leave out a crucial keyword, and you won't notice.
Further you code will get out of canonical order making it harder to
read and compare.

The Java event system uses a single arguments object to represent as
many arguments as necessary. This works best for upcalls. The object
still needs to be created.

Builders, like java.lang.ProcessBuilder, have a similar result to
keyword parameters, but are more flexible.

http://download.java.net/jdk6/docs/api/java/lang/ProcessBuilder.html

Fluent interfaces, like Packer, give a slightly different spin to
builders. You call the function you want and then call a series of
methods to alter attributes for it.

http://martinfowler.com/bliki/FluentInterface.html
https://packer.dev.java.net/

You can give long argument list better type safety and readability by
defining simple specialist types rather than using general types. I
think the main problem here is the psychological impact of the keyword new.

Tom Hawtin
 
E

Eric Sosman

Roedy Green wrote On 01/02/06 11:51,:
Let us say you invent a generic method to create the header on a
webpage. Let's say it has a whacking huge number of parameters.

Now along comes a new heading that needs a wrinkle, one extra parm
passed. You could create a new method with N+1 parms, and have the old
N-parm method call it with a default.

Let's say this process continues. You end up with mess, and no way of
keeping track of what parameter is what.
[...]

PageParams p = new PageParams(); // all values defaulted
p.setFiddle(true);
p.setDiddle(42.0);
p.setGriddle("cast iron");
// ...
webPage.createHeader(p);
 
M

Mandar Amdekar

At a high-level, there are only a few reasonable options:
1. Varargs
2. Map (where keys indicate what named parameter you're talking about)
3. Encapsulation
 
R

Roedy Green

sounds like a normal case of unrefactored code...

So, the only valid approach to this messy code is to change your design,
not the language or IDEs.

What is the way you would correct the problem?
 
R

Roedy Green

PageParams p = new PageParams(); // all values defaulted
p.setFiddle(true);
p.setDiddle(42.0);
p.setGriddle("cast iron");
// ...
webPage.createHeader(p);

This pattern could also be used like this
new webPage( p );

The nice thing then is no half formed webPage objects ever get out in
to the world, even if half formed PageParams do. Is this what is
called a "Builder" pattern?

You can create a validate method that checks that everything is
compatible, or that adjusts the defaults based on the data provided.
This logic then is nicely separated from the logic that actually does
something with all this information.


I think that is the best solution I have seen yet.
 
A

Andrew McDonagh

Roedy said:
What is the way you would correct the problem?

An OO approach.

Thomas & Eric have already posted suitable approaches that I would have
taken, so no need for me to repost.


One thing they didn't mention, is that any method needing to accept a
large number of parameters is highly likely to be doing to much. And
these methods tend to be on classes that are also doing to much.

Using the following design principles (all google-able), will naturally
create a design that does not suffer from your code's condition:

Single Responsibility Principle
Dependency Inversion
Dependency Injection
Open Closed Principle.
Interface Segregation Principle

....to name but a few.

Andrew
 
J

Juhan Kundla

Hei!

Let us say you invent a generic method to create the header on a
webpage. Let's say it has a whacking huge number of parameters.

Now along comes a new heading that needs a wrinkle, one extra parm
passed. You could create a new method with N+1 parms, and have the old
N-parm method call it with a default.

Let's say this process continues. You end up with mess, and no way of
keeping track of what parameter is what.

So instead you do a textual search an replace of all calls in the
universe to add a default parameter to a N+1 parm method.

Now the calls get pretty ugly, lots of null, false, "". So when you
come to maintain them, you can't tell which parm is which.

How might such a problem be tackled? I had five ideas:
[...]

What do you think? Any other approaches?

I would refactor the classes having methods with lots of parameters. In
your example, i think, there is already the solution to your problem. You
only need to implement classes for the nouns in your example and perhaps
use the Builder pattern.

You create WebPage class, which has Header as a property. Header is
probably composed of a List of different Headings.

Header myHeader = new HeaderBuilder()
.addHeading(new HeadingWithWrinkle("foo"))
.addHeading(new NormalHeading("bar"))
// Etc
.create();

WebPage myPage = new WebPage(myHeader);


Juhan
 
A

Andrew McDonagh

Juhan said:
Hei!
snipped



I would refactor the classes having methods with lots of parameters. In
your example, i think, there is already the solution to your problem. You
only need to implement classes for the nouns in your example and perhaps
use the Builder pattern.

You create WebPage class, which has Header as a property. Header is
probably composed of a List of different Headings.

Header myHeader = new HeaderBuilder()
.addHeading(new HeadingWithWrinkle("foo"))
.addHeading(new NormalHeading("bar"))
// Etc
.create();

WebPage myPage = new WebPage(myHeader);


Juhan

I'm curious as to why do you feel there is a difference between a
webpage 'header' and any other part of a web page?

A more likely design I would use would be along the lines of the
composite pattern - seeing as a web page is just a tree of markup
language constructs.
 
J

Juhan Kundla

Andrew said:
I'm curious as to why do you feel there is a difference between a
webpage 'header' and any other part of a web page?

After re-reading everything, i think, that this was probably because
the English is not my native language. I was somehow thinking that the
Header is the HTTP header and the WebPage has such Header and also the
HTML part.
A more likely design I would use would be along the lines of the
composite pattern - seeing as a web page is just a tree of markup
language constructs.

Absolutely!


Juhan
 
R

Roedy Green

I'm curious as to why do you feel there is a difference between a
webpage 'header' and any other part of a web page?

I don't generate the whole page, because I use macros embedded in the
HTML to generate headers footers etc. Each macro is written in Java.
Prior to uploading, I refresh the macro expansions, compact the files,
and untouch to undo false deltas.

This way, I don't need any code on my server but a vanilla HTTP
server. Yet I manage to pull off all sorts of things very similar to
what you can do with JSP. My scheme is less flexible, but faster
since all pages are pre-generated.

If you view source on any of my web pages you can see the embedded
macros. I leave the unexpanded macro in place as a comment.
 
N

Noodles Jefferson

Roedy Green said:
Let us say you invent a generic method to create the header on a
webpage. Let's say it has a whacking huge number of parameters.

Now along comes a new heading that needs a wrinkle, one extra parm
passed. You could create a new method with N+1 parms, and have the old
N-parm method call it with a default.

Overload the method.

public void aMethod(String something) {

}

public void aMethod(String something, String somethingElse) {

}

Then you don't even have to worry about it. The arguments you feed it
will determine which version of the method you use.

aMethod(Roedy); // use the one with one string arg
aMethod(Roedy, Green); // use the one with two string args.

But you can't do that forever if you're piling on the params though.
You'll just overload yourself into oblivion then.
Let's say this process continues. You end up with mess, and no way of
keeping track of what parameter is what.

So instead you do a textual search an replace of all calls in the
universe to add a default parameter to a N+1 parm method.

Now the calls get pretty ugly, lots of null, false, "". So when you
come to maintain them, you can't tell which parm is which.

How might such a problem be tackled? I had five ideas:

1. with keyword parameters. They can go in any order. Ones left out
get as standard default. The problem with that is, it requires a
major addition to Java syntax, and you can't proofread. You may
inadvertently leave out a crucial keyword, and you won't notice.
Further you code will get out of canonical order making it harder to
read and compare.

2. With an SCID/IDE that inserts temporary comments between positional
parameters to identify them. You can further click to see the full
javadoc on a parm.

3. With an SCID/IDE that has hoverhelp for a positional parameter.

4. With a SCID/IDE with a gather feature. It temporarily pulls
together all method calls in the universe into one page. You can then
more easily cross-compare them. It is like a lot of tiny scrolling
windows so you can see each call in context. The calls are labelled
with the class/method where they came from.

5. You do the call with a number of aux set up calls then a master
call. The master call would contain all the mandatory parms, and the
aux calls would be for various groups of related optional parms. This
is like a poor-man's keyword scheme.

What do you think? Any other approaches?

--
Noodles Jefferson
mhm31x9 Smeeter#29 WSD#30
sTaRShInE_mOOnBeAm aT HoTmAil dOt CoM

NP: "The Road to Chicago" -- Thomas Newman (Road to Perdition
Soundtrack)

"Our earth is degenerate in these latter days, bribery and corruption
are common, children no longer obey their parents and the end of the
world is evidently approaching."
--Assyrian clay tablet 2800 B.C.
 
N

Noodles Jefferson

Noodles Jefferson said:
Overload the method.

public void aMethod(String something) {

}

public void aMethod(String something, String somethingElse) {

}

Then you don't even have to worry about it. The arguments you feed it
will determine which version of the method you use.

aMethod("Roedy"); // use the one with one string arg
aMethod("Roedy", "Green"); // use the one with two string args.
fixed


But you can't do that forever if you're piling on the params though.
You'll just overload yourself into oblivion then.

--
Noodles Jefferson
mhm31x9 Smeeter#29 WSD#30
sTaRShInE_mOOnBeAm aT HoTmAil dOt CoM

NP: "The Road to Chicago" -- Thomas Newman (Road to Perdition
Soundtrack)

"Our earth is degenerate in these latter days, bribery and corruption
are common, children no longer obey their parents and the end of the
world is evidently approaching."
--Assyrian clay tablet 2800 B.C.
 
C

Chris Smith

Stefan Schulz said:
None of the above. If the number of parameters gets overwhelming,
clearly it is time to throw them together and build a new class which
encapsulates them all, neatly grouping them together.

I'll be picky. "All" is misplaced there. You should group parameters
that are pieces of state belonging to the same conceptual object. You
may end up with a couple different objects, or an object and two ints,
or whatever. In any case, it's very likely that you have seventeen
parameters that are all peers and none of which belong in the same
object together.

This is the problem with the currently-fashionable mechanical
implementation of design "patterns" like the argument object. Someone
who applies "argument object" without thinking too much about it misses
the opportunity for better abstractions.

--
www.designacourse.com
The Easiest Way To Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top