Good Code
The good version treats missing users as part of the contract. The repository returns an Optional, the service checks its input, and the failure path is named.
Lesson 01
Make absence explicit at method boundaries with Optional or exceptions, instead of returning null from finder code.
public final class UserService {
private final UserRepository users;
public UserService(UserRepository users) {
this.users = Objects.requireNonNull(users);
}
public UserProfile profileFor(UserId id) {
Objects.requireNonNull(id, "id");
User user = users.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
return UserProfile.from(user);
}
}public class UserService {
private UserRepository users;
public UserProfile profileFor(String id) {
User user = users.findById(id);
return new UserProfile(user.name(), user.email());
}
}The good version treats missing users as part of the contract. The repository returns an Optional, the service checks its input, and the failure path is named.
The bad version lets null travel through the application. Reviewers have to infer whether findById can miss, and the actual error appears later as a less helpful NullPointerException.