Out of these two which is the best to use? Is it better to pass in the whole application object, or pass in only which is needed for the utility method? Please explain why.?
According to Clean Code (Uncle Bob). It's obvious, a function with two or more arguments is harder to understand than a one argument function.
For example, writeField(name)
is easier to understand than writeField(output-Stream, name)
.
The ideal number of arguments for a function is
zero (niladic). Next comes one (monadic), followed
closely by two (dyadic). Three arguments (triadic)
should be avoided where possible. More than three
(polyadic) requires very special justification—and
then shouldn’t be used anyway.
Common Monadic Form: There are two very common reasons to pass a single argument into a function. You may be
asking a question about that argument, as in boolean fileExists(“MyFile”)
. Or you may be
operating on that argument, transforming it into something else and returning it. For
example, InputStream fileOpen(“MyFile”)
transforms a file name String into an
InputStream
return value. These two uses are what readers expect when they see a function.
Dyadic Functions: A function with two arguments is harder to understand than a monadic function. For example, writeField(name)
is easier to understand than writeField(output-Stream, name)
.
Though the meaning of both is clear, the first glides past the eye, easily depositing its
meaning. The second requires a short pause until we learn to ignore the first parameter.
And that, of course, eventually results in problems because we should never ignore any
part of code. The parts we ignore are where the bugs will hide.
There are times, of course, where two arguments are appropriate. For example,
Point p = new Point(0,0);
is perfectly reasonable. Cartesian points naturally take two
arguments. Indeed, we’d be very surprised to see new Point(0)
. However, the two arguments in this case are ordered components of a single value!Whereas output-Stream
and
name
have neither a natural cohesion, nor a natural ordering.
Triads: Functions that take three arguments are significantly harder to understand than dyads. The
issues of ordering, pausing, and ignoring are more than doubled. I suggest you think very
carefully before creating a triad.
For example, consider the common overload of assertEquals
that takes three arguments:assertEquals(message, expected, actual)
. How many times have you read the
message
and thought it was the expected
? I have stumbled and paused over that particular
triad many times. In fact, every time I see it,I do a double-take and then learn to ignore the
message.
Arguments Object (you asked for this): When a function seems to need more than two or three arguments, it is likely that some of
those arguments ought to be wrapped into a class of their own. Consider, for example, the
difference between the two following declarations:
Circle makeCircle(double x, double y, double radius);
Circle makeCircle(Point center, double radius);
Reducing the number of arguments by creating objects out of them may seem like
cheating, but it’s not. When groups of variables are passed together, the way x
and
y
are in the example above, they are likely part of a concept that deserves a name of its
own.
Argumen Lists: Sometimes we want to pass a variable number of arguments into a function. Consider, for
example, the String.format
method:
String.format("%s worked %.2f hours.", name, hours);
If the variable arguments are all treated identically, as they are in the example above, then
they are equivalent to a single argument of type List. By that reasoning, String.format
is
actually dyadic. Indeed, the declaration of String.format
as shown below is clearly
dyadic.
public String format(String format, Object... args)
So all the same rules apply. Functions that take variable arguments can be monads,
dyads, or even triads. But it would be a mistake to give them more arguments than
that.
void monad(Integer... args);
void dyad(String name, Integer... args);
void triad(String name, int count, Integer... args);
In short, every system is built from a domain-specific language designed by the programmers to
describe that system. Functions are the verbs of that language, and classes are the nouns.
If you follow the rules here in, your functions will be good and nicely organized.
But never forget that your real goal is to tell the story of the system, and that the functions
you write need to fit cleanly together into a clear and precise language to help you with
that telling.
If I have a chance to modify your code, I will modify as below:
//it's already fine:
public printUsernameAndGroup(String username, String group){
sout(username);
sout(group);
}
//I changed printUsernameAndGroup to printUserInformation and Application to User for more readable
public printUserInformation(User user){
sout(user.username);
sout(user.group);
}
But it's just my suggestions as to your current code. For the whole projects design and methods, it's up to you and I hope you got what you really needed to know in here.