tiny methods
If you had this:
public void attemptRegistration(User user) {
if (UserTable.count() >= 1000) {
preventRegistration(user);
} else {
continueRegistration(user);
}
}
Would putting the body of that if-statement into its own method be a worthwhile refactor?
public void attemptRegistration(User user) {
if (atMax()) {
preventRegistration(user);
} else {
continueRegistration(user);
}
}
private boolean atMax() {
return UserTable.count() >= 1000;
}
What if that condition was more complex? Now is it worth it?
public void attemptRegistration(User user) {
if (atMax() || registrationClosed()) {
preventRegistration(user);
} else {
continueRegistration(user);
}
}
private boolean atMax() {
return UserTable.count() >= 1000;
}
private boolean registrationClosed() {
return Registrar.isClosed();
}
How about combining those two private methods?
public void attemptRegistration(User user) {
if (shouldPreventRegistration()) {
preventRegistration(user);
} else {
continueRegistration(user);
}
}
private boolean shouldPreventRegistration() {
return UserTable.count() >= 1000 || Registrar.isClosed();
}
Or breaking it down even further?
public void attemptRegistration(User user) {
if (shouldPreventRegistration()) {
preventRegistration(user);
} else {
continueRegistration(user);
}
}
private boolean shouldPreventRegistration() {
return atMax() || registrationClosed();
}
private boolean atMax() {
return UserTable.count() >= 1000;
}
private boolean registrationClosed() {
return Registrar.isClosed();
}
What if I told you these private methods are only ever used in
attemptRegistration(User)
?
Does the language being used change what you think?
def attempt_registration(user)
if prevent_registration?
prevent_registration(user)
else
continue_registration(user)
end
end
def prevent_registration?
at_max? || registration_closed?
end
def at_max?
UserTable.count >= 1000
end
def registration_closed?
Registrar.closed?
end
After all, it could’ve been written in much fewer lines:
def attempt_registration(user)
if UserTable.count >= 1000 || Registrar.closed?
prevent_registration(user)
else
continue_registration(user)
end
end
At least we can all agree on naming that magic number:
MAX_USER_COUNT = 1000
…Maybe.
I’ve committed to or abstained from all of these refactorings at points in my career, and I’ve received pushback for all such cases.
I’ve settled on what I like best though: I like tiny methods. I love
tiny methods. I think of their names as terse, compiler-enforced
documentation of what’s happening. They also introduce a level of
indirection that gives a single point to refactor if something
changes. Like imagine if prevent_registration?
actually had to be this:
def prevent_registration?(user)
at_max? || registration_closed? || blacklisted?(user)
end
Now I just look for occurrences of prevent_registration?
instead of
at_max? || registration_closed?
. Well, hopefully no one used
registration_closed? || at_max?
. Even if I was in a sane (statically typed)
language I wouldn’t get the benefit of the IDE’s refactoring tools,
unless it was smart enough to let me specify I’m looking for these two
predicates as arguments to a ||
…
ugh() // ...Whatever, I'll just keep putting my comments on the same line as what they're about on so you'll criticize that instead of my tiny methods >:)