WWDC 2020: form vs function

I have seen a handful of these takes about WWDC and while I appreciate what they’re saying, something rubs me the wrong way about it.

We all miss getting together with friends and meeting people, but this overall “I get that the content is better, but networking!” sentiment some developers have shows that they value their own nostalgia and enjoyment of networking over better WWDC sessions and accessibility for the wider community.

WWDC’s primary purpose isn’t for you to make new friends. Its purpose is to help inform developers of new Apple technologies.

This year tens of thousands of developers got to have a much better WWDC with better, tighter content because of this new remote format. WWDC videos often contain the best information about new technologies and serve as a valuable reference for years. Often times the best way to learn about a particular technology is to go back and watch the WWDC session where it was first introduced, and for everything that was introduced this year, we have fantastic materials.

And although networking and seeing friends at WWDC in person is fun, attending in person is a privilege. Only a small percentage of developers have the substantial funds (and depending on what country you’re from, the ability to safely travel into the US without hassle from customs), and are lucky enough to win the lottery for a ticket.

WWDC in person is great for the people who get to go. But every year as the developer community grows that becomes a smaller percentage of the community. If being in person with others at WWDC brings new friendships and opportunities to the attendees, then it just means that attending WWDC amplifies your privilege, and we need to acknowledge the inequality that leads to.

Ideally, I hope next year’s WWDC format doesn’t completely abandon the perks and better video production values we got in 2020. We would have a live keynote and SOTU for Monday, and prerecorded sessions would be released throughout the week. Instead of presenting live sessions, Apple engineers could instead give more labs and in-person assistance during WWDC week, Apple engineers could be offering sessions with individual developers remotely throughout the rest of the year. That would make for a better WWDC for everyone.

Or maybe Apple will want to stick with a WWDC where everything is pre-recorded and remote (that’s probably a lot less stressful for them!) and instead of there being a single Apple developer conference that’s massive and expensive, smaller, local conferences can sprout up around the world for people to enjoy each other’s company and talk shop. It wouldn’t be quite the same as what WWDC was before, but then again, Apple’s developer community is a lot bigger, diverse, and spread out than it was before, and it’s time for WWDC to adapt to that new world.


Live-ish glucose data on Apple Watch

Since I was diagnosed with diabetes a few years ago, one of my best coping mechanisms has been to lean into it by using it as an excuse to play around with gadgets to track it.

And lest you think that’s a waste of time, it’s really effective! There is a direct relationship between how well controlled my diabetes is and how much I’m tinkering around with this stuff.

One of the most powerful tools in my diabetes management arsenal is a system called the FreeStyle Libre. Instead of having to prick my finger every time I want to check my blood sugar, I instead will insert a sensor onto my arm every two weeks, and whenever I want to check my blood sugar I can scan the sensor by swiping my reader next to it. Or if I don’t have my reader with me, the sensor uses NFC so my iPhone can scan it too.

When I scan the sensor, I instantly get my current blood sugar level, plus 8 hours of past blood sugar data.

glucose data from LibreLink app

But the LibreLink app sucks. It isn’t a particularly good iOS citizen; instead, it feels like it’s just trying to mimic the reader’s own interface. And despite having this treasure trove of data, it won’t sync to HealthKit. You have to use a proprietary app called LibreView (although through a series of steps I can export the data and eventually get it into the Health app).

Basically, there are two extra features I wanted for my Libre sensor:

  • ability to see current glucose level by glancing at a complication on my watch
  • having glucose levels automatically synced to the Health app


Because the Libre sensor is NFC based, I would need something extra if I wanted to actually push data from the sensor to my iPhone/Watch.

And there does exist such a device called the MiaoMiao. It piggybacks on top of your Libre sensor and connects to your phone via Bluetooth, scanning the sensor every five minutes via NFC and pushing the data over to your phone.

There are multiple apps that work with MiaoMiao, and on iOS you can use either Spike or Tomato. After unsuccessfully trying to get the Spike app set up and realizing it was kind of a lousy iOS app, I opted to try Tomato, which is at least in the App Store.

The Tomato app works, but it is kind of a low-quality Chinese made app with the trappings you might expect from such an app–poor translations, a UI that lacks care, mandatory login with your Google, Facebook or WeChat account (Sign in with Apple was strangely absent despite supposedly being mandatory via App Store policy) and Watch complications that either truncate your data, or make really poor use of space.

apple watch face with blood glucose complications

However, the app does sync with HealthKit, if you have a premium subscription (interestingly, it doesn’t use Apple’s in-app purchase mechanism either; they prompt you for PayPal. I have no idea how Apple approved that as that is a blatant violation of App Store policy and usually the kind of thing Apple watches like a hawk).

So instead of using Tomato’s own watch complication, I am instead using HealthFace to set up a complication for my watch that displays the most recent blood glucose value.

This works beautifully!

apple watch face with HealthFace app complication

Ideally I’d like the HealthFace app to be able to display a chart of the last few hours of values so I have some sense of my glucose trend, but now that I have the watch complication I am watching its value often enough that I have a mental idea of how it looks anyway.


Some random facts that I wondered that aren’t answered elsewhere:

  • If you’re in the US it will take forever for the MiaoMiao to ship from China. I ordered it in February and it didn’t finally arrive until late June, although they lost the first one and had to ship me a second one.
  • If your MiaoMiao arrives and your sensor is already activated, the MiaoMiao can still connect to it. You don’t have to wait for a fresh sensor.
  • You can still pair your Libre sensor with both the reader and your phone while still using the MiaoMiao
  • The MiaoMiao sensor’s stickers aren’t that great at staying attached. I had to use some medical tape to tape the sensor down to my arm, but since then it’s stayed put.

Parting thoughts

As appreciative as I am that all these parts can work together like Lego pieces to give me a working solution, I’m still a little frustrated that Abbott doesn’t provide a decent end-to-end solution.

In Europe there is a new version of FreeStyle Libre with sensors that are Bluetooth-enabled, but the sensor only uses Bluetooth to alert you of highs or lows, and doesn’t push the actual glucose data to your reader, so that’s still a dead end.

But at some level this neglect is a blessing. Abbott’s not offering anything like a full SDK or anything for its sensors, but they’re straightforward enough to reverse engineer that we can at least cobble together our own solutions.


A new WWDC

Speaking as someone who’s never attended a WWDC in person, today’s sessions felt like an overall improvement over an in-person event. Presentations felt tighter and more polished overall. It was probably a little less nerve-wracking for the speakers to have everything recorded ahead of time, even if they miss out on some of the live audience feedback and applause.

I realize that for the people who have attended WWDC in person this is for sure a downgrade for a lot of reasons, but for the tens of thousands more developers who get to experience the conference this time as first class citizens, this is an overall upgrade.

WWDCs for the past… decade or so have felt stagnant in their format that dates back to Steve Jobs. This year’s WWDC feels like Apple is finally breaking free of that legacy and trying something new that is true to the reality of Apple’s scale today. This year’s WWDC format also feels more true to the nature of working as a developer, something Apple hinted to in the outro video for the Platforms State of the Union, showing developers working in a variety of settings, sometimes late at night, sometimes with children around. By embracing a distributed and more asynchronous conference format, you are making WWDC feel like it’s for everyone, not just a privileged relative few who can make the journey.

Apple didn’t want to do this year’s WWDC like this; they were forced to do the event like this because of COVID-19, and I’m sure they’re eager to do live events again when it’s safe. And that’s great! I can’t imagine it gets much better than working hard on something great for people and hearing that thunderous applause when it’s introduced on stage. But the community has changed, and the defaults should change too.

It’s Time to Allow Sideloading iOS Apps

Apple’s firm rejection of letting Hey’s iOS app in the App Store is just the latest in over a decade of controversy over the rules and restrictions Apple puts on App Store apps.

I’m sick of having to keep calling on Apple to reverse some stupid App Store policy decision every several months. Let’s eliminate the problem at its core and stop requiring iOS apps to be distributed on the App Store.

We don’t need the App Store to be exclusive for iOS to be a safe platform. iOS’s security model is great, and sideloaded apps can be made safe by adopting notarization as Apple has for macOS. No one realistically thinks the human app review process is meaningfully making apps safer.

And this would be great for Apple; it frees them up to run the App Store however they want to because developers always have an alternative if they run afoul of App Store policies.

Maybe Apple feels pressure from investors to keep the services revenue gravy train running, but there’s no reason to believe that allowing sideloading is going to slow that down. The App Store will keep growing without exclusivity, just as the Mac App Store has. The App Store wins by being the most convenient way for customers to buy things from developers, and non-power users will always trust Apple to curate an App Store full of apps they know they will trust.

The iOS platform is a massive market, and Apple hasn’t been a good steward of its primary distribution channel. If Apple wants the truckloads of money that come with making the most profitable mobile platform, it needs to accept that it can’t keep running it with monopolistic, rent-seeking behavior.


Tech’s lip service to racial injustice

As protests of police violence continue in the US we’re beginning to see the steady trickle of large tech companies posting to social media about the events in solidarity.

These companies only started putting out statements after massive civil unrest started to form. George Floyd was killed May 25. The next day footage of his killing became widespread, but it wasn’t until days later, when there was massive protesting in the streets, that companies began putting out statements expressing empathy.

And as kind as these gestures appear, they don’t make up for the fact that these same companies are more than happy to participate in being racist in the first place. Companies will happily pay lip service to a less racist world, but if it meant having to turn a way a customer that embodies institutional racism (like ICE, for instance), that company will just throw up its arms and insist that it’s their duty to sell to these customers.

When employees try to object to this behavior, the companies’ executives will dismiss these employees’ viewpoints as a “difference of opinion” and that they can’t just use opinion like that as a basis for doing business with a customer.

A difference of opinion.

As in, “it’s my opinion that we shouldn’t do business with an organization that is rounding up people and putting them in literal concentration camps.” You know, just a little difference of opinion!

Law enforcement agencies around the US have deep-seated cultural issues of institutionalized racism. It’s baked into the behaviors of police officers and misconduct is incredibly widespread. Law enforcement is able to carry out its misconduct because it has the help of thousands of vendors that sell them the things they rely on, from cars, to uniforms, to computers, to software.

Every tool and service that a police department uses is made by a vendor, and every vendor has a choice not to offer their products and services to police departments if they don’t believe the police departments are behaving with good conduct.

But none do.

I’ve yet to see a single tech company come out and say “we’re going to audit our relationships with law enforcement agencies and we will end our relationship with agencies that don’t meet our standards”. Shopify’s CEO shared a heartfelt comment expressing his disgust with the injustice of George Floyd’s killing, but apparently he felt that cutting ties with Breitbart would be too much of an injustice to them (he since deleted his original post on Medium).

It’s nice and cheap to put out a statement denouncing racism and companies are happy to do it. But ask a company to take a meaningful step to stop racism and they’re all too eager to shy away from it.

To tech companies, systemic racism is a PR problem to be managed as long as it’s easy to do so, not an opportunity to acknowledge their own substantial role in it.


Default values for hashes in Ruby

I was recently working on some code that involved hashes of arrays. As I was reading through some behaviors of Hash in the Ruby docs, I was delighted to see that you could pass an object to Hash.new and it would be the default value returned when you tried accessing a key in a hash that didn’t exist.

So, let’s try this out a little bit!

2.1.1 :002 > arrays[:colors] << :blue
 => [:blue] 
2.1.1 :003 > arrays[:colors] << :red
 => [:blue, :red] 
2.1.1 :004 > arrays[:colors]
 => [:blue, :red] 

Looks like it’s working! Let’s use another key.

2.1.1 :005 > arrays[:shapes] << :quadrilateral
 => [:blue, :red, :quadrilateral] 

Wait, whaaaa? Let’s see how my :colors array is doing:

2.1.1 :006 > arrays[:colors]
 => [:blue, :red, :quadrilateral] 

Oh, no! What is going on with this hash?

2.1.1 :007 > arrays
 => {} 

Okay, let’s read those Ruby docs more closely:

new → new_hash
new(obj) → new_hash
new {|hash, key| block } → new_hash

Returns a new, empty hash. If this hash is subsequently accessed by a key that doesn't correspond to a hash entry, the value returned depends on the style of new used to create the hash. In the first form, the access returns nil. If obj is specified, this single object will be used for all default values. If a block is specified, it will be called with the hash object and the key, and should return the default value. It is the block's responsibility to store the value in the hash if required.

There are two subtle things at play here. First off, giving hashes a default value doesn’t mean that anything is stored in the hash when you try to access a nonexistent key. That explains why my arrays hash is still empty even after I’m shoveling things onto arrays. This is sensible default behavior; a hash could grow without bound if by default a new value got added to a hash whenever it was accessed by a nonexistent key.

The second subtlety here is a reminder that in Ruby, objects are mutable. We are providing the hash a single object instance (in this case, a new empty array) that is returned as the default value when you try to access a key in the hash that doesn’t exist. If I change that array by appending things to it, I’ll still get back that same array object in the future when I access the hash by a nonexistent key.

I want the hash to work so that when I access a nonexistent key, I get back a new empty array, and that array is added to the hash. We can do this by passing a block to Hash.new:

2.1.1 :008 > groups = Hash.new {|hash, key| hash[key] = []}
 => {} 
2.1.1 :009 > groups[:colors] << :red
 => [:red] 
2.1.1 :010 > groups[:colors] << :blue
 => [:red, :blue] 
2.1.1 :011 > groups[:shapes] << :octagon
 => [:octagon] 
2.1.1 :012 > groups
 => {:colors=>[:red, :blue], :shapes=>[:octagon]} 

I’ve been using Ruby for years and I lost at least an hour recently because I wasn’t accounting for this subtle behavior.


Channeled Procrastination

This was originally published on Carbon Five’s blog


I procrastinate.

In high school it was a huge issue for me, because as a high schooler I was still inexperienced at it. I frequently found myself in last-minute mode, moving swiftly from one self-induced crisis to another.

College wasn’t any better. The assignments were more spread out, but the due dates tended to be final due dates, whereas in high school there were usually several interim deadlines for milestones.

Constantly having a lot of irons in the fire was a persistent source of low-key anxiety for me throughout high school, but in college I came to terms with the fact that I am never going to have a truly clean slate during the semester. That to-do list will never be empty, and I stopped letting it be a source of anxiety.

Instead, I started leveraging my procrastination strategically. If I am feeling like procrastinating on some task, I just procrastinate. That’s what Nike means when they say “Just do it,” right?

Instead of hating myself for lacking discipline and focus, I pick from a buffet of other things that need my attention. And then later on I’ll go and do the thing I originally wanted to do, only now this time I’ll do a better job because my mind’s in the right space to do the work. If the due date creeps up and I still haven’t been motivated to do it, the looming deadline usually is motivation enough, and I get my task done. The only difference: I didn’t spend the whole time feeling bad for procrastinating.

If I need something done by the 30th and I finish it on the 10th, that task isn’t somehow more done just because I finished it earlier. You don’t save any money paying a credit card bill 2 weeks before the due date instead of on the due date. So who cares if you did it at the last minute?

Common wisdom is that procrastination is a character flaw; that if you procrastinate it’s because you’re lazy or something. But what good does it do to think that? If you treat your procrastination as a prioritization tool, you can get more done and you won’t be agonizing over your work.

There are lots of characteristics that benefit from not being seen as a character flaw. Are you forgetful? Set up infrastructure and other things around you to help you remember things. Are you prone to making a costly typo when deploying some new code to a server? Automate it with a script that validates things to make sure you didn’t make a stupid mistake.

Now, while everyday procrastination can be innocent enough, keep an eye on your procrastinating, because persistent procrastination can be a symptom of psychological issues. If you are not usually prone to procrastination and you find yourself doing it more recently (or if you’re procrastinating on things you usually don’t procrastinate on), that could also be a symptom of something deeper going on emotionally. Some good first steps to help understand your feelings and behaviors better include journaling, talking to an insightful and supportive friend, and talking to a therapist.

With that, I’ll get back to the the task I was putting off!


ARKit and the taller skyscraper

Having seen some of the apps that were put into the App Store this week with ARKit support, it really hearkened back to an analogy Steve Jobs loved to make when OS X was first being developed.

Building software, he opined, was a bit like building a skyscraper. There’s a certain number of floors that you can build on your own before the whole thing collapses under its own weight. At a certain point it just gets too complex for you or your team.

But with good APIs (such as the ones OS X provided), you still can build that same number of floors, but with the help of those great APIs, you are already many floors higher when you first start building. 

ARKit perfectly embodies this principle. A few years ago, building your own AR system was a ton of work and was hard to get right. But since Apple has included AR APIs in its SDK, you now get AR for free. 

That suddenly means that a ton of little apps can now be made and have AR as part of them, when they wouldn’t have been practical to build at all before. Adding an AR component to a simple game? Easy! Want to make a tape measure app that lets you measure things around you? Now that’s easy to do with AR.

I don’t think AR is going to be a revolutionary change to how everything in mobile apps works. But it’s now within easy reach of every iOS app developer who wants to try something with it. Investment in these APIs give Apple incredible long-term advantages that are hard for competitors to catch up with.

You Don’t Need To Be First

“Guys, it’s crunch time.”

You feel dead inside as you process the words.

“We’re gonna need to be doing some late nights here for awhile. We need this done by July 16 or… ” he trails off.

“or it won’t be done by July 16,” you think to yourself.

So one late night you’re eating pizza with the project manager and you ask, “why the rush?”

“Well, our competitor is working on this thing too, and if they come out with it first then they’re going to win this whole market and we won’t have a future.”

“Of course,” you respond after looking up from your Blackberry. “I’ll stop messing around on MySpace and get to work.”

You open up Rhapsody to find some music to jam to, then you fire up WordPerfect and finish up with the report you promised to get done.

Yep, you think to yourself. We better get this project off the ground first or no one will ever use it, like when that one company tried making their own version of Hydrox. What were those called? Oh, yeah, Oreos.