PurelyFunctional.tv Newsletter 346: Tip: just throw ex-info

Sign up for weekly Clojure tips, software design, and a Clojure coding challenge.

Issue 346 - September 30, 2019 ยท Archives ยท Subscribe

Clojure Tip ๐Ÿ’ก

just throw ex-info

Special thanks to Sean Corfield for this tip!

Last week I recommended you explore the basic hierarchy in Java that starts with Throwable at the top. The JVM requires that anything you throw be an instance of Throwable (that means of type Throwable or any of its subclasses). It's important to understand that hierarchy so you know what to catch. Java defines quite a lot of exceptions for different problems that could happen.

However, in the Clojure world, this is generally seen as a mistake. The Java standard library enumerates all of these different problems, creating a class for each one. It then organizes them into a hierarchy, presumably for the convenience of being able to surgically catch large swaths of them with a single catch statement. But did they get the hierarchy right for your software? And anyway, what can you do with those nice errors Java throws for you?

Let's see.

Would you expect a FileNotFoundException to have a method letting you know the path of the file that wasn't found? I would. Does it have that method? No.

Or what about MimeTypeParseException. Shouldn't it tell you what MIME type it tried to parse? But it doesn't.

When you examine it, most exceptions don't contain any information specific to the situation. Nothing to help you debug the problem (if it's a bug) or fix the problem (if it's an expected situation). In fact, the only difference between them is their classname. The exception hierarchy is a glorified, hierarchical enumeration.

That's one of the reasons we just use ex-info in Clojure. ex-info is a function that creates an ExceptionInfo. It's a subclass of RuntimeException that has a message and data. The message is a human-readable string. And the data is whatever you want. I usually use a map. I throw information in there that I might want later. Sometimes, if I need to distinguish different exceptional situations, I'll throw a piece of data in there I can dispatch on. Then you throw it. The examples on the clojuredocs page are pretty good.

ex-info is a great example of how Clojure smoothes out some of the warts of its host.

Book discount ๐Ÿ“–

I got a package in the mail last week. It was from Manning, my publisher. Guess what was in it?

Eight of these puppies.

Buy the book. BTW: That 50% discount works on everything at Manning.com. Copy this: TSSIMPLICITY.

If you take a selfie with me wearing it and post it to Twitter, Manning will send you a present!

Currently recording ๐ŸŽฅ

Oy! My course Property-based Testing course is tough. I have made much progress on the distributed systems testing lesson. But nothing published this week.

Distributed systems testing is hard. You know it's hard. That's why we need special tools to do it. I have built a distributed system that you can use, complete with a server and a client. And now I'm testing it. I am successfully testing it. But I want to fully grok it before I record this episode to that you can learn the maximum from this lesson. There are lots of wrinkles and each needs to be addressed.

I don't want to oversimplify this subject. It's hard and you deserve superpowers. Distributed systems are hard (impossible?) to test with example-based testing. But how do you ensure that a system is eventually consistent? How do you ensure that no data is lost when there are conflicts? Can you exercise a system to find the synchronization bugs?

Yes. And we're going to do it in this course.

BTW: the only way to get the course now is to get a membership. Do it!

Brain skill ๐Ÿ˜Ž

feedback

Work it harder, make it better Do it faster, makes us stronger More than ever, hour after hour Work is never over --- Daft Punk

Programming is hard. There's so much to learn. You're learning the environment. You're learning the language. You're learning the development tools. You're learning your codebase. And you're learning your problem domain. There's learning and unknown stuff all the time.

One of the best things you can do to help you learn is to increase the frequency and information density of feedback. When I look back to the most stressful, more time-consuming debugging sessions, it's always debugging with very little feedback. In those cases, I've got a long edit-compile-run cycle. I've got to run the code, click around, enter some text, before I can even get to the problematic part of the system. And then I'm getting tiny bits of information. Maybe the only piece of information I get is "the problem isn't on line X". Slow and sparse feedback is stressful.

Spend time to optimize your workflow for speed of feedback. Work in smaller chunks---whatever size chunk is a slight challenge for your mind. Get lots of information---pretty-print data structures, do lots of println debugging. Get more information out of the system. Write code that exercises exactly the part you want. Do you want to run one line? Do it. One function? Do it. A whole flow? Do it. Remove human input from the process. You are only slowing the process down if you have to fill out fields and click around.

Bottom line: harder, better, faster, stronger.

Clojure Challenge ๐Ÿค”

Last week's challenge

The challenge in Issue 345 was to make a higher-order function that rate limits the given function using a token bucket.

You can check out the submissions here.

This week's challenge

exponential backoff

Our computers have real limits. Limited memory. Limited threads. Limited computations per second. Etc. We often treat our systems like they have unlimited resources, which is fine, until they get overloaded with work.

Two weeks ago, we wrote a higher order function to retry a function three times if it failed. However, if a function fails because the system is overloaded, trying again immediately is not going to help anything. In fact, it could make it worse.

A better response would be to wait a time before trying again. If it still fails, double the time and try again. Then double again, etc, until a limit is reached. This is known as exponential backoff.

Your job this week is to implement exponential backoff. Extra credit if you can tell it how long to wait before ultimately giving up.

As usual, please send me your implementations. I'll share them all in next week's issue. If you send me one, but you don't want me to share it publicly, please let me know.

Rock on!
Eric Normand