A large fraction of the flaws in software development are due to programmers not fully understanding all the possible states their code may execute in.
- John Carmack, In Depth: Functional Programming in C++
As apps get more complex, there's more states in disparate parts
Requiring more effort to understand
Or more opportunities for error
Building an API Client
Pass credentials to API Client methods
public interface MetadataClient {
public CoreType getCoreType(long id, Credentials credentials);
public Analysis getAnalysis(long id, Credentials credentials);
...
}
We make many requests for the same job (same credentials)
Pain to pass around creds or recreate
Prevents developers from using the client as much as we'd like
Just set the credentials at the start
// at start of message processing
metadataClient.setCredentials();
// ... do work
metadataClient.clearCredentials();
Started using our metadata client in other contexts
Always forgot to set credentials
Subtle assumptions led to brittle classes
State is useful...
but needs to be obvious
indicate the state with a type
Java's declarative static typing will always remind us
public class AuthenticatedClient {
private final MetadataClient client;
private final Credentials credentials;
public AuthenticatedClient(MetadataClient client,
Credentials credentials) {
this.client = client;
this.credentials = credentials;
}
public Analysis getAnalysis(long id) {
return this.client.getAnalysis(id, this.credentials);
}
...
}
Obvious when client is authenticated or not
Prevents a whole class of errors
Even deeper than "Let the compiler catch it"