Category Archives: Books

Reducing Technical Debt: Top Five Coding Resources

When I wrote my book about technical debt, I decided to concentrate more on personal mindset, team dynamics, and organizational influence. I did this because I thought that the coding aspects of paying technical debt were well-covered, and that I could just refer to them.

Even with these resources, I had still been on teams that struggled with more foundational questions of whether code was debt at all, whether it was worth paying, how to explain it to our management, and how to prioritize and plan projects to do something about it. That’s what my book is about.

If you want to read some free chapters of Swimming in Tech Debt, sign up here:

Here’s my list of resources that are helpful when you need practical steps for addressing tech debt that you have identified and prioritized.

These resources cover Seams, Refactoring, Substitutions, Accretions, and Tidyings. A full toolkit of techniques to tackle debt.

#1: Working Effectively with Legacy Code [ad] by Michael Feathers. In this book, Feathers defines legacy code as code without tests. So it makes sense that the bulk of the book is the description of techniques for adding tests to code that wasn’t designed to be testable. Feathers introduces the concept of a seam, which is code you add to a function that makes it possible to control what that function does from an external source. The key point is that, in production, its behavior is completely unchanged.

Here’s a trivial example to illustrate a seam. It will seem like overkill, but the technique is useful in real-world code. Given a function like this:

def calculate_sales_tax(amount, zip_code):
  rate = db_lookup_sale_tax_for_zip(zip_code)
  return amount * rate

In a codebase without tests or database mocking, functions like this are risky to change. The goal is to get it under test before we refactor it, so let’s do it with a seam to learn the idea.

The first step is to change it to this:

def calculate_sales_tax(amount, zip_code):
  rate = 0.08
  if not TESTING:
    rate = db_lookup_sale_tax_for_zip(zip_code)
  return amount * rate

By adding the if not TESTING: we’re accomplishing two things:

  1. We have not changed the production code
  2. We have made the code testable

So, the next two steps are to add tests, and then to refactor (which is safer because the code is under test). To see the utility of seams, you have to imagine doing this systematically in the giant spaghetti functions you find in legacy codebases. Also, in the book, Feathers shows more sophisticated ways to do this than just an if statement.

The beginning of the book sets up the seam concept, and the bulk of the book is examples of how to do this with more realistic code. This is the best “How To” book for tackling technical debt in legacy projects that I have read, and its existence meant that, in my book, I could concentrate more on the questions of “When to” pay technical debt and “Who should” do it.

The point of a seam is to make refactoring safe. So, the next book on this list is the seminal work on refactoring.

#2: Refactoring: Improving the Design of Existing Code [ad] by Martin Fowler. The main contribution of Refactoring was to make the term (“refactoring”) ubiquitous. Unfortunately, even Fowler had to admit, the term is often misused. Whenever you go to daily update, and someone mentions refactoring, you could be sure that they are not doing what Fowler described.

To Fowler, a refactoring is a tiny act. His book catalogs about a hundred types. Examples include Renaming a Variable and Extracting a Variable. Each of these takes seconds. The more complex ones might take minutes. Hardly something you’d avoid or mention. Refactoring is something you are meant to do all of the time. Assuming, of course, that your code is under test.

You can freely refactor in code that is under test because the point of a refactoring is to improve the code without changing the behavior. It’s quick because the verification is automatic. Without that, safe refactoring would take longer because you need to write tests first.

So, enabling refactoring might take time. Instead of saying that you are refactoring, a more correct thing to note in your updates is that you are automating tests on code that you need to change, so that you don’t introduce regressions. In addition, you are reducing the chance of problems being found in review or QA. This is something that does take time, but also has value. If you label this activity “refactoring”, you risk being asked not to do it.

In my book, I talk about refactoring along with the more expansive idea of Substitution, which comes from Barbara Liskov and was formalized in her paper with Jeanette Wing.

#3: A Behavioral Notion of Subtyping by Barbara Liskov and Jeanette Wing. This paper is about how to design classes in an object-oriented language so that they can be subtyped safely (and how to do that subtyping). It’s related to the ideas in design by contract and opposes the notion of allowing for breaking changes. Liskov substitution is about replacing components in systems where you cannot (or will not) update the rest of the codebase to accommodate them.

It does this through subtyping, but I have always interpreted it as applying to almost any change I make to a system, not just class inheritance. In Object-Oriented programming, subtyping is one way to add new functionality to a codebase, but in my experience, it’s not the main way. In my current work, I don’t use OO or subtyping much at all. But, I substitute code all of the time.

In the paper, the authors describe a way to subtype that is safe to deploy because it does not violate any assumption in the system. This way of thinking applies to any change you might make to code. If you can, it’s better to change the code in a way that doesn’t invalidate all of your other code. Or, if you must, you know that you aren’t “substituting” any more, and there’s a lot more work to do.

Like a refactoring, a substitution should not break tests, but unlike a refactoring, substitutions do not aim to preserve all behavior. In fact, the entire point of a substitution is to add functionality. The paper describes how to do it safely.

To sum it up, your new code will be substitutable for your old code if (in addition to any language syntax requirements): (1) it does not add required pre-conditions to the caller, (2) does not break promised post-conditions, (3) does not violate any invariants, and (4) does not mutate anything assumed to be immutable.

The paper is formal and might not the best entry-point. But, the Liskov Substitution wikipedia article describes it well, and if you want to read more about how I apply substitution to any code change, I cover that in Chapter 5 of my book.

Another great entry-point on this subject is the video Spec-ulation by Rich Hickey

#4: Spec-ulation (video) by Rich Hickey. In Spec-ulation, Rich Hickey talks about the concept of accretion and how to use it to grow software. Accretion is related to substitution and refactoring and is another way to approach changing code (to pay off tech debt, for example).

Rich makes two interesting (and related) points about accretion. (1) like Liskov, he defines safe actions such as “doing more” and “requiring less”, which map to pre- and post-conditions (2) additionally, he argues that Clojure’s syntax makes many more accretions (i.e. substitutions) non-breaking.

In her definition of substitution, Liskov states that all compile-time, syntax, or language level errors introduced by new code are (by definition) non-substitutable. The paper is about “behavior” breaking substitution that is syntactically correct, but will fail at runtime.

For example, in C, if you add a new parameter to a function, that function is not substitutable because all callers need to be changed. In languages like Clojure, adding a parameter is not a syntax error because there is a default and callers don’t need to change. Rich’s talk is about the many syntax affordances in Clojure that allow future accretion (and is a warning about using new tools to subvert them).

He argues that language features like strong type checking, which offer compile-time correctness, limit software growth through accretion because changes that would be non-breaking (and safe) cause syntax errors. This can work well if you control all of the code and can update it. But it causes problems in public code libraries. Clients cannot upgrade their dependencies to get bugfixes and new features if that means their build will be broken for code that was working fine.

The takeaway here is to look at your language’s features and see some of these affordances as a way to pay off tech debt safely. For example: one, often overlooked, feature is namespaces. Using them, you can keep old and new (replacement) code running side-by-side until you are sure it’s ok to remove the old one.

I learned so much about growing code from Kent Beck in eXtreme Programming: Explained, but a more recent book from Beck is more specific to technical debt.

#5 Tidy First?: A Personal Exercise in Empirical Software Design [ad] by Kent Beck. This book builds on Beck’s previous books and the ones inspired by them (like Refactoring). In it, he introduces the idea of a tidying, which like a refactoring, aims to improve code without changing behavior. It is also meant as something to be done all of the time and to be quick and safe (because of tests).

Tidyings, if possible, are even smaller than refactorings. They are more about making code more readable now rather than making it easier to change (which refactorings do). Tidyings are things you can do to help you be a more active reader of code. For example, getting the reading order right and using whitespace better to chunk the code. Kent describes it as a way to get back into the original spirit of refactoring (tiny, safe changes that don’t alter behavior).

With seams, refactorings, substitutions, accretions, and tidyings, you can do a lot to improve a codebase and make it easier to change. This reduction of resistance to change is what I mean when I say to pay tech debt, and these resources detail the main ways I do it.

My Current (late 2025) Interleaved Reading List

Yesterday, I wrote about Interleaved Reading (reading multiple books at once) and how it gives me a chance to reflect and retain a book’s contents. I try to pick very different books so that I have one to pick back up to match my energy.

I started Hypermedia Systems [affiliate] to give me a foundation on HTMX for a new project. A couple of chapters in, I decided to just try it. Now that I have something working, I went back to read the more advanced chapters. I like learning new tech this way rather than just reading because the building reinforces what I read. I also don’t want to just build because books like this are also about mindset, architectural patterns, and theory. Now that I have something working, I’ll just read the book through and should be done soon.

Earlier this year, I went to Germany and I wanted to be able to speak a little German while I was there. I had three months, so I crammed with DuoLingo and picked up Fluent Forever [affiliate] (here’s my review of it and the Fluent Forever app). There was no way I could implement that whole book in three months, but it did really help.

When I got back from my trip, I decided to switch to Spanish. I’ve been doing that for about six months and I’m ready to resume the book for more tips. This is a book I am reading just enough to implement the technique and then putting down. It might take months to finish.

I decided to pick up The Inferno [affiliate] by Dante (Cialdi translation) because I heard that there were references to it in Severance. I technically started it by reading the front matter and the first chapter (Canto), but I haven’t been able to get it into my routine. I have a small trip soon with flights back and forth. I should be able to finish it then.

I got Thinking in Systems [affliliate] by Donella Meadows as research for Swimming in Tech Debt, but stuck to the chapters on feedback loops (which is why I was reading it). It was hard to put it down, but I had to, and now I’m finishing it.

Even though some books take a while to finish, I sometimes find a book that I just want to read and finish immediately. Mostly this is because there is some information in the book I need. For example, when I went to LA recently, I bought and read Radically Simple Strength [affiliate] by Paul Horn after hearing him on a podcast. I have been wanting to lift weights more seriously, but I always overdo it and then stop. Horn’s method sounded like what I needed, and I finished it on the flight. It’s been working so far.

Before I interleaved books, I might have not bought a new book or waited until I was finished with my current one. Now, it’s more natural for me to be juggling a few for different time periods, so I can always put them all down if I just want to finish one.

I don’t know why it took me so long to interleave my reading. I consume other media this way naturally (e.g. TV series, podcasts, blogs, music). It might have made more sense when I needed to physically have the book on me, but they are mostly in Kindle now (and so on every device I own), so I have them all with me and can switch whenever I want.

If you don’t do this, it might sound confusing, but since I am usually working to retain the knowledge in between reading, it’s actually easy to pick the book up again.

Interleaved Reading

After graduating college, my book choices have been self-determined, and for a long time, I read them serially. This is weird because up until then I was always reading more than one book at time (by necessity).

But, a few years ago, while researching learning methods and incorporating spaced-repetition (i.e. flash cards) into my life, I saw a recommendation to interleave reading. The idea is simple: You read more than one book at a time. This might be obvious to some, but it wasn’t to me. It was liberating.

One problem of reading a book all the way through is that you don’t have time to consider a chapter before moving on. When you interleave books, you have time to ruminate on them in the background. Better than that, you can use spaced-repetition to build flash cards that you practice before moving on. Then, while you are reading, the older chapters are periodically shown to you, reinforcing the whole book as you read.

Another exercise is to write your own synthesis of the chapter, applying it to your personal interests. This kind of note can be a blog post or a page in your Digital Zettelkasten. Over time, these original thoughts might build up to something bigger. For me, it was my book.

Finally, I read a lot of books that are meant to be used, not just read. They offer their own exercises. For example, here’s a post about the way I use The Artist’s Way, a quintessentially useful book, which encourages you to read a chapter a week and then do some work.

Before I did this, retention was hard. Now, it’s effortless (a few minutes a day in Anki) or the effort is welcome (it generates a blog post). But, it does mean I put books down intentionally, and so I need a different one to read while I work on retaining the first one.

(I meant to write about what I’m currently reading today, but I thought it would be good to write about this first so I can reference it. I’ll get to my current reading list tomorrow)

My Antilibrary

I buy books as soon as I think I will read them (usually from a recommendation), but it might take time for me to get to them. I used to lament this, but then I read this take. In The Black Swan: The Impact of the Highly Improbable [affiliate], Nassim Nicholas Taleb writes:

You will accumulate more knowledge and more books as you grow older, and the growing number of unread books on the shelves will look at you menacingly. Indeed, the more you know, the larger the rows of unread books. Let us call this collection of unread books an antilibrary.

Here’s what’s menacing me now from my antilibrary and will probably read soon:

  • Write a Must-Read [affiliate] by AJ Harper: This was recommended in my writer’s accountability group as something to read before you write a book. It’s too late for that, but I have a general interest in the topic. I’ve only had this for a week.
  • Software Productivity [affiliate] by Harlan D. Mills. I found a reference to this book in a reread of Peopleware [affiliate] almost exactly a year ago. It’s out of print, but I found a cheap used copy and got it. It’s been on my desk almost since then.
  • Vibe Coding [affiliate] by Gene Kim and Steve Yegge. I got this when it went on presale a few months ago. I better read this soon, because it will age quickly.
  • The Real Play Revolution [affiliate] by Ash Perrin. Ash is a clown who travels worldwide to refugee camps to entertain children. I saw him speak at PINC in Sarasota two years ago and bought the book there (mostly to support his efforts). There’s another PINC coming in a few weeks (Dec 11-13), which I highly recommend if you are in the area.

I usually read multiple books at the same time, picking up the one I have energy for at any given time. I try to keep them different from each other, but they are usually all non-fiction. I’ll write about that tomorrow.

Swimming in Tech Debt Book Update

I am aiming to be done with my book, Swimming in Tech Debt, by the end of May 2025. But, very soon, I will start to post edited excerpts. Until now, all of my posted excerpts have been first drafts, but I’ve been working with a professional editor who is helping me make the manuscript better. If you want to read those excerpts, sign up here:

Applying My Book Selling Content Strategy to Social Media

This is the final part of a series on how I am marketing my book via content generation.

In this final part, I will talk about Social Media, which I treat as a mix of Part 2 and Part 3. I have a feed that I control, but it’s mixed into a communities with norms. Posts are conversation starters, and the comments replying to them should be on-topic. I treat each social media site differently, but a common thread is that I try not to link to my work, and I make each post or comment self-sufficient and useful in the reader’s feed.

Mastodon: I used to post to Mastodon rarely, but I have recently begun to understand it better. I only follow software developers and people I know in real life (who, on Mastodon, seem to skew towards being software devs). If I post something personal, I don’t use hashtags. But, for anything that I think would be interesting to software developers, I use hashtags to cast a wider net. Doing this has made Mastodon much more interactive to me. I also follow all of those hashtags and engage as I would like to be engaged (mostly by replying when replying is asked for and “yes, anding” anything else I can in a positive way). Posting on Mastodon is mostly a way for me to get ideas and practice writing.

LinkedIn: I have written about how I use LinkedIn before. Basically, it’s to keep in touch with people I know and like. So, in a way, it’s more like what I do in communities, but since my posts are in my feed (and people can follow, unfollow, mute or block me), I feel more free to talk about my work unprompted. I still follow nearly a 0-link policy. Most posts are a trial draft of something I intend to write, so there’s nothing to link to yet anyway.

Reddit: And on Reddit, in the software developer subreddits that I participate in, I just try to answer the questions as asked. These questions are often great writing prompts. I try a draft in Reddit, and then expand on it in this blog later. I do this a little on Hacker News as well. It’s not often thought of as social media, but my StackOverflow contributions are similar.

In all of these places, I am not anonymous, and my bio links to this site. If someone were interested in what I had to say, they could easily find this place, add it to their RSS reader, podcast player, or subscribe to my email list.

I don’t know if this is the most effective way to market my book. I suspect it’s not if the goal is the number of subscribers or sales. But, it’s what I would appreciate in others.

Applying My Book Selling Content Strategy in My Communities

This is a follow-up to My Content Strategy for Selling a Book and Applying My Book Selling Content Strategy on Sites I Control. In this post, I will tell you how I market my book in communities that I am a part of on Discord, Slack, Meetup, and IRL with friends, clients, or mentees.

I don’t.

For sites that I control, there’s an expectation that I would talk about my projects. The posts on this site are meant to be useful, but they are based on my experience—they would make no sense if I didn’t explain what I was working on.

But, in communities, we’re having conversations. We’re building relationships. Having fun. It’s just not the place. This doesn’t mean I never talk about my work—sometimes that’s what we’re talking about (our work). And when the book is finally launched, I will ask my software developer friends to read it (because I think it would help them). But, even though I don’t have a strategy to market to them, the conversations we have drive my marketing strategy.

Fairly often, our conversations lead to me writing something. In fact the past three posts (including this one and the next one) are based on a conversation I had in my writing group about my plans for marketing my book. The post, Network with Alums Just Ahead of You, was based on a conversation I had with a mentee. PM-led vs. Engineering-led Time and If code reviews take too long, do this first are based on conversations I have had with clients. Those are just the recent ones.

A lot of my posts over the past 20 years started out as conversations. It’s more of a product development (content generation) strategy than a marketing one, but I believe that these conversations are evidence that the market has these problems too, so it’s marketing in the research sense.

Applying My Book Selling Content Strategy on Sites I Control

As I wrote yesterday, the core belief that drives my marketing strategy for Swimming in Tech Debt is that I truly think the book will help software developers get things done in codebases with tech debt. Given that conviction, and the fact that I care about software developers, I don’t feel shy in asking you to read my book.

On sites that I own, I just overtly write about the book and the processes that I used to develop it. This content goes out to my email list, this blog, and my podcast. Each place is slightly different.

The subscribers to my email list are expecting updates about the book. That’s the specific reason I give for signing up, so sending those updates is not only expected, but I would be not meeting my obligation if I didn’t send that update. That being said, I usually try to send something along with the update that would be interesting to people who signed up.

Similarly, readers of this blog are ostensibly expecting me to write about what I am working on because all of the advice I give on this site is based on my experience. If you are subscribed to this blog (and read it and like it), then I am sure that you’ll like the book—about 1/3 of the content is based on posts here. So, I don’t think you’ll mind me mentioning it.

The podcast is a little different because it’s only about writing and not software development. In season 4 of my podcast, I am going through the steps that I took to write the book. If you are a software developer with a blog, I think I have tips for you to turn your posts into a book. If you don’t have a blog (or even private writing) yet, then the first three seasons are about developing a writing habit that results in a corpus of work to draw from. I talk about my own book in order to explain the process of writing it, but content from the book isn’t appropriate for the podcast.

So, for places I own and that are tied to my identity, I feel free to just write and talk about the book. For all other places, I just want to be a good citizen. The way I do that is to try to use a 0-click strategy. I don’t know if this is the most effective, but it’s what I personally value.

I’ll write about that tomorrow.

My Content Strategy for Selling a Book

I am hoping to be done with Swimming in Tech Debt in a few months. Most of the work between now and then will be getting the book through three editing passes, which gives me a lot of down time. I’m using that time to market the book via content creation. This blog post is part of that.

I don’t mind just saying that overtly because I am following the advice of Zig Ziglar in Selling 101 [affiliate link]. If you don’t know him, Ziglar was one of the selling gurus and motivational speakers of a half-century ago. I would say that it’s the exact kind of person I wouldn’t read, but he’s often mentioned by Seth Godin, so I bought the book and read it years ago. He’s not at all what I imagined—a core part of his philosophy is integrity.

This line has always stuck with me:

If what you are selling is not good enough for your friends and family, then why are you selling it? If it is good, then why would you want to keep it from those you care about most? […] The key is your conviction that you really are offering something that will strengthen the friendship.

Here’s another:

Here is the most important step [to] take when it comes to helping others. If you truly have a desire to help other people; if you truly believe in your product or service; if you truly want the prospect to benefit […] always ask for the order.

It is with this conviction that I am writing these posts to tell you about my book. I think that most of the people that read this site got here because they are software developers, and if you have come back after reading, then my way of thinking at least resonates with your way of thinking. But, I don’t just want to post an advertisement (or even an addvertisement). I want each thing I write to be useful on its own, not a pitch for the book.

So, that’s my strategy—I am telling people something I think will benefit them. To do this, I am posting on Mastodon, LinkedIn, Reddit, here on this blog and in my podcast, to my email list, and other places. I have different criteria for what I post where, which I’ll go into soon.

Books That Propelled Me in 2024

These three books did the most to help me make progress in 2024

1. Nonfiction Alchemy [affiliate link] by Jordan Ring

I already finished a draft of my book before I read Nonfiction Alchemy, so I learned some of his lessons the hard way. The biggest change I made after reading it was to my title. I had been using a more literal “promise” based title, but wished it was pithier. His description of how he came up with his title and why helped me come up with Swimming in Tech Debt, which I think works a lot better. The subtitle will do the work of conveying my promise.

The new title is more visual and communicates my main metaphor of using your encounters with tech debt as a trigger to make progress—“swimming” rather than “drowning” in tech debt.

I wrote more about this in Titling a book and Book Title as Visual Metaphor.

2. A Philosophy of Software Design [affiliate link] by John Ousterhout

So many gems—it should be required reading in any CS program. Ousterhout’s target is complexity in software, which is very related to technical debt. My book is more about any code that resists change, which includes well-written, simple, easy to understand code that just can’t be changed in the way you need it to be. This book is about understanding the sources of complexity and fixing them.

3. Slow Productivity [affiliate link] by Cal Newport

This is Newport’s latest book in a continuing series about his approach to work and life. If you haven’t read Deep Work [affiliate link], I would start there and move onto Digital Minimalism [affiliate link]. This book shows how to make big things at a slow pace. I worked on my book in my marginal time: a hour or two a day. But writing hundreds of words a day, a thousand every week, builds up. There were edits, restarts, rewrites, etc. But the pace was sustainable, and I owe a lot of that strategy to this book. (Also see The Four Disciplines of Execution [affiliate link] — which is referenced in Deep Work)