iPhone 12 Mini

So my iPhone X decided to get a cracked screen just a week before. I dropped it like I had done countless times before, but this time the right side of the screen went kaput. Because of the timing, I had to swear to a couple of friends that this wasn’t intentional. 😂

Nevertheless I ordered a mini because:

  1. It’s the cheapest new iPhone.
  2. It’s small and I have memories of nice one-handed phones.

And it got delivered in like 3 days which is super fast where I am. First impressions:

  1. The screen is smaller but it’s very easy to get used to it from a X-sized form factor. It doesn’t really feel any smaller.
  2. If you upgrade every 3 years or so like I do, it’s so nice to see how much our phones improve. Truetone is really sweet. The speakers are much louder. And the display is so much closer to the glass. Tiny year-over-year improvements add up to a lot.
  3. The new cameras are noticeably better than those of the X. I also got Halide, and will probably try to get some shots with it soon.
  4. It’s remarkably easy now to get everything up even if you do a clean install. Just install a few apps & sign in.

An ode to “My Mister”

I’m a sucker for good romance movies and TV shows featuring difficult and ambiguous relationships, and the last few years have been a real treat. There was the unrequited love and deep affection in 96, the bittersweet tale of George and Malar in Premam, and the last wonderful instalment in the Before Sunrise series.

And now, there’s one more to add to the list. The Korean drama My Mister is just a wonderful take on a love story between a middle-aged man and a girl 20 years his junior. If you haven’t watched it yet, stop reading and go watch it. The rest of this will have spoilers.

Some assorted observations:

  • The acting is just excellent throughout. Lee Sun-kyun (of Parasite fame) is just wonderful as Dong-hun, and I also really liked Lee Ji-ah for a wonderful performance in a difficult role.
  • Korean names are so hard to make out in the original dialogue. I don’t find this much difficulty with any other language. I suspect some unusual contractions are used every time, or the pronunciation is really different from how it is in English. Or they speak really fast.
  • Each episode is over an hour long. With 16 episodes, it’s an exhausting binge watch: I would suggest to spread this out over a few weeks.
  • I loved how Dong-hun thought about and reacted to Lee Ji-an’s advances. He obviously isn’t attracted to her, but the deep affection that he slowly develops for her and the comfort that her messages provide him is just wonderful to watch. The slow burn from a casual interest, to concern, to affection, and then love is probably the crux of the show: the drama and politics surrounding his promotion and his wife’s infidelity are all just side-shows to set up a stage for two wonderful people to meet each other.
  • It’s also a beautiful depiction of how a woman falls in love. Lee Ji-an starts listening in to Dong-hun to seduce, frame and then fire him from his job, but she is initially obviously surprised at his reactions, and his continued understated kindness turns that to near obsession. She is always listening, anxious when she sees him struggling, frantic when she thinks he’s about to commit suicide, and despite her worries over giving herself away, she just can’t stop listening to him. There’s nothing interesting happening at the other end: most of the time, we listen to just a guy huffing and puffing his way through life. His frustrations with his cheating wife, and his closeted despair when his brothers find out are all intense, but most of time, she’s just listening to the most mundane things he does. She shares his joy and his despair, and uses the wiretap to send messages and comfort him at his lowest. The way we can listen to what she is listening to is just a great plot device, almost a concrete distillation of show, not tell.
  • True mentorships between men and women have a hard time on screen, and while it’s true that My Mister portrays Li Ji-an as a damsel in distress, the last episode really turns it around. She’s become a successful woman in her own right, without much of Dong-hun’s help. I’ve been lucky enough in my life to get mentored by (& mentor) a few wonderful women, and it’s silly how this isn’t portrayed more in a non-romantic way.
  • I loved one scene where a group of Dong-hun’s friends walk Lee Ji-an home, and in response to a question, she tells them: “I just want to be older, like all of you. So many of my problems will be solved then.” Everybody turns and just looks at her. While youth is wasted on the young, it’s also that the old forget how difficult it is to grow up. Or rather, as Jung-hi (one of Dong-hun’s friends) remarks on the way back, “You know, I also didn’t have an easy time at her age.” Our memories always look rosier than they are.

Do watch My Mister. It’s just a beautiful story.

Improvements to my Linux Desktop

I’ve gotten a bunch of comments and feedback about my Linux switch, so I thought I’ll write a followup post about how it’s been about 2 months in. Just a disclaimer that this is from the PoV of a long-time Mac user, and most of my irritants are about going back to my familiar defaults for which I almost have muscle memory. Luckily, Linux is configurable, and I’ve got it pretty well configured right now.

Look & Feel and Aesthetics

This is one of those things that is very important to me. The default configuration on any Linux is pretty terrible when you compare it to a Mac, but there’s a lot you can do to make it better. Here’s how my current desktop looks like.

Yup, that is indeed Pop!_OS

What did I do to make it look like this? Well, I pretty much followed this guide exactly. This does mean replacing the default Gnome desktop with XFCE, but that’s pretty much required if you want a Global menu like on the Mac. It does feel a bit too much aping the Mac tbh, but that’s much better than most distro defaults.

Here’s two other things I did in addition to that guide:

I made a workspace switcher panel with this configuration, that provides me some nice icons on the bar, and lets me move between virtual desktops much easier.

I put 4 Emoji icons, largely picked at random to differentiate between the desktops.
You need to pad the name like this otherwise there isn’t sufficient padding in the panel.
Finally, here’s the panel configuration. Nothing special, I just disabled Show miniature view.

Frankly, this is one feature I’ve always liked on Linux deskops. There is of course Spaces on the Mac, but it feels too overwhelming sometimes, and you lose touch of where you are.

I also copied over the SF Pro fonts from my Mac, and made that the default UI font. Even then, the font rendering on Linux can still use some work.

Honestly the aliasing doesn’t seem to matter much.

Keyboard Shortcuts

So I really tried to get used to the Linux shortcuts. But honestly they are just terrible. I mean why use your pinky-finger Control as the primary modifier key? You are just setting yourself up to get carpel tunnel. And if you are going to have a keyboard shorcut, at least make it uniform across apps. Ctrl + V to paste everywhere, except the terminal, where it’s Ctrl + Shift + V 😠. So I found Autokey, and set it up to port over my favourite macOS shortcuts:

This is just a bit of work to set up at first, but then works really well.
If you use the terminal in VS Code, you need to remap Copy and Paste to this, coz that’s the only way to make Super+C/V work in the VS Code editor and its inbuilt terminal.

This works awesome! Except in a few cases when it doesn’t. Autokey seems to sometimes stop working when you have 2 shortcuts configured differently based on window scope. So at times my Super + C stops working in the Terminal. I’m yet to figure out a solid solution for this.

Emojis

The state of emojis on Linux is… terrible. There are many half-complete solutions and none really work well. The sort of best I’ve found is this onscreen keyboard called Onboard & an emoji layout for that:

Yes, compared to what’s available on macOS, this is just terrible emojis all around. Sigh.

I’ve also mapped it to the same Ctrl + Super + Space shortcut on the Mac:

You can also see my other shortcuts, Ctrl + Super + Q and Shift +Super + 4 for e.g.

Apps

Here are a few native apps I’ve found interesting!

Wonderwall to download wallpapers:

LibreOffice which is quite nice right now!

The inbuilt Gnome Calendar app which is… serviceable, but the Mac equivalent isn’t too much better.

A native Spotify client!

A free VMWare Player that pretty much serves as the Fusion-equivalent on the Mac.

Suffice to say, I don’t miss apps much. I do get a bit envious about the design aspect though. Mac apps culturally are much better groomed.

Well that’s it! Ping me on Twitter for any questions, and I’ll be happy to answer them.

Advanced Typescript: Narrowing & Predicates

In the last part of this series, we talked about how you can infer types in Typescript. In this part, we’ll take a look at a related use-case: making the Typescript compiler happy by narrowing the type of a sum type.

What’s Type Narrowing?

Let’s first describe the problem. In Todoist, you can complete & archive both tasks and sections. Let’s say we model it like this:

type TaskCompletedData = {
    subTasks: Task[]
    showHint: boolean
    cursor?: string
}
type SectionCompletedData = {
    completedItems: CompletedTask[]
    tasksLeft: number
    showHint: boolean
    cursor?: string
}

Now it doesn’t really matter what these properties are, I’m just going to use them for illustration, but if we want to build a function to work with a generic completedData variable, it can become hard to “narrow down the type” to what we’re interested in. See for example:

function getCompletedCount(completedData: TaskCompletedData | SectionCompletedData) {
    //how do I make Typescript happy here?
}

The answer is to use the Javascript in operator to check for existence of properties:

function getCompletedCount(completedData: TaskCompletedData | SectionCompletedData) {
    if ('completedItems' in completedData) {
        return getSectionsCount(completedData)
    } else if ('subTasks' in completedData) {
        return getItemsCount(completedData)
    } else {
        throw `Unexpected value for completedData: ${completedData}`
    }
}

Why can’t you simply call getSectionsCount direct? That’s because Typescript can’t really guess the type of a variable at compile-time (& there’s no Typescript at runtime). Writing the function in this way means you have adequate guards in place so that when Typescript does its job of compiling down, you still have reasonably safe code when all types are erased. It’s not the prettiest of code for sure, but it’s part of the tradeoff of using a fully-erased type system.

Type Predicates

A counterpart to type narrowing is type assertions and type predicates. Note type assertions are the most commonly abused system to “force” the compiler to understand one type as another. The syntax is pretty simple:

const a = "Hello"
getCount(a as any)

In the above example, we are widening the type of a so that it’s compatible with a possible different type that the getCount function expects. Using as casting in this way is frowned upon and possibly never has a place in a good codebase. Type predicates however, are a safer way to achieve the same thing.

Note: to use type predicates, you need a reasonably newer version of Typescript. But it doess make writing these type guards a bit cleaner. Here’s an assumeNotNull Jest test helper that we have in both the Todoist and Twist codebases.

function assumeNotNull<T>(value: T): asserts value is NonNullable<T> {
    expect(value).not.toBeNull()
}

The current Jest type definitions for expect(value).not.toBeNull() don’t really communicate with Typescript that subsequent calls to expect(value) will always have value as not null (this is because the first expectation will throw and break the test). Here we’re writing a helper function to make this explicit. The important bit to note here is the asserts value is bit, which is called a type predicate. These type predicates are very flexible, and can be used to nudge Typescript in a lot of different ways.


Now both predicates and type narrowing may seem like extra boilerplate that comes with Typescript adoption, and if you are used to writing Javascript, initialy it definitely does seem like that. I sometimes do think of these as “stuff I do to keep the Typescript compiler happy.” From a longer-term software maintanence perspective though, building a strict tsconfig, and sticking to a well-typed codebase has huge rewards. There’s nothing wrong in prototyping your solution in a .JS file, without even having any types at all. And once you start converting the solution to Typescript, the compiler warnings and errors will guide you to writing more safe code.

Well that’s it for this instalment. See you next time!