Reviewing a Record Number of Submissions for RSECon26

Posted on Fri 26 June 2026

I am currently chair of the talks team for RSECon26. This year, we had a record number of submissions, which made the selection process incredibly hard—we had to reject so many excellent submissions because we did not have enough space in the schedule.

Since several people asked us about how the selection process works, I wrote an explanation including a few statistics to illustrate the incredibly high average quality of submissions. Go ahead and read it over on the Society of RSE’s website!


rebeccapurple

Posted on Sun 07 June 2026

Since the early years of web standards, Eric Meyer was an important advocate for and contributor to CSS. In 2014, after his daughter died of cancer, the web standards community added her favourite colour to the CSS specification in her memory.

It is now called rebeccapurple.


For this site’s theme, I use rebeccapurple a lot. Partly because it’s one of my favourite colours. And partly as a reminder: Even something as seemingly dry as a web standard specification is written by humans. Humans form communities. And every web standard—every technology—embodies the values of its community. Sometimes in hidden ways, sometimes in visible ones.

Everytime I see this colour, it’s a gentle nudge to myself to help shape communities in line with my values.


Also: Fuck cancer.

Seriously.


Bowie

Posted on Thu 08 January 2026

I’ve lost track of the number of times I’ve realized that a song I’ve heard on and off for years (on the radio, in movies, in cover versions from other artists, …) was actually by David Bowie.

A few years ago, I spent six weeks listening through his studio albums in chronological order. It was pretty awe-inspiring how one person could dabble in so many genres over the decades, yet always have something interesting to contribute—how, independent of genre, he was always so clearly himself. This multifacetedness makes it almost impossible to pick a favourite song. I like the sci-fi weirdness of Space Oddity, sure; but I equally enjoy the crooning in “Heroes”, the theatricality of Life on Mars, the glam rock of Moonage Daydream, and so many others. Yet, perhaps my real favourite is Hallo Spaceboy, from 1995’s 1. Outside album: It completely blew my mind right from the start—Bowie is doing Industrial?—and then blew my mind a second time at the awkward queer yearning of the lyrics.

This week, ten years after his final album release and his death, feels like a good time to re-listen to this old Incomparable episode celebrating Bowie’s life and career.


X

Posted on Wed 03 December 2025

A year ago today, I went to the Standesamt (German equivalent of the register office) with my long-time girlfriend. No—not to get married. But rather, to finally fix a mistake someone had made decades ago on my birth certificate.

I’m non-binary. I’ve been out in all areas of my life for about 7–8 years, among close friends for almost 10; and I’ve been wondering about my gender identity long before that.1 For most of that time, however, it seemed impossible to get this officially acknowledged. In 2021, when the then-incoming German government announced plans to introduce gender self-determination, I was elated and anxious to see details and impatient. When the law finally came into effect in 2024, it was flawed but so much better than the slow, expensive and deeply invasive process it replaced. And, most importantly to me, it finally recognised non-binary gender identities on equal footing with binary ones.

The same night that the law came into effect, I emailed the Standesamt to register my intent to correct my gender marker. Some bureaucratic back and forth and a mandatory three-month waiting period2 later, I finally got an appointment for December 3rd, 2024. In the weeks leading up to it, I oscillated between excitement and anxiety—what if there is some unexpected hurdle? What if …? What if …? … On the day, waiting in the hallway of the Standesamt before my appointment, I was getting incredibly nervous. My heart was in my throat; I was staring at paintings hanging in the hallway but they barely registered; only holding my girlfriend’s hand helped me make it through moment after moment until—a few minutes delayed—I was invited into the office.

The appointment itself went about as well as I’d hoped. Confirm the chosen name and gender, sign the form, pay the processing fee and voila!—after a decade of waiting, I was finally, officially, government-recognisedly non-binary! 🎉

After that, it took a week or so to get a corrected birth certificate and another couple of weeks to receive a new passport which says “Geschlecht / Sex / Sexe: X”. And it’ll take many more years for certain companies or governments to recognise that X. But to hell with them. I’m proud to be non-binary. I’m proud to break their buggy databases. And today, I have an anniversary to celebrate.

💛🤍💜🖤

  1. In hindsight, there were signs for at least 20 years; maybe more. ↩︎
  2. I did mention the new law still had flaws … ↩︎

A Year as an RSE

Posted on Sun 09 March 2025

Just over a year ago, I started a new job.

Since 1 April 20201 I had worked as a postdoc in the EPAP group at King’s College London. It was a fantastic opportunity to research astro- and particle physics; to work with many excellent colleagues on Hyper-Kamiokande and SNEWS 2.0; and to travel the world for conferences and collaboration meetings. Over the coming years, however, I started to get restless. More and more, I noticed that I loved collaborating on open-source software more than any other parts of the job (except, perhaps, the travel)—and while I got to do this as a postdoc, I had very few options to advance in academia while staying focussed on software development.

Several unsuccessful fellowship applications and months of soul searching later, a KCL-internal newsletter advertised job opportunities in a brand new Research Software Engineering team. I jumped on the opportunity, applied despite some chaotic circumstances2, aced the interview and got a job offer.

During the whole application process I was both excited and apprehensive.

On my first day, the head of the RSE group welcomed me at reception, gave me a quick tour of the office and then took me aside while we were grabbing coffee: “I wanted to check—how do I pronounce your name correctly?” I tell him. “Jost, okay. And your pronouns are they/them?” I confirm, quite surprised. “Yeah, I saw that in your email signature. We’ve already been using they/them internally when talking about you; but if we ever mess up, please do correct us!”3

And from that moment, I was certain I had made the right choice.


After that, the first year was a bit of a blur.

Day two, I jumped in at the deep end and helped run an Intro to HPC course. I then did more teaching throughout the year, became a certified Software Carpentry instructor and started contributing to an intermediate course on Python optimisation.

I worked on projects ranging from cardiology to chemistry to internal tools for our larger e-Research group, all while continuing to contribute to astroparticle physics projects I’d worked on as a postdoc. I wrangled C++ build systems, made breakthroughs using NumPy’s array broadcasting, learned a lot about modern HTML/CSS/JS and explored complex PHP web frameworks. Through all that, I almost entirely got rid of the impostor syndrome I’d struggled with because I didn’t have any formal computer science training.

I started a book club with my colleagues. Joined the Society of RSE mentoring scheme, where Yo Yehudi was a fantastic mentor and helped me feel at home in the RSE community. Wrote an (unsuccessful, for now) funding proposal to start an RSE network across the Circle U university alliance, then a successful smaller-scale proposal for a collaboration between KCL and a single other institution.

I still got to travel—for RSE-related conferences like RSECon 2024 and FOSDEM 2025, of course, but also for physics-related events (a SNEWS 2.0 Hackathon and a DSNB workshop).

… and I did many, many more things.

My initial apprehension was completely unfounded. The atmosphere in our RSE group is warm and supportive. I get the benefits of working from home most of the time, but still look forward to the one day every week (or two), where I meet my colleagues in the office. I enjoy the variety of projects to work on and technologies to learn about.

I am certain: I have made the right choice.

  1. What a time to start a new job! ↩︎
  2. The application deadline was in the middle of a Hyper-K collaboration meeting where I would be in Japan. Since the run-up to these meetings is often quite busy, I wrote much of my cover letter at Shanghai airport, jet lagged and waiting for the connecting flight to Tokyo. Then I realised that, while I had a current CV, I’d have to rewrite much of it since it was tailored for academic positions in physics; so I rewrote my CV the following day, still jet lagged, in a hotel room in Toyama. ↩︎
  3. And to this day, every single colleague in our RSE group has gotten my pronouns right every single time. ↩︎

“Clean Code” Book Club: Conclusions

Posted on Mon 04 November 2024

The final chapters of Clean Code contained step-by-step examples for code refactorings in chapters 14–16, as well as a list of rules in chapter 17. Both were not quite suitable for the format of a book club, so we worked through one of the refactoring chapters together but stopped after that.

Now that we’re done, I spent the past six weeks or so pondering how I feel about this book. My initially high hopes for the book were disappointed by chapter 2 or 3. Over the following chapters, I increasingly found myself wondering, who this book is for. I wouldn’t recommend it to experienced programmers, who would get very little out of it. I certainly wouldn’t recommend it to beginners—while there is plenty of good advice here, there’s also enough bad advice1 and utterly terrible example code that it might do more harm than good. Maybe an intermediate Java programmer might get something useful out of it? But for RSEs like us, it was definitely not a useful book.

Despite all that, I still enjoyed the book club immensely. I’m a physicist by training; and while I got a lot of experience writing software during my PhD and postdoc, I received almost no formal training in software development. Being self-taught used to give me impostor syndrome—still does, sometimes—especially when I started working as a Research Software Engineer. Reading through this book, realizing I was already familiar with most of the contents, discussing it with colleagues and being able to make convincing arguments where I disagree with advice in the book … all this gave me a lot more confidence. More confidence, almost certainly, than I would’ve gotten from reading a better book.

So for me, at this particular time in my life, this may have been just the right book? Very strange, indeed.

  1. or at least, advice that should be taken with far more grains of salt than the disclaimer in chapter 1 provides ↩︎

“Clean Code” Book Club: Chapters 10–13

Posted on Wed 11 September 2024

Continuing with our book club on Robert Martin’s “Clean Code”, in July and August we’ve discussed chapters 10 (“Classes”) to 13 (“Concurrency”). (As usual, this post collects most of my notes and some points from our group discussion; completeness is explicitly a non-goal.)

Chapter 10: Classes

This chapter was written by Robert Martin together with Jeff Langr.

The first rule of classes is that they should be small. The second rule of classes is that they should be smaller than that. (p. 136)

That’s a less than auspicious way to start the chapter.

However, instead of using lines of code, this chapter uses responsibilities of a class as a measure. This is far more reasonable, since it’s actually related to code cleanliness. As a guideline, it cites the Single Responsibility Principle:

a class or module should have one, and only one, reason to change. (p. 138)

That is good advice in principle; but once again, we find ourselves struggling with a philosophical question: What is one reason? How fine-grained do we define our concepts? The authors advocate for a very fine-grained approach, using the metaphor that we want our tools neatly organized into toolboxes instead of in a single jumbled pile. However, I’m wary of overdoing it, since a proliferation of toolboxes can become overwhelming, too! (Imagine if—instead of a drawer for kitchen utensils—your kitchen had separate drawers for whisks, for slotted spoons, for mixing spoons, for potato mashers, for ladles, for spatulas, for measuring spoons, for skimmers, for graters, etc.)

Cohesion is suggested as a useful indicator: High cohesion indicates that all parts of a class operate together (or “change for the same reason”), while low cohesion indicates that a class might be split into multiple, more cohesive parts. This discussion made me wonder whether there are tools to visualize code cohesion. (Though if we make our classes as small as the authors would like us to, it’s probably fairly easy to determine the cohesion with a quick look over the code.)

Also, there were several editing issues in code listing 10-10 (for example, the order of subclasses differed from order of functions in 10-9, for no discernible reason; and it looks like a few lines in the PlaceholderList and PrepareInsertSql classes were deleted accidentally, so both classes got smushed into each other).

Chapter 11: Systems

Since the contents were highly Java-specific and not transferable to any other languages, we skipped this chapter in our book club. (Several of us noted that this chapter felt very out of place in the book, both in terms of writing style and target audience.)

Chapter 12: Emergence

This was a nice summary of many key aspects from previous chapters, so we didn’t have too much to discuss. I found it a little strange to have such a chapter located at this point in the book—it might have worked better to swap this with chapter 13, to close the first part of the book with this summary chapter, before getting into the worked examples in chapters 14–16.

Chapter 13: Concurrency

In this chapter, Brett L. Schuchert took up the unenviable task of summarizing concurrency in 13 pages (plus a 30 page appendix with more detailed code examples). Due to this short length, the chapter felt lacking in several areas: for example, there was no discussion of the distinction between multithreading and multiprocessing; and subsections on different execution models (Producer-Consumer, Reader-Writer, Dining Philosophers) or writing correct shut-down code contained brief descriptions of the problems, but no actionable advice. Both the Java-specific focus of the book and its age introduced further gaps, since many concepts or approaches that are more prominent in other languages or simply younger than ~15 years (async/await, promises and futures, actor model, …) were missing completely.1

Those inherent limitations aside, the chapter did a good job dispelling some myths and misconceptions around concurrency. I especially liked the example demonstrating (including the full byte code in the appendix!) how even a simple line of code like ++lastIdUsed; is non-atomic and can lead to threading issues.

Concurrency Defense Principles

Referring back to the Single Responsibility Principle (“A method/class/component should have a single reason to change”), this subsection highlights that concurrency design is a reason in its own right. Code to manage concurrency should thus be separated from domain-specific code. The three corollaries discussed here (limit the scope of data, use copies of data, threads should be as independent as possible) effectively lead towards a functional programming style; though sadly the author did not explicitly mention this.

Testing Threaded Code

To me, this subsection was a highlight of the chapter, containing clear descriptions of the problems in testing multithreaded code and actionable advice on solving them:

  • Treat spurious failures as candidate threading issues
  • Get your nonthreaded code working first
  • Make your threaded code pluggable
  • Make your threaded code tunable
  • Run with more threads than processors
  • Run on different platforms
  • Instrument your code to try and force failures
  1. That’s before we get into implementation details of individual languages, other than Java. E.g. most relevant to us, Python has a couple peculiarities like the Global Interpreter Lock (which enforces that only one thread at a time executes Python bytecode) and how it interacts with binary extension modules like NumPy. ↩︎

“Clean Code” Book Club: Chapter 9, Unit Tests

Posted on Sun 14 July 2024

Continuing with our book club on Robert Martin’s “Clean Code”, last week we’ve discussed chapter 9 (“Unit Tests”). (As usual, this post collects most of my notes and some points from our group discussion; completeness is explicitly a non-goal.)

Chapter 9: Unit Tests

This chapter—the only testing-related one in the book—focusses specifically on unit tests. There’s nothing here on integration tests; nothing on doctests; almost nothing on continuous integration or automation, except that tests should be “convenient to run”. And while the latter is understandable, given that the book was written over 15 years ago, it is a significant omission for a modern reader.

In the chapter’s introduction, Martin starts by describing an ad-hoc testing procedure common in the mid-90s, then lauding how the Agile and TDD movements have caused a “mad rush” to integrate testing into programming.

The Three Laws of TDD

While Martin is a strong proponent of Test Driven Development (TDD), I think his description of it here is doing TDD a disservice by being eyeroll-inducingly dogmatic:

First Law: You may not write production code until you have written a failing unit test.

Second Law: You may not write more of a unit test than is sufficient to fail, and not compiling is failing.

Third Law: You may not write more production code than is sufficient to pass the currently failing test. (p. 122)

So, on the one hand, Martin calls these “laws” and wrote them to be extremely prescriptive—he clearly wants us to take these literally. On the other hand, if we take these literally, then we’re never allowed to refactor our production code or test code; because refactoring, by definition, does not affect whether tests fail.

Kent Beck, who “rediscovered” TDD, wrote a much better summary of the process of TDD. To the above three steps (Martin’s “laws”), he adds a step 0 (think about the test scenarios to cover) and a step 4 (refactoring).1

Keeping Tests Clean

Test code is just as important as production code. It is not a second-class citizen. It requires thought, design, and care. It must be kept as clean as production code. (p. 124)

Yep.

Though I’d add that, typically, test code should be strictly simpler than production code. (And this, in turn, makes it easier to keep the tests clean.)

It is unit tests that keep our code flexible, maintainable, and reusable. (p. 124)

… because they enable us to make changes to our code, without having to worry about introducing new bugs by accident. We talked for a bit about our personal experiences where tests—or their absence—impacted how confident we were about making changes to code and how that impacted our development process.

A corollary: When we discover a bug, in addition to fixing it, we should think about how to improve our tests so they discover similar bugs in the future. We won’t be able to avoid making mistakes; but at least we can learn from them and try to fail better next time.

That can mean adding new unit tests for a currently untested part of the code; or covering an edge case we didn’t think about earlier; or adding new elements to our test suite (e.g. run the test suite under multiple operating systems, once we realized parts of our code are subtly OS-dependent2).

Domain-Specific Testing Language

I’m not completely sold on this. Yes, developing your own Domain-Specific Testing Language may make your tests look cleaner; but the price for that is a significantly increased amount of helper code. (At what point do you need to start writing a separate test suite to test your DSTL?)

While Martin doesn’t discuss this trade-off, his first example (listings 9-1 and 9-2) gives a good example where this approach helps produce cleaner code.

A Dual Standard

Then, however, we get to listings 9-3 and 9-4 … 😱

The “before” version of the code (listing 9-3) was pretty much fine; whereas Martin’s “improved” version in listing 9-4 is awful. From the terrible function name (wayTooCold();) to its unexpected side effect (executing controller.tic();) to the cryptic assertEquals(“HBchL”, hw.getState());, it breaks several rules that Martin himself wrote down earlier in this book. And perhaps worst of all—the code is hard to talk about.3

(The supposed main point of this subsection, by the way, was that the getState() function introduced for this DSTL is implemented in a cleaner but less efficient way. Martin argues that while this is not suitable for the embedded real-time system running in production, it is preferable for a more powerful test system. But yet again, this book is not making that point well because the example contains too many other distractions.)

One Assert per Test?

Here, Martin rejects the school of thought that claims every test should have only one assert statement; suggesting instead a “one concept per test” rule. After reading earlier chapters, I found this surprisingly pragmatic.

  1. I also much prefer his overall tone to the one Martin adopted in this section. Instead of Martin’s dogmatic commandments, Beck simply describes a pragmatic approach to programming. ↩︎
  2. “Of course the path separator in URLs and local file paths is always the same. I mean, no reasonable OS would use anything other than a slash as a path separator, right?” 🫣 ↩︎
  3. “The state is uppercase h, uppercase b, lowercase c, uppercase h, uppercase l but it should be uppercase h, uppercase b, lowercase c, lowercase h, uppercase l.” ↩︎

“Clean Code” Book Club: Chapter 8, Boundaries

Posted on Mon 17 June 2024

Continuing with our book club on Robert Martin’s “Clean Code”, last week we’ve discussed chapter 8 (“Boundaries”). (As usual, this post collects most of my notes and some points from our group discussion; completeness is explicitly a non-goal.)

Chapter 8: Boundaries

Here’s a boundary I like to set: I don’t want a sketch of a boy leering at a towel-clad woman in the bathroom in my programming books. The cover image for this chapter is kinda creepy.


This chapter, written by James Grenning, covers ways of interacting with third-party code (or even first-party code that’s not yet written; or that you don’t want to closely couple to).

One key point that came up again and again in our discussion was that not all dependencies are equal. On one hand, there are things like a logging framework—an example Grenning uses throughout this chapter—, where a typical application might use a small number of functions hundreds of times throughout the code base. On the other hand, there are dependencies like SciPy, where some piece of research software may use a mix of statistical functions, numerical integration or interpolation algorithms, constants and more: the overall API surface it’s exposed to is much larger, but most elements are used a small number of times or even just once.

Unfortunately, this chapter focusses solely on the first case; it does not discuss how to identify cases where these approaches may not be appropriate. I was also missing a more nuanced discussion of the downsides of the approaches advocated in this chapter.

Using Third-Party Code

Providers of third-party packages and frameworks strive for broad applicability so they can work in many environments and appeal to a wide audience. Users, on the other hand, want an interface that is focused on their particular needs. (p. 114)

The example here is a good illustration:

public class Sensors {
    private Map sensors = new HashMap();

    public Sensor getById(String id) {
        return (Sensor) sensors.get(id);
    }

    // ...
}

The Sensors class is a Map of individual sensors; but instead of exposing the full API of Java’s Map to the caller, it encapsulates the actual Map and provides its own, more limited API.

This interface lets the Sensors class explicitly enforce design and business rules; e.g. ensuring that any object added to the Map is of the Sensor type. It also allows the Sensors implementation to change over time, without changing the interface exposed to callers.

On the other hand, if the interface is too restricted, it could be frustrating to callers. E.g., if I had a Sensors class in Python, I’d expect it to support language idioms like

for sensor in sensors:
    # do something with each sensor here

and the class would feel terribly broken if that didn’t work.

Another potential downside is inconsistency: Over time, developers become familiar with the interface of common data structures (like maps, lists, etc.) in their language; so if Sensors inherits the interface of Map, they will be able to pick that up instantly. However, if Sensors implements its custom API that deviates from the familiar interface (e.g. by having a function getByID instead of get), it has a much steeper learning curve.

Now, whether the advantages are worth these trade-offs depends on the context: Developers on a large corporate Java app may value the enforced structure higher; whereas I, as maintainer of open-source scientific Python codes, prefer a more familiar interface for occasional users or first-time contributors. However, it’s a little disappointing that the book did not acknowledge these trade-offs.

Exploring and Learning Boundaries / Learning log4j / Learning Tests Are Better Than Free

These three closely related sections have led to extensive discussion during our book club. There were several points here, that we were really struggling with.

First, the suggestion that every project should write their own custom wrapper for log4j. A convenience function to set sensible defaults during initialization? Sure. But a full wrapper? That may make sense in some situations—but as above, it comes with trade-offs that the chapter simply doesn’t acknowledge. And for a dependency like SciPy, writing my own wrapper simply doesn’t make sense.

Next, we discussed “learning tests”. We commonly explore third-party code by playing around with it in the REPL before using it in our own code; but contrary to the chapter’s claim, writing tests still has a nontrivial overhead.1

We also weren’t sure, what benefit the “learning tests” are supposed to deliver. The sample code in the chapter only showed very basic tests that verify that the code executes successfully; i.e. that the log4j functions aren’t removed/renamed or get a completely different signature (such as additional required arguments). But in compiled languages, these are checks that a compiler would already perform, before even running the tests. More subtle semantic changes to an—outwardly identical—API may not be caught by the compiler; but even then, existing tests of your own code are effectively “integration tests” for your dependencies, that would catch such changes if they affect your own code.

So: What is the benefit of these learning tests? If I think about it for a while, I might come up with some edge case; but is that truly worth the ongoing cost (energy usage, time, complexity, …) of this significantly larger test suite?

Using Code That Does Not Yet Exist

This all seems sensible; and the Adapter Pattern introduced here can indeed be quite powerful. Unfortunately, as above, the chapter doesn’t discuss the limits of this approach. Sure, it works great if the API you’re mocking is fairly small—just a single function in this example. But what happens if you have a much more complex dependency, whose API design isn’t obvious?

  1. Though Java didn’t get an official REPL until 2017, long after “Clean Code” was written. ↩︎

“Clean Code” Book Club: Chapters 5–7

Posted on Tue 11 June 2024

Continuing our book club on Robert Martin’s “Clean Code”, over the past month we’ve started to rotate who leads the discussion on each chapter. When I’m not the discussion lead, my notes have been a bit less detailed. Accordingly, posts from now on may be shorter and less comprehensive; completeness continues to explicitly be a non-goal.

In this post, I’ll cover chapters 5 (“Formatting”), 6 (“Objects and Data Structures”) and 7 (“Error Handling”).

Chapter 5: Formatting

Pick a vaguely reasonable style, use it, be pragmatic about it. That’s it.

Robert Martin discusses his personal style preferences and thinking behind them in some detail in this chapter. Overall, it’s a reasonable style; but we didn’t discuss details since that would just risk devolving into bike-shedding.

Instead, we used most of the hour-long session to talk about our experiences with automatted tools. Code formatters like black, clang-format or others may be helpful; on the other hand, automated tools are notoriously bad at being pragmatic and may be more frustrating than helpful in some cases.

Chapter 6: Objects and Data Structures

Objects hide their data behind abstractions and expose functions that operate on that data. Data structures expose their data and have no meaningful functions. (p. 95)

Once you get used to the fact that Martin’s definition of “data structures” is different from what we typically think of as data structures, this distinction makes sense.1 Martin then explains nicely how data structures lead to procedural code; and how this makes it easy to add new functions that operate on these data structures, without having to change existing data structures. On the other hand, Martin explains, objects enable object-oriented code, which makes it easy to add new objects without having to change existing functions.

This complementarity is quite elegant; however, we discussed in the book club that it’s not always helpful in practice. Research software is often quite exploratory, so when writing some initial code, it may be uncertain how it will be extended in the future; or it may be necessary to add both objects/data structures and functions.

The Law of Demeter

This section led to a lot of discussion and we were somewhat sceptical.

For one, method chaining is not bad per se; while it may be considered sloppy style in Java, it is a very established pattern e.g. in jQuery (which is explicitly designed to enable this).

But more importantly, we were not convinced by the law itself. According to the Law of Demeter, Martin says, the following code …

Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDir();
final String outputDir = scratchDir.getAbsolutePath();
String outFile = outputDir + "/" + className.replace('.', '/') + ".class";
FileOutputStream fout = new FileOutputStream(outFile);
BufferedOutputStream bos = new BufferedOutputStream(fout);

… is bad form, because it knows too much about the objects returned by getOptions() and getScratchDir(). But passing those returned objects as an argument into a helper function, which then knows the exact same things about these objects, would supposedly be fine. I’m sure there are more complex examples with a layered architecture, where this would make sense. But in this specific example that would just add unnecessary layers of indirection to obey a constraint that feels arbitrary.

In Martin’s defense, he doesn’t propose adding helper functions. Instead, he suggests creating another function on the ctxt object. Naïvely, one might come up with a ctxt.getAbsolutePathOfScratchDirectoryOption(); function as a direct replacement for ctxt.getOptions().getScratchDir().getAbsolutePath();. However, exposing all chained functions like that would lead to a combinatorial explosion.

Instead, Martin considers how that scratch path is actually used by the calling code, and recommends a function that specifically fulfills this use case:

String classFileName = className.replace('.', '/') + ".class";
BufferedOutputStream bos = ctxt.createScratchFileStream(classFileName);

The downside here, which Martin ignores, is that as different use cases appear, this could equally lead to an explosion of methods on the ctxt object. (And what’s more, it requires the ctxt object to be aware of any higher level code calling it and to change in response to changes in higher level code. Not a great software design.)

Chapter 7: Error Handling

Error handling is important, but if it obscures logic, it’s wrong. (p. 103)

Leaving aside some Java-specific bits that weren’t applicable to other programming languages that our group commonly uses, this was an interesting chapter that sparked some good and nuanced discussion in our book club.

Use Exceptions Rather Than Return Codes

In principle, we agreed that exceptions—where available—are preferable to return codes.

The code example for this section quite nicely separates error handling from application logic. However, it assumes that all we do in response to errors is to log them. What if we want to handle the errors in other ways, e.g. by restoring a previous state or prompting the user for input? That would by necessity mix error handling and application logic.

Write Your Try-Catch-Finally Statement First

We agreed it’s typically a good idea to think about the overall structure first (What am I going to do? How can it fail? How do I handle failure?), before writing the implementation details. However, the example goes far beyond that, giving step-by-step instructions on how to do test-driven development (TDD). That is rather beside the point here and doesn’t make much sense without explaining the motivations for using TDD, which will only be covered in a later chapter.

Define Exception Classes in Terms of a Caller’s Needs

Often, the caller doesn’t care and doesn’t want to know about the details of how an operation failed; it just matters whether it did, in fact, fail. Adding a wrapper class to hide away those details, as recommended in this section, works well enough in those cases. On the other hand, it would usually be preferable if the library implements a class hierarchy of exceptions. That way, callers can choose whether to look out for, e.g., a generic ConnectionError or whether to handle each ConnectionError subclass (ConnectionAbortedError, ConnectionRefusedError, etc.) individually; all without having to write their own wrapper.

Define the Normal Flow

Hm … on the one hand, this concrete example looks cleaner when using a default value. But on the other hand, picking a particular default value is tying the implementation of the ExpenseReportDAO class very closely to the higher-level business logic using it, which could lead to severe issues. For example, what if the business logic requires a different default value in some other circumstances? (E.g., when claiming expenses for conference attendences, the default is a per diem; but when claiming expenses for hosting a visitor, there is no per diem.) Or what if the per diem varies by location and needs to be entered by the admin staff manually?

If the ExpenseReportDAO class raises a MissingExpensesError and lets the higher-level business logic handle it differently depending on context, that’s all straightforward to implement. But if it returns a fixed default value automatically, handling other cases becomes much more difficult. (Perhaps even impossible, if the calling code can’t distinguish between, say, a per diem of £30 and actual expenses that happen to sum to £30.)

  1. Some details of this chapter were very Java-specific. For example, in Python it’s common to access member variables directly, rather than defining getters and setters; there is also no enforced distinction between private and public variables. In practice, though, naming conventions (e.g. using a leading underscore for “private” variables) or documentation usually fulfill that function well enough, so the main points of this chapter apply in Python, too. ↩︎