The Hidden Complexity
One cannot seriously talk about Clean Code without considering the clean handling of error situations. Error handling represents a separate responsibility that should be separated from business code. The goal remains, as with all Clean Code principles, clear separation: Domain code should be recognizable at first glance, without being overlaid by try-catch blocks or if conditions for checking error codes.
The Foundation of Good Error Handling
Try-catch-finally was a first important step toward separation of concerns: The try block contains the business "happy path," while the catch block handles the exception. When defining our own exceptions, we should observe these principles:
Prefer unchecked exceptions: They avoid boilerplate code and lead to clearer interfaces
Technical vs. business exceptions: Clearly distinguish between technical errors and business exceptions
Provide context information: Exceptions should contain meaningful information about the error context
Exception design from client perspective: Design exceptions as needed by users of your API
Among common programming languages, Java is practically the only one that knows checked exceptions – a concept now considered problematic and doesn't need further elaboration here.
Avoiding Null Values
Two more essential aspects of Clean Code error handling:
Don't return null values: They force the caller to perform additional checks
Don't accept null values as method arguments: They make the behavior of methods unpredictable
These rules may seem trivial, but with increasing experience, one recognizes their importance – in line with Jeff Atwood's well-known maxims "Code is a liability, not an asset" and "the best code is no code at all." Why are null values problematic as method arguments? They require the reader of the code to understand and consider the method's behavior in this special case.
Object-Oriented Solution Approaches
In an object-oriented programming language, many error handling scenarios can be elegantly solved or even avoided. The Special Case Pattern and the Null Object Pattern offer clean alternatives here.
Structured Error Handling
The Compose Method Pattern is excellent for structured error handling. My typical approach looks like this. Incidentally, this method also works excellently in languages without an exception concept such as Go.