Gunnar's blog - Programming

Map in a Java Stream, What is it?

Working with streams often requires 'mapping' of objects. What is mapping, and why do people do it with streams?

Mapping is how to convert one type of object to another with a stream. Say you have a set of Fruit and you want to show people what is in your set. It would be helpful to have a list of fruit names to do so.

fruitList.stream().map(fruit -> fruit.getName()).collect(Collectors.asList);

That's pretty simple; you can imagine how to do that in real life with a basket of fruit.

Pick up a piece of fruit, write its name down. Pick up another piece of fruit, write its name down, etc.

Mapping also lets you you can't easily simulate in real life. Say you have a Fruit set and you want Oranges, instead of Apples (I think this is closer to transmutation than swapping, but it's a metaphor, ymmv).

You can do that, with Java:

fruitList.stream().map(fruit -> {
    if( fruit instanceof Apple){
        return new Orange();
    }
    return  fruit;
}).collect(Collectors.asSet);

Have fun out there, and map all the things!

Filter Null Value from a List with Java8 Lambda


A common task with Java streams is to clean up the input data so later steps can work without thinking too hard. Likely the #1 most common cleanup step is to remove nulls from a Collection.

Streams make it easy:

myCollection.stream()
  .filter(Objects::nonNull)
  .do.what.you.need

Compare with the classic approaches:

while(myCollection.remove(null));
// do what you need, but you better not need that original list, because it's gone...
myCollection.removeAll(Collections.singleton(null));
// do what you need, but you better not need that original list, because it's gone...

Like the stream approach, these are short and sweet, but unlike the stream approach they modify the original list. The first example is also pretty slow.

I like the stream approach because I can chain additional tasks after the filter task, including map. sorted, reduce and more!. I find the traditional imperative iterative approach to be not only wordier, but conceptually harder to follow.

Make an Immutable Object - in Java


Immutable objects are objects that don't change. You make them, then you can't change them. Instead, if you want to change an immutable object, you must clone it and change the clone while you are creating it.

A Java immutable object must have all its fields be internal, private final fields. It must not implement any setters. It needs a constructor that takes a value for every single field.

Immutable objects come in handy in multi-threaded environments and in streams. It is great to rely on objects not changing mid-stream. Bugs caused by a thread changing another thread's object are often subtle and are very, very hard to track down. Immutable objects stop these whole class of problems in their tracks.

You don't have to take my word for it - see what experts around the web say.

Contents

  1. Making an Immutable Object
  2. Common gotchas
    1. Primitives
    2. Collections
    3. Arrays
    4. Objects
  3. How to Change an Immutable Object
    1. Where to put Builders?
  4. Handling Bad Data in Immutable Objects
  5. Wrapup

Gotchas!

a lonely tree on a rock

Lists, arrays, maps, sets and other non-immutable objects can be surprising. A private final object with no setter is fixed to the object it was initially assigned, but the values inside that object aren't fixed (unless the object is immutable).

That means you might have an ImmutableShoppingList myShoppingList = new ImmutableShoppingList(new String[] {"apples","anchovies","pasta"}) and expect that the shopping list will always have "apples", "anchovies" and "pasta".

Someone could call myShoppingList.getList()[0] = "candy bars"; and change your list to be "candy bars", "anchovies" and "pasta", which is unhealthy and clearly not what you want.

Primitives

Good news! Primitives are immutable, so you don't have to do anything special.

Collections

Good news! java.util.Collections provides a number of convenience methods that make converting a Collection to an UnmodifiableCollection a snap.

Check out:

Collections.unmodifiableCollection
Collections.unmodifiableList
Collections.unmodifiableMap
Collections.unmodifiableNavigableMap
Collections.unmodifiableNavigableSet
Collections.unmodifiableSet
Collections.unmodifiableSortedMap
Collections.unmodifiableSortedSet

I suggest you store the fields as generic Collections (List, rather than ArrayList), and make the unmodifiable in the constructor, like so:

public class ImmutableShoppingList {

    private final List<String> list;

    public ImmutableShoppingList(List<String> list){
        this.list = Collections.unmodifiableList(list);
    }

    public List<String> getList(){
        return list;
    }
}

This allows you to use IDE code generation to make the getters, which is nice, and contains all the input modifiers in one place, which is also nice.

Bad news! If you hang onto the reference to the collection when you create the collection, you can still modify it, even if you store it as an unmodifiable collection internally. Here's an example:

List<String> originalList = new ArrayList<>();
theList.add("apple");
ImmutableShoppingList blah = new ImmutableShoppingList(originalList);
originalList.add("candy bar");

The supposedly immutable shopping list started with an apple, and had a candy bar added to it after creation. What can we do about this?

Clone the list!

public class ImmutableShoppingList {

    private final List<String> list;

    public ImmutableShoppingList(List<String> list){
        List<String> tmpListOfHolding = new ArrayList<>();
        tmpListOfHolding.addAll(list);
        this.list = Collections.unmodifiableList(tmpListOfHolding);
    }

    public String[] getList(){
        return (String[]) list.toArray();
    }
}

When we create the immutable object, we deep clone the collection, which severs the connection to the original reference. Now when we run the "sneak a candy bar in" example, "candy bar" gets added to originalList, but not the ImmutableShoppingList.

Arrays

Bad news! Java doesn't have any convenient methods to prevent arrays from being modified. Your best bet is to either hide the original array and always return a clone, or to not use arrays in the underlying implementation and instead convert a Collection object to an array.

I prefer to stick with Collections, but if you must have an array in your object's api, this is the approach I would take:

public class ImmutableShoppingList {

    private final List<String> list;

    public ImmutableShoppingList(String[] list){
        this.list = Collections.unmodifiableList(Arrays.asList(list));
    }

    public String[] getList(){
        return (String[]) list.toArray();
    }
}

Objects

Object fields can be easy. If the sub-objects are also immutable, good news! You don't have to do anything special.

If the sub-objects are not immutable, they are a lot like a collection. You need to deep clone them, or the original reference can change your supposedly immutable data out from under your feet.

Often, you end up working with pre-existing mutable objects, either in your codebase, or in libraries. In this case, I like to create an immutable object wrapper class that extends the mutable class. I find a static getInstance(MutableObject obj) method can be helpful, but a constructor ImmutableObject(MutableObject obj) is also a useful thing to have.

What About When I Want To Change An Immutable Object?

a woman having a good time in a shop

It happens to everyone. You need an an object, but you don't know everything about the object. You can't quite commit to an immutable object.

In this case, I reach for the builder pattern.

The builder pattern creates a temporary object with the same fields as the desired object. It has getters and setters for all the fields. It also has a build() method that creates the desired object

Imagine a small immutable object:

class ImmutableDog {
    private final String name;
    private final int weight

    public ImmutableDog(String name, int weight){
        this.name = name;
        this.weight = weight;
    }

    public String getName(){
        return this.name;
    }

    public int getWeight(){
        return this.weight;
    }
}

Here's what the builder would look like:

class ImmutableDogBuilder {
    private String name;
    private int weight;

    public ImmutableDogBuilder(){}

    public ImmutableDog build(){
        return new ImmutableDog(name, weight);
    }

    public ImmutableDogBuilder setName(String name){
        this.name = name;
        return this;
    }

    public ImmutableDogBuilder setWeight(int weight){
        this.weight = weight;
        return this;
    }

    public String getName(){
        return this.name;
    }

    public int getWeight(){
        return this.weight;
    }
}

Note the setters I really like this pattern of returning this on each setters in builder classes, because it creates a very fluent api. You could use this ImmutableDogBuilder like this:

ImmutableDogBuilder dogBuilder = new ImmutableDogBuilder().setName("Rover").setWeight(25);

You can imagine in classes with more fields that this compacts your code a lot.

Where To Put The Builder?

There are two schools of thought here.

On the one hand, you can create a separate class for the builder. This is easy, it is very conventional, and your IDE will probably group the classes together, because they probably have similar names.

On the other hand, you can embed the builder class in the immutable object class as a public static inner class.

I prefer to embed builder classes in immutable objects, because I view the builder as a helper for the immutable object, and not a standalone thing. It keeps them together and tightly coupled.

What About Immutable Objects With Bad Data?

a very dirty car

It happens to everybody, especially if you accept input. Bad data!

Bad data is no good, but immutable bad data seems especially wrong - you can't even fix it!

I use two approaches to prevent bad data from getting turned into immutable objects.

My primary approach is a suite of business rules that test for sane, permissible data. The business rules look at builders, and if the builder passes, I deem it ok to create the immutable object.

My secondary approach is to embed a small amount of business logic in the immutable object. I don't allow required fields to be null, and any nullable field is an Optional.

For example:

class ImmutableDog {
    private final String name;
    private final Optional<int> weight

    public ImmutableDog(String name, Optional<int> weight){
        Objects.requireNonNull(name);
        this.name = name;
        this.weight = weight;
    }

    public String getName(){
        return this.name;
    }

    public Optional<int> getWeight(){
        return this.weight;
    }
}

This is an ImmutableDog that requires a name, but does not require a weight. It's important to know what to call a dog, but it's not strictly necessary to know that Fluffy weighs 15 lbs.

Objects.requireNonNull will immediately throw a NullPointerException if a name is not provided. This prevents the creation of a nonsensical immutable object. It also allows users of the immutable object (such as streams or functions) to skip handling nulls. There are no nulls here.

Using Optional<int> makes consumers of ImmutableDog immediately aware that they may have to handle a null. Providing the Optional api gives downstream users an easy, functional way of handling nulls.

Wrapup

a colorful celebration

Immutable objects require some special care and handling, but their utility is worth it.

The main principles to keep in mind are:

  1. Clone arrays, Collections and Objects internal to your immutable object
  2. Use builders when you need a mutable object
  3. Use Optional to indicate nullable fields in your object's api
  4. Fail fast on bad data - Objects.requireNonNull can help

Go forth, and stop mutating

Host a React App with Dropwizard


drop of water

Dropwizard is a great Java framework for building RESTful applications. It helps you quickly set up a server with a RESTful api, and has lots of useful features right out of the box for making production-grade apps.

React is a great Javascript library for building webapps. Via create-react-app, React comes with excellent tools for running a development server and creating a production build. The create-react-app production build makes a directory full of static html and Javascript files. You could host these with Apache, or nginx, or any variety of webservers.

It is convenient to minimize the number of pieces of infrastructure an application requires, so hosting the static files with the api server is appealing. The standard way to host static files with Dropwizard is to include them in the jar, so they are accessible from the classpath. There is no way to externally host static assets out of the box.

Fortunately, some kind souls created the Dropwizard Configurable Asset Bundle which allows you to configure an external directory to be hosted at a uri by Dropwizard.

Setup

origami wizard's duel

I've created a skeletal Dropwizard echo server and a teeny-tiny React app to go with it. The Dropwizard server is a plain vanilla configuration except for the addition of this dependency in the pom.xml

<dependency>
    <groupId>io.dropwizard-bundles</groupId>
    <artifactId>dropwizard-configurable-assets-bundle</artifactId>
    <version>1.2.2</version>
</dependency>

and this addition in the app.yml

assets:
  mappings:
    /assets: /
  overrides:
    /: /teeny-tiny-react-app/build

and this change to the configuration class:

... extends Configuration implements AssetsBundleConfiguration {
...
@Override
public AssetsConfiguration getAssetsConfiguration() { return assets; }
...

and this addition to the app initialization:

bootstrap.addBundle(new ConfiguredAssetsBundle("/assets/", "/", "index.html"));

and finally, this addition to the app run command:

env.jersey().setUrlPattern("/api/*")

But What Does It Mean?

These configuration changes add the dropwizard-configurable-assets-bundle to your project, assign the /assets classpath to the / uri, and the / uri to the /teeny-tiny-react-app/build directory.

They also include a setting that makes Dropwizard look for index.html if nothing matches the incoming uri.

Finally, they host the Dropwizard resources at /api/*.

How Do I Use It?

bulldozer

This configuration allows for two usage modes - development and production.

In development mode, proceed as normal. Fire up Dropwizard java -jar muh-sweet-rest-api.jar server app.yml then move over to your React dev environment and start coding while running npm run start.

In production mode, fire up Dropwizard, and then do a React build npm run build. This will create a production-optimized build of your React app, which you can place where Dropwizard expects to find it.

You'll have two options to view your React app - the default localhost:3000 or Dropwizard-served localhost:8085

The default port is hosted by React's built in server and has all the auto-reloading goodies you are used to.

Dropwizard's port hosts a static build, so it doesn't auto-reload as you code. It will, however, automatically serve new code if you manually deploy it.

Why should I do this?

girl on slide

You should do this if: * You are already running a Java backend * You want to deploy React changes separately from Java changes * You have an ops team that will let you touch the war deploy location, but not the html deploy location (or vice-versa) * Messing with proxying is difficult (environment specific)

You should not do this if: * You want the frontend and the backend in lockstep * Proxying is easy * You already have one or two html servers * You don't want to use Java

Credits

Turn Your Spaghetti Code into Functions - Part 3


Start with Part 1 and Part 2 first.

Picking up where we left off in Part II, let's set the stage for using a validator. We left our example elephant in a cool convertible, but let's upgrade his ride to a rocket ship. We'll start like all good rocket scientists - with a round of cleaning!

elephant driving a space shuttle

After mise en place, we will be ready to implement a Validator and Result, which will create a single, standard, expandable format for business rules and an api for consuming results from business rule queries. No more guessing what a rule-compliant call looks like! No more stringing together crystal towers of nested boolean logic!

Cleanup

There are a couple places where we used .and() to combine predicates in an if block. Replace those with an independent predicate, so all if blocks refer to only one predicate

static final Predicate<WidgetTransfer> suffientAmount = trans -> trans.getTransferer().getAccount(trans.getFromAccount()).getBalance().compareTo(trans.getAmount()) < 0;
    static final Predicate<WidgetTransfer> isPartner = trans -> trans.getTransferTypeCode().equals("200");
    static final Predicate<WidgetTransfer> isFriendsAndFamily = trans -> trans.getTransferTypeCode().equals("710");
    static final Predicate<WidgetTransfer> isFriendAndFamilyDiscountLegal = trans -> trans.getAreaCode().matches("574|213|363|510");
    static final Predicate<WidgetTransfer> isPartneringArea = trans -> trans.getAreaCode().matches("907|412|213");
    static final Predicate<WidgetTransfer> isDirigibleForbiddenArea = trans -> trans.getAreaCode().matches("213");
    static final Predicate<WidgetTransfer> isDirigibleCategory = trans -> trans.getTransferer().getCategory().equals("D");
    static final Predicate<WidgetTransfer> isInternal = trans -> trans.getTypeCode().equals("I");
    static final Predicate<WidgetTransfer> isBlockSize = trans -> isBlockSize(trans);
    static final Predicate<WidgetTransfer> isTotalOverCap = trans -> isTotalOverCap(trans);

    static final Predicate<WidgetTransfer> parterTransferReqs = trans -> isPartner.and(isPartneringArea.negate()).test(trans);
    static final Predicate<WidgetTransfer> dirigibleTransferReqs = trans -> isPartner.and(isDirigibleForbiddenArea.negate()).and(isDirigibleCategory).test(trans);
    static final Predicate<WidgetTransfer> friendsAndFamilyReqs = trans -> isFriendsAndFamily.and(isFriendAndFamilyDiscountLegal.negate()).test(trans);
    static final Predicate<WidgetTransfer> internalBlockReqs = trans -> isInternal.and(isBlockSize).test(trans);
    static final Predicate<WidgetTransfer> internalTotalCapReqs = trans -> isInternal.and(isTotalOverCap).test(trans);

    public static final String checkWidgetTransfer(WidgetTransfer transfer) {
        String businessRuleErrors = "";

        if (suffientAmount.test(transfer)) {
            businessRuleErrors += "Insufficient balance to transfer ; ";
        }

        if (parterTransferReqs.test(transfer)) {
            businessRuleErrors += "This area is not a transfer eligible area. ; ";
        }

        if (dirigibleTransferReqs.test(transfer)) {
            businessRuleErrors += "D Category Transferer can only be transferred in transfer area 213. ; ";
        }

        if (friendsAndFamilyReqs.test(transfer)) {
            businessRuleErrors += "This area is not a transfer eligible area. ; ";
        }

        if (internalBlockReqs.test(transfer)) {
            businessRuleErrors += "Amount is too small for I type transfer. ; ";
        }

        if (internalTotalCapReqs.test(transfer)) {
            businessRuleErrors += "This transfer is too large. ; ";
        }

        return businessRuleErrors;
    }

The above code has a lot of boiler plate - but it's boiler plate that is invisible to the average Java dev. All those if blocks are boiler plate. You have to type them again, and again. What if I told you, you could use a validator and clean up all your business rules? Think of the miles of conditionals in your business code, and imagine each reduced to a single composable function call.

Boilerplate Removal

Another problem is that checkWidgetTransfer returns a string. This pushes the responsibility for determining if an error has occured onto the calling method. All checkWidgetTransfer callers need a section that looks like this:

String result = checkWidgetTransfer(transfer);
if(null == result || 0 == result.size()) {
    //continue
}else{
    handleError(result);
}

Multiply this by every bizarre process that Bob in accounting, Carol in sales uses and Duane in HQ uses. It can get.... big.

We can save on typing, share conditionals and share business logic by using the Validator and Result technique. Here's what it looks like from the caller's perspective:

checkWidgetTransfer(transfer).onError(err -> handleError(err));
//continue

This provides an api for the caller that indicates what an error condition is. Callers no longer have to guess that an empty string is a pass, and a non-empty string is a fail. The api provides a place to put error handling, which can take an existing function, or have an on-the-fly lambda in place. Sweet!

You still have to write up Bob, Carol and Duane's favorite workflow. but things are compact and you don't have to go down many twisty branches, each more a like than the last.

Now with a Validator

What if you didn't have to write any if/then/else statements? What if you you only had to write the logic, and something else would handle stringing that logic together. A validator can make that possible.

Here's what the implementation of checkWidgetTransfer looks like, using a validator:

public static final Result<WidgetTransfer> checkWidgetTransfer(WidgetTransfer transfer) {
    Validator<WidgetTransfer> widgetTransferValidator = new Validator();
    widgetTransferValidator.addRule(suffientAmount, "Insufficient balance to transfer");
    widgetTransferValidator.addRule(parterTransferReqs, "This area is not a transfer eligible area");
    widgetTransferValidator.addRule(dirigibleTransferReqs, "D Category Transferer can only be transferred in transfer area 213");
    widgetTransferValidator.addRule(friendsAndFamilyReqs, "This area is not an eligible area");
    widgetTransferValidator.addRule(internalBlockReqs, "Amount is too small for I type transfer");
    widgetTransferValidator.addRule(internalTotalCapReqs, "This transfer is too large");
    return widgetTransferValidator.validate(transfer); 
}

The validator can take as many rules as needed, and each rule gets a name and a matching message. The validator ensures every rule is applied to the transfer, and a Result is returned, containing either the error messages or the transfer.

Implementation Details

I implemented a Validator as a HashMap of functions to error strings. The validate method tests each function, and if the test is true, collects the matching message in the Result.

I implemented Result as an Either. Callers have the option of getting a boolean hasErrors or passing in a Consumer to onError. The important thing about a Result is that it is never null and it guides the developer to the correct method of handling an error.

Wrap up

With just a tiny push, we helped our elephant reach orbit. We've gone from bog standard spaghetti business logic to pure functions embodying composable business logic. Thank you for coming along for ride. I welcome comments or feedback at gunnar@gunnargissel.com, or @monknomo on Twitter

Credits

Thank you Oliver Dodd for the elephant

Thank you NASA, ESA, N. Smith (U. California, Berkeley) et al., and The Hubble Heritage Team (STScI/AURA) for the Carina Nebula

Photo of the shuttle Endeavour by Mr. Littlehand

Boiler Plate from Les Chatfield

Blastoff by Matthew Lancaster

Java 8 Stream Cheatsheet


Streams are a way of working with objects in a collection.

Streams allow a person to say what they want to have at the end. Contrast that with the imperative approach that requires a person to say how to collect what they want to have at the end.

Streams also allow for trivial multi-threading.

Basic Stream Methods

There are a couple basic methods that govern stream interaction. The general idea behind these methods is manipulating a collection of objects so that the only objects remaining are the ones you want.

If I had to pick the indispensable methods for working with a Stream, I'd say Map, Filter, and Collect are on it.

Filter Filter takes a Predicate, and leaves only the values that the Predicate is true for.

Map Map takes a Function, and transforms the values in the stream from one type to another

Sorted Sorted takes a Comparator, and orders the values in the stream according to the ordering specified in the Comparator.

Collect Collect stops the stream and puts the values from the stream into some kind of Collection, like a List.

toArray toArray() stops the stream and returns an array with the elements contained in the stream.

Finders

A common task, when using a collection, is to get an element out of the stream. These are generally used after Filter and Map, to guarantee that the element you find matches some criteria and is of the preferred type.

findAny() findAny() returns an Optional containing an element in the stream (or nothing, if the stream is empty). Order is not respected here, especially in parallel stream situations.

findFirst() findFirst() returns an Optional containing the first element in the stream (or nothing, if the stream is empty). Order is respected when using this method

max(Comparator comparator) max returns the maximum element of the stream for the given Comparator

min(Comparator comparator) min returns the minimum element of the stream for the given Comparator

Matchers

Another common task is to determine if the objects meet some given criteria. These "matcher" methods indicate whether some, none or all the objects in a stream meet a given criteria.

allMatch(Predicate pred) Returns true if all elements in the stream match the Predicate

anyMatch(Predicate pred) Returns true if any elements in the stream match the Predicate

noneMatch(Predicate pred) Returns true if no elements in the stream match the Predicate

Stream Modifiers

From time to time, a stream is not quite the "right" stream. These methods create a new stream with slightly different characteristics than the old stream, whether it is a different length, different starting point, or a guarantee that only unique objects are contained.

distinct() distinct() creates a new stream that has only distinct elements (based on .equals) in it

limit(int maxSize) limit(maxSize) creates a new stream by truncating the original stream to be no longer than maxSize.

skip(long n) Skips the first n elements of the stream, and creates a new stream out of the rest

sorted() Creates a new stream, where the elements are sorted according to natural order

sorted(Comparator comparator) Creates a new stream, where the elements are sorted according to the Comparator

Stream Characterizers

Another common task, when working with collections, is to determine some characteristics about the collection as a whole. The stream api provides a method to figure out how big a given stream is.

count() count() counts the number of elements in the stream

Turn Your Spaghetti Code into Functions - Part 2


Read Part 1, first.

In Part 1, we started with an example of common business logic code, and an analogy based on cramming an elephant into a Smart Car. We did some refactoring to untangle the nested if/else blocks, but we left after we finished cramming the elephant into a Smart Car.

In many ways, it feels "good enough", but what if I told you we can get it better? Java 8 brings us a new tool to contain and use the logic within an if statement - the Predicate. In terms of elephants driving cars, we can get it driving a stylish convertible.

So you have a lot of conditional logic, and you find yourself copy-pasting conditions from one logic block to the other. It's easy, it's seductive, but it's wrong. Copy pasting is error prone and extra work! If you're like me, you try to work as little as possible - that's the computer's job. Java 8 provides a new tool to prevent copy-pasting and keep your code DRY.

Using Predicates allows us to encapsulate logic as a variable. This makes for two features that are particularly powerful

  1. Variable names communicate the intent of the logic
  2. Logic is resusable and individually testable

And Now, With Predicates

Before Java 8, I wasn't tuned in to the functional programming world. The last time I remember hearing about Predicates was in school when I was ignoring a grammar lesson. It turns out that, when programming, Predicates can really improve your code.

A grammar school

Here we will make the if/else blocks more readable by creating Predicates out of the logic they represent. Predicates can be named, which allows developers to name rules in a way that allows for clear discussions with even non-technical users.

static final Predicate<WidgetTransfer> suffientAmount = trans -> trans.getTransferer().getAccount(trans.getFromAccount()).getBalance().compareTo(trans.getAmount()) > 0;
static final Predicate<String> isPartner = ttc -> ttc.equals("200");
static final Predicate<String> isFriendsAndFamily = ttc -> ttc.equals("710");
static final Predicate<String> isFriendAndFamilyDiscountLegal = ac -> ac.matches("574|213|363|510");
static final Predicate<String> isPartneringArea = ac -> ac.matches("907|412|213");
static final Predicate<String> isDirigibleArea = ac -> ac.matches("213");
static final Predicate<String> isDirigibleCategory = cat -> cat.equals("D");
static final Predicate<String> isInternal = tc -> tc.equals("I");

public static final String checkWidgetTransfer(WidgetTransfer transfer) {
    String businessRuleErrors = "";

    String transferTypeCode = transfer.getTransferTypeCode();
    String areaCode = transfer.getAreaCode();
    String category = transfer.getTransferer().getCategory();
    String typeCode = transfer.getTypeCode();

    if (suffientAmount.test(transfer)) {
        businessRuleErrors += "Insufficient balance to transfer ; ";
    }

    if (isPartner.test(transferTypeCode)
            && isPartneringArea.negate().test(areaCode)) {
        businessRuleErrors += "This area is not a transfer eligible area. ; ";
    }

    if (isPartner.test(transferTypeCode)
            && isDirigibleArea.test(areaCode)
            && isDirigibleCategory.test(category)) {
        businessRuleErrors += "D Category Transferer can only be transferred in transfer area 213. ; ";
    }

    if (isFriendsAndFamily.test(transferTypeCode)
            && isFriendAndFamilyDiscountLegal.negate().test(areaCode)) {
        businessRuleErrors += "This area is not an eligible area. ; ";

    }

    if (isInternal.negate().test(typeCode)
            && !isBlockSize(transfer)) {
        businessRuleErrors += "Amount is too small for I type transfer. ; ";
    }

    if (isInternal.negate().test(typeCode)
            && isTotalOverCap(transfer)) {
        businessRuleErrors += "This transfer is too large. ; ";
    }

    return businessRuleErrors;
}

The Good

  • Each if block is readable in something approximating "business English"
  • The rules are defined as Predicates
  • The rules are portable and reusable.
  • The rules are also individually testable, without having to test each branch at once

The Bad

  • This technique still uses && which is not idiomatic with functions in Java
  • We are forced to use && because the Predicates take different types of objects, so we can't chain them together
  • While the Predicates that make up the rules are portable, the rules themselves are made of multiple Predicates and are not portable
  • Nothing has been done that can't be done with ordinary methods
  • Good old public boolean isSufficientAmount(String amount) would suffice
  • We still have to create all these property variables to get the appropriate values to give to our Predicates

Predicate Chaining

Let's fix some of the stuff on the 'bad' list from the previous example.

We can get rid of && by using just a little bit more of the functional interface and refactoring the Predicates to all take the same type of object, in this case a WidgetTransfer object. The goal is to make our Predicates like legos - interlocking and interchangeable.

lego elephant

static final Predicate<WidgetTransfer> suffientAmount = trans -> trans.getTransferer().getAccount(trans.getFromAccount()).getBalance().compareTo(trans.getAmount()) > 0;
static final Predicate<WidgetTransfer> isPartner = trans -> trans.getTransferTypeCode().equals("200");
static final Predicate<WidgetTransfer> isFriendsAndFamily = trans -> trans.getTransferTypeCode().equals("710");
static final Predicate<WidgetTransfer> isFriendAndFamilyDiscountLegal = trans -> trans.getAreaCode().matches("574|213|363|510");
static final Predicate<WidgetTransfer> isPartneringArea = trans -> trans.getAreaCode().matches("907|412|213");
static final Predicate<WidgetTransfer> isDirigibleArea = trans -> trans.getAreaCode().matches("213");
static final Predicate<WidgetTransfer> isDirigibleCategory = trans -> trans.getTransferer().getCategory().equals("D");
static final Predicate<WidgetTransfer> isInternal = trans -> trans.getTypeCode().equals("I");
static final Predicate<WidgetTransfer> isBlockSize = trans -> isBlockSize(trans);
static final Predicate<WidgetTransfer> isTotalOverCap = trans -> isTotalOverCap(trans);

public static final String checkWidgetTransfer(WidgetTransfer transfer) {
    String businessRuleErrors = "";

    if (suffientAmount.test(transfer)) {
        businessRuleErrors += "Insufficient balance to transfer ; ";
    }

    if (isPartner.and(isPartneringArea.negate()).test(transfer)) {
        businessRuleErrors += "This area is not a transfer eligible area. ; ";
    }

    if (isPartner.and(isDirigibleArea).and(isDirigibleCategory).test(transfer)) {
        businessRuleErrors += "D Category Transferer can only be transferred in transfer area 213. ; ";
    }

    if (isFriendsAndFamily.and(isFriendAndFamilyDiscountLegal.negate()).test(transfer)) {
        businessRuleErrors += "This area is not an eligible area. ; ";
    }

    if (isInternal.negate().and(isBlockSize.negate()).test(transfer)) {
        businessRuleErrors += "Amount is too small for I type transfer. ; ";
    }

    if (isInternal.negate().and(isTotalOverCap.negate()).test(transfer)) {
        businessRuleErrors += "This transfer is too large. ; ";
    }

    return businessRuleErrors;
}

The Good

  • We get rid of extra variables that hold string values from the WidgetTransfer object
  • We compact our if-blocks while retaining readability
  • We only evaluate one type of object

The Bad

There is very little bad about this refactor point. The conditionals are all very easy to read. It's clear what each rule is, and what branch. If I didn't know what I have planned for the next article, I would be satisfied to stop here.

Next Steps

elephant driving a convertible citroen

All our rules are Predicates and each rule takes the same kind of object, a WidgetTransfer. That makes our rule composable in the fashion demonstrated above, but there are some improvements we can make to how we compose the business rules.

The first improvement is to combine small rules into larger rules - we are doing this in conditional statements, but it is just as easy to do so in a Predicate. We can also create a Validator object to create a collection of business rules and error messages. A Validator dispenses with the need to create a complex nested if/else logic structure, and is a concrete unit of business logic that can be shared, re-used and tested.

Sign up for my email list to get notifcations about updates in continuing series, and a monthly digest of interesting programming and tech leadership articles

We will go over using Validators in the to-be-written Turn Your Spaghetti Code into Functions, Part III

Credits

Thank you roebot for the left facing Smart Car

Thank you Oliver Dodd for the elephant

Thank you Phillip Pessar for the convertible

Thank you JPL and NASA/Space Telescope Science Institute for the edge-on galaxy picture

Thank you Philip Sheldrak for the grammar school

Turn Your Spaghetti Code into Functions - Part 1


Developers can sink a lot of hours into fighting business rule code. Spaghetti business rules make it so little changes need to be copy pasted repeatedly throughout if/else blocks. It's like trying to shoehorn an elephant into a Smart Car, when it should be like snapping together legos.

Anyone who has worked on a 'mature' set of business rules knows that untangling what is going on is extremely hard. If cramming the elephant into the Smart Car was tough, getting it out is an order of magnitude tougher. I'm going to show how to make your Smart Car-driving elephant a little happier.

Business rules are your money-makers and form the essence of your business's being. They also change a lot. This dynamic often leads to rushed work in business rules and over the long run creates a nasty mess right in the heart of your money maker. A nasty mess is hard to read and even harder to figure out what it is supposed to be doing.

Further, the OO way of encapsulating business rules is either fundamentally inadequate, or so widely misunderstood by working developers that the common pattern is a god class that mutates everything it touches. Testing a huge class, stuffed with spaghetti and mutators is daunting, at best, impossible at worst. No tests make it very hard to develop without fear.

Here's a set of techniques for making the code easier to follow, so you can put your effort into understanding your stakeholders and making sure what's in the code is what they want to be in the code.

This will teach you how to untangle business rules, so you can easily work with them.

Readability

Deep nesting impairs readability. Even when developers use tabs well and are consistent with their curly brace usage, around the 3rd layer of if/else statements, it starts getting hard to tell what particular branch you are reading.

Is this the one with the null child object? I'll just check for null again here really quick

Avoid this kind of impulse by structuring your code so there is never any doubt about what you are checking.

Long conditions that reach deep into child or grandchild objects also impair readability. Stakeholders never say (unless they've been terribly abused) something like:

If the transfer type code is 200 and it's not in areas 907, 412 or 213, then it's not allowed

  1. That's got more "nots" than a human likes to say
  2. Humans don't usually go on about codes.

They might say something like:

If it's a partner transaction, we only allow it in partner areas

If your code takes mental backflips to match how your stakeholders talk, you're gonna have a bad time. So are they, and they won't even know why.

Testability

Gnarly business rule code is hard to test. The twists and turns of deeply nested if/else statements are easy to get lost in, easy to forget a branch and sometimes just plain impossible to set up in a testing harness. No tests mean every change is dangerous - you are one misplaced }, or backwards > from giving your users a headache.

Gnarly business rule code seems to encourage devs to mutate the objects it is validating. I don't know why this is, but I've seen it many times in the wild. State mutation amps up the testing difficulty by an order of magnitude. Now, not only must you test for messages and expected errors, but you must detect changes to the object you are validating. Are they intentional? Are they correct?

Who knows? I promise no one wrote it down.

Response speed

Stakeholders, users, managers and developers constantly engage in timeline tug of war. Technical debt hamstrings developers' ability to give their users what they need. A good 'tell' that your system has a lot of technical debt is users can easily describe a feature, but developers can't easily implement it. The simplest things turn into month long bushwhacking exercises.

To me, nothing says bushwhacking like coming down a mountain, getting off trail and fighting through Devil's Club and loose scree -

Wait. I meant nothing says bushwhacking like coming into a method and getting on the wrong nested if/else branch and fixing something that wasn't broken in the first place. Or noticing that 100 lines of code have never, ever been executed, because they wouldn't work. Or any number of the fun surprises that spaghetti-fied business rules bring.

Composability

Composability lets you create new rules out of old rules. Most new business rules have a lot in common with existing rules. The ability to combine existing rules and add that one special case is extremely powerful. Your stakeholders will be amazed at your turnaround time!

The spaghetti style is anti-composable. Copy-pasting, duplicating code and mangling switch statements are practically requirements with spaghetti-ed business rules. Good luck re-using something to get at the one

Example Bad Code

Here's an example of standard Java business logic that evaluates a business object (BusinessTransfer) and creates messages to return to the user if it violates business rules:

public static final String checkWidgetTransfer(WidgetTransfer transfer) {
    String businessRuleErrors = "";

    if (transfer.getTransferer().getAccount(transfer.getFromAccount()).getBalance().compareTo(transfer.getAmount()) < 0) {
        businessRuleErrors += "Insufficient balance to transfer ; ";
    }


    if (transfer.getTransferTypeCode().equals("200")) {
        if (!transfer.getAreaCode().matches("907|412|213")) {
            businessRuleErrors += "This area is not a transfer eligible area. ; ";
        } else if (!transfer.getAreaCode().matches("213")) {
            if (transfer.getTransferer().getCategory().equals("D")) {
                businessRuleErrors += "D Category Transferer can only be transferred in transfer area 213. ; ";
            }
        }
    } else if (transfer.getTransferTypeCode().equals("710")) {
        if (!transfer.getAreaCode().matches("574|213|363|510")) {
            businessRuleErrors += "This area is not a transfer eligible area. ; ";
        }
    }


    if (transfer.getTypeCode().equals("I")) {
        if (isBlockSize(transfer)) {
            businessRuleErrors += "Amount is too small for I type transfer. ; ";
        }
        if (isTotalOverCap(transfer)) {
            businessRuleErrors += "This transfer is too large. ; ";
        }
    }

    return businessRuleErrors;
}


public static boolean isBlockSize(WidgetTransfer transfer) {
    return transfer.getAmount().compareTo(1000) < 0;
}


public static boolean isTotalOverCap(WidgetTransfer transfer) {
    return transfer.getAmount().compareTo(1000000) > 0;
}

The above example is inspired by actual code running in the wild. What I show here is simplified, and anonymized. It's as hard to read as the original.

Reading it takes knowledge of what a "200" transfer type code is or what is acceptable data for different transfer area codes. The parentheses are nested, which makes copy-pasting (a common technique for working with this style of code) perilous. A dev can't afford to miss a single curly bracket without causing a hard-to-debug problem.

Logic Block Paradigm Shift

A quick way of refactoring long branching if/else code is to dispense with branches and with elses. By rephrasing each business rule into a positive constraint, a developer can check to see if the constraint conditions are met, rather than walking a branching logic tree. This technique increases line count a little, but improves readability a lot.

Another low hanging fruit is to create instance variables to hold values, rather than use getters (or worse, nested getters!). This gives the ability to name what a thing is in the context you are using it in, rather than relying on getters to have a good name in your context.

public static final String checkWidgetTransfer(WidgetTransfer transfer ) {
    String businessRuleErrors = "";
    Integer balance = transfer.getTransferer().getAccount(transfer.getFromAccount()).getBalance();
    Integer transferAmount = transfer.getAmount();
    String transferTypeCode = transfer.getTransferTypeCode();
    String areaCode = transfer.getAreaCode();
    String category = transfer.getTransferer().getCategory();
    String typeCode = transfer.getTypeCode();


    if (balance.compareTo(transferAmount) > 0) {
        businessRuleErrors += "Insufficient balance to transfer ; ";
    }


    {
        if (transferTypeCode.equals("200")
                && !areaCode.matches("907|412|213")) {
            businessRuleErrors += "This area is not a transfer eligible area. ; ";
        }
    }


    if (transferTypeCode.equals("200")
            && areaCode.matches("213")
            && category.equals("D")) {
        businessRuleErrors += "D Category Transferer can only be transferred in transfer area 213. ; ";
    }


    if (transferTypeCode.equals("710")
            && !areaCode.matches("574|213|363|510")) {
        businessRuleErrors += "This area is not an eligible area. ; ";


    }


    if (!typeCode.equals("I")
            && !isBlockSize(transfer)) {
        businessRuleErrors += "Amount is too small for I type transfer. ; ";
    }


    if (!typeCode.equals("I")
            && isTotalOverCap(transfer)) {
        businessRuleErrors += "This transfer is too large. ; ";
    }

    return businessRuleErrors;
}

The Good

  • The above code is much more readable.
    • Each business rule is contained in its own block of logic
    • All the properties needed to determine whether a condition has been met are named.
    • You can describe each business rule as written and it very nearly sounds like English.
  • The logic blocks are small and discrete.
    • There are no nested curly braces, so you'll have a hard time getting lost in the code.

The Bad

  • Business knowledge of what codes mean is still required
    • What is a "200" transfer type code? The code doesn't say, so hopefully it is documented somewhere...
  • Negative conditionals abound - if (!typeCode.equals("I"))
    • Negative conditionals are a little hard to say, and are harder to reason with than positive conditionals.
  • Still mutating those businessErrorMessages
    • This is just one more thing to set up in a unit test

What's Next?

I'll continue this refactoring discussion in a couple future posts. Check out my example refactoring repository for a preview!

We're going to see:

  • How to use Predicates to make your life better
  • Using actual objects, and not just their properties, to make your life better
  • Using Functions and validator objects, to make your life better

We'll try to get that elephant in his Smart Car, but mostly we'll try to make your life better.

Credits

Thank you Volantra for the right facing Smart Car Pic

Thank you roebot for the left facing Smart Car

Thank you Oliver Dodd for the elephant

Thank you Neils Heidenreich for the mutant strawberry

Thank you Peter Stevens for the Devil's Club

Thank you to Erica Schoonmaker for the picture of the books

Footnotes!


I was reading away on the internet when I saw a cool thing. Footnotes that popup when you hover over the little 1 note.

Lukas Mathis generously offered his code to the public, so I borrowed the code in his bookmarklet for Daring Fireball. I wasn't quite doing Gruber-style footnotes, which the code assumes.

Gruber Style Footnotes

A Gruber-style footnote has two parts:

  1. The superscript link
  2. The footnote with a return link

The superscript link, in Markdown, looks like this: <sup id="fnr-footnotes-1">[1](#fn-footnotes-1)</sup>. The important parts are that the <sup> element has an id that starts with "fnr" (for "footnote return", I assume), and a link to the footnote that starts with "fn".

The footnote with a return link looks like: <a id="fn-footnotes-1">1: </a> This is an example footnote here - see how it has a return link [⏎](#fnr-footnotes-1). The important parts are the link with an id that starts with "fn" and the return link to the superscript link's <sup> element.

The script I borrowed assumes you have both parts of the Gruber-style footnote, with the appropriate prefixes and return links.

I adjusted the script's color a little to match my theme, but here it is, more or less unchanged from Lukas Mathis' original:

$(document).ready(function() {
  var sups = document.getElementsByTagName("sup");
  var footnotehtml = [];
  for (var i = 0; i < sups.length; i++) {
    var sup = sups[i];
    if (sup["id"] && sup["id"].substr(0, 3) == "fnr") {

      var footnr = sup["id"].substr(3);
      console.log(footnr);
      var footnote = document.getElementById("fn" + footnr);
      console.log(footnote);
      if (!footnote) continue;
      console.log("asdfasdfaf");
      footnotehtml[i] = footnote.parentNode.innerHTML;
      console.log(sup);
      sup.setAttribute("footnoteindex", i);
      sup.onmouseover = function(event) {
        var footnotepopup = document.getElementById("footnotepopup");
        if (footnotepopup) footnotepopup.parentNode.removeChild(footnotepopup);
        var index = parseInt(this.getAttribute("footnoteindex"));
        var popup = document.createElement("div");
        popup.innerHTML = footnotehtml[index];
        popup.id = "footnotepopup";
        popup.style.position = "absolute";
        popup.style.left = event.pageX - 125 + "px";
        popup.style.top = event.pageY + 25 + "px";
        popup.style.width = "15em";
        popup.style.textAlign = "left";
        popup.style.backgroundColor = "Gainsboro";
        popup.style.border = ".1em solid black";
        popup.style.borderRadius = "6px";
        popup.style.padding = "1em";
        document.body.appendChild(popup);
      };
      sup.onmouseout = function(event) {
        var footnotepopup = document.getElementById("footnotepopup");
        if (footnotepopup) footnotepopup.parentNode.removeChild(footnotepopup);
      };
    }
  }
});

Footnotes

1: This is an example footnote here - see how it has a return link

Credits

Thank you to Erica Schoonmaker for the picture of the books

Changing an Uncontrolled Input to Controlled Error in React


React wants form inputs and the like to keep their state inside React, inside of inside the input. This style is called a "controlled input". They also offer "uncontrolled input" where the input manages its own state.

React apparently does not like inputs switching from controlled to uncontrolled. I was developing a form with the docs open next to my editor and I kept getting a Warning: CustomInput is changing an uncontrolled input of type text to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info:https://fb.me/react-controlled-components

As far as I could tell, my input was set up to always be controlled. I changed javascript around and googled for quite some time before realization set in

I was Switching a Form Value from '' to null

This is apparently a no-no in React's controlled component land. My initial state set up had all empty strings, and the only subsequent state manipulation was to get data from webservices. The webservices I'm working with return a fairly faithful representation of data from a database - nulls and all.

I solved it by converting my state variable to const in the render method - with a twist:

const nullable = this.state.nullable == null ? '' : this.state.nullable;

A little sprinkling of last minute converters and all is well.

Thank you Sebastian Dooris for the sprinkles

Page 1 / 2 »