How to Get Changes Through QA Faster

In PR Authors Have a lot of Control on PR Idle Time, I made the argument that there is work the author could do before they PR their work that would get a PR review started faster. I followed up in A Good Pull Request Convinces You That it is Correct to show how to make the review faster once it started. The upshot is you do a code review on your own code first and fix problems you find. That work doesn’t take long (an hour?), but shaves off hours and days off the code review.

The same technique works for QA: Do your own testing and update the issue/bug/story/card in your work database to make it clear what the change was and how you have already tested it (with proof).

The worst case scenario for a code review and QA are the same: your code has a defect that you should have found. You can do work up-front to make sure this doesn’t happen, and that work is short compared to the wasted time that not doing it will cause.

I assume that you will test your code before you submit it. Hopefully you do that through automated unit-tests, which should include edge cases. You should go beyond that and anticipate what QA will check.

Like with code reviews, this extra work takes a couple of hours and potentially saves days of back-and-forth between your testers and you. If you don’t have any ideas of what to test then check with AI chatbots—they are pretty good at this and can even generate the test.

If you can’t automate the test, then you still need to manually test it when you write it, so it’s a good idea to make some record of this work. For example, for UI code, which is hard to unit test, create a document with before and after screenshots (or make a video showing what you changed).

These ideas also help with another source of QA feedback—that they don’t even understand what the issue/story/bug is. The way I head that off is by attaching a “Test Plan” document with a description of how to see the change in the application and what specifically was changed. A video works here too.

When QA finds a problem that I could not have found, then I am relieved. But, when they kick something back because it wasn’t explained well or I made a stupid mistake I could have easily found, I feel guilty that I wasted their time (and mine). I’ve never regretted taking a little time at the end of a task to help it go smoothly through the rest of the process.

How Product Managers and Engineering Teams Can Work to Together To Tackle Tech Debt

I participated in a discussion with Arin Sime and Kent McDonald about tech debt and how PMs and Engineers can work together to address it.

A lot of what I said is covered in detail in my forthcoming book, Swimming in Tech Debt. Here’s an overview of the topics we discussed:

  1. What we mean by Technical Debt
  2. How much time to allocate to it
  3. Whether it’s sometimes ok to ignore it
  4. What to do with code so bad everyone is afraid to touch it
  5. Vibe Coding (of course) and whether it’s a tech debt creating machine

If you would like more detail on anything we talked about, reach out to me on LinkedIn.

The Infinity-X Programmer

Forget about the 10-X programmer. I think we’re in a time where AI coding assistants can make you much better than that.

Even if you think I’m crazy, I don’t think it’s a stretch that some programmers, particularly less experienced ones, will get a big relative boost compared to themselves without AI. Meaning, they could become 10x better using Cursor than they would be if they didn’t use AI at all.

The norm is less for experienced devs. I think I’m getting about a 2x or 3x improvement for my most AI-amenable tasks. But when I have to do things on projects where I don’t know the language ecosystem as well, it’s much more. So, it’s less about overall skill, and more about familiarity. As long as you know enough to write good prompts, you get more of a multiple the less you know. For example, for my main project, I might save an hour on a 4-hour task, but a junior dev might save days on that same task. Even if I finish it faster this time, they are still going to improve on that same kind of task until we’re about the same.

But, I also think it’s possible to get very high objective, absolute multipliers against all unassisted programmers with projects that are not even worth trying without the AI assistance.

I’ve started calling this Infinity-X programming. I’m talking about projects where it would take weeks for a programmer to complete, but no one is sure that it’s worth the time or cost. Using tools like Cursor and Replit, I’ve seen instances where a person with some programming ability (but not enough to program unassisted) do it on the side, working on it for fun just because they want to. They get somewhere fast, and now we might approve more work because we can see the value and it feels tractable. I’ve seen this happen a few times in my network lately.

It’s not just “non-programmers”. I’m also seeing this among my very experienced programmer colleagues. They are trying very ambitious side-projects that would be way too hard to do alone. They wouldn’t have even tried. But, now, with AI, they can make a lot of progress right away, and that progress spurs them on to do even more.

Without AI, these bigger projects would be too much of a slog, with too many yak-shaving expeditions, and lots of boring boilerplate and bookkeeping tasks. But, with AI, you get to stay in the zone and have fun, making steady progress the whole way. It makes very big things feel like small things. This is what it feels like to approach infinity.

February 2025 Blog Roundup

I started using Cursor in February. I went from 0 to a usable commit in less than 20 minutes. Here is my progression:

I continue to be impressed by Cursor and use it for almost all programming now.

I wrote about catalysts at work (inspired by an old post: An Unnamed Programmer in Peopleware is One of my Heroes):

I am working on a book about tech debt called Swimming in Tech Debt. I spent some time thinking about swimming:

I continue to write about code reviews

The Central Question of a Code Review

When I prepare code for a pull request, I construct it commit-by-commit in a reading order that convinces you that it is correct. So, when I stage code, I ask myself: “Is the code in this commit obviously correct?” If it’s not, then I probably need to add commits before this one that make the code more clear because I only make explanatory comments on a PR as a last resort.

A PR comment becomes code in a few steps. Step one is that I make comments in the code instead of in the PR. This is better because now anyone reading the code will understand it better. A PR comment isn’t tied to the code unless you think to check the logs and follow that back to the PR.

Step two stems from my belief that a random comment explaining a block of code indicates that that code isn’t clear. This is usually something you can fix with a behavior-preserving refactor. Maybe a variable name is unclear or some code should be extracted into a function. The name of that new function should make the intent of the code inside it easier to see.

But, changing this code might break something, so step three is try to cover this area with unit-tests. When I read a commit with unit tests, I know that all of the cases in the tests are checked, so my job is to think of things that aren’t checked.

It’s tempting to want to fix things in code you are reading, but if they aren’t clarifying the work at hand, that might be a waste of time. By concentrating my efforts on making the PR easier to review, the code will be merged faster if I fix the code.

Supernote Manta: Review at Eight Weeks

I’ve been using the Supernote Manta as my exclusive object for taking notes and reading e-books for eight weeks. This review is a follow-up to Supernote Manta First Impressions and Supernote Manta: Review at Four Weeks.

Before choosing the Manta, my requirements for an electronic writing device were:

  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.

It has delivered on all of these requirements, but there are some disappointments (as I mentioned in past reviews), with the main one being that the on-screen keyboard is terrible.

But there are other issues. For context, here is how I currently use the Supernote.

  1. I made a PDF journal using My 2025 Journal PDF for Supernote A5. I write in this daily.
  2. I use the Kindle app on the Supernote for all e-book reading.
  3. I make new notes all of the time for various ad-hoc uses. Each of these becomes the start of new kind of dedicated journal. For example, my wife and I have a monthly “family meeting” to discuss our finances—my notes are now all together in a note file. Previously, they were spread throughout my paper daily journal.

So, I have to manage a bunch of files, which isn’t great on the Supernote. It has a very “functional” file manager, but it’s bare-bones. Now that I have a lot of files, I am running into limitations.

The first problem is that I didn’t think through a folder and file naming strategy before making notes, and now I just have a bunch of randomly named files. I would like to rename them, but the keyboard is so janky, that I have just put it off. On a Mac, this would take less than a minute, but it will just be frustrating on the Supernote.

Related to that, when you take the “New Note” icon, you can’t see the folders or other files. So (as far as I can see), you can’t put the new note in a folder with the shortcut and if you have a naming scheme, you aren’t reminded of it by seeing the other files. This dialog uses the entire screen, so there’s plenty of room to show the folders and files (like any typical “Save as…” dialog).

Another issue is that I can’t reliably lasso an area (select objects by drawing an outline around them). It’s a two-finger gesture in the corner along with using the stylus, but most of the time I do it, the stylus draws the shape instead of lassoing the objects. After a few tries, I do it accidentally—I have not figured out how to do it reliably, but also, I have not investigated this to find out if I am doing the gesture and pen movement as documented. It feels like I am getting worse at this over time.

This all being said, I am very happy with the Supernote. I use it all of the time. As I was writing this post, the Supernote asked to update itself. So, I hope that they addressed some of these issues. The keyboard is mostly a speed issue, so hopefully, not hard to improve.

What To Do If You Have a Tech Interview This Week (or Tomorrow)

Your goal is to be able to answer questions that you can answer. If they ask a question and you have no idea at all, then you might not get an offer. But, if they ask a question that you definitely know, you will feel bad if you flub it.

So, practice. If you have a friend that can do a mock interview, do it. If you have time to practice leetcoding, set it at a level you can do and just practice coding under a little pressure.

You are not trying to learn more algorithms, you are trying to get better at performing what you already know.

See also Professional Performances

How it Feels to “Program” with AI

When I type a prompt into the chat pane in Cursor, it is indistinguishable from programming to me. The part where I tap tap tap on the keyboard and code comes on the screen isn’t programming, that’s typing. The part where I use keyboard shortcuts to navigate the IDE isn’t programming either. Both of those parts (the typing and navigating) is being done by a robot when I prompt Cursor, but the programming is still done by me.

When I look at a ticket in JIRA that says, for example, “add a way to archive a contact” in my React/Node/MySql application, when I estimate, I think

  1. Add an archived field to the contact entity, default to false, set as non-nullable
  2. Generate a migration and run it on my local database
  3. Add DB service functions to archive and unarchive contacts
  4. Write unit tests for those DB service functions
  5. Add GQL mutation functions to archive and unarchive a contact
  6. Add archived to client GQL queries
  7. Add archived to the client-side contact model by running the GQL code generator
  8. Make sure to set up the model’s archived field from the GQL query in Redux
  9. Add a Redux reducer to set the archived field
  10. Add Client-side functions to optimistically update the redux and call the GQL mutation (undoing on error)
  11. Add an “archive”/“unarchive” button on edit on the contact edit dialog (show the one that applies to the contact)
  12. Look at lists that show contacts and decide if they need a way to filter archived contacts out or not

I can tell you from experience, that I can do steps 1, 3, 4, and 5 with a prompt that has basically what that says and at-mentioning the files that will be updated and that serve as a model (I probably have another entity with an archived field). Step 2 is a yarn script for me that compares the schema in my code to the one in my DB. Steps 6, 7, 8, 9, and 10 would be another prompt, and finally I will do 12 & 13 manually or with completions because I might want to adjust the UI.

Before Cursor, I still wrote out that list because I like to Build a Progress Bar for My Work that helps me make an estimate, keep on track, and know if I am not going to make it. When I work with Junior devs, I often develop this list with them to communicate what I want done with more details.

Is this programming? I think so. Instead of TypeScript, I am “programming” in a loosely specified, natural language inspired, custom DSL. I run scripts to generate my migration code from schemas and my client side models from GQL queries, and to me, prompting Cursor is basically the same thing.

Fluent Forever Review

I’m learning German for a trip this spring. Last week, I found out about the book, Fluent Forever [affiliate link] by Gabriel Wyner, which I really love. He also has an app with the same name—it’s fine, but very buggy. It’s hard to recommend the app, but I am convinced his process is going to work for me, and the app is better than trying to his process without it. I bought it after trying it out—despite the bugs. If you read the book, and want to do the process, then you should consider the app.

One reason Wyner’s process resonates with me is because it is centered on Spaced Repetition flash cards, which I already use for other things. I use Anki for spaced repetition practice, but his process isn’t easy to implement in Anki.

Wyner recommends building very custom flashcards that don’t use translation. So, I wouldn’t put an English word on one side and the German translation on the other. Instead, he recommends using an image in place of an English word. He wants you to associate the new language with an image so that you map the word directly to a concept, and don’t have to mentally translate through your native language. Since, I am thinking about how to Apply Program Language Learning Techniques to Learn a Foreign Language, and I never translate between programming languages, this makes sense to me.

Each card in his system is personal to you. He doesn’t supply pre-made cards—he wants you to build them. Building them is part of the process. For example, when I made the card “Großmutter,” I spent at least 10 minutes looking at pictures of my grandmother before I found the perfect one. To represent a concept, sometimes I need to combine several images. That time helps cement the concept before I have even tested my memory with the card. Also, I know what I mean by the image—this would be hard to do with someone else’s images.

The Fluent Forever app helps you build cards, implements a spaced-repetition algorithm, speaks the words (to teach pronunciation), and has many other helpful features. Like I said, if you want to learn this way, the app is better than trying to replicate it with Anki or paper (although the book does show you how to do it). It’s also cheaper than the popular language learning apps. The book, though, is worth a read if you want to learn a language.

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: