There was a lot of negativity in response to the new MacBook Pro announcement on October 27. I don’t subscribe to many of those ideas (some of the more cataclysmic responses were a little over the top), but I am disappointed enough that after more than a decade of owning Macs, I’m switching back to Windows.

I want to be clear: Apple’s new laptops are excellent, they will sell well, and this is not some sort of death knell for the Mac. However, for these machines to excel in the ways that they do, certain compromises had to be made, and those particular compromises matter a lot more to me than the improvements do. (That is, I value high-performance graphics in a 15″ pro computer over the admittedly impressive strides Apple has made in size and weight.)

I will miss the incredible screen, the best trackpad in the industry, macOS’s UNIX underpinnings1, and the ability to connect power, display, and additional USB ports all through a single cable.

Most of all, though, I’ll miss the incredible 3rd party software available for macOS. As far as I know, there is no high-quality equivalent on Windows to TweetBot, Alfred, or Keyboard Maestro2, let alone pro apps like those from Panic or The Omni Group. And good luck finding a solid RSS reader like ReadKit or Reeder.

Price

There have long been accusations that there is an “Apple Tax” – the idea that Apple products are overpriced compared to their PC (or Android, or whatever) brethren. This myth hasn’t been true (at least in the Intel era3), but it has endured. With the introduction of the Touch Bar4 and the significant price increases it entails, I think the “Apple Tax” complaints are ready to see a revival.

The Windows Option

I’m an iOS developer at work, so I will continue using and enjoying Macs.

At home I primarily use my computer for regular putzing around, and playing games. Last time I bought one in 2011 I went for the top-of-the-line 2015 MacBook Pro because it had a solid discrete GPU. I was planning on doing the same this time, but the very best GPU that Apple offers for its new machines is underpowered, and goes for around the same price as much more powerful mobile GPUs. Here’s a quick comparison of the new MacBook Pro and the most MacBook-like Windows laptop5, the Razer Blade.

MacBook Pro, mostly upgraded.

  • 2.7 GHz Core i7
  • 1 TB SSD
  • 16 GB RAM
  • Radeon Pro 460 (4 GB VRAM)
  • CAD $4,099.00

Razer Blade, fully upgraded.

  • 2.6 GHz Core i7
  • 1 TB SSD
  • 16 GB RAM
  • GeForce GTX 1060 (6 GB VRAM)
  • CAD $3,899.99

I’ve had a hard time finding comparisons between these GPUs since they’re both brand new, but this not-quite-apples-to-apples comparison suggests the Razer Blade’s GPU is 2-3x faster in most measurements, and the computer it comes in is two hundred (Canadian) dollars cheaper.

More than double the performance for less money, in a package that more or less exactly matches the last-gen MacBook Pro6?

Sign me up!


  1. Although, I’ve been trying Windows 10’s new support for running bash natively, and it works really well. More on that another time. 

  2. Luckily the folks at Smile now have a Windows TextExpander app

  3. The reason I bought my first Mac in 2006 (a 13″ white plastic MacBook) was because it was the only laptop on the market that was a) reasonably small; b) reasonably powerful; and c) reasonably priced. I fully intended on wiping it immediately and installing Ubuntu or something. This was the time when PC folks like myself were still convinced Macs were Fisher-Price toys for people who didn’t understand computers. How condescending we were. 

  4. On the subject of the Touch Bar: I think it is an interesting innovation. I don’t agree that it’s a solution in search of a problem. I do think that it’s been added to the wrong product, at least given the way Apple is explaining it to us. It seems like a great tool for people who watch their hands as they type, and who aren’t comfortable with keyboard shortcuts; I think it should be on the MacBook. (Yes, I’m certain we will see awesome “pro” applications of the technology, too.) 

  5. Read: not hideous, enormous, or heavy. 

  6. Meaning the one released in 2015. The new Razer Blade is the same thickness as that older model at 0.7″, lighter at 4.16 lb vs 4.49 lb, and has a higher-density screen with (according to a review on YouTube I can no longer find) full coverage of sRGB. Admittedly, battery life is not nearly as good. The new MacBook Pros beat the Razer Blade on each of these counts, but in my estimation the older machines were fine in these respects. 


I wrote last year about Swift protocol extensions. If you define a method in a protocol extension that isn’t defined as a protocol requirement, it is dispatched statically, whereas methods defined as protocol requirements are dispatched dynamically. (See the original article for a detailed explanation.)

In March, there was an update – an acknowledgement by the Swift team of this shortcoming and a possibility for a change in behaviour.

Now Ole Begemann writes about Kevin Ballard’s post on swift-evolution explaining very nicely why this limitation exists in the first place:

So essentially, while protocols have a virtual function table, protocol extensions do not, and cannot easily have one because a type adopting the protocol won’t necessarily know about all extensions at compile time and therefore cannot add the extension methods to its own vtable. Opinions may vary whether dispatching protocols dynamically all the time would be a viable alternative, but it’s clearly not what the Swift team has in mind for the language.

Kevin’s post is very informative and worth reading in its entirety.


I wrote in August of last year about some potential confusion coming out of the decision to statically dispatch calls to methods defined in a protocol extension that were not defined in the protocol itself. (Whereas calls to methods defined in the protocol are always dynamically dispatched.) This allowed the protocol / extension designer to differentiate between customization points (methods defined in the protocol) and non-customizable code (methods not defined in the protocol, but implemented in an extension).

It looks like Apple’s received some feedback around this, and Doug Gregor acknowledges this is his “Completing Generics” Manifesto. (Update May 5: Austin Zheng has created a formatted version of the manifesto, available on GitHub.) However I’m not optimistic that this will get changed in future versions of Swift, as he puts it in his “Maybe” section:

Maybe

There are a number of features that get discussed from time-to-time, while they could fit into Swift’s generics system, it’s not clear that they belong in Swift at all. The important question for any feature in this category is not “can it be done” or “are there cool things we can express”, but “how can everyday Swift developers benefit from the addition of such a feature?”. Without strong motivating examples, none of these “maybes” will move further along.

Dynamic dispatch for members of protocol extensions

Only the requirements of protocols currently use dynamic dispatch, which can lead
to surprises:

protocol P {
  func foo()
}
extension P {
  func foo() { print(“P.foo()”)
  func bar() { print(“P.bar()”)
}
struct X : P {
  func foo() { print(“X.foo()”)
  func bar() { print(“X.bar()”)
}
let x = X()
x.foo() // X.foo()
x.bar() // X.bar()
let p: P = X()
p.foo() // X.foo()
p.bar() // P.bar()

Swift could adopt a model where members of protocol extensions are dynamically dispatched.

Fingers crossed, but I think the ship has probably sailed on this – I wonder if the change of behaviour would result in more confusing bugs than this quirk of the language did in the first place.


One of the biggest lessons I learned in the fallout of my concussion last year is how important posture is, especially to desk workers like me. Post-Concussion Syndrome has a major muscular component – tight neck and back muscles press against nerves that send confusing signals to your brain, prolonging concussion symptoms like dizziness, fatigue, and visual disturbance. Treatment of this aspect of PCS is fairly standard physiotherapy fare – stretching and strengthening.

One of the most important ways to keep tight muscles from getting out of control is to maintain good posture. Most of us tech workers tend to stay in a very head-forward position, craning toward the screen, shoulders hunched over the keyboard.1

This is a sure way to cause neck and back strain.

Instead, we should be sitting up straight, shoulders down and back, neck straight, and chin tucked in. It feels weird, and it takes a while to get used to. When I’m at my desk with my mind focused on more interesting things I continually forget about maintaining posture. I have a post-it sitting directly above my monitor, and that helped me remember for a while, but now it’s just part of my surroundings and I no longer notice it.

My physiotherapist recommended a periodic reminder to keep me focused on my posture. I wrote a shell script, so that my computer could prompt me from time to time to stop slouching. It runs in the background, and at a random interval,2 it speaks aloud using the say command and posts a notification using terminal-notifier, which you can install as a gem or via Homebrew on a Mac.

max=30
min=6
message="Fix your posture, dummy!"

function randomSeconds {
    range=$(($max - $min))

    rand=$(($RANDOM % $range))

    minutes=$(($rand + $min))
    seconds=$(($minutes * 60))

    echo $seconds
}

while :
do
    seconds=`randomSeconds`
    echo "Sleeping $(($seconds / 60)) minutes"
    sleep $seconds
    terminal-notifier -title "Posture" -message "$message" -group posture-notifier > /dev/null
    say $message
done

And of course, we should all remember to get up and walk around about once an hour. Staying static is actually one of the hardest things for our muscles to do. They’re designed to keep us in motion, so let’s oblige them!

I think I’ll write another post about workstation ergonomics at some point – I see a horrifying array of bad setups wherever I go, and we could all use a little improvement.


  1. We’ve all seen images like this one courtesy of
    The Moxie Institute‘s film Connected.

  2. Our brains are too smart for our own good. If you set up a reminder to go off every twenty minutes, you internalize it eventually and fixe up your posture “automatically” around the time when you expect the reminder. Then, when it arrives, you consciously check your posture, observe that it’s great, and start to slouch again a few minutes later. A randomized reminder keeps you on your toes. 

Handlebars is Logicless

Like, really, really logicless.

Handlebars is the templating system that I chose when writing Concussion, the engine that powers this blog. It’s one of the big names (I’d heard of it even though I’d never done any Node work before) and it has built-in support for Express via handlebars-express. Since it’s obviously so widely used, I figured it would be fine for my purposes. And while everything turned out fine in the end, I had to change the arrangement of responsibilities in my app to get around some unexpected problems, because as it turns out, Handlebars is logicless.1

The README points this out right at the top:

Handlebars.js is an extension to the Mustache templating language created by Chris Wanstrath. Handlebars.js and Mustache are both logicless templating languages that keep the view and the code separated like we all know they should be.

Which is all it has to say about the matter. Seems reasonable enough. If you’re doing anything approaching MVC, the view should be responsible solely for how the data is presented to the user. It shouldn’t do anything.

Handlebars takes this to a bit of an extreme.

There’s logicless, and there’s Logicless.

I think we can all agree that views (“templates” in Handlebars) shouldn’t directly act on models and shouldn’t implement business logic, but I do think that they should be masters of their own domain when it comes to turning data into something the user can see and interact with. By definition, they are a transform on a set of data. Handlebars recognizes this, and allows you to use all sorts of helper functions. You can include or omit a block of content based on the presence of a certain variable, call a function to properly format a value, or shell out to a sub-view (or “partial”).

What you can’t do is provide an arbitrary JavaScript expression to an if block, although you wouldn’t know it by reading the docs:

You can use the if helper to conditionally render a block. If its argument returns false, undefined, null, "", 0, or [], Handlebars will not render the block.

The if block can only accept a value (which could be a variable or the output of another helper). And because you can’t use an expression, you can’t do comparisons.

This should be a requirement of any templating engine.

Maybe I’ve just been spoiled by using PHP in the past, where (at least in CakePHP, the framework I’ve worked in) the templates are just regular PHP files, but I think having the basic ability to perform comparisons is absolutely central to a view’s ability to do its job. I want to be able to show (or not show) a section based on the view’s own choosing, not because a value is truthy or falsey.

Example: Pagination

This is a super simple example. Here’s how I want to accomplish a pagination view:

  • If the current page is greater than 1, show a link that navigates to page current - 1
  • If the current page is less than the number of pages, show a link that navigates to page current + 1

However, in Handlebars I have to do extra work in the controller to accomplish this:

  • If the current page is greater than 1, create a new variable previousPage = current - 1
  • If the current page is less than the number of pages, create a new variable nextPage = current + 1

Then in the template:

  • If previousPage exists, show a link that navigates to page previousPage
  • If nextPage exists, show a link that navigates to page nextPage

In addition to making more steps, this increases coupling between the controller and the view, something we should be always striving to reduce.2

GitHub Discussion

There’s a long and contentious discussion on Handlebars’ GitHub repository. The maintainers of Handlebars are gently sticking to their guns, which is understandable. Some of the commenters on that discussion are extremely dismissive. But there are many commenters who wish for more expressiveness in if blocks. Mike O’Brien sums it up best:

An if helper is there, IT IS LOGIC. So the whole logic-less argument is a total straw man

[…]

I totally agree with and understand not having business logic in templates. But unless you’re doing extremely trivial templates your going to have some view logic there. Handlebars obviously recognizes this since the if helper exists. Working around a hamstringed if helper by adding a bunch of view logic in your code is not the answer […]

Solutions

  • Prepare your data in such a way that your templates don’t need to perform any math or comparisons. This is what I’ve done – basically what I showed in the pagination example.
  • Build an unwieldy set of helpers (or one multi-purpose helper) as shown here.
  • Use a different templating system. EJS and Underscore templates look like good candidates – they read a lot like the PHP templates I’m used to, with all the good and bad that entails. doT also looks nice. Additionally, there are a lot of engines that allow comparisons out of the box but still disallow full access to JavaScript, if that suits your fancy.

Think I’m wrong? Got something to add? Let me know on Twitter!


  1. Although you have to make it to their GitHub README to find out. Their homepage makes no mention of this limitation. 

  2. In this particular example there’s not a huge difference in how coupled things are, but the fact that I had to change what happens in my controller in order to make my view happy irks me enormously. We didn’t need to provide more data, the view just required it to happen in a certain way. That’s coupling.