Have No Side Effects
Clean Code introduces side effects in a somewhat casual terms:
To make it more formal: a side effect is any operation that:
- Modifies state outside the function's scope
- Interacts with the external world (I/O, network, database)
- Relies on non-deterministic behavior (e.g., random number generation, system clock)
- Throws exception (which can alter the program's control flow in unexpected ways)
Pure functions—those without side effects—are easier to reason about, test, and reuse. They work like black boxes: given the same inputs, they always produce the same outputs, with no hidden dependencies or interactions.
However, the example provided in Clean Code is somewhat incomplete and misses critical aspects.
public class UserValidator {
private Cryptographer cryptographer;
public boolean checkPassword(String userName, String password) {
User user = UserGateway.findByName(userName);
if (user != User.NULL) {
String codedPhrase = user.getPhraseEncodedByPassword();
String phrase = cryptographer.decrypt(codedPhrase, password);
if ("Valid Password".equals(phrase)) {
Session.initialize();
return true;
}
}
return false;
}
}
"The side effect is the call to Session.initialize(), of course. The checkPassword function, by its name, says that it checks the password."
He implies that renaming function would get rid of side-effects: "we might rename the function checkPasswordAndInitializeSession, though that certainly violates 'Do one thing'"
This analysis misses several critical issues:
UserGateway.findByName(userName)
- From the name this looks like a remote call to some-kind of storage, which is also a side-effect. And it also creates temporal coupling: the checkPassword would fail if there is no connection to the UserGateway.UserGateway
is a singleton - i.e. it is a global implicit dependency.
A more formal understanding of side effects helps spot issues more easily.
This also makes it obvious that moving input arguments to object fields, especially when function has to mutate them to keep intermediate state, is incompatible with idea of side-effect free.
In rewrite suggestion from chapter 2, all new methods have a side effect - they mutate fields - Modify "state outside the function's scope":
private void printGuessStatistics(char candidate,
int count) {
String number;
String verb;
String pluralModifier;
if (count == 0) {
number = "no";
verb = "are";
pluralModifier = "s";
} else if (count == 1) {
number = "1";
verb = "is";
pluralModifier = "";
} else {
number = Integer.toString(count);
verb = "are";
pluralModifier = "s";
}
String guessMessage = String.format(
"There %s %s %s%s", verb, number,
candidate, pluralModifier
);
►print(guessMessage);Interracts with the outside world - prints to STD-IO
}
public class GuessStatisticsMessage {
private String number;
private String verb;
private String pluralModifier;
public String make(char candidate, int count) {
►createPluralDependentMessageParts(count);Calling a function with side effects spreads those effects to the caller
return String.format(
"There %s %s %s%s",
verb, number, candidate, pluralModifier );
}
private void createPluralDependentMessageParts(int count) {
if (count == 0) {
►thereAreNoLetters();Calling a function with side effects spreads those effects to the caller
} else if (count == 1) {
►thereIsOneLetter();Calling a function with side effects spreads those effects to the caller
} else {
►thereAreManyLetters();Calling a function with side effects spreads those effects to the caller
}
}
private void thereAreManyLetters(int count) {
►number = Integer.toString(count);Modifies state outside function scope
►verb = "are";Modifies state outside function scope
►pluralModifier = "s";Modifies state outside function scope
}
private void thereIsOneLetter() {
►number = "1";Modifies state outside function scope
►verb = "is";Modifies state outside function scope
►pluralModifier = "";Modifies state outside function scope
}
private void thereAreNoLetters() {
►number = "no";Modifies state outside function scope
►verb = "are";Modifies state outside function scope
►pluralModifier = "s";Modifies state outside function scope
}
}