rvm implode

I’ve been working with a bunch of independent Ruby projects lately and struggling with rvm and rbenv, gem and bundle to get the Ruby sandbox for each just right.  Then while working on some Android code I hit upon gradlew which sandboxes the gradle environment.

I’ve begun to feel like my machine is just a series of sandboxes strung together as opposed to a coherent computer, and while that may seem awesome (bio-diversity rocks!), the diversity goes hand in hand with operational complexity.  You end up producing a greater and greater variety of incompatible software, the slightest version skew brings the house down and if your sandboxing fails you, there’s rarely a safety net.

Add to that the fact that homebrew is treating /usr/local like a globally shared folder on my machine, requiring what should be read-only system software to be world writeable! Yup, you guessed it, things end up getting corrupted/removed accidentally in the normal course of use.

I’m really getting frustrated with the operational quality of a lot of the software I’m dealing with. As someone who manages people and machines as well as actively develops, I’m more sensitive to this. Sure it allows for rapid changes to complex software but if you can’t reliably deploy and maintain the stuff, you’re just backloading the cost from development to your QA and Dev-Ops folks.

Developers, please resist the urge to use shiny tools that let you quickly cobble together systems that you can only guarantee “runs clean on my machine for now”.

Here’s an interesting article that agrees with me on the problem, but not the solution DevOps Isn’t Killing Developers.  

Here’s an unintentional case in point from Martin Fowler.

Java Optional

I’ve used the various @Nullable and @NotNull annotations available but I’ve never been thrilled with them. They are confused through the various competing versions and they a stopgap solution.  These warn you when you’re about to get yourself in trouble but they don’t offer any improvements on handling the possible situations, you still need to add the boilerplate code.

For my coding style, Optional implementations offer a much nicer solution.  The contract with an optional is as clear as any of the annotations, and they provide support methods that help reduce the boilerplate code.

That said, there are competing implementations of Optional too, and they are not all created equal.  Java 1.8 has a good one, as does Guava, and I’ve included one in almost-functional.

A good optional needs some variant of:

    Optional<T> filter(Predicate<? super T> predicate)
    
  • If a value is present, and the value matches the given predicate, return an Optional describing the value, otherwise return an empty Optional.
  • <T> orElseSupplier(Supplier<T> other)
    
  • Return the value if present, otherwise get the value from the Supplier.
  • <T> orElseThrow(String msg)
    
  • If optional is not empty return it’s value, if empty throw a NoSuchElementException with message. This gives the Optional some of the behavior of a Try.

These sorts of methods remove all the boilerplate code to handle non null comparisons, lookup a value on null, and throwing an exception when you get a null.

Consider:

String filename = args[0];
if (filename == null) {
   throw new NoSuchElementException("Requires filename");
}

Versus:

String filename = ofNullable(args[0]).orElseThrow("Requires filename");