Category Archives: Software Development

Write Test Plans for Every PR (and do them)

On the ticket/issue/item attached to your PR, write out the steps to see the change in the application your PR introduces. Even better, record yourself doing them. Not just the happy path, but also show the types of errors that can happen and how the application shows them.

I wish I did this more when I worked on a team, but when I did, everything went smoother through code review and QA. Not because it helped the reviewer or QA engineer—I’m sure it did.

Mostly it helped because I made sure I did all of the steps in the test plan before I posted the PR. Also, writing down a test plan put me more in a tester’s mindset where I was trying to think of things to check and finding problems before I submitted my work.

With all of those things out of the way, the reviewer and QA engineer could concentrate on bigger picture things to check.

How to Find Bugs in a Code Review

I have written that the primary reason to review code is knowledge sharing, not finding bugs, and that the way to use code reviews to prevent bugs is to reject PRs that aren’t obviously correct. But what should you do if you really want to try to find bugs during review?

Run the code—preferably in a debugger from a test.

The best tip I got from Steve Maguire’s Writing Solid Code [affiliate link] was to step through my code in a debugger as I was writing it. The original version of this book (1993) came out before xUnit based unit-testing took off, so I don’t remember him mentioning them. But, I think a unit-test is a better way to do this.

If you don’t have a test that puts you at the line of code you want to inspect, then driving the code manually while stepping through the code in a debugger is a good-enough option. Of course, not having appropriate tests is probably a good enough reason to send the PR back, but if that’s not your team’s culture, and you want to find the problems manually during review, at least use a debugger.

It’s more likely you’ll see problems if you are actively engaging with running code. You will be anticipating what is going to happen as you step through, and if the code behaves differently, you’ll notice. You’ll either find a problem or learn something.

How to use Code Reviews to Prevent Bugs from Getting Into Production

When code has a bug in it, that is way more of an author problem than a reviewer problem. I don’t think it’s right to expect reviewers to find bugs (or to rely on it). It’s way harder to do that unless you actually run the code.

So, I would suggest that to fix the problem of buggy code making it into production, you do more things at the author level, since the author should be running the code a lot through tests and in the debugger. If you have a code reviews checklist, give it to the author, who should be reviewing their own code before PR’ing it.

Then, the reviewer should be verifying that there is evidence that the author actually did thorough work. The review checklist should be verifying the author provided evidence that the author did the pre-PR checklist. Check the tests, check their coverage, check UI screenshots, check that code is doing “something” with edgecases and that those are tested. Instead of looking for bugs, the reviewer should be learning the code and looking for higher level issues.

The author should be providing code that is correct and easy to see that it’s correct. If the reviewer doesn’t think it’s obviously correct, they should reject the PR. The presence of such a review will make the author do more thorough work.

My Year in Weeks

I released my 2025 Journal PDF (for Supernote) yesterday, and in the middle of describing it, I realized that I have never explained how I plan my year around weeks and 13-week blocks. There are mentions of it in a few posts, but nothing canonical.

I use a week as my main planning timespan, not months or quarters. Additionally, I use Monday as the first day of the week, which is normal for a lot of the world, but not Americans. When I think of how a week flows, the Saturday and Sunday are a unit. I think of them as the start of the week, but almost no software will let you do that, so I got used to them being at the end.

So, all of my projects are estimated in terms of weeks, and I program in sprints that are a multiple of weeks. Then, I split the year into four 13-weeks “quarters”, which is close to a year (364 days). This year, 2024, started on a Monday, and because it was a leap year, April 1 and July 1 were exactly on 13-week boundaries (Oct 1 was only a day off), so my system correlated to normal quarters about as well as it ever could. This doesn’t happen again until 2052. I hope I am there to see it and that I still care.

My journal is set up to follow the flow of a week. Days of the week tend to be similar to each other—so, there is a feel to a Monday, a Tuesday, a Sunday, etc. But March 3rd will not be like April 3rd or October 3rd. A lot of recurring meetings are weekly or bi-weekly, or on the “Third Thursday of the Month” or some other pattern that works well with my system.

When a year doesn’t start on a Monday, I have to incorporate some of the previous year into it. For me, 2025 starts on December 30, 2024. I usually start my yearly goals in the previous year just to get a running start, so it doesn’t really matter if a few extra days get into my journal.

If I have to deal with something that is on a month or quarter boundary, they are just a regular day in the journal. External deadlines can be on any day.

If this sounds good to you, you can use my 2025 Journal (PDF).

My 2025 Journal PDF for Supernote A5

I finished adding features to Page-o-Mat to support the journal I wanted to make for 2025 to use on a Supernote Manta. I fixed some bugs and added the following features:

  • Internal Links to pages: This is supported in titles, section titles, and rectangles
  • Start/End Dates on Pages: This is so I can show a date range in a title
  • More support for using expressions as values: This is so I could calculate a page link inside a loop or do more date math.

My Journals do not use heavily templated pages—Most pages are nearly blank, but they have a 5mm dot grid on them. You could do bullet-style journaling, sketches, or whatever you like.

The main opinionated thing I do is that my year is based around four 13-week “Quarters”, not the months or the typical quarters, and my weeks start on a Monday.

So, 2025 starts on Monday, December 30, 2024 and goes to Sunday, December 28, 2025. I did add on the week after, though so that Dec 29-31 are in the Journal (and the rest of that week). The full 2025 journal is 53 weeks with a little of 2024 at the beginning and a little of 2026 at the end.

Download my 2025 Journal

Since this was created with Page-o-Mat, you could customize it and make your own. See the config file in /config/2025-journal.yaml in the repo. The script uses Python—I added installation instructions to the README.

EDIT: More explanation of my system in My Year in Weeks

Page-o-Mat Updates for Electronic Journals

I wrote Page-o-Mat because I had an idea for a paper journal that I wanted to make. I could have just made a PDF, but making each page was a repetitive task that was easier to do with code. I could have just made a python script to make just that journal, but I was still designing the journal, so I put some configuration in a YAML file. Once I did that, the config grew to the point that it became a language for making journals. I made my 2023 journal with it and got it printed by LuLu.

In mid 2023, I wanted to make a different kind of journal (one for writing Morning Pages), and so I added some features to draw shapes on pages, which I also used to make covers. Later that year, I made my 2024 journal with it without needing more features. I hadn’t touched it since then.

I like my custom paper journals, but they are thick and heavy, so I am trying something different for 2025. I finally found an E-Ink tablet that I can use to replace my Kindle and get a more portable writing/journaling solution too.

I’ve been looking at E-Ink writable tablets. After considering the Kindle Scribe, Daylight, and Remarkable, I decided that I cared about a few things:

  1. It had to be hard to use the machine for anything but reading and writing because I want it to be more like factory equipment.
  2. It had to have a long battery life (like the Kindle).
  3. It had to be easy to get files to and from the device (unlike the Kindle).
  4. It had to be able to read Kindle books.
  5. It had to be readable in sunlight (I live in Florida and read at the beach).
  6. It had to be A5-sized.

The only device I found that met all of these criteria was something that Supernote used to make and said they would make again. I signed up for updates and waited. Then, I forgot it existed. I almost got a Daylight in the meantime, which is a nice device, but it’s too nice—it can easily run any Android software, so it’s too general purpose. I want a “worse is better” machine.

But a few weeks ago, I got an email from Supernote that the A5 is available, so I bought one—it arrives later today. In the meantime, I’ve been reading more about its capabilities, and I see that I can make my own planner for it by just bringing over a PDF, which is what Page-o-Mat produces.

I could make one just like my 2023/2024 planners right now with Page-o-Mat, but one of the advantages of an electronic journal is internal linking. So, I could be looking at a page of all months, tap and jump to a month overview, then tap and jump to a day overview (and back). All you need to do is add tappable zones to the PDF that link to a page.

So, yesterday, I added simple support for that to Page-o-Mat and pushed up the change along with a simple example.

This won’t be enough for my 2025 journal, but helped me get back into the codebase again. I have a week to get the features in so I can make a journal and use it on January 1st.

The only two things you need to know about software project management

  1. If someone asks when something will be done, they are asking for the date when they can use it.
  2. Every day, ask yourself what could happen to make it so the software won’t be ready to use by that date and do something about that.

The result of project management is that the software is ready to be used on the publicized date.

The details about how to figure out the date should be, what it will be, negotiating that difference, how to communicate it, how to change it, who “they” are, what “they can use it” means, changing that definition, what kinds of problems could happen, what to do about a problem, how to track all of this, etc is what project management work is, but in the end it just boils down to those two things.

How to introduce tests to a codebase without them

I wrote Unit Testing Old Code in January 2004, and I stand behind the recommendations. In short, use unit tests to accomplish what you are trying to do right now. Tests will help you refactor and optimize without breaking something, they will help you represent new learnings as you read code, and they are a good thing to write to reproduce a bug before you fix it. In all three cases, it’s a means to an end.

Later that year, Working Effectively with Legacy Code [affiliate link] came out with the definitive advice on how to add tests to a codebase without them—introducing the concept of seams. Generally, seams are a way to change what code does with external control. It might not be the way you’d design it from the start, but it’s a good way to migrate untestable code to being testable. I reread it recently and the techniques are still useful and easy to adapt to modern languages.

If I were to update my advice from 2004, I’d say to adopt diff-cover. It’s a script that filters down your code coverage reports to show the test coverage of the changes in your branch. This lets you try to hit high coverage numbers on each PR without necessarily having high coverage overall.

Other than that, if you have an untested codebase, I’d still say not to make it a project to add tests widely. It’s something I do it in my codebase even though its coverage is high. I want to keep it that way.

If you don’t have any tests, I’d get the infrastructure into place to run tests locally and in CI and a few to get a few tests going. Then, use tests to get your work done faster. I cover this in my book, Swimming in Tech Debt, which isn’t coming out until March, but I have a story of how I did this at Trello that was published in The Pragmatic Engineer.

Mastodon via Hashtags

I have been on Mastodon for a little over two years, and until a week or so ago, I didn’t really get it. Most of my social media usage and posting has been on LinkedIn, which I use because I know the people there in real life and care about what is happening to them. I post there because I also think they care about what’s going on with me. So, I have groomed my feed down to mostly those people. I thought I could replicate this on Mastodon, but that didn’t work.

The problem is that I know very few people on Mastodon in real life. I followed those that I could find, but I don’t keep looking for them, and Mastodon doesn’t suggest people I might know. I tried to augment this with hashtags, but I didn’t choose many and they happen to have very low traffic. So, my feed is dominated by a few people that I don’t know mostly posting about their lives and not on topics I care about.

But I recently decided to follow more higher traffic hashtags and that has made a big difference. It makes me think that Mastodon is somewhere between LinkedIn and Reddit. Reddit is about the topics. LinkedIn is about the people. Mastodon is something in-between.

Here’s how I use it now:

  1. I post to trial blog posts. This blog post was a toot a few days ago.
  2. I don’t link back here much. It might not be the best way to use social media, but I like the idea of content that’s fit for the media. My favorite toots are self-contained, so that’s what I mostly try to do. You can find this blog in my profile.
  3. I follow people that I see a few times. I figure they will mostly post on the topic.
  4. I follow people that star or boost me because I feel like they are probably also using Mastodon similar to how I use it.
  5. I mute accounts that post too much to hashtags. Mostly, these are businesses, not people.
  6. I have a few mute words to keep political news out of my feed.

This has made Mastodon more useful for me. I end up with a feed that is mostly about topics that I want to write about, and I post things I am thinking about. It’s supporting my aspirations to write more, and so I’ll keep using it this way for now.

If you want a code review to go fast, do it yourself

I am the only developer in my codebase right now, so I do all of my own code reviews. I post a PR, and then go review it. It goes quickly—I rarely have to wait.

But this is not what I’m talking about.

If you post a review, and the reviewer finds a lot of problems, that’s not because they are good reviewer. If QA finds obvious bugs, we know it’s because the work is bad. This is the same thing. Code reviewers and QA should not be finding obvious problems because there shouldn’t be any.

One reason this happens is that we feel pressured to get work done quickly, and so we post PRs that are not finished. The code can pass a simple review, but perhaps it doesn’t deal with edge cases or does things in a sloppy way with no unit-tests or is convoluted in a way that works, but is hard to read. Maybe the code is AI generated and PR’d after a cursory check.

The problem in each of these cases is not that AI generated code or that code was convoluted or that tests weren’t there. It’s that the author didn’t review their own code and fix these issues before opening the PR.

So, the author got their task done quickly, but now the code review eats up all of that saved time. It also obscures the problems that could have been found if the reviewer hadn’t gotten tired of making obvious comments. The author ends up spending more time, the reviewer is wasting all of their time, and all of this causes a big gap between calendar time and implementation time, which is a driver in incorrect estimates and low developer productivity.

The low productivity problem is insidious. It feels like we’re coding as fast as we can, but the unnecessary wait time builds up and makes projects late. Those wait times are rarely taken into account in an estimate—nor should they be. Instead of accounting for them, you should be eliminating them.

So, don’t post PRs of unfinished work that is going to cause the PR to be sent back (or worse, cause the ticket to be reopened). The best way to do this is to do your own code review first, fix all of the problems you find, fix up the commits, and then post the PR for a real review. By that time, the code should be correct and easy to see that it’s correct. That means:

  1. You ran all of the automated checkers/formatters already and they all pass (maybe even ones that are not in your CI).
  2. You tested your changes (see diff-cover to filter code coverage reports to your branch’s changes)
  3. You tested edge cases
  4. If you got to a solution with convoluted code (which is totally fine), you did a refactoring pass to make it easier to understand
  5. If you generated code with AI, you did your own editing pass on it to fix obvious problems (like distracting comments).
  6. You did an AI assisted code review of your own code and thought about each issue critically. Collect examples of your past reviews that got comments that should have been avoided and use them to prompt your AI reviews (to avoid repeating mistakes).
  7. The PR commits are created carefully to be easy to review one-at-a-time. So, whatever problems you found are not added on commits, but squashed to make it look like the code was written correctly to begin with. Don’t make a reviewer read code in one commit that is fixed or removed in a subsequent one.
  8. If you know that there are things that are unfinished in this PR, you explained that in your PR description and when they will be done.

Do this for your own enjoyment at work. When you find your own problems, it makes you feel good about yourself and boosts your self-esteem. When someone else points out your flaws, it doesn’t.