Apple creates great experiences, but migrating to a new computer tends to not be one of them. There are several different ways of migrating, it’s not clear what the relative differences are between them, and when it’s taking a lot longer than you expect it’s not clear why. The seemingly never-ending migration hits programmers especially hard.
After running into this problem yet again recently, I did some research and experimented until I figured out what was wrong and how to fix it. Here’s what I learned.
Target Disk Mode
You may have gotten used to booting your old computer into Target Disk Mode and then having the new computer migrate the contents of the old hard drive over during setup. Don’t do that! I don’t exactly understand why, but it seems that Target Disk Mode can’t transfer at Thunderbolt speeds; it just degrades to regular USB transfer speed.
Instead of Target Disk Mode use Migration Assistant. Migration Assistant is an application you run on your old computer. It will restart into a special mode that is complementary to the setup mode your new computer boots into and will allow your new computer to transfer files from your old computer at Thunderbolt speeds.
Make sure you have a Thunderbolt cable. The situation with USB-C and Thunderbolt is confusing. The ports look identical and the cables almost look identical. The charging cable that comes with your Mac is not a Thunderbolt cable. You’ll know if you have a Thunderbolt cable because it will have a Thunderbolt symbol on at least one end of the cable.
The transfer can also be done over WiFi for convenience if you don’t have much data to migrate, so Migration Assistant will ask you to connect to your WiFi network, but it’s not very clear why it’s asking. It’s extremely easy to misunderstand what is happening and connect to your WiFi network even though you have no intention of migrating your data that way. If you then also mistakenly use a USB-C cable instead of a Thunderbolt cable, you can wind up starting the transfer thinking it’s using Thunderbolt when it’s actually using WiFi.
Not all USB-C ports on all MacBooks are Thunderbolt ports. I believe the 2016 and 2017 13-inch MacBook Pros without Touch Bar only support full-speed data transfer on the left two ports. You can’t use the right two ports. The 2016 and 2017 13-inch MacBook Pros with Touch Bar and the 2016 and 2017 15-inch MacBook Pros all have full-speed data transfer on all four ports. It’s really confusing. Thankfully, all the 2018 MacBook Pros with Touch Bar now support full-speed data transfer on all four ports.
Zip your code folder
The final hurdle is the files themselves. I noticed that the transfer speed would fluctuate all over the place. Sometimes it would spike up to Thunderbolt speeds but often it would slow to a crawl, causing the transfer to take hours longer than would be expected.
Eventually I realized that even though I only have about 400 GB of data to transfer, the reason why it takes so much longer than expected is because I’m a programmer.
Migration Assistant does a file-level copy—it copies each file one at a time. There’s overhead in starting to copy a file and finishing copying a file. That means it’s much faster to copy one big file than a lot of little files, even if in aggregate they’re the same size as the big file.
The work programmers do doesn’t take up a lot of space so it deceptively seems like the data should transfer quickly, but the package managers we use to install dependencies generally create a lot of files. I just looked at one project and the dependencies totaled ~120,000 files. Multiply that across 20 or 30 projects and that is what makes the transfer take so long.
The fix is to zip up the folder where you keep your code, delete the original folder, do the transfer, then unzip it afterwards.
Before I got around 5 MB/s when migrating. Sometimes it would spike up to 20 MB/s but only briefly. I don’t even know how long the transfer would have ultimately taken because I cut it off after 20 hours with only about two-thirds done.
I made another attempt after figuring all this out. This time the transfer started at 5 MB/s but slowly ramped up to 105 MB/s and held steady there for the rest of the migration.
It took 1 hour and 45 minutes. 🚀
Years ago I wrote about the different styles of
private declarations in Ruby and my personal preference. It was the best I could see at the time, but it was only marginally better than the rest and totally non-standard. Now I think I’ve finally arrived at a style that is superior to all of them.
To recap, the common style is this.
Despite being ubiquitous, it’s actually awful. If your file is large, the only way to know if a method you’re looking at is private or not is to keep scrolling upwards until you either see a
class declaration. All Rubyists have done this so many times now it’s become habitual. We’ve all internalized this as normal and we don’t ever think about how absurd it is. There’s a better way, though. If you’re a savvy Rubyist, you might be aware that the
private declaration doesn’t affect class methods.
# Not actually private
Never having tried to directly call a class method I’d declared as private, I didn’t discover this for years. To actually make a class method private you have to use
# Now this is private
Which led me to realize you can do the same thing with instance methods and
# This is private
And even better, the private declarations can be inlined.
private def something_private
private_class_method def self.classy_private
This works because the return value of a method declaration is the method name as a symbol, which gets passed as an argument to
Whatever your initial gut reaction is to the repetition, it will quickly be replaced by the surprising relief of knowing immediately whether the method you’re working on is public or private and not having to jump around to find out. I’ve been using this for the last several months and it’s great. Try it—you’ll come to love it too.
Single-quoted strings or double-quoted strings; the eternal conflict rages on.
Between years of freelancing and open-source work I get to see a lot of different codebases. The most common quote style I see is using single quotes by default and double quotes when interpolating. When I ask why I always get the same suspicious answers:
- The style guide says to use single quotes.
- Single-quoted strings are more performant.
- You know at a glance whether a string is being interpolated or not.
I’m going to try and settle this once and for all.
There are a number of style guides, but the two most popular ones are Bozhidar Batsov’s and GitHub’s, which is based on Bozhidar’s.
Bozhidar’s enumerates the two options—using single quotes as a default and double quotes when interpolating, or just using double quotes all the time—but only recommends being consistent in whichever you choose. In a previous version he notes that the latter style is a bit more popular in the Ruby community, although I have no idea if that is true or not.
GitHub’s says to just use double quotes all the time.
RuboCop is an awesome tool built by Bozhidar that analyzes code for style guide violations. The default configuration is to use single quotes. However, Hound, a service built on top of Rubocop by Thoughtbot defaults to double quotes.
I don’t know where the idea came from that single quotes are preferred in the style guide, but if anything double quotes are preferred. At best, you could argue there is no consensus.
I understand where this myth comes from—it sounds plausible. I was going to write a bunch of benchmarks but Lawson Kurtz already did it. It’s possible there was a performance difference at some point in the past, but if there ever was, there hasn’t been for a long time.
I find this one especially curious. Exactly how long a string are we talking about? How far offscreen horizontally or vertically are these strings going that you need to be able to discern from a quote mark at the beginning or end whether or not interpolation is happening? Most of my strings fit on one line. I can tell at a glance whether or not interpolation is happening by just looking at the string.
My favorite reason for using double-quoted strings is that I think they’re easier to read. Single quotes are not particularly distinctive—they’re too similar to too many other characters. When intentionally looking the difference is obvious, but when quickly scanning text it’s slightly harder to parse single-quoted strings than double-quoted strings. I have no empirical proof for this—it’s just anecdotal observation—but when I point it out most seem to notice the difference.
If you don’t agree that double-quoted strings are more readable that’s fine, but that doesn’t mean it’s a draw and using either is equivalent. If you use both quote styles then every time you make a string you have to think about which quote style to use. You also have to change the quote style when you add or remove interpolation from an existing string. If you always use double quotes then you never have to waste any time thinking about it.
Look at that, it turns out there’s a performance difference after all.