Author Archives: Lou Franco

Write While True Episode 25: Stopping vs. Quitting

I reread the book Art and Fear by Bayles and Orland and they had so many ideas for how to get people to make art, that it worked for me to start my blog going again, and then ultimately restarting this podcast.

For part two of this four part series on Art and Fear, I’m going to share the what they said that inspired me to not quit. Here’s the quote.

Quitting is fundamentally different from stopping, the latter happens all the time. Quitting happens once. Quitting means not starting again, and art is all about starting again.

That quote is really the inspiration behind season two, and the episodes I’ve made since I restarted.

Transcript

Observations on the MIT Study on GitHub Copilot

I just saw this study on GitHub Copilot from February. Here is the abstract:

Generative AI tools hold promise to increase human productivity. This paper presents results from a controlled experiment with GitHub Copilot, an AI pair programmer. Recruited software developers were asked to implement an HTTP server in JavaScript as quickly as possible. The treatment group, with access to the AI pair programmer, completed the task 55.8% faster than the control group. Observed heterogenous effects show promise for AI pair programmers to help people transition into software development careers.

The researchers report benefits to less experienced developers, which is at odds with this other study I wrote about and my own intuition. However, all of the developers were experienced Javascript developers, and not literally learning programming, which is where I think the more detrimental effect would be.

Using Zeno’s Paradox For Progress Bars

This was originally published on my now defunct Atalasoft blog in December 2006.


When showing progress, if you have a list of a known length and processing each item takes about the same time, you can implement it like this pseudocode:

for (int i = 0; i < list.length; ++i) {
    process(list[i]);
    // notifyProgress takes a numerator and denominator to 
    // calculate percent of progress
    notifyProgress(i, list.length);
}

One common problem is not knowing the length beforehand.

A simple solution would be to pick a value for length and then make sure not to go over it.

int lengthGuess = 100;
for (int i=0; list.hasMoreItems(); ++i) {
    process(list.nextItem());
    notifyProgress(min(i, lengthGuess), lengthGuess);
}
notifyProgress(lengthGuess, lengthGuess);

This works ok, if the length is near 100, but if it’s much smaller, it will have to jump at the end, and if it’s much bigger, it will get to 100% way too soon.

To fix this, we might adjust lengthGuess as we learn more:

int lengthGuess = 100;
for (int i=0; list.hasMoreItems(); ++i) {
    process(list.nextItem());
    if (i > 0.8 * lengthGuess) {
        lengthGuess = 2*i;      
    }
    notifyProgress(i, lengthGuess);
}
notifyProgress(lengthGuess, lengthGuess);

In this last example, whenever i is 80% of the way through, we set lengthGuess to 2*i.  This has the effect that the progress goes back and forth between 50% and 80% and then it jumps to the end.  This won’t work. 

What I want is:

  1. The progress bar should be monotonically increasing
  2. It should get to 100% at the end and not before
  3. It should look as smooth as possible, but can jump

An acceptable effect, would be to progress quickly to 50%, then slow down to 75% (50% of the way from 50% to 100%), then slow down again at 87.5% (halfway between 75% and 100%), and so on.  If we keep doing that, we’ll never get to 100% in the loop and can jump to it at the end. This is like Zeno’s Dichotomy paradox (from the Wikipedia).

Suppose Homer wants to catch a stationary bus. Before he can get there, he must get halfway there. Before he can get halfway there, he must get a quarter of the way there. Before traveling a quarter, he must travel one-eighth; before an eighth, one-sixteenth; and so on.

To do that we have to keep a factor to use to adjust the progress we’ve made (playing around with it, I found that using a factor of 1/3 rather than 1/2 was more pleasing).

int lengthGuess = 100;
double begin = 0;
double end = lengthGuess;
double iFactor = 1.0;
double factorAdjust = 1.0/3.0;
for (int i = 0; list.hasMoreItems(); ++i) {
    process(list.nextItem());               
    double progress = begin + (i - begin) * iFactor;
    if (progress > begin + (end-begin) * factorAdjust) {                   
        begin = progress;
        iFactor *= factorAdjust;
    }               
    notifyProgress(progress, lengthGuess);
}
notifyProgress(lengthGuess, lengthGuess);

The choice of lengthGuess is important, I think erring on too small is your best bet.  You don’t want it to be exact, because we’ll slow down when we get 1/3 toward the goal (factorAdjust).  The variables lengthGuess and factorAdjust could be passed in and determined from what information you have about the length of the list.

How to fix WCErrorCodePayloadUnsupportedTypes Error when using sendMessage

If you are sending data from the iPhone to the Apple Watch, you might use sendMessage.

func sendMessage(_ message: [String : Any], replyHandler: (([String : Any]) -> Void)?, errorHandler: ((Error) -> Void)? = nil)

If you do this and get the error WCErrorCodePayloadUnsupportedTypes this is because you put an unsupported type in the message dictionary.

The first parameter (message) is a dictionary of String to Any, but the value cannot really be any type. If you read the documentation, it says that message is

A dictionary of property list values that you want to send. You define the contents of the dictionary that your counterpart supports. This parameter must not be nil.

“property list values” means values that can be stored in a Plist. This means you can use simple types like Int, Bool, and String and you can also use arrays and dictionaries as long as they are of those simple types (e.g. an Array of Ints)

I ran into this issue because I tried to use a custom struct in the message dictionary, which is not supported.

Note: I made this post because google is sending people to Programming Tutorials Need to Pick a Type of Learner because it mentions WCErrorCodePayloadUnsupportedTypes incidentally, but isn’t really about that.

Pre-define Your Response to the Dashboard

A few days ago, I wrote about using Errors Per Million (EPM) instead of success rate to get better intuition on reliability. I also recently said that Visualizations Should Generate Actions. Sometimes it’s obvious what to do, but if not, you can think through the scenarios and pre-define what actions you would take.

Here’s an example. This is a mock up of what a dashboard showing EPM over time might look like. The blue line is the EPM value on a date:

The three horizontal lines set levels of acceptability. Between Green and Yellow is excellent, between Yellow and Red is acceptable, and above Red is unacceptable. When we did this, we thought about using numbered severity levels (like in the Atlassian incident response playbook), but we decided to use Green/Yellow/Red for simplicity and intuition.

We also pre-defined the response you should have at each level. It was something like this:

LevelResponse
GreenNone
YellowThere must be at least one item in the current sprint with high priority to address this until the level is back to Green. It can be deployed when the current sprint is deployed.
RedAt least one person must be actively working to resolve the issue and doing hot fix deploys until the level is back to Yellow.

The advantage of this was that these actions were all pre-negotiated with management and product managers. This meant that we could just go ahead and fix things (at a certain level) instead of items getting lost in the backlog.

When we created this dashboard, we were in the Red, but we knew that going in. We worked to get ourselves Green and in practice, we were rarely not Green. This is another reason to pre-define your response, as it becomes too hard to remember how to handle situations that rarely happen.

Writing by Speaking

A few weeks ago I wrote about the tools and materials of writing and concluded that using clauses to make interesting, well-ordered, complex sentences was a core skill.

I got this idea from David Lambuth’s book, The Golden Book on Writing [amazon affiliate link]. This is a book a lot like The Elements of Style [amazon affiliate link] by Strunk and White. Like Strunk, he was an Ivy League University English professor and turned his class notes into a pamphlet sized book.

Here’s another gem from the book:

Write down your idea as you would in speech, swiftly and un-selfconsciously without stopping to think about the form of it at all. Revise it afterwards.

I can’t easily write “as you would in speech”, so I’ve been trying to learn by speaking my writing. To be fair, extemporaneous speaking is also difficult, but it does feel like something that I can improve with practice. I talked more about the details in Write While True Episode 20: Extemporaneous Writing.

Costly Signal Theory Applied to Job Applications

If a particular job is your top choice, you should be willing to do more than is necessary to get it. In evolutionary psychology, this is called a Costly Signal.

A costly signal is something we evolved to show genuine fitness in a world where there has been an arms race between deception and deception detection. You prove your fitness to a skeptical evaluator by doing something that is relatively easy for you, but would be too hard for someone less fit. It has to be something that is hard to fake.

Because it can’t be fake, the first step is genuine two-way fitness between you and the job. In a normal job search, it’s likely that you will know this before the employer. So, if you feel like a job would be an excellent choice for you and that you would be the top candidate for it, your behavior should reflect this belief.

The extra work you do should be relatively easy, but not necessarily easy. If it feels like too much work, then that might be an indication that the fit isn’t good. I would caution that some people undervalue themselves. If you have this tendency, then I’d get an opinion from a colleague or mentor of what they think your chances are.

Related articles

Write While True Episode 24: Thousands of Variations

One of the things that got me back to podcasting after a two year break was rereading Art & Fear by David Bayles and Ted Orland.

This time, while I was reading it, I kept a lot of notes and found four themes that resonated with me and helped me get going again.

The first theme is very practical. It’s what they think is the secret to being prolific. For the past two months I have been applying it a lot.

Transcript

When 99.8% Success Wasn’t Very Good

One of my projects at Trello was looking into and fixing a reliability problem we were having. Even though it seemed solid in testing, we were getting enough support tickets to know that it must be worse than we thought. We collected data on its success rate and found out that it was successful 99.8% of the time. To move forward with doing more work on it, I had to convince our team and management that 99.8% was bad.

At the time, there was a company-wide push at Atlassian to improve reliability, and there was a line-manager assigned to oversee it across Trello teams, so I spoke to him. I showed him the data, but also told him that there’s an overall feeling on our team that it’s affecting our customers more than it seems.

He suggested that I flip the ratio and instead look at the data as Errors Per Million. When you do that, with the same data, you get 2,000 errors per million attempts. This particular thing happened around 2 million times per day, so that was 4,000 errors per day. That partially explained the issue, because it wouldn’t take much for the support tickets to get out of control. Luckily, not all 4,000 were of the same severity, and many were being retried. Still, that number is too high.

The other thing I found after more analysis, was that the errors were not evenly spread across the user base. They tended to cluster among a smaller cohort, which was experiencing a much worse EPM than then rest of the users.

With that in hand, we greenlit a project to address this by targeting the most severe problems. We found several bugs. Eventually we got the success rate to 99.95%.

It’s not clear that 99.95% is four times better than 99.8%, but the equivalent EPM after the fixes is 500 (as opposed to 2,000 before). What surprised me is how different a reaction a high EPM got compared to equivalent numbers. 2,000 EPM is literally the same as 99.8% success and 0.2% failure rates, but the latter two seem fine. Even if I say we get 2 million attempts per day, it’s hard to intuitively understand what that means.

When I said 2,000 EPM, we instinctively felt that we failed 2,000 users. When I said we get 2 million attempts, everyone knows to double EPM to get 4,000 incidents per day, and we felt even worse. That simple change in reporting made all the difference in our perspective.

June 2023 Blog Roundup

WWDC was in the beginning of June, so did my usual posts about it

But, the Vision Pro was interesting enough to write about a few more times

I kept up with my Podcast and released every Sunday in June

In episode 23, I talked about how I pre-recorded five podcasts so I could take a break. So, at least I know that the next four will be on schedule in July.

I generally want to write about diagramming more. I am including visualizations in that general theme as well.

Finally, I generally write tips for working as a software engineer. Here are a few more