Review of Sora’s Quest by T. L. Shreffler

Wow. This is a good one.

Here’s a link to the book: http://amzn.to/1UmwKhE

I download several free ebooks every week. I start a lot and bail once I get bored or get angry that the writer is going with some tired-out cliche.

So I started Sora’s Quest in that frame of mind — looking for an excuse to delete this book.

And this book is a fantasy book, which is a genre filled with the worst crap. Especially at the free tier. Honestly, once self-published ebooks became a thing, petabytes of beastmaster erotic fan fiction burst out on the internet.

So, like I said, I wasn’t optimistic.

But the first chapter was pretty good. A guy discovers his brother has just been assassinated moments before. He uses some magic to track down the assassin that is making his escape.

Magic is to fantasy what time travel is to science fiction. It’s hard to pull off well! Skilled fantasy writers bring something novel to the mechanics of magic works. And they explain it just enough so I understand why people do what they do. But they keep the plot moving.

Unskilled writers forget that they’re on borrowed time. They shift from the story line to an exposition of their made-up metaphysics, and it just kills the momentum.

Or even worse, they use something blatantly yanked from elsewhere. That’s usually a sign I’m reading something like a book version of those horrible bar bands that cover currently popular songs.

But this author introduced magic in this world cleverly and succinctly. Blood magic requires sacrificing living things.

The magician catches up with the assassin, but the assassin turns out to be way more difficult to kill than expected, and the magician gets wounded in the fight while the assassin gets away. And the chapter ends with the magician swearing to avenge his brother’s murder.

The story hops in perspective to follow Sora, a 17-year-old noble lady, preparing for something like a society debut. Her mother disappeared when she was an infant and her dad is an aloof jerk, mostly interested in getting her to marry into a family that will improve his status.

Lily is Sora’s maid, and their relationship reminds me of the dynamics between the maids and the ladies in Downton Abbey.

Anyhow, the coming out ball begins, and then Sora performs her “blooming” dance, and then accidentally falls down, which is just an awfully embarrassing thing.

But then the skylight above the ballroom shatters, and her father is gravely injured. Sora realizes that this was no accident when she runs into an assassin in the hallway who is about to kill her, but then decides to take her with him as a hostage.

And that’s the end of the second chapter. I was hooked. And I was surprised by how much I liked this book. Every chapter after that pulled me in more. The story bounces between the magician tracking down his brother’s murderer, and Sora who has been kidnapped by that same assassin. The story starts off following the magician, and we sympathize with him wanting to avenge his brother. But then by switching to the perspective of the people he is hunting down, and by coloring them in enough, the reader ends up empathizing with that crew as well. It becomes clear that they have their own sense of morality that’s not so different after all, especially given their situation.

So it’s not clear who are the heroes and the villains. Everyone is just trying to survive.

And there’s a gorgeous twist at the 80% mark that I really enjoyed.

Here’s the thing I’ve noticed too often about female characters in the fantasy genre. They’re usually damsels in distress or basically Xena Warrior Princess ice cold commando types. They’re paper-thin characters that are completely predictable and unrelatable.

But Sora comes off (to me, at least) as real. And she evolves and adapts plausibly. She’s not a brat and she’s not a robot.

Last thing — the author clearly spent a ton of time daydreaming and constructing this world’s history. There are all sorts of little hints about it all. Humanity won some “war of the five races” thanks to using anti-magic devices, and the other races are now almostly extinct. I really liked how she described the old civilizations (spoiler: author is a girl).

I just bought the sequel to this one. It seems to follow the assassin and for the first time we get to see into his thoughts. He’s an opaque dead-eyed killer for most of Sora’s Quest, and I hoped we’d find out his back story.

Honestly, this is an exciting story in a fantasy world that’s different from the usual Tolkien-inspired elves and dwarves tropes we’ve all read a million bazillion times. And an interesting female character!

Mary Dunbar is the best candidate for Cleveland Heights Council

I’ll vote for Mary Dunbar tomorrow in the Cleveland Heights election.

Here’s why:

  • She actually replies to my emails! And it ain’t just me. You’ll see she engages with people often, online and in person. She’s the only candidate that showed up at Heights chicken coop tour, for example, and she wasn’t even in support of the legislation.
  • She’s passionate about improving our city’s walkability and bike infrastructure. This is one of the last advantages Cleveland Heights has. We need to guard this with our lives. You may not think that bicycling and pedestrian access is that big of a deal, but you are wrong times infinity. Getting people out of their cars and walking around instead has myriad positive effects.
  • She doesn’t promise anything grandiose. It’s so tempting to make grand sweeping statements and wild accusations or big promises or irresponsible rhetoric. You don’t see that coming from her.
  • Last point — this town skews too far into the progressive Democrat direction. We need an intelligent critique to prevent groupthink.

Beware the trap of the local optimum

Lots of problems look a little like this:

1-11. Local and global optima.

The Y-axis measures success at whatever problem you’re trying to solve.

You start at the farthest left point on the curve and you can move left or right a little bit every time you work on the problem.

After you make it to the top of the first hill, the only way to make it to the top of the second hill is by going down first.

In jujitsu, if I’m lucky enough to get to mount, my instinct is to camp out there. Maybe I can submit the other guy by sweating on him. I’m in a relatively safe position now, so I don’t want to take risks. In other words, I’m at the local optimum.

If I go for a submission like an arm bar, given my current skill level, my opponent will probably escape the mount, and I’ll be in a worse position afterward.

So in a self-defense situation, it might be smart to camp. The failure penalty is high!

But in class, because the cost of failure is so low (really, I just don’t get to feel like a badass when I tap out) I am wasting an opportunity to learn (and move to the right along the curve)!

RIP hen #1

For two years now, I’ve been letting my hens free range around in a fenced-in section in my back yard during the day. They love it.

Went out to check for eggs today after work and found one of my girls had been killed in the coop.

Head bitten off. No other signs of predation. Internet forums say this was likely a possum or a raccoon.

Going to set up a live trap tonight. And some wire snares.

I raised these girls since they were a day old. Can’t really remember the last time I was this angry and sad.

What’s good and bad about github issues

Ticketing / workflow / bugtracker systems are always nasty. Github’s is pretty good. Maybe the best of what’s out there. But it ain’t perfect.

Here’s what I like:

  • It’s ready to go immediately once you start your github repo.
  • You can link a commit to an issue by mentioning the issue number in the commit.
  • Labels let you store a TON of metadata.

And what I dislike:

  • No obvious way to tell if somebody is actively working on an issue. More generally, no “status” field exists on an issue.
  • No obvious way to do a query like “label X or label Y”.
  • No command-line interface.
  • Since github doesn’t include a built-in mailing list, github issues often get used for support requests. Then when somebody explains “here’s how to do … “, the issue gets closed, and that helpful expensive-to-write documentation is hidden away. The solution here is for github to host a mailing list for every repository.

I really like my gardening boots

You don’t need many tools to start gardening. You can dig holes with a stick or a sharp rock. You can start seeds in tin cans. You can use all sorts of stuff to carry water. You really only need dirt, sun, and seeds. So don’t run out and buy a bunch of stuff!

But when you realize you’ve got the gardening bug bad, there’s a few tools that really help. First off, you need some rubber boots. Otherwise, you’re going to track mud everywhere. That’s going to make your significant other very annoyed!

I bought these boots in 2006. They’ve held up very well over the last seven years. They’re waterproof, thick enough to block thorns, easy to hose off, and the sole is thick enough that I can push on a shovel with them.

They’re made here in Illinois, USA, by Boss Manufacturing Company. They’ve been around since 1893!

You can order them on Amazon. You can’t order them direct from the company.

Note: I will get some commission if you order the boots from the link below, so if you hate me, you should not click on that link.

old-school code checklist

You can’t call it old-school code unless a majority of these are true:

  • global vars are all registered at the top of the file, and are used to track state
  • Comments contain author’s initials and a date
  • Last line of the file is just the number 1;
  • Uses LDAP
  • You recognize the dude that wrote it because you’ve seen his email address at the bottom of some man pages

Obscure python syntax error

Been writing python for a long time. When I wrote this code, I could not figure out why I was getting a syntax error.


d1 = dict(
user_id=99,
display_name='Matt Wilson',)

d2 = dict(
email_address='matt@tplus1.com',
**d1,)

It is the trailing comma after **d1. It is not OK. Which is really weird, because the trailing comma after display_name=’Matt Wilson’ is just fine.