Think Twice Before Downgrading to a Free GitHub Account
Today I learned that if you downgrade from a paid to a free GitHub account, you’ll lose any branch protection rules you’ve added to your private repositories. It’s my fault for not reading the fine print more carefully, but still – it would have been helpful for them to toss up an alert or something that makes it obvious that by downgrading to the free tier there will be destructive side effects on features you probably set-and-forgot years ago and have taken for granted. I live in mortal fear of making a dumb mistake and losing irreplaceable source code. Downgrading to free account is, in my estimation, Step One on the path to me making such a mistake.
Please note also that when upgrading back to a Pro account, any branch protection rules you had before were permanently deleted when you downgraded to the free tier. They will all have to be recreated from scratch. So if you were considering downgrading to a free GitHub account, I don’t recommend doing so if you use private repositories for code that you care about. And if you have already downgraded to a free account, double check that you can live with the consequences of accidentally force pushing or deleting an important branch.
Update: I received a friendly reply from GitHub CEO Nat Friedman. :)
iOS App Analytics a Necessary Evil, or Maybe Just an Evil
I have yet to see an iOS project where implementing client-side analytics (page loads, event logging, behavior tracking) wasn’t unspeakably awful to implement. A litany of sins:
Brittle: It’s far too easy to break existing behaviors when rearranging code, reordering screens, replacing outdated logic, etc.
Needy: Metadata attached to arbitrary events often requires tying together data that’s scattered across unrelated objects. Making it available at a given analytics call site forces you to punch ghastly holes through all your precious tiers of responsibility.
Volatile: Last-minute additions to feature requirements often end up requiring deep refactoring to replace all the plumbing you thought sure was not Lucy Van Pelt footballable not this time, I’m sure it’s going to ship unscathe— oh god no.
Unfriendly: You get effectively zero help from the compiler or static analyzer to help you do it right. Missing an analytics call? Too bad, nobody will notice until you’ve shipped to production and Brycepants the Product Guru has a meltdown because it looks like nobody has retooted a shitpost since version four-dot-fucked hit the App Store update tab.
Incomprehensible: Translating biz dev douchebag bingo into an expressible model is an exercise in futility. It’s even worse for whoever has to come along behind you and refactor your mess.
Costly: Once you’ve started using a particular solution/platform you’re effectively locked into it for the lifetime of the project. Often you don’t even have a say on the initial choice, either. Shame on me, shim on you.
And these are just the problems with implementation details. Let’s not forget how morally and/or legally perilous the entire enterprise is, stockpiling user data without regard for its half-life — which is effectively infinite — or for all the incalculable damage that can be done in five, ten, twenty years when Faild Strtup Dotcom goes bellyup and all it’s data gets dumped onto the lap of the highest bidder.
There are many reasons to just abandon this foul mess, and only one indestructible, immovable reason not to: you can’t run a business if you don’t know what your customers want. We all understand this dilemma, but understanding it doesn’t make it any easier to stomach.
Reference Types vs Value Types: the Original Sin of Programming
Gentle reader, you might know where this is written, better than I have written it here, and perhaps canonically: there aren’t that many kinds of code, right? It seems to me that in any language, any given statement or expression can be reduced to one (or a composite) of these two kinds of activities:
Reference activities: - initializing/mutating/messaging/destroying a reference type (or an external resource, which I’d argue is effectively the same thing).
Value activities: - evaluating/transforming/returning a value
A notion I’ve been struggling to nail down in words over the past several years is how—still struggling here—all pain seems to stem from one original sin: real-world programs require both kinds of activities, reference and value, but those two activities are as incompatible as oil and water. To write a useful program, you need to undertake reference activities and value activities, but the two don’t want to be mixed. The act of writing the program is itself the cause of the problem!
Programming paradigms — OO, Functional, Procedural, Imperative — and application design patterns — MVC, MVVM, VIPER, YADA•YADA – all seem to be answers to the problem of how to resolve the impedance mismatch between reference and value activities, but a side effect is that in the act of proposing a solution they implicitly suggest to the developer the paradigm has done the hard work of understanding the diagnosis for you, so you don’t have to. When inevitably a given paradigm runs aground on a blind spot, too often the ensuing debate becomes about the merits of particular paradigms and not nearly enough about achieving a universal understanding of the nature of the problem that all paradigms aim to solve.
I believe that it is vastly more important for a developer to internalize the “simple” lesson of how reference types and value types differ. It’s Programming 101 material, but so much of what we do is merely a footnote to that difference. The more one internalizes that insight, the easier it becomes to reason about this or that paradigm, the easier it becomes to jump to a different ship as project needs change, lacking loyalty to any solution but fiercely deepening one’s understanding of the diagnosis.
Little Weeds of Dread
A sobering comparison occurred to me last night: the same way that I can never again fully enjoy the software on the little devices in our pockets and on our wrists, knowing as I do how an app is made and being able to spot when one is not made well, perpetually bracing myself for whatever horrors await at the end of each flickering transition and every unrelenting activity indicator – it is like the anxiety of becoming parent, a parent who was once a child also but whose simple childhood joy has since been choked by the little weeds of dread that take root in the soul of every adult, as one cannot reach adulthood without acquiring unspeakable knowledge, accompanied by horrifying detail, of how a life is made and how easily a life can be unmade.
TIL: Boy, Have I Been Misusing SCNetworkReachability
After reading this discussion — courtesy of Jeremy Sherman — I learned that I’ve been misusing SCNetworkReachability for years. I’ve been allowing certain user-facing states and features to be influenced by the current reachability state, even to the point of blocking some user-initiated network requests. In ’sodes, for example, I’m currently preventing a playback attempt whenever the network is unreachable.
Turns.
Out.
SCNetworkReachability, like all networking, is not reliable enough to support that kind of behavior. If there’s a false negative (which is much more common than one might think), it means the app becomes needlessly unusable.
SCNetworkReachability should only be used to influence what you do about a network request that has already failed, not an initial request that has yet to be attempted. Use a negative status to determine whether or not you attempt an automatic retry, or to tweak the user-facing language of an alert. Use a positive status to consider retrying an earlier failed request. Never prevent a user-initiated request from being attempted just because SCNetworkReachability thinks there’s not a reachable network.
You can see the code I’m using to monitor reachability status right here on GitHub. To drive the point home to myself, I’m probably going to change the public API of my network reachability wrapper from this:
var isReachable: Bool {...}
to something that more accurately models the truth:
enum ReachabilityStatus { case probablyNotButWhoKnows case itWorkedThatOneTimeRecently } var status: ReachabilityStatus {...}
SCNetworkReachability, or rather the realities of real-world networking at whose mercy SCNetworkReachability remains, is just not reliable enough to deserve a Bool.