What’s the point of your library if you won’t tell me how to use it?
Friday morning. 9:00 AM. Last day of the work week. Your Trello board says there’s one more feature to add to Rocket Smack! and that’s the ability to post your high score to Facebook. You’ve never integrated with a social network before and you have a whole day to get it working. You’re excited to get started! You’ll get to use the Facebook SDK for the first time!
Oh, you poor sap. You’ll be working through the weekend and you don’t even know it yet.
Among developers, the Facebook SDK is notorious for being an incredibly complicated framework to work with. I can go on all day with the reasons why:
- The documentation doesn’t cover all of the standard use cases.
- A lot of standard boilerplate you’re told to put in your code leaves you wondering why it wasn’t simply included with the library in the first place.
- A lack of clarity about the architecture of the API. What’s Facebook Connect? What’s the OpenGraph? Just tell me how to post a pic!
- The documentation is talking about three different versions of the library at once. Extremely misleading.
- There’s multiple ways to handle authentication.
- The native iOS 6 implementation only partially replaces the original Facebook SDK. Try posting a status to your own Application with the native UI.
- The iOS version of the library installs with a package manager! WTF?!
Sadly, this isn’t a blog about how to use the Facebook SDK. I don’t have enough hair left to dare get into that. No, this is a blog about how Facebook could have gotten it right by teaching how to use it effectively.
Mogenerator: even if you figure out what it’s for, you won’t know how to use it
My first case study is a tough one for me because it’s one of my favorite iOS libraries and I use it, without hesitation, in every app where I use Core Data. It’s indispensable, brilliantly executed, and works extremely well.
But, oh @rentzsch, you did a great job of trying to keep it a secret from me!
If you’re not familiar, let me tell you what Mogenerator does and the problem it solves. You see, if your iOS app is going to use Core Data, you’re going to want to have Objective-C classes that represent each entity in your data model. So, for example, if you have a User entity, you’ll want a User.h and User.m to serve as a concrete class instead of using NSManagedObject everywhere. In addition, good OOP principles suggest that you should add methods to this User class that will operate on it. All of this is straightforward until you realize that XCode does a horrible, horrible job of making this easy for you. For one thing, generating the User class can be tricky to do and, once you do it, any future re-generations will completely overwrite what you had before. This means that if you added a method such as -fullName (a readonly concatenation of the User’s first and last name), the re-generation will delete it! Mogenerator fixes this by using the classic two-class design pattern where a private base class is overwritten when the User model changes and a derived class that contains your own methods is left alone.
Cool, huh? Now, if you google for Mogenerator you’ll find the GitHub page and be presented with this README:
mogenerator is a command-line tool that, given an .xcdatamodel file, will generate two classes per entity. The first class, _MyEntity, is intended solely for machine consumption and will be continuously overwritten to stay in sync with your data model. The second class, MyEntity, subclasses _MyEntity, won’t ever be overwritten and is a great place to put your custom logic.
Great. The problem is that’s all it says! The pretty homepage is even more useless. No info on how to generate the classes, where to do it from, options, or anything…well, there’s a link to somebody’s blog that explains how to do it (and the author’s quite a handsome man), but that didn’t get written until years after Mogenerator was created!
How did I learn Mogenerator? I saw it implemented in a codebase at work. How did they learn how to use it? I think they knew the developer personally. This explains why I am always running into iOS developers who don’t use Mogenerator and should be. This could’ve all been fixed with a better explanation of the problem Mogenerator was designed to solve and a simple walkthrough of how to add it to your project and use it.
Brilliant work by the developer is nearly lost due to a criminal lack of documentation.
Sinatra: teaching an entire framework in just 19 words
The Sinatra framework can teach Mogenerator a lot of things about how to introduce itself. With just 19 words, 4 lines of code, and 4 lines of console output, the Sinatra homepage will leave you infatuated, informed, and psyched to use it!
Don’t believe me? Take a look for yourself.
If you’ve never heard of Sinatra, and you clicked that link above, then in the blink of an eye you just learned that Sinatra is a web service DSL that lets you create endpoints by simply fetching a gem, writing a block, and running a script. All so brutally easy and intuitive you’ll want to break down and cry. Think about how easy this is compared to, say, using a Java WAR with Tomcat. Heck, this even makes Rails look like a bloated piggy.
It’s rare to find such a beautiful example of conveying the intentions of your platform in such a simple way and with such charming character, but it’s real easy to find something that does the exact opposite.
GDataXML: oh hai, here’s that XML/YouTube/Picasa/Finance/Code Search library you wanted that we deprecated so JSON?
Deprecated? How about defecated? In the early days of iOS development, you might have gone looking for a high-level XML library to use and found Google’s own GDataXML. What a piece of dog crap! (You should be using RaptureXML anyway.) Google decided that the best way to serve something so narrow in focus is by combining it with a pile of other libraries you’ll likely never care to use. Look at this list! Blogger, YouTube, Contacts, and Maps? I just want to parse some XML! To top it all off, the whole thing is further complicated by a smattering of deprecations and strange JSON superseding. That’ll teach you for wanting to do something so simple.
Now, assuming you can even get the library to compile (HINT: it won’t), you’ll then be participating in the cat and mouse game of their documentation. Want to parse some XML? Here’s the YouTube API! Wait, no it’s deprecated, you should use the JSON version. What, you don’t want to parse JSON? OK, how about Picasa? What? OK, OK, if you want XML you need to look at this directory. You happy, now?
Google’s problem isn’t that there’s no documentation, it’s that’s it’s all over the place! Every page is dry, monotonous and overloads your sensory organs with links, links, links! Now go back and compare this with Sinatra to appreciate the difference.
By the way, I once tried to use the YouTube stuff for an app and after an hour I just decided to use the REST API instead. Why? The REST API documentation is much more concise, on a single page, and the documentation for our next platform is an absolute pleasure to read.
ASIHTTP: what would you like to do? great! here’s how!
I was conflicted on whether to go with ASIHTTP or AFNetworking for this, but I chose ASIHTTP because it preceded AFNetworking by several years and served as the shining model for documenting a network API. Plus, the docs for AFNetworking weren’t so good early on and only recently have improved greatly.
OK, so ASIHTTP is a high-level networking API designed for Mac and iOS that takes the low-level stuff Apple was feeding us and makes it, *cough*, usable. What makes the ASIHTTP documentation so brilliant is that the designer, Ben Copsey, didn’t write it for network engineers…he wrote it for users.
What do I mean?
Go ahead and look at the setup instructions where screenshots and arrows literally point the way. I’ve never had a problem integrating it into my projects. It just works.
Now, how to use it? Simple. Look at How to use it. Here, Ben lists all the most common use cases. Synchronous, asynchronous, blocks, queues, cancellation, GET, POST, files…it’s all there and the API has some wonderful method naming. The language he uses is for those of us that just want to hit a web service and get some data. Sure, there’s plenty of advanced stuff to read about if you like, but the basics are perfectly laid out. Want to access Amazon S3? Extra modules are easy to access and you get even more tutorials that’ll show you how to use it.
If only everything was presented this well! ASIHTTP succeeded because it knew its audience wasn’t interested in ASIHTTP itself. They just wanted to send a tweet or access temperature data from a server. It shows you how and gets out of your way. Next, we look at a library that implements a simple concept and then so spectacularly over-communicates how to use it that all we can do is laugh!
RegexKitLite: how to use regular expressions in 1,000 pages of brutal detail
I don’t hate regular expressions. In fact, I love them! I began my career as an expert Perl ninja and used regular expressions as often as I took a breath. Unfortunately, Objective-C doesn’t implement regular expressions natively and even though Apple’s added foundation support gradually over time, it’s still a bit of a mess. Luckily, there’s a library that implements the full stack and it’s called RegexKitLite.
Now, regular expressions are not easy per se, especially if you’re a rookie. Whole books have been written to teach how to construct patterns to match just about any esoteric thing. Optional strings? Repeating patterns? If/else conditions? Non-greedy matches? Ranges? Yeah, there’s a lot there. However, what’s easy to explain is how to perform the match.
Well, at least it should be. BEHOLD! THE REGEXLITE DOCUMENTATION!
What in god’s name is that?! It goes on forever! This is a great example of where RegexLite could have learned from ASIHTTP. You don’t need to teach me how to use regular expressions (there’s a link for that), just teach me how to use your library one use case at a time. Give me a section titled “Check if a string matches a pattern” and then list the lines of code to do it. Instead, RegexLite includes whole paragraphs of text that nobody wants to read and code examples that are dozens of lines long! In addition, the tutorial, API reference, and entire history of the library are all crammed into one document. I don’t care why the library is mysteriously titled -Lite, I just want to use it! It’s nearly impossible to find the information you want.
How could this be improved? Separating the documents and writing concise use cases would improve the documentation immensely! Better still, the API itself needs to be fixed. Methods often have 5 or more arguments. Why?! Perl only ever needed two arguments: the pattern and the string! In RegexKitLite, many of the methods let you supply a range of the text to search. What for? It’s a narrow use case! Almost always you’ll want to search your whole string. Let the users extract the substring themselves if that’s what they want to do. Why complicate your API for a tiny minority of use cases that has such an easy remedy?
To this day, I still use this library when I absolutely need it, but for new projects I routinely find myself finding non-regex solutions because I don’t feel like figuring out how to use this library all over again every time.
Tips for writing proper documentation…
If you’ve written a new framework, do yourself a favor and put some thought into the documentation, too. If you do it right, users will not only find your code easy to use, but they’ll also recommend it to their friends. I love to suggest great resources to people and see them get just as excited as me! And which do I love? Here’s what I look for:
- The project homepage should explain the problem it’s trying to solve while supplying examples if necessary.
- There should be a big button titled “Get Started Now!” on it.
- The documentation should include the basics for writing client code. Keep it short.
- The API reference should explain what the methods do and not just give the names of the arguments.
- You should use language that’s accessible and has some personality. Writing dry, technical jargon is a classic mistake. (Read the typical IBM document to understand.)
- Use images, where appropriate, rather than text. If you have iOS and Android versions of your code, use the Apple and Android icons to make the documentation easier to scan and navigate.
Alright, there you go. Get writing!