Skip to content

Instantly share code, notes, and snippets.

@MatusMak
Created December 2, 2019 13:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MatusMak/a7d0f350beed9cc433d6d10a2a837fed to your computer and use it in GitHub Desktop.
Save MatusMak/a7d0f350beed9cc433d6d10a2a837fed to your computer and use it in GitHub Desktop.
Utilizing functional principles to make simple things such as logging more enjoyable

Recently, I came across a scenario where I had to log a list of entries whenever that list was not empty. Basically, I was removing invalid data that I have received from outside and I wanted to warn about this in a case users would complain they are missing these entries.

Anyway, I had to do an equivalent of this several times in a row:

if (anyCondition) {
    logger.warn("Hey, something is not okay!");
}

It works, but it bothers me a little bit that I am wasting so much space. You can argue that I could have write it as a oneliner - if (anyCondition) logger.warn("Hey, something is not okay!);, but this kind of formatting makes me super angry and I have learned by experience that expanding it with explicit block brackets is the way to go.

Then I realized - there is still hope for making this oneliner! What if designers of logger interface borrowed some ideas from functional style of programming and using method chaining created fluent API? Our snippet from above would probably turn into something similar:

logger.when(anyCondition).warn("Hey, something is not okay!");

The idea behind this is very simple. Method when will return the same logger instance if the condition is true, otherwise it will return a dead logger that only consumes calls but does nothing - null object. Here is a reference implementation:

public interface Logger {
    
    Logger when(boolean condition);
    
    void warn(String message);
}

public class ActiveLogger implements Logger {

    private static final Logger INACTIVE_LOGGER = new InactiveLogger();

    @Override
    public Logger when(boolean condition) {
        return condition ? this : INACTIVE_LOGGER;
    }
    
    @Override
    public void warn(String message) {
        System.out.println(message);
    }
    
    private static class InactiveLogger implements Logger {
        
        @Override
        public Logger when(boolean condition) {
            return this;
        }
        
        @Override
        public void warn(String message) {
            // Don't do anything, just consume the call
        }
    }
}

One additional benefit this brings is that we can chain conditions as we please. Say, for example, I would be required to log my invalid entries only if user enables such a thing somewhere in parameters. This is how it would look like in comparison to the current approach:

// Using `when`
logger.when(loggingEnabled).when(anyCondition).warn("Hey, something is not okay!");

// Using `if`
if (loggingEnabled && anyCondition) {
    logger.warn("Hey, something is not okay!");
}

// How it would actually look like (because we have multiple entities)
if (loggingEnabled) {
    if (anyCondition) {
        logger.warn("Hey, something is not okay!");
    }

    // more logging
}

In real life, I would probably advise to use only up to two or three conditions. If you need more to log a simple message, chances are you are doing something wrong.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment