Write While True Episode 26: Making Makes a Maker

I decided to do a four-part series on the lessons I learned from Art & Fear by David Bayles and Ted Orland.

This week, in part three, I want to talk about a quote about what art means to the maker.

Transcript

Notice What You Notice

In my podcast, I am doing a four part series on lessons I learned from Art & Fear [amazon affiliate link] by Bayles and Orland. Tomorrow, I’ll release part 3, but today I want to share a passage that I think of often, but didn’t make the series (emphasis mine).

It’s all a matter of balance, and making art helps achieve that balance. For the artist, a sketchpad or a notebook is a license to explore — it becomes entirely acceptable to stand there, for minutes on end, staring at a tree stump. Sometimes you need to scan the forest, sometimes you need to touch a single tree — if you can’t apprehend both, you’ll never entirely comprehend either. To see things is to enhance your sense of wonder both for the singular pattern of your own experience, and for the meta-patterns that shape all experience. All this suggests a useful working approach to making art: notice the objects you notice.

When I am reading, when I am working, I am trying to be aware of when I smile and feel a rush of insight or understanding. I am trying to realize that I am noticing something. Notice my notice. I don’t know what to do with it yet, but what I am doing is making some kind of mark—taking down a note or a photo—just to remember the moment so I can deal with it later.

A Little Linear Algebra Helps to Make Games

I started playing with raylib to make a game that is the opposite of Asteroids. Just to start, I need to be able to draw a triangle that is rotated by some angle around its center, and that’s simple if you understand transformations. Raylib does include a raymath module to do basic vector math, but not specifically what I needed.

So, again, I’m feeling The Unreasonable Effectiveness of Mathematics in Programming. I’m not sure you can make any reasonable game without some transformations.

Following a Lot of Blogs in NetNewsWire

I use NetNewsWire as my RSS reader. It’s a locally installed app on my mac and iOS devices that uses my iCloud account to sync between them.

I have been following about a dozen blogs that generated a few posts a day. But, last week, I downloaded an OPML file with a list of blogs by HackerNews users. It has over 1,000 feeds in it.

Here’s my experience with dealing with that in NetNewsWire (NNW).

To start with, I made a new folder for the import. Once I started the import, NNW struggled to download all of the posts. When the progress bar was done, it appeared that many of the feeds had no posts. It didn’t give any feedback about what exactly was going on, but there were still hundreds of feeds and thousands of posts downloaded.

I started to go through them and delete any that didn’t meet my minimum criteria for a blog feed or were on topics I didn’t want to follow this closely.

I noticed that over time, NNW seemed to be downloading the feeds it had skipped during import, so it seemed to be auto-retrying periodically (probably just on its normal poll schedule).

There were far too many posts to ever read, so I just marked everything as read and waited for new posts. Every day there are quite a few, so this is what I have been doing.

  1. If I find a post I think I will like in a quick skim, I star it in NNW
  2. If I don’t want to read the post at all (usually because it’s way off topic for me), then I take a quick look at the feed and probably delete it.
  3. When I have time, I read the starred posts.
  4. I take a look at the feed of the starred post, and if it seems like I’d like to follow it more closely, I move the feed to a folder of curated HN blogs.
  5. I follow the curated folder closely. There’s been a lot of great content, and it’s giving me things to explore and write about (e.g. This raylib post with my first impressions)
  6. I check out the full list only when I have nothing to read (starring and deleting as appropriate)

Generally, I recommend NNW, but it does seem to struggle with 1,000+ subscriptions. However, it didn’t crash or completely fail, and does seem to be catching up. The benefits to me are that I can read offline and I don’t have to pay for a syncing service.

raylib First Impressions

I just ran into raylib (because I’ve been reading a ton of HN blogs) and it’s making me dream of Programming With the Joy of a Thirteen Year-Old. All I wanted to do when I was 13 was make games and raylib looks like a fun way to do it.

I read the homepage, played a few games, and then read their source. Here’s what I love

  1. You write in “easy” C. I searched for pointers and signs of dynamic memory and found none in the simple games I read. I’m sure it’s there in more complex games, but they aren’t making you use pointers just to get started
  2. It runs in the browser. It’s C, so it’s expected that it would be cross-platform, but it can also compile to something that runs in the browser.
  3. No external dependency philosophy. Dependencies are just future tech debt.
  4. No (or very little) magic. It’s just a library. Games are mostly a loop of reading the controller, updating some state, and rendering that state. That logic is very clear in raylib code.
  5. Simple games are simple. I played three classic games and then read their source. They were each one file and followed similar logic.
  6. There’s is more to it. Once you progress from the simple stuff, it looks to be full-featured with other things you might want in a game library. But, you don’t need to use any of it at first.

I might play around and see where I can get with Nebulous.

Minimum Blog Feed Criteria

There was a post on HackerNews recently asking for everyone to post their personal blog. A few days later, some people had hacked up projects based on that data, including this OPML file, which you can import into a feed reader to follow all of the blogs.

I imported it and realized immediately that there were way too many to follow, so I started to cull them. I still have a long way to go, but I noticed a few things that made me want to delete feeds from my list immediately.

Here’s my list of things your feed should have:

  1. A title. For some reason, there are a bunch of untitled feeds. The <link> tag has a title attribute, and I’m pretty sure that if you leave it blank, most readers will pick up the site’s <title> tag.
  2. The full post. I don’t know if it’s intentional or just a default of some blog software. If you have a feed, I recommend putting the full post in it.
  3. A recentish post. I know it’s hard to keep a blog up-to-date, but if you are going to add your site to a list, go put up a new post if your latest is very old. Even if it’s just a short intro and a few links to your best posts.
  4. Not too many posts. I possibly post too much, but there were a few blogs with several posts each day. They were short posts, but I still found that they dominated my unread list too much, so I ended up deleting them.

There were other reasons I deleted blogs, but most of them had to do with the general topics of the blog, which were just not interesting to me personally.

Thinking Fast with Keyboard Shortcuts

The book Thinking, Fast and Slow [amazon affiliate link] by Daniel Kahneman describes our brain as having two thinking systems, a fast one and a slow one. The fast system is automatic and multitasking, while the slow system is methodical and single-focussed. When you are doing something complex, you are usually concentrating your slow system on the main problem, while the fast system can be doing several related (and even unrelated tasks).

This is the main reason I try to memorize and practice several keyboard shortcuts for the programs I use every day. I am trying to get as much of the mechanics of the code editing into my automatic, fast thinking system.

There is a common belief that mousing is faster than keyboard shortcuts, which probably originated with this AskTog article:

We’ve done a cool $50 million of R & D on the Apple Human Interface. We discovered, among other things, two pertinent facts:

  • Test subjects consistently report that keyboarding is faster than mousing.
  • The stopwatch consistently proves mousing is faster than keyboarding.

This is probably true for the general case and for when the user is learning a new UI. But, the study, Comparison of Mouse and Keyboard Efficiency, suggests that:

[…] for heavily-used interfaces, keyboard shortcuts can be as efficient as toolbars and have the advantage of providing fast access to all commands.

For me, the key is that shortcuts have to be able to be deployed with no conscious thought.

Programming often requires you to keep several interrelated thoughts in your head until you get the code written and working. For example, even for simple web UI blocks, you have to think of the semantic structure of the tags, the layout, and the style. To write that code, you will have to possibly jump through a few files and parts of those files. So, to keep from adding more cognitive overhead, you want to make the manipulation of the editor as automatic as possible.

This is something I think that can never be accomplished with the mouse, but is possible for a small set of shortcuts. That set should be the most common actions that happen while you are actively programming. The goal is to keep your slow system and short term memory focussed on the programming task at hand.

For me, that is:

  1. Cut, Copy, Paste, Undo, Redo
  2. In-file navigation with arrows and modifiers (including using Shift for selection)
  3. Find and multi-file Find
  4. Show the current file in the project navigator
  5. Open another file, tab cycling
  6. Jump to the definition of the identifier under the cursor
  7. Comment (or uncomment) the current selection

I do these commands all of the time. I often need to string a series of these commands together. Doing the equivalent without the commands risks engaging your slow thinking system and breaking you out of flow.

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

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.