I think we have all heard the old story: A man asks a woman if she will sleep with him for a million dollars. Of course, she says yes. He then offers her two dollars and she gets mad, saying, ‘What do you think I am?’ He answers, ‘We know what you are. We are just haggling over the price.’
I think most people would agree that killing Hitler (or anybody else who has killed millions of people) would be justified. And, conversely, most of us would agree that killing someone who has done no harm to anybody is utterly unacceptable (though I can think of some police officers who would disagree).
So we know what sort of people we are, we’re just haggling over the price. How many people does one have to kill in order to justify killing someone? Was Brian Thompson responsible for enough deaths to justify his killing?
My answer is, of course, “no”. But for two reasons. First is that I decry any sort of violence and killing. I am vegan, so I am opposed to harm to any animal, not just humans. (People love to ask vegans silly hypotheticals, if you are tempted, go read some Gary Francione instead)
Secondly is the same reason I oppose the death penalty: Assuming they are guilty of the crime (which is sometimes not the case in this country) it is the easy way out for them, they will suffer for a few moments and then they are free of any consequence for what they did. But the victims and those they knew will continue to suffer for years. So I want the perpetrator to actually pay a penalty comensurate with the crime, to have to live in a tiny concrete room for the rest of their days, constantly reminded of what they have done.
Brian Thompson should not be dead. He should be in jail and stripped of his assets. Let him experience the medical bankruptly he inflicted. Let him put up a GoFundMe for his medical expenses. Maybe he should be forced to spend all his days on the phone with health insurance companies appealing claims denials. That would be a suitable community service for him.
However, thinking about all these denied insurance claims brings me back to the debate about Obamacare. I was particulary amused by the “death panel” myth. Amused? Yes, because we already have death panels! They are called health insurance companies. Their claims denials, for some, lead to death.
Assuming such decisions have to be made, I would prefer it to be made by a government agency. At least we have a nominal amount of control and accountability with such an agency via the ballot box and such. A private health insurance company has no accountability and no appeals; its sole purpose is to maximize profits, which logically, inevitably, leads to claims denials. The more the better.
I guess we can bring the claims denials back to that old joke (especially since I am not really qualified to discuss the nuance of this topic). Is 48.3 million denials (that’s 17%) too many? Is one? We’re just haggling over the price.
I would suggest reading Cory Doctorow’s post Predicting the Present. He is a much better writer.
Most of my childhood was on a farm. I experienced death all the time. When I was about 8, I was closing up the hen house for the night and found her, a small hen, sitting on the floor, rather than on the roosts like the rest, her head twisting in a gentle, spastic way. Though I was young, I could see she was in a bad way. I took her into the barn where my father was shoveling out the manure. I sat down on a bale of hay and held her. She could not move in any sensible way, she could not stand, and her head would slowly twist to the left, and then spring back to normal, and repeat. That got slower and slower until finally she slumped over, her wide-open eye staring vacantly towards the rafters. She didn’t even have a name, she was just one of the brown hens. I found a shoe box and my father helped me dig a hole by an old apple tree where we buried her. I don’t think there were any tears or grief, just a bit of sadness; just another day on the farm.
In mid 2003 I had just moved in with my fiance, and both of her cats had died recently, so when the downstairs neighbor said she had a friend with an unintentional litter of kittens, we went to visit. Many of them were skittish, but one came right up to us, friendly and fearless. She was the one. She was a beatiful black and white, mostly snow white and black on top, with a large sawtooth border. We took her home and briefly discussed names, but quickly settled on “Freya”. A fitting name. Little did we know that she would rule our lives for the next 21 years. She was wild, energetic, and there was no doubt as to who was in charge in the house.It would take me far too long to write about our entire life together, but I’ll give a few snippets. Write them down before the mists of time blur the memories beyond recall.
My step son would always take her to bed with him; he would scoop her up and attempt to hold her, but she would wriggle and claw at him until he got into his room and closed the door, after which she should sleep next to him. After he grew up, this kind of stopped, but she would still sleep next to him while he watched football; in fact, that’s how she spent her final afternoon. She was wildly energetic, often tearing through the house at top speed ending with a climb up a doorway. She was often able to get to the very top, and she would look around as if trying to figure out a way to get higher. One day she even mistook my step-son for a doorway and climbed him. Everyplace we have lived has had several doorways scratched up. As she was aging I would always report this to the vet as an indication of her continued vigor. One morning right before a trip to the vet, she climbed a doorway right near my desk. I had no idea at the time, but that was one of the last times she would ever do that. After that she would run up to a doorway, and just get her front paws up and then stare upward longingly. Eventually, it was just a stare, and that was months ago.She was not a cuddly lap cat. I don’t think I heard her purr until she got much older. But she loved to curl up next to her humans more so as she got older. As long as it was on her terms. She would sleep pushed right up against my wife, but if I ever slept on my back, she loved to lay on top of my legs. After I took a shower in the morning, I would sit on the bed for a bit in my robe, and she would rush over, barely waiting for me to get in position before she trying to climb on top of me.
As she got older she really started to appreciate laptops, or, as I think she thought of them as “lumpy butt warmers”. My wife would often come back from a break to find her sitting on her laptop and an enormous string of nonsense letters in a freshly composed email. My wife got the habit of putting a notebook and stapler over her keyboard to prevent this. A habit which is now just a constant reminder of what has been lost. One funny habit she had was that she would drop her cat toys (usually little plastic fur covered mice) into her drinking water, and we would find her water a bright purple or pink from the cheap dye leaking out. Before we moved to our current house we stayed at my in-laws for a few days, who had a mouse problem. One morning my wife got a shock when found an actual mouse, dead, in Freya’s water bowl. We are not sure if this instinct was to ensure they were dead, or to clean them. It is fortunate, for all the small animals near our house, that she was an indoor cat, I am sure she would have left a trail of death and destruction in her wake.But the last few years were hard. She collected a number of maladies, one of which was a spinal issue which hindered her ability to walk, so she had a limp and one leg would thump when she walked. But even so, she would still chase her sister around (which was more fun for her than her sister), and she would still try to jump around in ways that was risky to impossible given her age. Her lack of flexibility eventually left her unable to groom herself. A few days ago her eating diminished to almost nothing and no amount of coaxing or bribing her with churu on her food would work. I knew this was a bad sign.
Whenever we would find her sleeping she would jump up to greet us, but on Monday when she tried to do this, her back legs would no longer cooperate, she spun in circles trying to get moving. We had a difficult night, and she did something she would never do: she wet the bed, undoubtedly because she could no longer move. We knew it was time. She spent her last day sleeping next to her sister, which is something they had never done for all the years they spent together. I think they both knew. At the end of the day on Tuesday, she passed peacefully in the arms of those who loved her. She was finally free of pain, but ours was just starting. As I said at the outset, growing up on a farm inures you to a lot of death. But none of that helped me deal with the hole in my heart right now. I spent more that a third of my life with Freya. Everyplace I look I expect to see her, and physical reminders are everywhere. At mealtime I still put out two plates, and get all her special food and medications out in preparation, only to put most of it back, never to be used again. Every day I find another physical reminder of her, and collect them together. This morning I found the piece of tulle she loved to play with. Maybe someday I’ll be able to look at all that without sobbing.A couple of days into the Olympics, by step-son pointed out that the US had not won ANY medals in one event: shooting. I was shocked. For the United States the gun is the holiest of holy! How could we not get any medals? To my relief, in the subsequent days the US did win some medals, including a single gold, but we still placed third overall. What a tragedy!
I came to the conclusion that the structure of the existing Olympic event was not fully compatible with the gun culture in the United States. We should push to get a new event which would better reflect our true skills as a country. The event should take place in a large room, the targets scattered randomly in the room, some of them partly behind obstacles like desks, chairs, and tables. The targets should be smaller, maybe 4 feet tall. The goal would be to burst through the door and shoot as many targets as possible. There would be several rooms set up like this, and the goal is to go from room to room and shoot as many targets as possible in limited time (the average 911 response time). The firearms used would be limited to ones which can be legally purchased in the shooter’s country, which should further guarantee the US supremacy in the event.
I do hope you will all consider my Modest Proposal carefully; I feel this sort of event would truly showcase one of our greatest skills as a nation. We must not throw away our shot.
Many of us do not think much about school shootings, as we are often far removed from them. In my case, had I lived one mile to the east and had my daughter been one year older, she could have been in one of those classrooms at Sandy Hook. As such, I often paraphrase what Phil Ochs said about the events at the 1968 Democratic National Convention: “It doesn’t really matter if you were in Sandy Hook or not, because Sandy Hook is going to come everywhere in the US, and we will all get to meet Adam Lanza, in person, one way or the other.” (the original quote was in his intro to the song “William Butler Yeats Visits Lincoln Park and Escapes Unscathed” at a performance in Vancouver, 1968, listen here)
One of the unfortunate side effects of Moore’s Law is that the immense amounts of computing power at our fingertips masks over many horribly inefficient practices. For example, something I have commonly done for a very long time is use a sort, uniq, sort pipeline to tally up something; say you have a CSV containing users and the 2nd column is the country, so you want a quick list of how many you have from each country:
$ cat u | awk -F, '{print $2}' | sort | uniq -c | sort -n
1 ca
1 mx
14 in
16 us
Obviously for a short list that first sort is not expensive at all, but with my current laptop, I can do the same thing on a file with 2 million records and it finishes in 5 seconds, despite the massive sort. Obviously, this could be done using a O(n) algorithm like so (you could do this with Awk, of course, but I’m more fluent in Perl):
$ cat u | perl -ne '$a = (split(/,/))[1]; $c{$a}++; END { foreach my $i (sort {$c{$a}<=>$c{$b} } keys %c) { printf "%10d %s\n", $c{$i}, $i; } }'
1 ca
1 mx
14 in
16 us
(For those who have been through a job interview with me will recognize this question… few of you got it right)
Here’s a different example: When I was in high school the student government ran an annual fundraiser by doing a “computer dating” event: everyone would fill out a short multiple choice survey, and those would be sent off to some company to generate reports matching people.
One day, the computer teacher obliquely asked me if I could write a program that could take a list of people and randomly put together lists and generate reports. I knew what he was hinting at: let’s skip hiring the company and generate fake reports ourselves. I wrote that code, but, being a curious sort (and not entirely comfortable with the deception), I decided to try doing it the “right” way. The basic algorithm is simply to take a string of responses and match it against everyone else in the list, take the top ten matches and generate a report. Simple, right?
I worked on that program through the summer (keep in mind I was 16 writing in BASIC on an Apple ][), but I got it working. When we finally ran it on the full data set (a few hundred surveys), it sat and ran for over a week on an Apple ][ computer. [A personal note: since I was nursing this through, I saw every report slowly trickling out; my name came up on exactly one of those reports, and at number 7, at that. I was disappointed but not surprised.] We all know the same thing would, nowadays, be a few dozen lines of code and would run in seconds, despite being an O(n^2) algorithm.
So, this leads to the current problem. I was generating a report and I noticed that it was taking several minutes to run. That wasn’t a big deal, but my curiosity got the best of me, so I broke out a profiler and found this:
Holy cow! It makes sense as the source file has almost two million records, and I am parsing the date on every record. Who would have thought simple date parsing could take up so much time? I don’t know what I can do to make date parsing more efficient, but I did realize that I only need the date in some limited cases, so I changed the code to only do the date parsing at the time I actually need to compare timestamps, Changing this to lazy evaluation, bringing me into better alignment with the three virtues. The result:
Instead of parsing 1.8 million date entries, I now only parsed 82k.
Now, in my case, my code will never have to scale much beyond the current dataset, but if I did, there would be a catastrophe waiting to happen here.
The moral of the story is that we should all think about these seemingly minor decisions we make and think about what happens when the dataset scales up by orders of magnitude. That expensive sort or needless date parsing could hurt someday. Think about how your code will scale. Profile your code! You may discover things you didn’t expect.
I used to rant on here about awful error messages, but I kind of gave up as the problem kept getting worse. It seemed that error messages were getting less informative and error handling in code was getting worse. (I complained about this years ago) But here’s a cautionary tale about what the cost of this sloppiness can be.
So I inherited an internal service from another team, and one day I go to deploy an update, and the service will not start. I barely understand this thing or the language it is written in, and now I have to debug it!
At first I think the service is stuck trying to contact some external service which is gone. But after studying the error messages I find a cyclical nature to the errors: “starting service”, “starting subsystem x”, “starting subsystem y”, etc., “starting service”, repeating endlessly. So it is not hanging but crashing repeatedly with no error messages.
Now I come to the horrifying realization: If my service should go down for any reason, it will not start up again. I cannot patch the OS, or do anything which would cause a restart. If that happens, I will now have a crisis on my hands, and I don’t even know what is happening.
I poked around further and discovered that the on-disk logs had one more error message. I suppose this error did not make it out to the logging server before the service crashed. Sounds like another bug to me. But this error message was bewildering: “java.sql.SQLException: An attempt by a client to checkout a Connection has timed out.
” That makes no sense. First off, which database? The service connects to several. Secondly, the time between the previous log entry and this one is around 2 seconds; no sane person would set a timeout that short. I found a timeout setting which was, bewilderingly, set to 1 second! I changed it to 10 seconds. Now the time gap in the log was 20 seconds. I am not sure why it is off by a factor of two. Perhaps there are two attempts to connect, or there is a straight up math error.
Clearly there is something going wrong while connecting to the database, but that makes no sense: the database is running, and nothing has changed in any of the servers or network settings. That I know of. Better test it. The MySQL command line client gets through just fine. But maybe the library being used is at fault, so now I have to learn enough of this language to write a simple database client. Several hours later I have some code working. It works fine in every relevant context. So the “timeout” is, as I thought, a lie.
I dig through the stack trace and it seems whatever is going wrong is happening right here:
Connection out = driver().connect( jdbcUrl, properties );
if (out == null)
throw new SQLException("Apparently, jdbc URL '" + jdbcUrl + "' is not valid for the underlying " +
"driver [" + driver() + "].");
From the stack trace it is clear the exception is being thrown, but somewhere along the line that error message, as uninformative as it is (i.e. there is no indication of why it failed), is getting lost or suppressed.
Fortunately, one of the previous maintainers pointed out a way to enable more detailed logging. Miraculously, it revealed this error message:
java.sql.SQLException: The server time zone value 'UTC' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.
So a fatal error is happening when connecting to the database. But that fatal error is suppressed unless debugging output is enabled. Let’s just pause and re-read the last sentence. Furthermore, the message from the other exception shown above is getting dropped along the way. But regardless a helpful article on Stack Overflow which pointed out a simple solution to add “serverTimezone=UTC” to the URL. Problem solved!
Two great mysteries remain: What changed in order to cause the timezone disagreement? My best guess is that an OS update changed some obscure timezone setting in such a way as to cause one of the servers to become confused about their timezone. The other mystery is why this fatal error was only sometimes fatal, and that “sometimes” became more and more likely as time went on, so early on, the service would restart repeatedly but then come up after some number of retries, eventually this became infinite.
But regardless, this illustrates the cost of sloppy error handling and uninformative error messages. I spent two full weeks clawing through source code trying to find the actual problem (the whole time in a panic that my production servers might get restarted and my service would be entirely down with no way to bring it back). But once the real error message was exposed the problem was fixed in minutes. That’s two weeks lost because someone couldn’t be bothered to do proper error reporting.
Every decision produces regret. Sometimes it isn’t a big thing or it is quickly forgotten. But for other decisions the thoughts of what might have been weighs heavily. I find that the older I get, the more I think about these things.
The year 2000 was a momentous year for me, the pivot of my entire life. I spent the previous year working hard fixing y2k bugs and trying to make my failing marriage work. Only one of those worked out, but, regardless, both were over. I am sure everyone has had a situation where you were working on a project frantically for a long time. But once you finish and the weight is suddenly lifted, you are confused. You haven’t had to think about what needs to be done for some time, but suddenly you do. This was where I found myself at the beginning of 2000.
I think my father sensed this and had a suggestion: let’s buy a boat. He had several boats when I was a kid, and we talked about boats ever since, often we would go down to the local marinas to look at boats for sale. I joined a local sailing club a few years earlier, but found that sailing in and out of the marina to “race the buoys” for a few hours was not what I was after and dropped out. I wanted to try longer trips to more remote places. I wasn’t interested in big boats or sailing on the ocean. I spent the first 33 years of my life within a mile or two of the Columbia River. It speaks to me. I wanted to explore.
Given the pending divorce, I had no money to spare, but he offered to pay for it. I didn’t want to spend too much of his money, and I also don’t like big boats. We very quickly settled on buying a West Wight Potter 15. So he called up the factory and within a month we were in Los Angeles picking up our newly built Potter.
When I was young, my father told me that the river was navigtable as far as Lewiston, Idaho. I always thought such a river trip would be amazing. Going upriver was far too arduous in a sailboat; the current in the Columbia river is often nearing the hull speed of a small sailboat. So unless there was a strong, favorable wind, going upriver was not something which could happen quickly. But downriver is a different matter. If you throw a stick in the river at Lewiston, by my calculation it would get to the ocean in less than a week. So if I don’t have the wind at my back, I’ll have the current pushing me forward. My employer had a generous “sabatical” policy, which let me take 4 weeks of vacation after 5 years of work. That should be plenty of time for such a voyage. I started planning the journey for the begining of September.
But being single is not something I was accustomed to. I was married young and promptly tried to find someone to fill that gap in my life. My divorce was proceeding at a snail’s pace, and here I am casting about for a relationship. We all know this will not end well. And it doesn’t. The first woman was truly insane, which I should have noticed after two dates, not after two months. Then I met a woman at a software conference. I immediately imagine I found my soul mate. But she lives in Maine. No problem! I have vacation time scheduled in September! I have some cash I was going to use on boat equipment! I spend a week with her further convincing myself that she is the one. I make plans to change jobs so I can move across the country. Within a year I am living in Boston, and within two years I am, again, alone because I did not have a cool house in northern Vermont. The tricky thing about soul-mates is that it isn’t always symmetrical: just because you find your soul-mate, does not mean the other person found theirs.
By that time my father had sold the boat, and I was stuck where I was. I got on with my life, and while I didn’t end up where I expected, I am happy with it (aside from what happened in the last paragraph).
But I always think about that trip, and wonder what it would have been like. One day I thought: why not imagine it had? Write a account of the journey: an imaginary memoir, a hallucinatory travelogue, a speculation of what might have been. I had many adventures in the final 115 miles of the Columbia. Cast those into the story, sometimes reformed to fit the narrative, others as a verbatim flashback. And make up the rest. I still have the river charts and, with the internet, I can virtually explore many of the places.
In the course of doing this, I was looking at various photos on Google Maps. Curiously, there is an island which is not on my charts: Kelly Bar. Presumably it was made in the last few decades from dredging operations. But someone shared two pictures from that island, both of them showed a West Wight Potter anchored in a sheltered spot. I take this as a sign. My Potter needs to make that journey. Even if it is only in my mind.
Another sign I should do this was in a recent episode of Sideways, where the host said:
“All of us unconciously choose what to remember and what to forget. Sometimes we edit and retouch our stories to make them more vivid or satisfying. And this is why failing to get the facts entirely correct is not unusual. It’s inevitable. And it’s also deeply, inextricably, human.”
I don’t know if I will ever finish this, or if anyone is interested, but I will share anything I deem good enough here.
I first learned to program when the primary mechanism of error handling was to check the return value of each function call and react appropriately. This often led to awful code where functions are called with no checking, and things mysteriously fail several steps removed from the actual error. Therefore I learned to add in lots of error handling so that any error messages would be very specific and easy to fix, to the point that I was once told I had too much error handling. Theoretically more modern programming languages with their try/catch syntax would help, but I am not convinced of that. syntactic sugar is no replacement for programmer discipline. Here’s a case in point, what’s the difference between this:
open(F, "$confdir/config")
$conf = parseconfig(<F>);
dbconnect($conf->{db}{uri}) or die;
and this:
try {
open(F, "$confdir/config")
$conf = parseconfig(<F>);
dbconnect($conf->{db}{uri});
catch {
die;
}
I can think of at least 6 ways this could fail, all yielding the exact same error, in either version. Don’t tell me you’ve never seen code like either one of those!
But, moving on from hypotheticals, here’s a simplified version of my code:
use Search::Elasticsearch;
my $e = Search::Elasticsearch->new( nodes => [$esurl]);
die "Error: unable to connect to $esurl\n" unless $e->ping;
print "connected to $esurl\n";
Running it gets this error:
[NoNodes] ** No nodes are available: [https://es.example.com:9200], called from sub Search::Elasticsearch::Role::Client::Direct::__ANON__ at foo.pl line 31.
Hmmm… neither my die or print generated any output; it is crashing the entire program while inside ping(). So this is my fault, I didn’t realize this module was written assuming try/catch blocks would be used, but doing that doesn’t really change much. The error message is the same; I still don’t know why it is failing. The server at the url works perfectly fine. So I dig in with the Perl debugger, and finally narrow down the crash to this line in HTTP::Tiny:
_croak(qq{$type URL must be in format http[s]://[auth@]<host>:<port>/\n});
That looks like a potentially helpful error message! It’s too bad it is getting lost somewhere along the way. Going up the call stack I come to this:
return HTTP::Tiny->new( %args, %{ $self->handle_args } );
No error handling, no try/catch, they just blindly create the HTTP::Tiny object and hope it all works. There are a number of try/catch blocks further up the stack, but the error message gets lost along the way, and by the time my catch happens, it is gone. I did discover that enabling detailed logging via “use Log::Any::Adapter qw(Stderr);” did yield that error message:
http_proxy URL must be in format http[s]://[auth@]<host>:<port>/
at /usr/local/share/perl5/Search/Elasticsearch/Cxn/HTTPTiny.pm line 86.
Proxy?! There shouldn’t be a proxy set! After some searching I finally find that someone kludged /etc/environment with the proxy. Obviously that was a bad idea. I never could figure out what was wrong with the proxy url, but since it should not have happened, and I had wasted at least an hour on this, I stopped digging.
So what went wrong here? First the error message says that the proxy url is invalid, but it doesn’t show me what that value was. Secondly, that real error message got lost somewhere along the way. This sort of sloppiness is what leads to many of the awful error messages I have documented here previously (like this), and trying to catch the exceptions doesn’t fix sloppy code.
A few weeks ago I listened to Mike Shea talk about running a Ravenloft “funnel” for Halloween. And around the same time one of the players in my newly started Drakkenheim campaign had written up an elaborate backstory which had his character escaping from Drakkenheim as the meteor hit the city. As with peanut butter and chocolate, these two should go together quite well.
So first I need a way to generate a bunch of level 0 A5E characters. I have done some searching, but have not found anything yet. I may end up writing a tool, stay tuned.
I will do more research but it seems that it would go like this: have a pile of pregenerated characters, hand out one to each player. Roll initiative, the entire thing will be done in rounds (much like Shadowdark).
I am still trying to decide if I should have just one giant table, or split it apart into a table of encounters and a table of scenery. I am leaning towards the former in the interests of simplicity: one roll each round. But regardless, roll d100 plus the number of rounds played. The encounter table will be laid out to escalate, more difficult encounters are located at the end of the table, which will obviously go well past 100. Paint the scene, and run the encounter.
If a character dies, the player will grab a new one, and play proceeds.
Lather, Rinse, Repeat.
I was thinking of various ways to track progress towards a goal, but I have concluded the best way to do this is to set a real world timer. When that timer goes off, finish the current encounter, you have reached the city gates and have gotten to safety! You could measure the “success” of the game by counting how many rounds it took, the body count, or how many rounds each character survived.
I have a spreadsheet I am using to collect ideas for the encounter table. Suggestions welcome!
So I just ran into a piece of code which looked something like this
request = http.request(someurl)
if (request.status == 200)
{
mystuff = request.body.foo
}
I showed this to my wife, who knows almost nothing about code. She said “what if it gets a status other than 200?” Despite the fact that her one and only coding class was in high school and she barely remembers it, she has managed to do better than the veteran who wrote that code! I responded, “Well, at least they are checking for the status rather than blindly proceeding!” I should not have said that. Fifteen minutes later, in the same file, I ran into code which was like this:
request = http.request(someurl)
mystuff = request.body.foo
Larry Niven once said “That’s the thing about people who think they hate computers … What they really hate is lousy programmers.”
So after finishing Cory Doctorow’s book I have been thinking about all the enshittified platforms I have been entangled with and how to reduce my dependence on them. Then I start thinking about how they tricked me into these situations. And then I thought about the OGL debacle (here are my earlier ruminations on the topic), and how badly WotC mishandled things with respect to “monetizing” the brand. It seems like the enshittification playbook has been demonstrated repeatedly, so it was a colossal failure on the part of management there.
Here’s the way it should have gone:
[Since I started writing this, I heard an owner of a game shop pointing out that the digital bundles are a total rugpull against them. If most people will want to get access to the books on D&D Beyond, why buy them separately? The only reason you would go to the game shop is to get the special covers. This is some late-stage enshittification: “…abuse those business customers to claw back all the value for themselves.” Good job!]
I am not sure if “OneD&D” complicates this picture or not. I think the key for rolling that out is to ensure the platform works equally well for 5th and 6th edition, and then just put the new books up for sale. Make it easy to switch over, and, for now, make it easy to stay with 5th edition. Make sure to keep the revenue flowing for 5th edition. It would be tempting to force people to the new edition, but you do want to make sure the effort to switch to the new edition is really trivial (once the requisite amount of money has been spent). But which edition is in use is kind of irrelevant as long as the monthly membership fees keep flowing.
Before the OGL Debacle, I was on the verge of buying a source book bundle and a paid membership on D&D Beyond. I was even reading the playtests packets for the next edition. If they had followed the above strategy, instead of burning a whole lot of goodwill, I would have been fully committed to the platform as they rolled out the above strategy. At some point I may have caught on, but by the time I did, the switching costs would have been quite high and I may have begrudgingly stuck with it, as I am doing right now with Amazon and Google. And even if I did work up the gumption to cancel my subscription, I would have been virtually alone. And where could I have gone? Without the OGL debacle, there would have been far fewer alternatives, there wouldn’t have been Project Black Flag or C7D20, and maybe Level Up A5E would have dried up.
So it is really mind-boggling that they blundered to the degree they did, especially since several of the executives at Hasbro came from Microsoft which is the pioneer of building tech monopolies via shitty business practices. Had they been patient and careful, they could have dominated the entire industry.
Trying to think like an evil genius has made me feel kind of dirty. I think I’ll go take a shower and get back to planning my Level Up A5E campaign.
The topics I have discussed here over the years have veered around wildly according to my interests at that time, but, despite my domain name, I haven’t mentioned veganism in 8 years. Why not? Don’t get your hopes up! I have not become a born-again meat eater.
I didn’t even notice that the 23rd anniversary of me becoming vegan passed last month. After being vegan for that long it has kind of melted into the background. Even the day-to-day struggles of living in a world hostile to vegans has become mundane and routine.
When I first became vegan, I bought a bunch of cookbooks and learned how to cook, because there were few alternatives. I generally avoided going out to restaurants, because I was tired of the laborious process of explaining what veganism is and what I do or don’t eat and then having to send food back because they covered it with cheese. “No, I do not eat chicken… or fish… or cheese. No, I don’t miss it.” At that time, finding vegan food in the mainstream grocery stores was quite difficult (aside from fruit and veggies), and I would have to do most of my shopping at health food stores. And, even then, there were many things which had no vegan analogs (e.g. cheese).
But all this has changed. In my experience, being vegan has become easier than ever. I believe much of this can be attributed to the larger population of vegans. When I became vegan, the estimates were that less than 1% of the US population was vegan, but now it is over 3% (with some estimates as high as 10%, though that seems doubtful). While that doesn’t seem like much, it has more than tripled, and is now enough to swing an election.
So nowadays, if I need to find a restaurant, I just bring up Happy Cow and, most of the time, I can find something nearby. And if not, most people at least know what veganism is, and there are far fewer questions. And almost every mainstream grocery store has most vegan items I may want.
When I first became vegan I was a bit strident about it; I wanted everyone to become vegan. I still feel strongly that everyone should be vegan, but I don’t try to talk people into it anymore. In addition to the normal mellowing that happens as one ages, I think there’s an element of resignation. For all the people I have talked to over the years, I don’t know of a single person has ever become vegan as a result. The only person who is vegan because of me is my daughter, and she has never known anything else in her life.
So, I’m not going to put much effort into telling you why you should be vegan. You should! And the reasons are obvious. But I doubt anything I say will change your mind.
But, on the other hand, I do still have a number of photos in the suicide food category, and as soon as I come up with snarky descriptions I will post them.
When I watched Enola Holmes with my daughter, I really liked the protaganist breaking the fourth wall and talking directly to the audience. And I had a thought: What if someone ran an actual play D&D campaign with the same mechanism?
When I am listening to actual play podcasts, I often hear the players create an unexpected situation, sometimes I can even hear a sigh or some other reaction from the DM that indicates they didn’t expect it either. It would be really instructive in those cases to have the DM stop, turn to the audience and talk about the situation and what they are thinking about doing in reaction.
Anybody who has run a game knows what it is like to have players make unexpected choices. For example, in a recent game I had a player approach a person in a tavern, and rather than ask questions, simply punched him. OK, I didn’t expect that, and I don’t want a full bar fight, mainly due to the time it would take. The NPC had some magic at hand, so he makes a “suggestion”: “why don’t you just sit down and have a drink?”. The character makes his save, which I didn’t expect as it was a high DC. So I have another, well armed, patron step in and make it clear that a fight would not end well. Or should I have let the full bar fight happen? While a one-way soliloquy would not have helped my current situation, but it would have helped other DMs into the thoughts running through my head as a desperately tried to cope with the situation. Being a DM can be a lonely thing at times, and at least seeing others deal with the unexpected would be comforting.
I briefly thought about doing such a podcast myself, but then I think better of it given that I have no experience with audio recording, I have a really annoying sounding voice, and I don’t think my current group would be interested in being recorded. But if someone out there does this, let me know.
[I started writing this in 2016 and unearthed it amongst some old drafts. But 6 years have only intensified my feelings here, so here it is updated and finished]
I’m sure you’ve all heard the statement from Arthur C. Clark that “Any sufficiently advanced technology is indistinguishable from magic.” But I had an exchange which convinced me of a variation of that: “Any suffciently hyped technology is indistinguishable from religion.”
The case in point was a discussion with someone who seemed to think that Git was the only version control system which had checkin hooks. And after informing him that every modern version control system, indeed, every one of them I’ve used in the last two decades, has such things (in one way or another), he repeated the same thing later on in the conversation, as if unable to process this new piece of information which contradicted established dogma.
Another interaction was with someone who asserted that Git was “more secure”. When I questioned him as to exactly how it is more secure, we was unable to articulate anything meaningful. Then I pointed out that is was trivial to forge checkins (and even demonstrated it in front of him by doing a checkin in his name), but this didn’t phase him, and he returned, mindlessly, to his original point.
I have nothing against Git on the whole, I use it myself every day. I have minor gripes with it, mainly having to do with the arcane, counter-intuitive interface (like this). But my biggest gripe is the religious fervor with which it is hyped, the irrational one-size-fits-all, Maslow’s Hammer weilding, be-all and end-all, the perfect final pinacle of version control. For ever and ever. Amen!
There have been many “religious wars” in the software world over the years. Long ago I defected to the Emacs camp, so I know it well. But with all of those wars, there were always competing technologies; differing views on how to approach a problem. But in this case, there is only one left, all others have been shouted down into irrelevancy. At the time of Git’s ascendance, I was managing at least 6 different version control systems, and I thought this would just be one more to add to the mix. But I was mystified as my team was quickly sidelined as everyone mindlessly rushed to Git.
I am a believer in using the right tool for the right job, and Git is certainly the right tool in a lot of cases, but not every problem is a nail. Sometimes you need different tools.
I notice that I wrote about this earlier, but I am now taking the long view of this: every ascendant technology eventually declines as the next shiny thing attracts everyone’s attention. I look forward to the day something new comes along and pushes Git to the sidelines.
So I create numerous SVN replicas and since it takes several steps to do this, I have it automated all the icky bits in a script. Usually it worked fine, but this time, the whole thing mysteriously fails with this:
svn: E165001: Revprop change blocked by pre-revprop-change hook (exit code 255) with no output.
Let’s translate “with no output”: “somewhere along the line a programmer neglected to detect and/or issue an error message”. A fatal error never fails with no output unless someone, somewhere, screwed up the error handling code.
So I run the propset command manually… works fine. I run it with the debugger… all is well, but the propset command fails. I run the propset command in another window… works fine. Now, from in the debugger I run the propset with strace. Buried in the output I find this:
18704 chdir(".") = -1 EACCES (Permission denied)
18704 exit_group(-1) = ?
Sure enough! I had su’ed to the repository owner id, but my personal home directory was locked up:
$ ls
ls: cannot open directory .: Permission denied
One thing to note is that there is no attempt to issue an error message between the chdir() and the exit_group()! I wonder which would cost more: the programmer adding one line of code to issue an error message, or me spending half an hour figuring out this problem?
I should have known better.
I wrote previously about my experience getting legal threats from TSR (and wrote more details later on, though DM David has an excellent post from a wider perspective). That experience caused me to abandon D&D and for the next few years my group played FUDGE. I had hoped that many others would follow my lead, but since I am neither articulate nor charismatic, that came to nothing and this was all forgotten.
When I rediscovered D&D 20+ years later, the old TSR (They Sue Regularly) was long gone and it seemed the new stewards of the brand would be better behaved. I had briefly looked at alternative systems like Pathfinder, OSR, or even returning back to FUDGE. But the fact that WotC had put 3rd and 5th editions under the OGL, convinced me to stick with D&D, that I could trust them again. By late 2022, I was on the verge of getting a full D&D Beyond subscription and spending hundreds of dollars on a bundle of books on there and commit fully to using all the “official” tools.
We all know what happened next. They say that history doesn’t repeat, but it does rhyme. This time, rather than threatening a handful of hobbyists running ftp sites in their spare time, they threatened actual companies with nullifying their business model. So unlike last time when the “resistance” consisted of a few guys on a USENET newsgroup complaining, this time it was a large scale revolt, to the point that several companies vowed to cut ties with the OGL by building their own systems and licenses.
But given my experiences, I saw the OGL as a positive thing: a way to draw a clear line between what you could and couldn’t put in your own D&D related work. Even though where they drew that line was very generous to themselves and the whole thing was on very shaky legal ground. But it was still a known line, and as long as you followed their rules you, theoretically, had little to fear. Had the OGL existed in 1994, my ftp site would have continued running relatively unmolested. But I never would have predicted that they would attempt to revoke the OGL, thus turning a tool which enabled a vast expansion in the D&D market into a cudgel with which to threaten the entire community unless we paid their ransom.
I have long said that any organization which exists for long enough will eventually forget their original purpose. The TSR which sent me a threatening email was 20 years removed from the gaming enthusiasts putting together pamphlets in Gary’s basement, and 10 years removed from the founder even being at the company. It was no longer about the game, it was now about protecting potentially profitable turf. Or to put it in more modern terms “the brand is really under monetised. Of course, there was no way for me to know at the time, but this company was now circling the drain towards its demise three years hence; so I now also see those threats as an act of desperation to somehow right a sinking ship. WotC seems to be following that same process, forgetting who they were to pursue greater monetization.
As George W. Bush said “fool me once, shame on… shame on you. Fool me… you can’t get fooled again.”
So, I’m done being fooled… where to from here?
As Mike Shea has pointed out, once we own the books we can play the games forevermore without any interference from WotC. We own the game. This is true, up to a point…
But there is D&D Beyond. It is telling, given events 8 months later, that on the Mastering Dungeons podcast (21-Apr-2022) they expressed relief when Hasbro acquired D&D Beyond. There was a fear, before that, that WotC could pull the license and everything they had done on D&D Beyond would be useless or gone. So, it seemed, in that moment, that the acquisition would guarantee that D&D Beyond would no longer suffer that fate.
At the moment all of my D&D is played online, and the siren song of D&D Beyond is quite powerful. The online character sheets make life a lot easier, and being able to search for rules and spells is a huge time saver. But it is a company town, a walled garden. You can only get WotC products in there and you have to pay a significant amount of money for the illusory ownership of source books. You do not really own anything, it can be changed out from under you at any time. What will happen when 6th edition comes out? How long do you think they will let you continue playing 5th edition? What are the odds that 3rd party content (other than Critical Role) is ever allowed within their walls? Everything there is temporary and trapped within their enclosure. While the platform is not yet enshittified, the lack of interoperability means the only barrier is how much goodwill they are willing to burn for more monetization. The OGL fiasco shows that they are quite willing to burn a lot of goodwill. (For more on this general issue, read Cory Doctorow’s latest book, The Internet Con).
They have shown that they cannot be trusted.
So I want to avoid the siren song of D&D Beyond, and the best way to do that, and at the same time to support independent creators who were most harmed by the OGL fiasco, is to use a different system. But which one? I know there are many systems other that D&D, but I like D&D and I am an old man and have limited bandwidth for learning new systems. Especially to learn it sufficiently well to feel confident running games. So that leaves me with one of the 5e variants which have popped up lately. At the moment, Level Up Advanced 5th Edition seems like the most complete at this point, though I am keeping an eye on Tales of the Valiant. I am going to try out the former in my next campaign, perhaps something else in the next one.
The main puzzle is how to replace D&D Beyond. We are fortunate this happened before they rolled out a virtual tabletop, as I have already committed to Owlbear Rodeo. Having the rules and such available online is already there at https://a5e.tools. But the character sheets are the problem. They need to be online, as I like to review the characters before each session (as per the first of eight steps of lazy rpg prep), it seems the only immediate option is to share form-fillable PDFs. I guess I’ll start there. Stay tuned.
Sometime in 1997 I played my last D&D game. We were still playing AD&D first edition, as we had when we started about 13 years earlier. We had avoided 2nd edition as it just seemed like TSR was trying to sell us more books which we really didn’t need, and there didn’t seem to be enough improvements to justify the cost. Due to the events I related in a some previous posts, I stopped paying attention to what TSR was doing, and was unaware of what happened to company and the game for the next 20 years.
When I finally came back I was shocked to see it was now up to a fifth edition! I had heard references to the Edition Wars, but it seemed that a lot of the controversy was dying down. I had thought about just returning to first edition, since that is what I knew. That might have happened if all my D&D books hadn’t vanished in the intervening years. But since I had to start fresh, I decided to settle on 5th edition and started reading the rule books and listening to actual play podcasts.
I finally started playing the game in 2020 (thanks to the pandemic) and I have been pleased with 5th edition. It felt very familiar, the basics of the game were about the same, with a number of key fixes. When I played AD&D I remember thinking how some of the rules made no sense or that they were a bolted-on afterthought and I am glad to see most of those went away. I always thought the lack of a skill system was a problem, but the homebrew solutions I remember seeing were hopelesly complicated. Often in our games, we would just come up with some arbitrary number and roll a dice against it, but that never felt right. But I think the way 5th edition dealt with it was simple enough, but allowed most non-combat actions to be decided in a logical way.
All in all, I am really glad I missed the Edition Wars. Though I have been fascinated to learn about all this in retrospect, one of my favorites is The Editon Wars podcast Also the Plot Points Podcast has been reading the 1st edition DMG aloud and the commentary has shed a lot of light onto the weird corners of the original game.
I can see why people got so attached to their particular editions of the game, but if there is another Edition War, I may, once again, be AWOL. I plan to focus on getting together with my friends and playing the game. That’s what really matters.
My first attempt at DM’ing was The Keep on the Borderlands. I was probably about 16 years old and we bordered on being murderhobos. Even so, I was troubled when I hit this passage:
Of course, the players marched in and started killing kobolds. We had a brief discussion about how to deal with the young ones, and we soon decided that since their race was inherently evil, killing them was not a problem. But it always bothered me. To the point that I remember that moment vividly over 3 decades later.
A while back I saw discussions on Twitter about “inherently evil races”, and I immediately knew what they were talking about; I was right back in those kobold caves. This discussions even made it onto NPR.
Looking at the various threads on Twitter and Reddit and there are quite a variety of reactions. I am honestly confused by the controversy here. I don’t think anybody is saying there can’t be evil in the world, or that you can’t have evil Orcs or Drow. But when you see a Drow you can’t just assume they are evil and kill them without thought; you’re going to have to find out first. It may well be that the bulk of their culture encourages evil behavior, but there are always exceptions. You might even have to role play an interaction with them to find out where they stand before rolling for initiative.
It is good to see this discussion take place. As with so many discussions on the internet it generated much more heat than light. But for me, it was comforting to see so many others troubled by situations like the one above. At least I am not alone, and there are many others ready to change this.
So now when I role play the goblins in Cragmaw Cave (for example), I think about why they are there and what their individual motivations are. They are not mindless automatons who will fight to the last; they may flee, surrender, beg for mercy, etc. And if the characters persist in mindless slaughter, there could be consequences to that: they could miss out on key clues, or they could gain a reputation as genocidal maniacs. The goblins may react in greater force to them next time knowing this. They could spark an even larger human-goblin war, which could have even more consequences for the characters.
And if you don’t like that, and you just want old-fashioned inherently evil races, you can do that at your own table, just don’t expect to have a lot of company.