Saturday, April 29, 2017

Maven color logging on Cygwin

I'm quite happy Maven 3.5.0 has added color logging!

With earlier versions of maven, I used Jean-Christophe Guy's excellent maven-color extension. On Windows that involved some manual hacking of my maven installation, but on Mac, it was trivial with homebrew.

So now I'm getting color output from maven out of the box. Except when I don't.

You see, this new feature relies on the good JAnsi library. And JAnsi presently has an issue with color on Cygwin. When I'm at home, Cygwin is my mainstay, used on my gaming-cum-programming rig, so this is significant to me. What is the issue? No color—JAnsi detects I'm on Windows, and uses the native Windows console color handling, which doesn't work in Mintty or Xterm. Those use standard ANSI escape sequences, etc. rather than an OS-specific library.

Digging through the source for JAnsi, I find the trouble spot:

private static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("win");

Aha! The special Windows-handling code kicks in when the os.name system property contains "win" (in any case). Using the jps and jinfo tools that come with the JDK, I double-checked against a long-running maven build (16848 just was the PID used by the JVM for this maven build; use jps to list all current PIDs):

$ jinfo -sysprops 16848 | grep os.name
os.name = Windows 10

Some experimenting found a way to work around that:

MAVEN_OPTS=-Dos.name=Cygwin mvn clean

(You need to use MAVEN_OPTS rather than passing -Dos.name=Cygwin to maven; once maven starts the value is immutable.)

Color is back. It turns out, any value for os.name will work (for example, "Bob") as long as it doesn't contain "win". I picked "Cygwin" for explicitness.

UPDATE: I have to rethink this. Sure I get color now, but at the expense of maven test failing as maven no longer believes I'm on Windows, so is unhappy at the lack of a /bin/sh and general UNIX filesystem. One step forward, two steps back.

Friday, April 21, 2017

Quick Kotlin idiom: naming things

Kotlin is very much a better Java. A great example is this simple idiom for naming things:

open class Named<in T>(val name: String, check: (T) -> Boolean)
    : (T) -> Boolean by check {
    override fun toString() = name
}

So I can write something like this:

fun maybe_three(check: (Int) -> Boolean) {
    if (check(3)) do_the_three_thing()
    else println("\"$check says\", Do not pass go.")
}

maybe_three(Named("Is it three?") { i -> 3 == i })
maybe_three(Named("Is it four?") { i -> 4 == i })

The first call of maybe_three prints: Breakfast, lunch, dinner. The second call prints: "Is it four?" says, Do not pass go.

Many variations on this are possible, not just functions! What makes this example work nicely is delegation—the magical by keyword— for the general feature of naming things by overriding toString(); and for the function delegated to, the elegant lambda (anonymous function) syntax for the last parameter. You can delegate anything, not just functions, so you could make named maps, named business objects, et al, by using delegation on existing types without needing to change them.

Thursday, April 13, 2017

WSL, first experiences

I first tried Windows Subsystem for Linux in December 2016, but was not successful in installing, so I held off.

After getting the Windows 10 Creators Edition update, I saw how much work and love went into improving WSL, and decided to try again. I was rewarded.

On the whole, the installation was smooth, brief, you might even say trivial. There were Windows reboots to enable Developer Mode, and after installing WSL, but much solid effort has gone into making Windows reboots quick and painless, and with a regular Linux distro I'd have rebooted anyhow after upgrading, so no disgruntlement.

And what did I get for my efforts? WSL bash is bash. Just bash. Really, it is just plain old bash, with all the command line tools I've grown accustomed to over 30 years. The best praise I can give a tool: It just works. And WSL just works. (But see Almost there, below.)

Out of the box WSL runs Ubuntu 16.04 (Xenial), the official LTS distribution (long-term support). This is a sane choice for Microsoft. It's stable, reliable, secure, tested, trusted. For anyone wanting a working Linux command line, this is a go-to choice. Still, I updated it.

Things I changed

Even with all the goodness, there were some things I had to change:

The terminal
I immediately installed Mintty for WSL. I've grown to love Mintty on Cygwin, trusting it as a reliable and featureful terminal emulator without going overboard. It's a tasteful balance, well executed. And CMD.EXE, though much improved, still is not there (but may head there; we'll see if PowerShell wins out).
DBus
Not to get into flamewars, I just accept that Ubuntu uses DBus. By default it doesn't run on WSL, but this was easy to fix, and it made upgrading Ubuntu smoother. Using sudo, edit /etc/dbus-1/session.conf as others have suggested (I did it by hand, not with sed). You may have to repeat after upgrading Ubuntu.
The Ubuntu version
It seems trivial, but I was unhappy that diff --color didn't work. Am I shallow—color? Some of the scripts I write for open source provide colorized diff output, and I'd like to work on them in WSL without disabling this feature. Microsoft made much hay over 24-bit color support in CMD.EXE. So I updated to Ubuntu 17, which includes diffutils 3.5 (the version in which --color was added). Microsoft does not official support upgrading Ubuntu, but I ran into no real problems.

Upgrading WSL Ubuntu

Caveat coder — there is a reason this is unsupported by Microsoft at present. I just never ran into those reasons myself. For example, I used DBus to make upgrading happier; I am not using any Linux desktop (graphical) programs, so maybe this could be a reason.

Researching several helpful Internet sources, I:

  1. Edited /etc/update-manager/release-upgrades to use "normal" releases, not just LTS
  2. Fixed /etc/dbus-1/session.conf
  3. Ran sudo do-release-upgrade to move to 16.10 from 16.04
  4. Re-fixed /etc/dbus-1/session.conf
  5. Ran sudo do-release-upgrade -d to move to 17.04 from 16.10

(Pay attention: there are many "yN" prompts were the default is to abort: you must enter "y" to these!)

When I am prompted to reboot, I quit the upgrade, close all WSL terminals, and start a fresh one. There is no actual kernel to reboot: it remains 4.4.0-42-Microsoft throughout. The kernel is emulated by Windows, not an actual file to boot, so upgrades only change the packages bundled with the kernel, not the kernel itself. The underlying abstraction is quite elegant.

Almost there

Can I drop Cygwin and make WSL my daily development environment? Not quite yet. For shell script work, WSL is excellent. But for my Kotlin, Java, Ruby, et al, other projects, I rely on IntelliJ IDEA as my editor (though Emacs might return into my life again). Filesystem interop between Windows programs (such as java.exe) and WSL is good but not perfect.

Other options

Cygwin on Windows
This is and has been my solution for bash on Windows for many years. I will move to WSL when I'm ready, but I'm not ready yet. I need my regular development cycle to work first. (See Almost there.) There are downsides to Cygwin, for example, coping with line endings, but it's been reliable for me.
Homebrew on Mac
This is work. My company issues me a Mac laptop, and I use it. For the most part, it is fine for work with colleagues and clients, though at times the Mac is a little strange, and much of the user experiences feels counterintuitive. Still, the software mostly works, and the hardware is incredibly good.

But why not just use Linux? Well, my daily machine at home is a Windows box. Because it's my gaming rig, and games I play don't run well in Linux, and getting a Mac desktop is not currently a pretty story.

UPDATE: More on how syscalls work.

UPDATE: Slightly dated (Microsoft is moving very fast on WSL—kudos!), this is a good video presentation on what happens under the hood.

Wednesday, April 12, 2017

Quick diff tip, make, et al

I'm using make for a simple shell project, to run tests before committing. The check was trivial:

SHELL = bash

test:
	@./run-tests t | grep 'Summary: 16 PASSED, 0 FAILED, 0 ERRORED' >/dev/null

This has the nice quality of Silence is Golden: say nothing when all is good. However, it loses the quality of Complain on Failure: it simply fails without saying why.

A better solution, preserving both qualities:

SHELL = bash

test:
	@diff --color=auto \
	    <(./run-tests t | grep 'Summary: .* PASSED, .* FAILED, .* ERRORED') \
	    <(echo 'Summary: 16 PASSED, 0 FAILED, 0 ERRORED')

It still says nothing when all is good, but now shows on failure how many tests went awry. Bonus: color for programmers who like that sort of thing.

Why set SHELL to bash? I'm taking advantage of Process Substitution. Essentially the command outputs inside the subshells are turned into special kinds of files, and diff likes to compare files. Ksh and Zsh also support process substitution, so I'm going with the most widely available option.

UPDATE:

Why are my arguments to diff ordered like that? In usual testing language, I'm comparing "actual" vs "expected", and more commonly you'll see programmers list "expected" first.

diff by default colors the left-hand input in RED, and the right-hand input in GREEN. On failure, it makes more sense to color "actual" in red and "expected" in green. Example output on failure:

$ make
1c1
< Summary: 17 PASSED, 1 FAILED, 0 ERRORED
---
> Summary: 19 PASSED, 0 FAILED, 0 ERRORED
make: *** [Makefile:4: test] Error 1

Tuesday, April 04, 2017

Maven logging and the command line

I usually set up my Maven-build projects to be as quiet as possible. My preference is "Silence is Golden": if the command says nothing on the command line, it worked; if it failed, it prints to STDERR.

However, sometimes I want to see some output while I'm tracking down a problem. How best to reconcile these?

Maven 3.3.1 (maybe earlier) introduced the .mvn directory for your project root (note leading DOT). In here you can keep a jvm.config file which has the flags to the java command used when running mvn. Here's my usual jvm.config:

-Dorg.slf4j.simpleLogger.defaultLogLevel=WARN
-Dorg.slf4j.simpleLogger.log.Sisu=WARN

This quiets maven down quite a bit, using the properties to control Maven's more recent logger, SLF4J. And I normally commit that into my project code repository.

And for those times I'd like more output? I could edit the file, but I don't trust myself enough not to accidentally commit those temporary changes. So I use the command line:

$ MAVEN_OPTS='-Dorg.slf4j.simpleLogger.defaultLogLevel=INFO' mvn

Ultimately mvn reads .mvn/jvm.config, putting the contents into the variable MAVEN_OPTS, and uses MAVEN_OPTS in the invocation of java, and you can override the variable yourself on the command line.

Sunday, April 02, 2017

DDD, A Handmaid's Tale

(No, this is not a post about the venerable and excellent GNU DDD.)

Documentation Driven Development—DDD—is a term I just made up (not really; read on). I was working on some code TDD-style ("first, write a failing test"), and also thinking about my user documentation. My usual practice is to get my tests and code into good shape, push-worthy, and then update the documentation with my improvements (one hopes). Then the thought struck me: I'm doing this wrong!

We write tests first as miniature specifications for the code. But my documentation is conveying to the public my specifications. In the world of closed-source software, this makes sense. You prepare the documentation to ship to customers (internal or external); generally holding off until the code is stable so your documentation is mostly accurate. After all, with closed source, users can't see your tests or the code: the documentation is their only view into how to use your code.

With open-source software, this picture is radically changed. Your users can see your tests and code, in fact, you generally encourage them to look, or fork! So now your tests are little visible public specifications. Why documentation then?

Personally I still like solid documentation on open source projects. True, I could just browse the tests. But that isn't the best way to start with code that is new to me. I'd like to see examples, some explanation, perhaps some architecture or high-level pictures. Hence, documentation.

So, back to DDD. If I'm pushing out my tests and code to a public repository as soon as they pass (or near enough), how is my documentation ever to keep up? How do I encourage others to clone or fork my code, and contribute? I still want new users to have good documentation for getting started; I still want my tests to ultimately define my specifications. The answer is easy: First write failing documentation.

This is not at all a new idea! See Steve Richert, Zach Supalla, and many others. An early form of this idea is Knuth's Literate Programming.

Failing documentation

What is "failing documentation"?

Firstly, just as with "failing tests", you start with documentation of how your code should behave, but which isn't actually the case. The ways to do this are the usual suspects:

  • Write examples which don't work, or possibly don't even compile
  • Write explanations which don't fit your code
  • Write step-by-step walkthroughs which can't be followed
  • Write architecture diagrams which are wrong
  • Etc, etc, etc, anything you'd put in documentation which is invalid for your current code

Then you fix it:

  1. Write failing documentation
  2. Write failing tests which correspond to the documentation
  3. Fix the code to make the tests pass, and the documentation correct

Afterwards you have:

  • Current, accurate documentation
  • Current, passing tests
  • Current, working code

Supporting ecosystems

As straight-forward as DDD is to explain, some software ecosystems make it easier to actually do than others. A standout example is Python and doctest. In doctest you write your tests directly in the API documentation as examples. This is a perfect marriage of documentation and tests.

Swagger is an interesting case. It's generally a documentation-first approach tailored for REST API specifications. But the documentation is "live documentation"—i.e., an executable web form for exploratory testing—rather than text and code examples to read. Using DDD, you would write your REST API specification first in Swagger, then write failing tests around that before fixing the code to implement. Clever people have leveraged this.

About the post title

The Handmaid's Tale is a sly reference to Chaucer's The Wife of Bath's Tale (featuring a strong protagonist balancing among bickering companions), and The Merchants's Tale sequence. Documentation has often been treated as subservient to code, an afterthought, when really it is the first thing most new users see about a system. Give it its due.

Saturday, April 01, 2017

Kotlinc on Cygwin

There may be a better way, but I found that running kotlinc to bring up the Kotlin REPL, while in a Cygwin BASH shell using Mintty, did not respond to keyboard input. A little research indicated the issue is with JLine, which has some understandable difficulties reconciling running under Cygwin with running under CMD.

The workaround I used:

$ JAVA_OPTS='-Djline.terminal=unix' kotlinc
Welcome to Kotlin version 1.1.1 (JRE 1.8.0_121-b13)
Type :help for help, :quit for quit
>>> println("FOOBAR")
println("FOOBAR")
FOOBAR

Requesting JLine to use UNIX-y primitives for terminal access solved the problem. I would like to hear about other solutions.

UPDATE: Edited for clarity. And some additional reading: