Write While True Episode 49: Tiny Habits

Brian: And so just getting yourself in position and getting started in this way tends to lead to more powerful, robust output. I guess I’ve reached the point where just by starting consistently every morning, I was cranking out a blog post a day for quite a while. And I guess that’s the other thing I’ll say too, is habits can come and go. You can lose a habit and it’s probably not helpful to beat yourself up about that because you can also regain them. If you’re in the middle of a sprint, you might write every single morning and you might produce quite a bit. And then you might finish that book or reach the end of that series of blog posts. And maybe you abandon your habit. It’s there to be reclaimed, I guess.

Transcript

26 for 26 March Update

At the beginning of the year I wrote down 26 fun mini-goals to try to do in 2026. I gave an update at the end of January and here’s another one with an update since then.

  1. I’ve been doing well with my vegan recipe books and I also found a great new recipe online for Sopa Locro de Papa that connects me to my Ecuadorian roots.
  2. I’ve donated all of the books I don’t want to keep (way more than 10), so that goal is done.
  3. I went to a new restaurant for valentine’s day in NYC.
  4. I appeared on the Thinking in Tech podcast where I talked about tech debt and AI.
  5. I released episode 48 of Write While True.
  6. I wrote one new Amazon Book Review for Forever Fit [ad] by Maxime Sigouin
  7. I started a new open-source project to package up some visualizations I have made in D3 and want to use in the Google Sheet I ship with my book, Swimming in Tech Debt.

If you want to see the sheet that I use to manage tech debt and get free emails on how to use it, sign up below:

Finding My First Open Source Contribution

I keep track of my GitHub open source contributions on this site’s GitHub page, but only back to 2013. According to GitHub, I opened my account in late 2010 to open a couple of issues on Yammer.net, which I was using to build an internal tool for Atalasoft that needed access to our Yammer data (Yammer was a precursor to Slack).

My first GitHub source contribution was to YUICompressor (a JavaScript compression tool) to output a Munge Map to aid debugging. I PR’d it in 2011. I needed this to help debug Atalasoft’s JS code in production.

But, that’s just GitHub. I’ve been posting code in other places before that. Here’s a multithreaded prime number sieve in clojure from 2008. Here’s a port of Apple’s CPPUnit to run on Windows from 2006. I found evidence that I published a JavaScript Code39 Bar Code Generator on my Atalasoft blog in 2008, which also has a Code39 web app based on it (which hosts the JS code). I have a lot of code snippets on StackOverflow, but only after 2008. My first post with code was in 2003 (comparing jUnit and NUnit).

I had a distinct memory of emailing an open source dev with a multi-threaded race condition fix for a C++ data structure that we used at Spheresoft. Looking at a list of our external libraries jarred my memory that it was WFC by Samuel R. Blackburn. I also found the WFC release notes in the Wayback Machine that mention my fix. He migrated WFC to GitHub much later, but I found a comment mentioning my fix. The actual diff predates the migration, but it’s the double-checked locking directly below the comment:

    // 1999-12-08
    // Many many thanks go to Lou Franco (lfranco@spheresoft.com)
    // for finding an bug here. In rare but recreatable situations,
    // m_AddIndex could be in an invalid state.

So, that’s 1999. Ironically, my oldest verified contribution is actually on GitHub, but predates its release by about eight years. Where’s my green square?

Before that, I have to go by memory because I can’t find the originals.

One thing that came to mind was back in college. I co-developed code for our computer center to draw plots on a Unix PC terminal (saving paper). Using that code, we also built a Unix PC driver for GNU Plot and sent it to them. I am pretty sure this was hosted on MIT’s Athena.

That would be in 1991 or so. I did some simple searches and didn’t find it, but supposedly there are FTP archives from that era, so I might try looking later.

Write While True Episode 48: Start a Collaboration

This is the beginning of season five, episode 48, and I’m going to tell you about something that we’re doing a little different now. This has always been a podcast where I, a software developer, talks to you, who I think are also software developers, about what I write and I’m trying to share with you tips and techniques for writing for people like us that want to write.

And in this season of Write While True, we’re going to start something new.

Write While True is now a collaboration between me and another software developer who writes. His name is Brian Hall. And throughout the entirety of this run of podcasts, I’ve talked a lot about the kinds of things I write, blogs, and I wrote a book, and this podcast.

Transcript

What Makes a Good First Vibe Coding Project

Code can be dangerous to run. It could have security issues. It could leak secrets. If you don’t know what you are doing yet, vibe coding is a good way encounter those problems fast.

Here are some aspects of a project that make it a good one to start learning how to vibe code. This won’t make them perfectly safe (no code that you don’t read could be). But, here’s where to start.

  1. It is a tool that only you will use
  2. It doesn’t need to deploy code to a server that is exposed to the public Internet
  3. It doesn’t need access to any services that require authentication
  4. It is meant to be a prototype
  5. It is run client-side only in a sandbox. For example: a 100% in-browser JavaScript or mobile app.

Games fit most of these.

I’ve been having fun with my nephew writing JavaScript games using PhaserJS. Agents seem to know this library well and we almost never need to look at the code. The games run in a sandbox (the browser) and don’t require any server-side code (that could be hacked).

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.

26 for 26 in January

A few weeks ago, I made a list of small wins I am going to try to have in 2026. To help me be accountable to them, I am going to make an update post each month. Here’s what I have done so far:

  1. I found a place to get Nattō (my farmer’s market) and got a jar last week.
  2. I added A+ Content to the Amazon page for my book.
  3. I tried Amazon Ads (I’ll write a post next week about my thoughts on that).
  4. I cooked one new recipe from one of my vegan cookbooks last night (I think it will be worth doing again).
  5. I left 4 books in donation mini-libraries.
  6. I joined CrossFit again (it’s my best option for a 3rd Place).
  7. I made a reservation for a new (to me) restaurant in NYC.
  8. I went to a gathering of neighbors in my building and met a few new people.

And I am making progress on some of the other things on the list.

Joke Templates

Back in the nineties, I was interviewing someone and he mentioned the idea of joke templates. I can’t remember his example, but when I told my boss, he said, “Oh yeah, I love the one where someone says a number and then you multiply it by seven and say it’s that many in dog years.”

My favorite joke template is the two problems one. I think it was originally: “You have a problem and you think, ‘I know: I’ll use a regular expression’ — now you have two problems.”

I’m a sucker for any variant on this. I just posted this to LinkedIn:

You have a problem with your AI code generator undoing its own work when you add something new, so … “I know,“ you think, “I’ll add another LLM to check the code of the first one.“ Now you have two problems.

RegExes aren’t AI, but it felt that way sometimes since they are so good at what they are good at. But, just like LLMs, they suck at what they suck at. Generally, they are great at finding answers that have objective, verifiable truth. But, they are not good at knowing a secret fact. The key is to provide the facts and ability to verify, and then let the LLM iterate to the solution.

26 for 26

I heard this idea from Gretchen Rubin originally and was recently reminded of it by John August. The idea is to make a checklist of things to do in the upcoming year (i.e. 26 things to do in 2026). It’s another alternative to resolutions (see also: Yearly Themes).

Each item should be doable. To me, it’s an extension of Making Happiness a Priority and my aspirational goals to be Fuerte Y Suerte.

  1. Bench my weight
  2. Be able to do 10 pull-ups
  3. Make a meal with soy curls
  4. Find a place locally where I can get Fermented Bean Curd and Nattō
  5. Add A+ Content to the Amazon page for my book
  6. Try Amazon ads
  7. Go to an intermediate Spanish meetup
  8. Cook one new thing from each vegan cookbook I have
  9. Leave 10 books in the donation mini-libraries around town
  10. Hang pictures of my family in my guest room
  11. Go to a live musical
  12. Go to a NY Liberty game
  13. Go to at least one arena-sized concert
  14. Have a coffee or lunch with someone who lives in my building (see Improving My Social Connection Index)
  15. Join a gym that has a social component
  16. Host someone new for dinner at my place
  17. Try three new restaurants for dinner in Sarasota
  18. Try two new restaurants for dinner in NYC
  19. Go for a weekend away to a new place in Florida
  20. Attend a local political gathering
  21. Release something new to open-source
  22. Get App-o-Mat on current Django and back to being a live server (not static pages)
  23. Publish 10 articles on third-party sites
  24. Appear on 5 podcasts
  25. Publish 10 episodes of my podcast: Write While True Podcast
  26. Write 10 Amazon Book reviews for books I love

Blind Sketching

I want to sketch more, but it seems a little like a chore sometimes. For example, I used to go to life drawing sessions, but it’s a four hour commitment with travel. So, instead I’ve been doing more quick, blind sketches. In ink.

A blind sketch is a sketch you do by looking only at the subject and not your paper at all. It takes at most a couple of minutes for me.

Here’s one I did from a hotel bed last week:

Blind sketch of some stuff on a shelf in a hotel

I like doing it in ink because there is no way to fix a mistake. You have to just move on.