“Your Username Is OG. Do You Know What That Means?”  

Here’s a jaw-dropping blockbuster episode from Reply All. Stop what you’re doing and listen to it. And when you’re done, remove every 2FA you have that uses SMS. That sort of 2FA makes you much less safe than no 2FA whatsoever.

Bringing Experience to a Spec Fight  

It’s worth hearing this episode of Rene Ritchie and Tom Boger (Senior Director of Mac Product Marketing) just to hear Rene say this:

At a certain point Apple just decided to bring experience to a spec fight.

I assume that if product A has fewer specs than product B, it’s probably better, and it’s the one I want. I don’t even bother to seriously engage with people who come to the table with the presupposition that the spec checklist is the primary — or worse, the sole — determinant for which of two products is better. Bringing experience to a spec fight is equivalent to bringing a gun to a knife fight.

CSS Querying for Dark Mode in macOS Mojave  

Paul Miller:

Safari 12 that shipped with Mojave does not have a way to detect whether a user has a dark mode or not.

The good news is: Safari Tech Preview 68 supports Dark Mode! And Safari 12.1 might support it in a few months too. The CSS itself is very simple.

As soon as Safari supports this media query, I’m switching Drinking Caffeine to using this as the determinant for whether you get light mode or dark mode. Until then, you can adjust it at the settings page.

How to Have a Sticky Footer in Flexbox  

Last night I threw together a quick repo to show just how crazy simple it is to have a sticky footer in CSS. I also changed out the footer here on DrinkingCaffeine.com to use this method.

Rest in Peace, the Ryan Fait Sticky Footer. You served us well for nearly a decade.

Addy Osmani on the State of Javascript  

I watch very little video but I highly recommend these 13 minutes. My favorite part is when Addy mentions “React, Vue, AngularJS…” in that order. You can quibble over whether React or Vue should come first, but Angular is undeniably lagging third.

How to Sequentially Resolve a Group of Javascript Promises  

Save this link in your quiver. Learn its reduce algorithm, and never again use nested timeouts.


setTimeout(() => {

  setTimeout(() => {
  }, 1000);
}, 1000);

Becomes this:

const messages = ['hello', 'world'];

const promises = messages.map(message => () => new Promise(resolve => {
  setTimeout(() => {
  }, 1000);

promises.reduce((promise, func) => promise.then(func), Promise.resolve());

This example looks silly (“you’ve introduced needless complexity!") but when you have a large set of promises that need to be linearly resolved, you’ll be glad you had this.

Ills of the Graphics Interchange Format

The Graphics Interchange Format1 might be useful for people who love sharing cats and 3-second movie clips. These people certainly think they’re useful, and I won’t take that away from them. But they have no place in the professional developer environment.

In the building of UIs, it often becomes necessary to share a brief clip that demonstrates the user experience. When it comes to this, you have two choices: you can use a MPEG-4 Part 144 uploaded to a service like Screencast, or you can use the Graphics Interchange Format uploaded to a service like CloudApp. The former choice is the better one. The problems with the Graphics Interchange Format are legion. I’ll enumerate the more burdensome.

  1. It takes longer to begin watching a clip in this format than in a standard video format. The reason is because you must load the entire resource before you can begin it. There is no concept of “buffering” or “streaming.”
  2. Not only does it take longer, but because there is no “play” button, you are not in control of when it starts playing. The resource begins playing as soon as it is ready to do so, not when you are ready to do so. What this means is that you must sit there idly waiting for the resource, rather than doing something else whilst you wait. You dare not switch tabs because the file will begin playing at a time you think not.
  3. Likewise, because there is no “pause” button and no ability to scrub, if you want to revisit a certain piece of a 30-second clip, or if your impatience gets the better of you in the previous bullet and you miss the start, you must wait the duration of the clip. This is egregious.
  4. The determination of whether the file loops or not is determined by the creator of the file, not by the consumer of the file. More often than not, the author chooses to loop, which means you have a hideous distraction before your eyes after the first or second viewing.
  5. In order to avoid said distraction, Slack has made it possible to disable the animation of Graphics Interchange Format files in settings. Because of this, sharing such a file is no guarantee that the recipient will actually receive what the sender intended — they might instead receive a static image frozen on the first frame. On the contrary, when you share a proper video, you have a guarantee that the recipient gets what you sent and nothing less.
  6. The colors are limited.
  7. The frame count is limited.

The Graphics Interchange Format robs mankind of everything that is decent and noble in frame sharing. Do not use this format for professional use.

  1. You’ll pardon the verbosity. I’m still recovering from the use of acronyms during my 4-month stint earlier this year in corporate America. ↩︎

The Actual Purpose of the Document Base URL Element  

The only time I think I’ve seen the piece of markup below used in real life is in the context of a Single Page Application:

<base href="/">

What I hadn’t realized, until yesterday, is that if you’re at a page like this:


And there’s a relative image referenced in the DOM like this:

<img src="avatar.png">

Then that will normally resolve in an HTTP request to https://example.com/user/12335/edit/avatar.png but if you have <base> element defined like above, then that will resolve in an HTTP request to https://example.com/avatar.png. It’s always a funny feeling when you learn something fundamental about something you’ve been familiar with for ages but haven’t given any thought to.

The Tesla Model 3 Is the Top Selling Car by Revenue in the US  

It’s also the 5th best selling car by units. This is incredible when you consider that a Model 3 costing $10,000 less is coming out in early 2019. If the Model 3 is performing this well with a $45,000 starting price, what will it be then? Tesla has gone from being a company that sells cars to rich coastal elites to being a company that sells cars to average American consumer.

As I was driving to work today I was struck by how arbitrarily noisy the highway is. A day may come where that noise is looked upon as the mark of an era that came and went.

Because the average energy cost per mile of an electric car is a third the cost of a gas car, why wouldn’t you want to enjoy the higher precision of an electric motor when the up-front cost is comparable? It’s a objectively superior technology. Through irrefutable, unstoppable math, the automotive industry is getting disrupted in an way unparalleled since its inception. The Tesla Model 3 is to cars what the iPhone is to phones. Honda and Toyota, heretofore the defining American automotive staples, are the new Research In Motion.1

  1. (That’s RIM, the company behind the BlackBerry.) ↩︎

The iPhone Browser That Ignores Responsive Design  

When you long-press the reload button in Safari for iOS and select “Request Desktop Website,” all you’re doing is changing your user agent. This doesn’t do anything for most websites, because most websites offer their mobility via responsive CSS. Responsive CSS pays no attention to the user agent — instead it looks at the viewport width. And in Safari there’s no way to customize your viewport width. That’s where the Desktop Browser for iOS comes in. It somehow modifies things so responsive websites think you’re using a browser that’s wider than it really is. Desktop Browser might be achieving this by simply removing the viewport meta tag from the head of the document. That tag often looks something like this:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1" />

The more I think about it, that’s probably how Desktop Browser is achieving this.1 However it’s doing it, it works consistently, and I love it.

  1. When you visit a viewport revealer in Desktop Browser that programmatically shows your viewport width, it registers as the correct one (375 pixel width on an iPhone XS). That’s why I don’t think Desktop Browser is spoofing the viewport width. ↩︎

You Needn’t SCSS or LESS to Create CSS Variables  

I didn’t know about native CSS variables until this week. Internet Explorer doesn’t support them, but nobody cares about IE.1

The only real reason left to use SCSS or LESS is for scoping. But nested CSS isn’t the right solution to scoping. The real solution is having CSS that’s scoped or modularized by its very nature. If you’re using a JavaScript framework, you can approximate this with CSS Modules (e.g. here is its port to VueJS). But the long term solution is the Shadow DOM.

SCSS and LESS will be extinct in a decade.

  1. I get a rush when I see people building websites that bring IE to its knees in hopeless, permanent incompatibility. ↩︎

How to Adjust the Brightness of an External Display on macOS Mojave  

One of the glaring bugs of macOS Mojave’s initial release is that you can’t adjust the brightness of an external display using the brightness keys. Nor can you do it from System Preferences. But you can adjust it by downloading Brightness Slider from the App Store. It’s free and it works. Hat tip to Jreinhal.

Update December 24, 2018: I noticed last week that this bug is now fixed. By pressing F1 and F2 on my bluetooth external keyboard, I can adjust the brightness of my external display.

The Essential Symbiosis of Algorithm and Heuristic

In his book Creative Selection, which I recommend very highly, Ken Kocienda talks about the importance of having software that takes heuristics into account. Much of computer software is algorithmically deduced. But not everything can be initially derived from algorithms. Some things require experimentation, trial and error, heuristic. Some of Ken’s examples:

  • Determining the proper size of icons on the iOS home screen so that they’re consistently tappable.
  • Determining how deep “pinch to zoom” should take you when looking at a photo.
  • Skewing the touch event to be higher than your touch’s placement so you feel like the tip of your finger is what interacted with the screen.

The only way to really get to these decisions is by heuristically using the software and finding what works best, and then extracting an algorithm from your findings. In addition to this, Ken said, “Sometimes we used heuristics to temper algorithms.” As an example, he talked about how they tweaked the auto-correction algorithm on the iOS keyboard to accommodate human behaviors and real-life situations that they hadn’t previously considered.

In contrast to this approach, we gaze upon the newly designed Pearsonified.com website, which continues to make heavy use of the Golden Ratio Typography Calculator and not much else. Chris has said, “I use math—not whimsy—to inform my designs."1 But whimsy is just a despondent term for heuristic. What Chris is really saying here is this: “I have little patience for heuristic when determining web design.” The Golden Ratio Typography Calculator has always bothered me, frankly, because it tries to remove this essential heuristic ingredient from the equation.2 It blames anyone who comes up with their own typography numbers as “whimsical.”

I’m glad the iPhone wasn’t designed with this dogma. Life’s too short to use software that was built purely by heuristic-barren algorithms. Long live informed whimsy and the liberal arts.

  1. As of about a week ago, this oft-seen maxim at the old site is now only viewable at web.archive.org. Its underpinning ideology is still alive and well at the new site, however. ↩︎

  2. While I’m slaying sacred cows, I’ll go on the record for saying that the results don’t even look that good. The line height is invariably too much. ↩︎

Why Primitive Parameters Are Bad

Consider the following JavaScript function call:


As you can see, we’re passing an argument of true. That’s a primitive type, and as such, it’s not clear what it’s doing. Now imagine if the referenced function were rewritten to take an object parameter instead. Calling it would then look something like this:

fetchUser({ forceReload: true });

This is much more clear. We can reasonably deduce that by passing true, we’re telling the code to ignore local cache and do a hard HTTP call to a server.

As a general rule, named parameters are better than simple boolean parameters. I’ve gotten to where I hardly ever write function definitions that have simple primitives as parameters, even if the function only has one parameter. Never underestimate the value of code readability.

A second reason why primitive parameters are bad is this: they make future extensibility harder. When it does come time to add a second parameter, you have to worry about changing the order of them. If you’re working with a team, you’ll soon be debating which parameters should come first. A lot of drama and intricacy can surround this. Usually developers want the most important parameters to go first. Once they’ve agreed on the order of importance, there’s still the debate about which parameters should have default values and which ones should be required. It especially gets messy if some of the more important parameters have logical defaults while some of the less important ones don’t. Once everyone’s finally agreed on how it should work in an ideal world, then there’s the debate about whether it’s worth refactoring every place that calls this method. Should you refactor, or just tack on the new parameter at the end with a default value as a less-than-ideal solution to avoid “busywork”? Remember, Chris has an unrelated work-in-progress branch that is touching this code a lot already, and he’d have to deal with a bunch of conflicts if the function signature were to get changed upstream. He’s ok with the change, but can it wait a couple weeks until his thing is done? There are so many opportunities for confusion and disagreement and frustration and subtle procrastination in all of this.

This whole debacle dissipates by simply using an object as your parameter. With named parameters, order doesn’t matter, because object properties are ordered alphabetically. And the best part? Thanks to object destructuring, you don’t even have to change the body of your function. If your function definition used to look like this:

const fetchUser = (forceReload = false) => {
  // function body that references `forceReload` boolean

It can now look like this:

const fetchUser = ({ forceReload = false }) => {
  // body remains unchanged

Never did an opening and closing bracket solve so many problems so effortlessly.

The Senseless Requirement for Having a Custom Avatar at the Apple Support Communities  

Roger Wilmut1, clarifying what it takes to upload a custom avatar in the Apple Support Communities:

You need to get to level 3 - 500 points: 50 ‘solved’ or 100 ‘helpful’ or a combination thereof. Welcome to the forums: I hope you enjoy answering peoples questions and hopefully gaining points (and karma) by helping them.

This is bonkers. I’ve never seen any other forum work this way. On Stack Overflow, an immensely more important website than discussions.apple.com, you get to use a custom avatar right out the gate. Same for every other major site I’ve ever seen.

I’m sure Apple has a reason for this restriction. There’s always a “good” reason, just like there’s always a perfectly rational explanation for walking around in white socks, crocks, cargo pants, and a fanny pack, with a side of wispy beard. But the fact that this problem has been solved by other communities proves that it doesn’t have to be this way. Apple should want as many people at its community to have custom avatars as possible. Default avatars are McDonald’s; custom avatars bring culture. It makes no sense to me why Apple restricts customer avatars to the 1%.

How to Hide Recent Apps From the Dock in macOS Mojave  

Until Mojave, if you quit an app that did not have “Keep in Dock” enabled, it disappeared from the dock immediately. Mojave changed that. Now it sticks around for a while. That’s irksome; I thought it was a bug until I realized it was a new Mojave feature. You can undo this feature by going into System Preferences -> Dock and disabling the checkbox labeled, “Show recent applications in Dock.” As a developer who builds new features for a living, I’m aware that developers love forcing their new code on users. But from a user’s standpoint, disruptive changes like this should be disabled by default.


There will always be a reason why the complexity is needed; why it’s an improvement, how it helps things. We as developers are attracted to complexity like a magnet, like a bug attracted to a deadly electric zapper. It’s a rite of passage; complexity means we’re smart, that we thought of it, and that we can handle it. But every time we introduce complexity, we don’t realize until later the complications we’ve added with it. The edge case bugs. The half dozen oh-I-hadn’t-thought-about-that problems.

Sometimes complexity is the only way to achieve the desired result. But often it’s not. Often you have a choice. Choose to keep it simple.

SMS Not Working on Mojave  

User rhettf, writing at the Apple Support Community:

Since updating to Mojave, iMessage on Mac is no longer able to send or receive SMS messages. You get the red exclamation point. I tried signing out of iMessage on the Mac. And also toggling the Text Forwarding to device on the iPhone. Is anyone else experiencing this problem?

My experience is a bit more nuanced than this on Mojave. When I send a text message to an Android user from my Mac on macOS 10.14, the message goes through — the recipient receives it successfully. But the Mac doesn’t recognize this as occurring. It eventually shows an error in the form of a red exclamation mark, as rhettf describes. Moreover, when the recipient replies, I get the reply on my iPhone but I do not get the reply on my Mac.

In other words, on Mojave, sending an SMS technically works, but receiving does not, and neither of these things work from a UI standpoint.

Update: I found a fix that works for my computer. As you can tell in the link, a lot of people have this bug still so my solution isn’t the canonical answer, but it did fix it for me. SMS messages now forward correctly to my Mac on Mojave. The secret was signing out of Messages on the Mac (Messages -> Preferences -> iMessage -> Sign Out) and on my iPhone (Settings -> Messages -> Send & Receive -> Apple ID: {email} -> Sign Out). After that, I signed back in, taking care to use the same email address everywhere. Technically I have a total of 3 different email addresses associated with iCloud, all with the same account, but you have to log in using the primary email address everywhere, and then it works. If you’re not sure which is your primary email address, you can view it here. The reason that it appeared that this problem began occurring on Mojave is because somehow my email address for Messages got changed to a different one. Maybe I messed that up when upgrading to an iPhone XS. In fact in hindsight, I’m not sure if the problem was upgrading to Mojave or getting a new iPhone. I did them both just a few days apart.

The Chapters  

If you’re into nerdery memory skills about the most popular book in the history of the human race, I made this for you using Svelte.

How I Clean My Computer Screen

I’m incessantly dismayed at how dirty are most people’s computer screens. This is avoidable. It makes no sense to spend thousands of dollars on a computer that you don’t keep clean.1

If you don’t keep your computer screen clean, it’s ugly in the short-term, and it’s downright damaging in the long-term. When it’s there for months on end, that grime has a way of eating the screen; you’ll never be able to fully get the scar tissue healed. A case can be made for meticulously cleaning your screen every week.2

After years of trial and error, I’ve come upon the perfect method for keeping my computer screen as spotless as it was the day I removed the protective paper. First I set the screen brightness to zero and turn the screen so it reflects the light. Then I use a Falcon Touch Screen Wipe to get the major stuff off. After that’s dried, I use a microfiber cleaning cloth to remove the dried water streaks. You can use one that came with your sunglasses. Or these on Amazon look promising. The key is to make small circular strokes and to stay gentle. I spend a few minutes with the microfiber cloth. It takes patience to get the screen completely spotless and lint free. It’s worth it.

If you don’t start with a wet wipe, you run the danger of scratching your display. If you don’t finish with a dry cloth, you can’t fully get rid of the water streaks. It takes both, in that order.

I do this every week, and my screen looks amazing. That’s all there is to it. You’re welcome.

  1. How many muddy Lamborghinis do you see cruising down the road? ↩︎

  2. Your mileage will vary depending on how much you travel with your computer, and how much you eat and talk near it. A weekly cleaning might be excessive if you’re a few levels of careful above me. In my case, spit, dust, and food are summoned to my screen on an almost daily basis. ↩︎

The iPhone Franchise  

Ben Thomas, two days ago:

Apple released a new flagship iPhone yesterday, the iPhone XS.

This is the time of year where your social circle rolls its eyes at the “lack of innovation” that Apple demonstrated with its new iPhones. It makes you smile wanly though, because you know they have last year’s iPhones, and somehow, by this time next year, they’ll own this year’s. That’s because the iPhone is a franchise. Ben Thompson does a fantastic job laying this out, and I recommend reading his piece in its entirety. It’s calm, objective, and adroit, as usual.

GitHub Removes jQuery From Its Frontend  

The GitHub engineering team:

We have recently completed a milestone where we were able to drop jQuery as a dependency of the frontend code for GitHub.com. This marks the end of a gradual, years-long transition of increasingly decoupling from jQuery until we were able to completely remove the library.

jQuery played an important role back when the ecosystem of native JavaScript DOM APIs wasn’t as robust as it is today. At this point, I don’t think anybody really needs jQuery. I removed it from Drinking Caffeine last November. Rest in peace, once-useful thing.

GitHub’s iterative approach is perhaps the most important takeaway in this piece. The company has proven that big refactors are achievable if you’re willing to play a slow steady game.

Chrome Celebrates Ten Years With a New Look  

Ellie Powers and Chris Beckmann:

Today we celebrate Chrome’s 10th birthday, and just like a kid on the cusp of double digits, we’re constantly growing and changing. In the case of Chrome, those changes happen every six weeks to bring you new features and security updates, but our 10th birthday update is bigger than normal.

The new Chrome is awesome. It’s a fantastic update to the world’s greatest browser. Some Mac pundits have decried its look as being un-macOSy, but seriously, I think Chrome has a better UI and UX than does Safari for Mac. Specifically:

  • Safari’s address bar animation that occurs when you focus on it is distracting and time-consuming. It makes me feel inefficient. I know you can start typing in Safari’s address bar before the animation has completed, but still. Perception is reality.
  • Safari’s address bar is narrower and shorter than Chrome’s, which means it’s harder to click it. Small targets make for bad UI/UX.
  • Safari’s developer console feels 5 years behind Chrome’s. It has fewer options and it’s harder to do stuff in it. That might just be because I spend a lot more time in Chrome’s, but I don’t think so.

Apple should learn from Google how to build a good browser.

On Apple’s Discontinuation of the iPhone SE

Yesterday Thomas Brand wrote a piece that decried the removal of the iPhone SE on the grounds that it was the company’s only affordable iPhone for some customers. The underlying assumptions rubbed me the wrong way. I’m compelled to counter them here. He wrote:

If you are looking for a phone with a smaller screen, a phone with a headphone jack, or or a phone that costs under $400, Apple no longer makes an iPhone for you.

That’s fair, but the universe of people for whom any of this is true is small. Most people are happy with the screen sizes, port options, and pricing of the new lineup. Apple doesn’t like a product line with a long tail, and the time to remove the SE has come. Simplify, simplify, simplify.


In short, Apple has discontinued their entry-level iPhone SE in favor of larger phones that require additional adapters and cost upwards of $750.

I’d be curious how many people actually use adapters with their iPhones on a regular basis. I’m sure they’re out there, but my gut is that it’s a very small (albeit irksomely whiny) community. The puck has moved on.


The iPhone SE kept me invested in the iOS ecosystem, and enabled me to purchase a Apple Watch without approaching the ~$700 iPhone ASP I normally attribute to laptop computers. Now that an updated iPhone SE is no longer an option, I am evaluating alternative cell phone platforms. I am sure I am not alone.

I don’t know anybody who uses a $700 laptop. With tax included, I paid $3,037.39 for the MacBook Pro on which I’m writing this. A friend of mine paid around that amount for the Windows laptop he uses. If you use a laptop for work, you’re paying many multiples of Thomas’ figure. $700 will buy you a fairly decent Chromebook or a really horrific Windows machine. Both options are very pedestrian.

Apple made something very clear this week. If you don’t have $750 for an iPhone, you aren’t in its target market. Apple’s always been this way, directionally: to own an Apple product, you pay big money, often more than the competition, and in return you get a great product that has culture and taste. That’s the value proposition, the rule of engagement. If you find this appealing, you participate in Apple’s store. Otherwise you don’t. Apple isn’t that interested in people for whom money is the primary consideration. Apple was founded by a self-identifying hippie, and it wants customers who care about more than money. If everything in your life lives and dies by the almighty dollar, then you’re never going to understand or appreciate Apple. The company has sometimes managed to ensnare such persons by offering a low-cost product; but whenever it pulls it, their true colors show. Apple did everyone a favor this week by removing an iPhone priced as the SE was.

(Hat tip to Pixel Envy.)

Assign to New Variable Names in an Object Destructuring  

I had no idea until today that this was possible. But take this:

const user = {
  device: 'android',
  statement: 'iPhone X has the exact same OLED screen that Samsung phones have, albeit overpriced.',

Let’s say we want the statement piece of this object, but we don’t like the property name. We can do like so:

const { statement: claimChowder } = user;

Now, the claimChowder variable has the value:

iPhone X has the exact same OLED screen that Samsung phones have, albeit overpriced.

Groovy, right?