Podcast: The Dream

A podcast I enjoy that investigates different topics. There are three seasons so far and I’ve only just listened to season 2 about “The Wellness Industry” as they call it. So far I’ve learned a lot about the history of dietary supplements and how they are not regulated in the US by the FDA which just explains so much to me: The Dream by Jane Marie.

Share · via If Books Could Kill Episode: The Secret ·

Podcast: If Books Could Kill

A podcast I enjoy that takes apart “airport” bestsellers of today (The Secret) and the past (The Population Bomb) and digs into the circumstances the books were written in, the authors and the background: If Books Could Kill by Michael Hobbes & Peter Shamshiri.

Share ·

Noah Gift - Educating a New Generation of Workers

An interesting read about the difficulties the education industry is facing.

Share · via O'Reilly Radar ·

An 80 character limit improves source code readability

An 80 (non-whitespace) character limit is sensible because it improves source code readability.

A regular argument for a higher limit is that it is more modern. Our displays are bigger and the limit comes from punch cards where it made physical sense. But does that history make the limit bad? And does the available screen real estate change anything?

We read code more than we write it. For prose typography recommends line lengths of 40 to 80 (sometimes 100) characters. And that has not changed with modern display sizes since our eyes and brains have not changed. One can argue that code is not prose, but both want to be understood by humans. One major difference is that code uses a lot of whitespace for indentation. A (sensible) nesting level of 5 and a default tab width of 4 adds ~20 whitespace characters. This results in 60 to 100 (sometimes 120) characters. Ideally our tools would allow for that distinction. Sadly, they don’t. Nonetheless: 80 characters are in the sensible range.

Is our screen real estate thus wasted? No. Modern displays make it possible to read code side-by-side. For example to review diffs (e.g. git or pull requests) or to open two files together (e.g. implementation and test). With the standard font size of 12 pt two tabs in Visual Studio Code can show 156 characters. A more legible 16 pt reduces that to 118 characters. Another reason to keep the character limit sensible. Otherwise one has to start scrolling left and right to read everything. This makes it harder to understand because one can never see everything. Ideally all tools would be responsive and wrap lines at the edge of the viewport dynamically (like e.g. Xcode). Sadly, they don’t.

In summary: a limit of 80 non-whitespace characters makes sense. To account for indentation I recommend a limit between 80 and 120. Everything else makes your code harder to read and understand.

Please be aware that this is an easy topic to discuss ad nauseam. Often everybody has a (strong) opinion about it. If you ever discuss this longer than 15 minutes, you are likely bike-shedding. Choose a value - even a random one - and stick with it. That consistency will help readability more than the difference between 90 and 110.

Examples to illustrate the point:

RUN \
    --mount=type=cache,target=/var/cache/apk,sharing=locked \
    apk add \
        git \
        make

# vs.

RUN --mount=type=cache,target=/var/cache/apk,sharing=locked apk add git make
_logger.LogInformation("Client timestamp for {}: {}",
    connectionId,
    webSocketRequest.ClientTimestamp);

# vs.

_logger.LogInformation("Client timestamp for {}: {}", connectionId, webSocketRequest.ClientTimestamp);
return map.map(MappingNode::getValue)
		.map(List::stream)
		.orElse(Stream.empty())
		.filter(t -> {
			if (t.getKeyNode() instanceof ScalarNode keyNode
					&& key.equals(keyNode.getValue())) {
				return true;
			}
			return false;
		})
		.findFirst();

# vs.

return map.map(MappingNode::getValue).map(List::stream).orElse(Stream.empty()).filter(t -> {
			if (t.getKeyNode() instanceof ScalarNode keyNode && key.equals(keyNode.getValue())) {
				return true;
			}
			return false;
		}).findFirst();
</pre>

Kent Beck - A Daily Practice of Empirical Software Design

Kent shares some of his perspectives on the difficulties of applying of software design every day:

A Daily Practice of Empirical Software Design - Kent Beck - DDD Europe 2023

I really enjoyed this talk, the pacing was great, the examples were highly understandable and I really like his explanations of all the trade-offs you meet every day.

PS And what I love most is that his new book is not dogmatic in the title. It does not tell you what to do, it asks you: Tidy First?

PPS The question mark is so powerful in every day problem solving. It does not think for you; it guides your thinking to hopefully better results. It’s sadly very effortful (since it requires turning on the slow part of your brain) and I have not found a great way to convince teams of their effectiveness yet.

Share · via Dear Architects Newsletter ·

Leslie Nielsen In Middle Earth

At first I thought it might be one of those AI mashups but it is actually delightfully edited: Leslie Nielsen in Middle-Earth.

Share · via Ronny ·

Using SSH to get internet access on a restricted (virtual) machine

If you ever have to work with a (virtual) machine that has restricted internet access, you can use this little trick to use your local host as a SOCKS proxy during your SSH session. This requires the server to allow TCP forwarding.

ssh -R 60374 $hostname

export http_proxy=socks://localhost:60374/
export https_proxy=$http_proxy

curl https://example.com

Kevlin Henney - Seven Ineffective Coding Habits of Many Programmers

Kevlin Henney talks about ineffective habits of programmers.

Share ·

Jason Fried on how to choose a price

Jason Fried:

Never ask people what they would pay for something. Pick a number out of your ass, put it out there, and see if people are going to buy it.

See the whole interview at The Next Web

Share ·

Export Dependencies Plugin - Use Maven and Buck in parallel

I was experimenting with Buck for work. I heard about it first at Devoxx UK 2015 and was wondering whether we could use it to speed up our CI builds.

Why only our CI builds?

One problem is that we’re a Windows shop and Buck only has Linux and macOS Support. Second we use Maven and the Maven IDE integration. We do this to reduce complexity for our apprentices and new hires.

This means Buck was never going to be a full replacement for us. But it could be of use on our CI servers which are Linux. What I needed was a way to produce BUCK files from the existing Maven pom.xml files. And the result of that work is the export-dependencies-maven-plugin.

To test it on your project call

mvn de.evosec:export-dependencies-maven-plugin:buck

It will convert your pom

<project
    xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>de.evosec</groupId>
    <artifactId>buck-single-dependency</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>18.0</version>
        </dependency>
    </dependencies>
</project>

to a target/BUCK file like this

java_library(
  name = 'COMPILE',
  visibility = ['PUBLIC'],
  exported_deps = [
    ':com.google.guava-guava-jar'
  ],
)

java_library(
  name = 'OPTIONAL',
  visibility = ['PUBLIC'],
  exported_deps = [

  ],
)

java_library(
  name = 'PROVIDED',
  visibility = ['PUBLIC'],
  exported_deps = [

  ],
)

java_library(
  name = 'RUNTIME',
  visibility = ['PUBLIC'],
  exported_deps = [

  ],
)

java_library(
  name = 'TEST',
  visibility = ['PUBLIC'],
  exported_deps = [

  ],
)

prebuilt_jar(
  name = 'com.google.guava-guava-jar',
  binary_jar = ':remote-com.google.guava-guava-jar',
)

remote_file(
  name = 'remote-com.google.guava-guava-jar',
  out = 'com.google.guava-guava-jar-18.0.jar',
  url = 'mvn:com.google.guava:guava:jar:18.0',
  sha1 = 'cce0823396aa693798f8882e64213b1772032b09',
)

And then you can use a BUCK file like this to build your project

java_library(
    name = "main",
    srcs = glob(["src/main/java/**/*.java"]),
    resources = glob(["src/main/resources/**"]),
    resources_root = "src/main/resources",
    exported_deps = [
        "//target:COMPILE",
    ],
    deps = [
        "//target:OPTIONAL",
    ],
    provided_deps = [
        "//target:PROVIDED",
    ],
)

java_test(
    name = "test",
    srcs = glob(["src/test/java/**/*Test.java"]),
    resources = glob(["src/test/resources/**"]),
    resources_root = "src/test/resources",
    source_under_test = [":main"],
    deps = [
        ":main",
        ":test_utils",
        "//target:TEST",
        "//target:OPTIONAL",
        "//target:PROVIDED",
    ],
)

java_library(
    name = "test_utils",
    srcs = glob(["src/test/java/**/*.java"], excludes = ["**/*Test.java"]),
    deps = [
        ":main",
        "//target:TEST",
        "//target:OPTIONAL",
        "//target:PROVIDED",
    ],
)

This was running for a while but I never got around to trying to get Buck to produce WAR files or build our GWT projects. In the end I realized that the increased complexity is too high a price for the promised speed-up of our builds. At the end of the day we’re just a small dev shop with “average” developers.