Tuesday, November 3, 2015

Windows 10's "Notify to schedule restart" option is evil

Happy Patch Tuesday, everyone.  This is actually my first Patch Tuesday on Windows 10, and I'm learning some interesting things about how it works in 10.

By default, Windows Update will reboot the computer automatically when it's not in use.  That's fine for most people, but since my computer is essentially a gaming rig, I don't want to trust Microsoft on the whole "when it's not in use" thing.  I have occasionally seen other software vendors screw this up, and I'd rather choose reboot times myself.  I rarely leave the computer on for more than 12 hours on end, so there is usually no need to reboot the computer anyway.  I opted for "notify me to schedule a restart," which seems sensible enough, right?

Wrong.  You see, when Windows Update "notifies" you, it does this by minimizing whatever you have open and popping up a system-wide modal dialog.

Yes, that's right.  A system-wide modal dialog (like a UAC prompt, so you can't click away from it).  Which steals focus and wasn't initiated by user action.

Seriously, guys?  That was the best UX design you could possibly come up with?

OK, let's review some basic UX rules that I thought Microsoft had down cold, but apparently they don't.  First, you do not steal focus.  Ever.  Whatever the user is doing is always more important than whatever you want to show them.  Microsoft applies this rule to other apps, but apparently can't be bothered to follow it themselves.  Second, dialogs are not modal.  To be more specific, dialogs should rarely be app-modal and (almost) never be system-modal.  UAC breaks this rule, but there are legitimate security reasons for it (if it were not system-modal, another app could steal focus or interact inappropriately with the dialog).  For Windows Update, there are no such reasons, other than the perennial "Windows Update must be as annoying as humanly possible" design aesthetic that Microsoft seems to go for with each new version of Windows.  Thirdly, dialogs are initiated by user actions.  Dialogs do not randomly appear when the user is in the middle of something, if at all avoidable.  For that use case, we have toasts, balloon tips, etc., which are all far less annoying.

It is 2015.  We should not be having this conversation, Microsoft.

Friday, September 18, 2015

Mercurial koans

A young acolyte approached Master Hg.  "Master Hg, what is the nature of Mercurial Branches?"

Master Hg replied, "Branches are markers attached to every commit, indelible and eternal."

The acolyte nodded.  "Master, if we use branches for tracking new features in our product, how are we to avoid namespace pollution?"

Master Hg regarded the acolyte coolly.  "Mu.  Branches are lines of development, forgettable and ephemeral."

At once, the acolyte was enlightened.

A student was working under Master Hg.  "Master, yesterday I discovered a seven-headed hydra in our history."

Master Hg nodded, saying nothing.

"I did not wish to fight the beast, but I noticed it resided entirely on a separate branch.  So I closed the branch, and thought it dealt with.  But today I looked again and saw the hydra still lived.  Why was the branch not closed?"

"The branch was indeed closed," replied Master Hg, "leaving six branches open."

Ed. note: This koan is obsolescent and has no successor.

One day, a traveler from a faraway land sought Master Hg's guidance.  "Master Hg, I wish to alter history."

Master Hg nodded, smiling warmly.  "What you seek is easily attainable.  History is supple and easily rewritten."

Excitedly, the traveler began researching in Master Hg's veritable library and shared his work with others.  After many days, he returned.  "Master, when I tried to share my changes with my friends, as I have done in my homeland, the DAG became extremely confused and I had to re-clone the server.  Why does Mercurial not work correctly?"

Anger flashed across Master Hg's face.  "What you seek is impossible.  History is unyielding and changing it the domain of the gods."

"But mere days ago," the traveler protested, "you told me otherwise."

"I find it curious you remember events which did not occur," replied Master Hg.

The traveler stormed out angrily.  It was many hours before enlightenment struck him.

Saturday, June 13, 2015

Tim Hunt: Not a martyr

As with most incidents relating to the feminism vs. "men's rights" debate, I had planned on quietly ignoring the Tim Hunt issue.  Like previous events (donglegate, elevatorgate, etc.), this one is a fairly straightforward issue (Should Tim Hunt have said those things?  No, of course not) with a lot of stupid internet drama on the side (though since I left reddit, I have seen a lot less of that), and I prefer not to contribute to the latter.

But then I read a fascinatingly unhinged article in Reason.  I got about halfway through before I decided I wanted to blog about it.  The basic premise seems to be that Hunt is being oppressed in some fashion.  The truly bizarre part, however, is who's (allegedly) doing the oppression.

Friday, April 3, 2015

Why I don't use hg-flow

I recently had a chance to read A successful Git branching model (the branching model underlying the popular git-flow and hg-flow extensions), and I found it rather interesting.  For NBTParse, I've been following a modified form of Mercurial's standard branching.  I thought about trying to adapt my work to use hg-flow, but I realized the differences are largely cosmetic:
  • My main development descends from the @ bookmark, just like the "develop" branch of Driessen's model.  Conveniently, Mercurial automatically updates to this bookmark when cloning, if there's no obvious target revision.
  • Although I rarely bother with them, feature branches are easily supported as bookmarked alternate heads of the default named branch.  I may use them more often once NBTParse approaches stability and it becomes necessary to keep the trunk stable(ish) leading up to a beta release.
  • I use release branches, much like Driessen.  Mine are named branches instead of bookmarks, but this is mostly a matter of the former not existing under Git.  The release branches also have bookmarks, which are reused from one branch to the next; this makes it easy to (automatically) find the current unstable release branch (it's just release-unstable), for example.
  • Much like feature branches, hotfix branches are just bookmarked alternate heads of release branches.  Again, I rarely bother with them, since my release branches remain open for as long as the released product is supported.  However, they can be useful if a fix is likely to require multiple commits or the attention of multiple developers.
  • Now we come to the "master" branch.  I must admit, I don't quite have a master branch, but I have the next best thing.  All my releases are tagged, and the latest unstable (and stable, once we hit stable) is bookmarked.  I can just do hg log -r 'tag("re:version-.*")' to find everything that would have been on the master branch if I had one.  If I only want stable releases, I can use a more precise regex (e.g. ^version-\d+\.\d+\.\d+$).  Oh, and those revsets work in Bitbucket's search interface, too.
I'm sure Driessen's model is extremely helpful for him and lots of other developers, and it's nice to see people looking at nontraditional branching strategies.  But I guess I just don't see much value in rearranging my commits like this; my revision DAG is complicated enough already.

Friday, February 20, 2015


For quite some time, now, I've been working on a Python library called NBTParse.  It's designed to manipulate Minecraft worlds.  It's been languishing in a not-ready-for-prime-time state for the longest time, but I've finally decided to start working towards a 1.0 release.  As a motivator for that, I've begun rapid releases of 0.x.0 versions.

Each new 0.x.0 release will happen on the first Thursday of the month.  0.2.0 dropped on the 5th, but I didn't think to blog about it until now.  It can be had from PyPI under the name nbtparse (that is, you can run pip install nbtparse as usual).  If you don't have a C compiler, you may have difficulty with this.

Let's talk about the current status of the library.  It's currently very rough, with a number of serious shortcomings.  The biggest is the lack of a lighting engine.  In short, it doesn't adjust lighting information after altering the terrain.  Because of this, terrain manipulation is highly risky at the moment, with great potential to corrupt saves.  In other words, back up your saves before playing with this.  But you knew that already; it's listed as pre-alpha in PyPI, after all.  Work on the lighting engine has not seriously begun yet, so this will likely remain the case for a long time.  On the other hand, I hope to at least have heightmap updating in time for 0.3.0 (this will hopefully prevent any corruption from actually crashing Minecraft, though you'll still experience lighting errors).

Another issue is Minecraft 1.8 compatibility.  In short, there is none.  While 1.8-isms are nominally accessible, they're not particularly fun to work with right now.  Fortunately, this is mostly a matter of sitting down and writing declarative code to describe the new features.  It should be fairly straightforward once I get around to actually doing it.  I hope to have this in 0.3.0.

Finally, the API is not yet stable.  Some aspects of the library may change as we move closer to 1.0, without backwards compatibility.

Sunday, October 19, 2014


A few days ago, I bought a $5 desk toy on Amazon. Now that it's here, I'm regretting the purchase. It's not nearly as good as I expected. Oh well, it's not that much money.
Do you ever wonder if you could have done things differently?
What do you mean?
Well, take that toy, for example. Could you have decided not to buy it?
Well, if I had known I wouldn't like it, of course I wouldn't have bought it.
That's not what I meant. Could you have chosen differently if you hadn't known?
What are you talking about? I didn't know and I did buy it. What more is there to discuss?
Were you making a real choice, or just following the laws of physics?
What is a "real" choice?
A choice which could have come out differently.
If I had decided by flipping a coin, then it could have come out differently. But that doesn't really strike me as much of a choice.
No, the coin's motion is determined by chaotic air currents and subtle physical factors. There isn't any real randomness there.
OK, what if I use a Geiger counter hooked up to a radioactive mineral? Unless you subscribe to a hidden variable theory (which I do not), the counter's clicking is truly random. No matter how much you know about the situation, you can never predict exactly when it will go off.
We're missing the point. I don't want to know whether a Geiger counter could have made a different choice. I want to know whether you could have made a different choice.
Either some part of my brain acts like a miniature Geiger counter, or no such part exists. If it does exist, then yes, I could have "chosen" differently, but I don't think you'll want to count that either. If it doesn't, then obviously not.
So you admit it! You did not make a real choice, because real choices don't exist. We're all slaves to physics.
Nonsense. I wanted it, and purchased it because I felt like it. My action directly resulted from my desire. No one forced me to buy it. Physics isn't a person, actively controlling my life. You still haven't given me a definition of "real choice."
A real choice is a choice you could have made differently, under the same circumstances, under your own conscious direction.
But why would I want to? At the time, I thought it was a grand idea. In that state of mind, why wouldn't I buy it?
That's irrelevant. The question is whether you could have chosen differently, not whether you actually would have.
What's the difference between "I could have chosen differently, but never would have," and "I could not have chosen differently?" Those sound like the same thing to me.
They're not. "Could" is physics. "Would" is choice.
But you just said choice doesn't exist. Besides, how can choice be independent of physics? Unless you want to start talking about an immortal soul or something...
It doesn't matter. A choice-making soul would have the same logical problems as a choice-making brain. And this quibbling is pointless. Choice, as I've defined it, doesn't exist. We both agree on that much, I think.
It doesn't exist because it is ill-defined.
No, it doesn't exist because it fails to refer.
The desk toy was just an example. Setting it aside for now, all of your arguments have been a priori, that is, logical reasoning divorced from empirical evidence. If you demonstrate by logic that something can't exist, it must be logically inconsistent. You've argued that your own definition of choice is logically inconsistent. Your position is the same as mine.

The above writing format is a blatant ripoff of Galileo. I find it rather convenient, but it is admittedly unoriginal.

Tuesday, September 23, 2014

Watch Your Back, Git

Changeset evolution is a big deal.  But nobody seems to be talking about it.  Well, except for this guy:

But even he says it's a small set of incremental improvements.  This is not small.  But it is all a little abstract right now.  Let's write a use case.