Blog

X-Touch Mini for Flight Simulation

Since I was a kid, I’ve loved aviation. Being poor and all, I could never dream of pursuing it in real life, so flightsimming has been my “cheap” fix for many years. I put cheap in quotes because this is an expensive hobby, even if you don’t overdo it. Although I spend quite a lot of money on software, I try to keep things in check on the hardware department, as flightsim equipment can be very expensive. For GA flying, it would be great to have a G1000, but at $2,199 USD, that’s a no from me.

Also, I’ve long flown the Boeing 737NG series, and setting up the MCP (the autopilot panel) with the mouse is quite the immersion killer, not to mention quite hard during busy phases of a flight. But € 1,299 is also not worth it, in my opinion.

That said, I’d really like some hardware controls. And that’s when I ran into the Behringer X-Touch Mini. The X-Touch Mini is not made for flightsimming, though; it’s a MIDI controller and as such, it doesn’t have the “niche tax.” I got it from Amazon at $180 CAD.

With some tinkering, I could make this control many planes, from the B737 to the Twin Otter. It’s great. I’ve long used SPAD.neXt to control all my planes for two reasons:

  1. I like tinkering with LVARs and also most third-party planes don’t expose all their controls to the simulator
  2. I like the fact that it autoswitches to the correct control profile for whatever plane I’m using

As an example, here’s how I set up a knob to control the checklists on the Honda Jet.

A screenshot of SPAD.neXt

It’s amazing! Also, I’ve been flying the ATR72-600 lately. Great plane! Also, it is similar enough to the Bombardier DHC8 (a.k.a. Dash-8) that it scratches my itch to fly regional Canadian routes, so I followed the excellent Les O’Reilly’s tutorial on setting the X-Touch Mini up for the ATR 72-600. Seriously, if you want to learn SPAD.neXt, check out his channel, it’s great.

However, I ran into an issue.

X-Touch Mini Leds not working

I could not get my leds to work with SPAD.neXt. No matter what I sent to the channel, the leds would not respond. I rewatched Les’ video, searched forums all over and never saw anyone having the same issue. I started suspecting a hardware problem. Eventually, I downloaded the editor from the Behringer’s website, solely for the purpose of seeing if I could get the leds to activate with it, to discard a hardware issue. This is when I found this —

Screenshot of the X-Touch Mini editor with the Global CH field highlighted

For some reason, my X-Touch Mini came with the global channel set to channel 12, instead of channel 1 as, it seems, is the normal setting. This is why none of the settings worked, so if you run into the same issue, now you know. So to fix this, there are two possibilities:

  1. Change all your SPAD.neXt settings to send the command to channel 11 (the channels are actually 0-based, so channel 12 in the UI is actually channel 11 in SPAD.neXt); or
  2. Change the global channel in the Behringer editor to 1 — which will be default channel 0 in SPAD.neXT. This is what I’ve done.

Once that was done, everything worked perfectly. The LEDs change status even if a channel happens inside the simulator, so you can rely on them to know the current status of your automatics and navigation/comms. Really happy with the setup.

Impressions on the Keychron Q6

I’ve had a soft spot for mechanical keyboards for a long time. It’s a cliché, I know. I’m not a fan of loud mechanical keyboards, mind you. I’ve had my hands on Cherry MX Blues and found them to be so loud as to be a distraction during calls. And I found the Cherry MX Reds to be, well, too quiet. I found the Goldilocks zone to be in the Gateron MX Browns.

I have also come to particularly like the Keychron keyboards. They have a bit of a shaky reputation online, but I’ve never had any problems with my Keychrons and I adore them. This Keychron K8 with Gateron Brows keys has been my main keyboard for the last 2-3 years.

Picture of a Keychron K8 keyboard

It is an awesome keyboard. I like how it feels, I like how it sounds, and I like how it clicks. It’s great.

The only thing my K8 lacked was a numpad, and since I have a certain passion for flight simulation, a numpad is something useful. I could buy a USB numpad. But where’s the fun in that? So this was the beginning of my search for a new keyboard.

After some online conversations, I settled for another Keychron favourite, the K4.

A picture of a Keychron K4 keyboard

And this keyboard feels amazing. I cannot stress this enough: it’s the most pleasurable clicking experience of my life. In theory, it has the same Gateron G Pro Browns as my K8, but for some reason, it feels better. I’m not sure how else to put this: they feel less metallic-y. I don’t know how else to put it.

Great size, great feel, great quality. I fell in love with this keyboard the moment I unboxed it. Except it has a terrible flaw that might be evident from the picture, but that I never noticed until I started using it. Do you see it? It’s right there by the arrow keys. Do you see it now?

There’s no spacing. The arrows are right under the Enter key but there’s no padding space between them and, say, the 0 key on the numpad. Years of muscle memory down the drain. I could not reliably hit the arrows without looking. I tried. The layout of the Del, End, PgUp, PgDown keys was also a bit foreign to me, although I was able to adapt relatively quickly to them. The arrows keys though, I simply could not. I replaced them with some texturized rubber keys but I was still unable to hit them reliably. It was a pity.

Enter the mighty QMK Q6.

A picture of a Keychron Q6 keyboard

This keyboard is a beast! It weights 2.5Kg, which is insane. But OMG it feels so, so good. If I had to choose, I would still pick the feel of the K4, but it’s close. The Q6 has better keycaps though.

In terms of sound, it sounds very close to the K8, maybe a tad softer but it’s hard to tell. In terms of feel, it’s between the K4 and K8. It feels closer to the K8 than to the K4, but yeah, somewhat in the middle between the two.

I love it. I credit it for the fact that I am writing this right now: I just feel like typing! I really like this. As an additional bonus, its firmware’s source code is open source. I don’t plan to use it for anything, but it’s good to know.

However, it is not perfect. Don’t get me wrong: I’m very happy with this keyboard but it does have one extremely questionable design decision that I honestly can’t understand: it doesn’t have feet. It just lies flat on the desk which feels quite awkward to me. I cannot understand the decision to do that. I solved it with some cheap adhesive rubber feet, so all is good, but why Keychron decided to ship it like this is beyond. So be aware of this.

Other than that, I absolutely love it.

In which I reminisce about the last few years

I just checked and it’s been exactly 1,594 days since I last posted on this blog. That’s 4 years, 4 months, and 12 days. This was, as is often the case with these, not planned. When I last wrote something here, I was working in a team set up as an R&D lab. Work felt quite fun and exciting and writing about it felt natural.

I then changed to jobs to a startup where things felt a tad different. It was a weird time for me: I met some great people there, people I still talk to and call friends. We put together a small team where I got to do some of the most fun work. Some of the people in that team I still talk to every single day. We’re still trying to put the group back together in some form in another company. And yet, my time in that company, outside that small team, made me feel quite small and inadequate. Writing about it did not feel natural.

I then joined HashiCorp, a company I’ve admired for years. I won’t go as far as saying this was a dream of mine, but when I got the offer, it sort of felt like it. I’ve been here for about two and a half years now and I’ve met some extremely brilliant people, and a few that I can call friends. I should have written about it. I wish I had. But by this time, the writing habit was already gone and life does what life does.

What else happened over the last few? Well, we became Canadian citizens. That was a blast, even if pandemic-style remove ceremony was a bit awkward.

We bought a house and got a new dog, Loki. He’s an English Cocker Spaniel, as would be expected of us, as he’s our 5th —

All in all, I can’t complain. On the other hand, I am getting older, which sucks, let me tell you that.

Anyway, I’d like to get back to writing a bit, I used to enjoy it quite a bit. We’ll see. Hopefully it won’t be another four years until the next post.

The Last of Us Part II

I’ve finished the game last night. I haven’t stopped thinking about it ever since. It was, to be very honest, a transformative experience, as far as videogames go. I understand why some people hate it and I’m sorry because I understand how much it sucks when you want to enjoy something but can’t. Art is subjective and no one is right or wrong.

That said, I want to talk about what I’ve experienced. Again, this is my experience with the game. I’m sure yours will be different and it is fine. If you hate this game, you’re not wrong. You feel what you feel.

With that out of the way, let me begin with the least controversial theme: the gameplay.

Gameplay

I thought the gameplay was an improvement on the first game. I don’t mean only the added functionality like ropes, and dogs tracking you. But the mission structures were more varied and some of them were, well, epic.

The sky bridge was awesome. So was trying to get near the sniper (Tommy) by advancing behind cover. The stalkers were a fun addition which gave me a lot of jump scares. That huge new infected monster at ground zero was… argh! Kill it now! The entire time spent on the seraphite island was amazing.

I also loved little things like figuring out the code for the safes.

The Story

This is what is dividing people, and it’s fine. Art that everybody agrees on is boring. The way I see the story, it is one of mirrored character journeys (as much of popular culture is.) Through three characters, we see the same journey at different points. I think this is genius. Here’s how I figure.

Joel

First all all, yes, it sucked to see him killed. That’s the point: we are supposed to be angry that he’s dead, that he’s killed in such a way. This is very much intended: it puts us in the place of Ellie. It is perfectly expected that you’d feel rage towards his killers. I think it becomes a problem when that rage is instead directed towards the game itself, a work of fiction, because then it makes it really hard to appreciate the rest of it.

Let’s talk about his character journey, shall we? In the first part, we meet Joel at the onset of the pandemic. We don’t know much about him before then but all signs point to an average joe and a good dad. Then his daughter gets murdered and we skip 20 years, by which time we are to understand that Joel is not a good man anymore. We learn that he was a killer, a robber, smuggler. He says he killed innocent people, he robbed (and presumably killed) good samaritans. He absolutely did not care for Ellie in the least at first. He wanted to abandon her to the soldiers and run when they caught up to them in Boston. It was Tess who made him stop.

In the first game, Joel was a “bad person,” a broken man who then had his redemption by protecting (and ultimately caring for) Ellie. (More on the “bad person” in quotes later.)

Abby

Abby’s journey is the same as Joel’s. Her dad gets murdered by a smuggler and that breaks her. She becomes a bad person. We’re made to understand that prior to the events in Seattle, she was a cold-hearted killer. She rose though the ranks of the WLF by becoming the “top scar killer” and even her friends think she’s, to steal Mel’s description, piece of sh*t. She’s a murderer.

And then comes Lev. At first, she too doesn’t care too much. He is just a scar. You see how Abby dehumanizes the seraphites all the time, the difficulty she has with ever calling them anything other than “scars.” She leaves them there but then she feels guilty and, reluctantly at first, goes back to them.

Abby was a “bad person” who had her redemption by protecting and caring for Lev. In a way, Abby’s journey is what we would have seen if we were able to follow Joel through those 20 skipped years.

Ellie

This is where things get interesting. Ellie is living in Jackson the life that Joel and Abby lived before their own traumatic events. When Joel dies, this matches the deaths of Joel’s daughter and Abby’s father. This is where Ellie is going to turn bad.

And we see that transformation unfold. We see our Ellie slowly go down the same path that Abby and Joel took years before and that we never got to see. She is consumed by rage.

Ellie is now becoming a “bad person” as well. But she’s not all the way there yet.

She’s also consumed by remorse. When she tortures Nora, she comes back to Dina visibly shaking and saying “I made her talk…” She’s devastated about what she’s done. Later she kills Owen and pregnant Mel, and again, that breaks her. And yet, she cannot stop.

Ellie vs Abby: why didn’t Ellie kill her?

The final confrontation is amazing. Abby is now in a different place, she’s now where Joel was after Ellie. It’s hard for us to forgive her, because we have seen her kill Joel, but nevertheless, that’s the place she is in. When Ellie cuts her down from that beach post, her first reaction is to run and cut Lev down. Lev is her Ellie. She doesn’t want to fight Ellie, she only wants to save Lev, just like Joel only cared about saving Ellie at the end.

But Ellie still can’t let go. She needs this! Or so she thinks. And so they fight. The fight fell heavy and, to me, very real. It was amazing and painful to watch and even worse to participate in. I did not want to fight Abby. All I wanted was for those two women to find peace now.

And then Ellie is about to kill her and she remembers Joel. More specifically, she remembers her very last conversation with Joel, about her inability to forgive but willingness to try. She also sees the changed man, who changed for and because of her, the man who went from “bad” to a “good” person. Killing Abby — who’s now on her own redemption path — will only turn Ellie into the bad person that Abby and Joel were.

And Ellie stops the cycle. She will not go down the same road. She honours Joel by refusing to become a bad person, something Joel would never have wanted for her. She will honour Joel by going back to the life both of them wanted for her.

Will she get it? Will JJ and Dina be waiting back in Jackson? We may never know, but I sure hope so.

“Bad people”

I think the biggest takeaway for me in this painful, yet wonderful journey of a game is how none of the protagonists were good or bad. Everybody is the hero of their own story. Since we played the first game as Joel with Ellie, that is our story and we are entirely on their side. But they were not “good,” not when it comes to the many lives they took over the course of their journey. We saw all those kills as completely justified: they were goons, they were going to shoot us! But then, from their perspective, they were doing the same thing we were. And the thing is, that doesn’t mean everyone is equally justified. It only means that from their own points of view, Ellie and Joel were the villains.

If doesn’t matter if we believe Joel was justified in taking Ellie from the hospital: from the point of view of Abby, her loving dad was murdered. It’s also not about convincing you and me that there are not moral absolutes. It’s that none of this matters to the characters themselves.

Conclusions

Again, I’ve finished this game almost 24 hours ago and I am still thinking about it. This game made me feel so many feelings. It made me mad, sad, and happy. Art that gets you to feel something is, well, good art in my book.

If you hated this game, it’s fine. We can’t all love the same thing. I am not trying to convince anyone, just sharing what I felt. I absolutely loved it with all my heart. This game will stay with me for a long time.

Try was worth trying

The Go proposal committee has declined the try proposal.

I am disappointed. I also think this is open source working exactly as it should.

The proposal was not dropped because one person with commit access disliked it. A concrete design was published, tools were written to try it on existing code, hundreds of examples and objections were discussed, and the people behind it kept answering questions long after I would have quietly disconnected my router and moved to the woods.

Most importantly, the Proposal Review Committee made its decision in response to that discussion. The closing note mentions problems the original design had missed, including debugging prints and code coverage. It also admits something more fundamental: many Go programmers do not agree that the verbosity of error forwarding is a problem worth changing the language to solve.

That is a good reason to stop. A language belongs to the people who have to read it, and a change to control flow needs more than a clever specification. The community worked through the tradeoffs together and the committee made the call. I may disagree with the result, but I trust the process far more after seeing it work.

Still, I think this will eventually look like a missed opportunity.

The argument against try was strongest when it was used inside nested expressions:

return write(encode(try(read(name))))

I do not want to debug that either. But bad nesting was not the only possible future. The ordinary form was much less alarming:

b := try(ioutil.ReadFile(name))
try(json.Unmarshal(b, &cfg))

One operation per line, errors still in the function signature, no exceptions, and an explicit if whenever local handling mattered. I think that style would have become normal very quickly. It looks unusual today mostly because it is new.

There is a difficult bias in evaluating syntax: familiar boilerplate does not feel like syntax anymore. We see if err != nil and read “return the error.” We see try and inspect every unusual corner because it is new. That scrutiny is necessary before changing a language, but it is not a neutral comparison.

Rust went through a remarkably similar argument around try! and later ?. People worried about hidden control flow and two ways to write the same thing. Once programmers had lived with it, many came to consider it one of the language’s better features. Go is not Rust and should not become Rust, but people do learn new control-flow notation. We already did it with defer and go.

There is another group absent from a discussion among current Go programmers: people who did not choose Go because they found its error handling tedious. It is almost impossible to measure them from inside the community. The people most comfortable with the status quo are, unsurprisingly, the people who stayed.

None of that means the committee should have ignored the reaction and forced try through. That would have damaged the language and the community more than a little error boilerplate ever could. Declining it was the right decision now, given the lack of agreement about both the problem and the solution.

But I suspect we solved the social problem by leaving the technical one untouched. Years from now we may add something remarkably similar under another name, after enough other languages have made the idea feel ordinary. Or we may simply keep writing the same four lines and insist they are valuable because we have become very fast at not seeing them.

Either way, try was worth trying. The proposal improved our understanding of the problem, and its rejection proved that the Go community can say no even after a great deal of work has been invested.

That is not failure. I just hope it is not the last word on improving error handling.