Category Archives: Development

Stagnation Or Stability?

Michael Lopp is moving on from Things, a popular to-do management app.

That’s an understatement. The title of the post is “R.I.P. Things,” and he wastes no time explaining that he is “throwing away” the app. This sounds juicy. What could have him so riled up?

How can I trust that I’m using the state of the art in productivity systems when I’m using an application that took over two years to land sync I could easily use? What other innovations are they struggling to land in the application? Why hasn’t the artwork changed in forever? What is that smell? That smell is stagnation.

The nut of Lopp’s rationale for tossing Things to the curb is the relatively slow pace of its development over the years. Delays in delivering long-desired features, namely sync, made him conclude that the software will not evolve in ways that suit his needs moving forward. He’s not giving up on Things because of specific shortcomings, but because of anticipated shortcomings and a loss of confidence in the developers of the app.

This line of reasoning gets my hackles up in part because I’m a cautious, deliberate developer. I tend to add features, rework user interfaces, and adopt new platforms at a pace that frustrates even my most loyal customers. I’m slow, but I’m good! When Lopp attacks Cultured Code, the makers of Things, and questions their core competence, I feel that I am being attacked as well.

But what really frustrates me in this case is the software has served him perfectly, and he thanks it with a slap to the face. It’s one thing to denigrate a product for failing to meet your expectations, or for exhibiting a clear lack of craftsmanship, but Lopp admits that those problems do not apply:

Part of me has been fine with this lack of change because I don’t need my productivity system to do much more than capture a task, allow me to easily categorize and prioritize tasks, make it easy to search and filter them, and do all this work frictionlessly. “Things does these things well,” I thought to myself, “I don’t need anything else.”

He applauds the app for allowing him to do his work “frictionlessly.” How does a software developer achieve this level of performance? By first building a quality product and then working deliberately over months and years to address the minor issues that remain. Woodworking makes a reasonable analogy: after a chair has been carved and assembled the job is functionally complete. It’s a chair, you can sit in it. It’s done. But customers will gripe with good cause about its crudeness unless the hard work of detailing, sanding, and lacquering are carried out. Only then will it be considered finely crafted.

As a seasoned software manager, I know Lopp appreciates how hard it is to achieve the stability Things has provided for him. But as a user, he’s as excited as any of us to see new, fresh designs. As an onlooker, it’s easy to associate dramatic change and motion with competence, and quiet refinement with laziness. We must draw on our own experiences attempting to build great things to appreciate how much work takes place in stillness, to have faith that even though things may appear stagnant, a benefit of frictionlessness is resulting. An app at rest may be in that long, arduous phase of becoming finely crafted.

There is a time for dramatic change as well, but it comes with costs. If after years of careful refinement a product is found to be lacking in some important way, bring out the hatchets. Chop it all to bits and rebuild from scratch. The possibilities of positive change in major reworks are exhilarating as a developer, and tantalizing to customers. But every reworked component of a product also resets that process of refinement.

Software should be criticized. Even apps that consistently wow me with their intuitiveness and polish leave me scratching my head about perplexing, nuanced failures. But criticize an app for its failure to do something important, not for an unspecific failure to change in general.

I’ve whined about stagnation, too. I waited years for an update to Keynote and over time, become more and more grumpy about the lack of change. The fact that it’s just about the best application I’ve ever used slowly lost sway in my judgement of the software and, by association, the team of developers who build it.

The next time I’m tempted to think harshly of a developer working at a slower pace than I’d like, I’ll try to step back and appreciate that I care enough about their software to be concerned. And more importantly to appreciate that they care about their software too. So much that they work slowly, deliberately, painstakingly in the pursuit of a frictionless experience for myself and other users.

The Imperfect Craft

For much of my career I viewed software development as a craft: a constructive endeavor with fixed standards of excellence. I thought that over a lifetime, I could assiduously refine my skills, inching toward some level of subjective mastery until eventually myself and others would agree that I had become “a real expert.”

Unfortunately it doesn’t work that way with software. The technological context in which software is developed and used changes constantly and dramatically. So most of the stringent guidelines we impose upon ourselves in the name of craftsmanship are at risk of being obsoleted by some new advance in hardware, in programming languages, or in the baseline services of the operating systems we develop for.

Ask yourself, or a software developer of a certain age: what were the guidelines for crafting excellent software 5 years ago? 10 years ago? 20 years ago? The farther back one goes, the less relevant the answers will be to our modern craft. Memory management? Not a significant issue for most programmers today. Multitasking? Obliterated by modern operating systems with efficient context switches. Concurrent programming? Constantly reinvented in the wake of multi-core CPUs, GPUs, and higher-level programming language features.

I have spent a lot of my professional life honing “the skills of programming.” That is, the set of skills that seemed important at the start of my career. But I’ve seen what happens to people who cling to outdated standards of craftsmanship: they become self-righteous, bitter, and delusional. Guided only by the hallowed rules of yesteryear’s geniuses, they and their work become marginalized. Without a foothold in the modern technological context, programmers who should be great are rendered effectively incapable of developing their craft.

I’m sure this problem is not limited to software development, but given the world’s obsession with computers and related technology, the software landscape is changing much faster than many of us can easily keep up with. The world demands that this craft change. The technology for sculpting, firing, and glazing a ceramic bowl has also changed over the years, but not at the same mind-boggling rate as prototyping, programming, and testing a software application has.

What if you happen to enjoy old-school programming? There’s nothing inherently wrong with crafting “retro software.” In fact, I’m sure that dabbling in outdated techniques will serve to round out a modern programmer’s abilities. But while a classics scholar may be intrigued or even obsessed with ancient Greek or Latin, she knows that in order to remain relevant she must publish her papers in modern English. And if Esperanto were to become the lingua franca for her craft, that is the language she would have to use.

In software, the lingua franca is changing all the time, whether by adoption of new programming languages, through nuanced idiomatic changes in the ways that we use languages, or because of evolving operating-system level facilities. We don’t have the luxury of assuming that the tools and techniques of our parents, or even our younger selves, are sufficient to move the profession forward.

As a modern software developer, I derive as much joy from remaining relevant as I do from the thrill of identifying and solving the particular problems in my work. To remain relevant, I have to reject my previous assumption that I would spend a lifetime refining my craft. Instead, I will spend a lifetime adapting the techniques of yesterday’s craft to the sometimes radically different challenges of today. I may never become “a real expert,” as I hoped I might be. But by diligently throwing out the old rules and embracing the new ones, I hope to come close.

Screenshot Lightning

Apple recently changed their policy regarding screenshots for iOS applications in the App Store: you must supply any changes to your screenshots by the time of approval, or the existing screenshots will be locked down until the next time you submit and are approved.

Long story short: you better have those screenshots ready at submission time or very shortly after. And the screenshots had better be something you are willing to live with for a good long while.

This is a dramatic change from the old policy, under which developers could update screenshots at their leisure. This afforded a workflow where a developer might put all of their effort into the actual development of the app, submit it, and then get to work fine-tuning their screenshots for the marketing aspect of selling in the App Store.

One reason for putting off the job of creating screenshots is that creating them is time-consuming and tedious, even with a relatively simple app. For a more complex app, or one that is localized into many languages, the challenge is that much greater.

Last night, at our local Boston CocoaHeads meeting, I learned about a well-timed solution for this problem. Kent Sutherland, the programmer for Flexibits, showed off how he uses an automated screenshot-capture procedure to tame the task of generating Fantastical’s many screenshots, in many languages.

His approach uses a novel technique in which the target app itself is built with customized screen-capturing code compiled right in. Then the app can be driven through the iOS Simulator with WaxSim, a command-line tool for launching the simulator with various options. He was kind enough to share a sample project in which he applies the same technique to Apple’s UICatalog sample app:

Click to download Kent’s UICatalog sample.

After downloading the sample, navigate to the “Screenshots” folder to find the real goodies. The Readme.txt in that folder has simple instructions for kicking off the process. In a nutshell: just open the Screenshots folder in the Terminal, and type “python make_screenshots.py output”. Then watch as the iOS simulator cranks through the process of generating 12 screenshots for UICatalog before you’ve had a chance to wipe that tear of joy from the corner of your eye.

I plan to build more iOS software in the future, and something like this will undoubtedly be a lifesaver when I have significant screenshots to generate. My only existing iOS app, Shush, only has 4 screenshots in one language, and I still found it tedious enough to re-generate screenshots that I hesitated to improve the UI because of the work of another round of, ahem, bitsplitting.

The same approach is also applicable to Mac apps. Currently I go through a similarly tedious procedure of manually navigating and cajoling the app into a specific state before taking a screenshot by hand. This could all be driven by automated capture code built into a custom version of the app, where I could also imagine other niceness such as adding annotations to illustrative screenshots, being added to the process.

If you’re selling apps on the iOS App Store, Apple’s policy change makes it imperative that you come up with a workflow for effortlessly and quickly generating screenshots. Thanks to Kent’s generous sharing of his approach, your work is mostly done for you.