• Drink lots of water
• Breathe deeply
• Exhale slowly
• Switch to Dvorak, spread the word
• Dissolve all forms of encountered adversity with compassion
• Question the nature of reality, consciousness, thought, the human experience, and recursive simulations
I was thinking recently about how most bugs don’t actually get filed. Not because Radar sucks and all that, but just because people are busy working at the time and intend to file them later, eventually, one day. Or, like in the case of myself, they’re just straight up lazy. But! one does usually have the time to post a quick tweet out of frustration, condemning the broken state of things, at which point a well meaning peer often has the audacity to be like “yo, radar or get the fuck out, harhar”, or even worse someone who actually works inside of Willy Wonka’s Chocolate Factory happens to follow you and subsequently calls you out for being the lame-o that didn’t file the bug on the thing that they work on, causing them not to be able to fix the bug, and in effect ruining everything for everyone. No one should have to be that lame-o.
So I propose a solution. Let someone else file it. Or file it later. Either way, put it on the interwebs in a special place with all of the other yet to be filed bugs, where they can be seen, discussed, even voted on, and with any luck actually filed as a Radar.
The way it work is, to post to LazyRadar just include the hashtag #lazyradar in your tweet. From there, anyone logged in with Twitter can attach a Radar id once it’s been filed, and anyone else can attach a dupe id. The idea is that 1) more bugs will get filed, 2) important bugs will get more dupes through visibility and 3) everyone can tweet freely without getting jumped by their peers.
I didn’t actually do any work on this. I just had the idea and my buddies @elliottkember, @dizzyup, @kachunchau and @reddavis whipped it up. If it works and is useful we’ll add more features, starting with OpenRadar integration. Or I should say, I’ll get them to do it.
S for Service. A new kind of thing that should also be encapsulated.*
A good service layer is easy to use and has entirely out of the box functionality. I usually do this kind of thing the same every time, using a pattern I’ve seen around that works well. For every service that an app needs to connect to I have a utility class that has an API for requesting specific things from the service. All networking code required to talk to a service is encapsulated inside one of these classes and the class just exposes a nice, handy API to get things done.
A good name for one of these things is usually My<#SERVICENAME#>Client or My<#SERVICENAME#>Service, where ‘My’ is your class prefix and ‘SERVICENAME’ is the actual name of the service the app is requesting things from. I lean towards MySomethingClient because it is more correct, since our app and specifically this utility class is technically the client to the service that it’s hitting.
Watch out for including things like ‘REST’ in a class name, because all things network specific are an implementation detail. I would reconsider names like Fetcher and DownloadManager as well. While we know the class is doing these things, I think this behavior terminology is too specific to include in a class name. Plus Fetcher sounds kind of lame, and Manager is a name I think should only be used wisely, if ever. Also, I personally don’t think Controller makes sense here, because it is something else, and at a project level the behavior of a service class called Controller usually isn’t clear.
So here’s how I do it.
The client API will have methods like…
- (void)requestThingamajigsWithCompletionBlock:(void (^)(NSArray *thingamajigs, NSError *error))block;
- (void)requestThingamajigWithName:(NSString *)name
completionBlock:(void (^)(FOOThingamajig *thingamajig, NSError *error))block;
All API methods call an an internal method like…
- (void)requestValueForEndpoint:(NSString *)endPoint
completionBlock:(void (^)(id result, NSError *error))block;
Each API method’s implementation builds an end-point, calls the request method and handles the result, which usually comes in the form of a JSON or property list object. A handy category for unpacking property list objects is arrayOfClass:forKey:. Once this internal method is set up it’s fast and easy to add more API calls. APIs that create or change things usually call an internal method like sendPOSTValues:toEndPoint:completionBlock:. And optional behavior like canceling and queueing can be added as necessary.
That’s about it. Service is a new layer that should be encapsulated, clean and easy to use, like Cocoa.
Here’s a quick and dirty sample I put together. If you have any opinions, feedback or better designs for this kind of thing, hit me up.
* Chris Parker’s great post on coding ruthlessly motivated me to finally post this.