Commit #7: Useful practices for leading an Agile team

2016 has passed, and people had different opinion on it. The internet seemed to think that 2016 is a complete disaster, though. Political turmoils, wars, death of famous figures, and our personal miseries propagated through social medias and memes. This meme depicts the thought pretty well:

I got my share of miseries for 2016, but the old hymn reminded me to count my blessings. I realised that through the whole year, I learned important lessons from my workplace.  One of the most valuable lesson I had was more chances to lead iOS team in projects.

Moving from a single contributor to a team leader wasn’t easy. I need to deliver stories while facilitate my teammates to deliver theirs. Along with other leadership principles that commonly known, I found out that these practices helped me on leading my team, which were establish shared grounds, foster ownership, and schedule technical retrospectives.

Establish shared grounds

Have you ever found a codebase that has different writing style on every file? Or worse, on every line? Something like this:

func aSampleFunction() {
let something = Something()
if something.isFree {
print("hey this is free!")
} else { print("and this is not") }
if (something.isStrange) print("this is strange")
else { print("who am I to decide") }
if something.isBroken
{
print("we need to fix this")
}
else
{
print("this is good as new!")
}
print("these brackets made me crazy!")
}

If you’ve been writing code for a while, you’ll know that this practice is bad. Inconsistent writing style allows us to miss details when reading the code. This make bug-fixing become harder. Even worse, it could cause a bug when somebody adding another code on the top of it. Personally, this kind of code grinds my gears, because I prefer writing and reading clean code.

I’m not making things up, since I have found such code on client’s handed over projects (sigh). The number of inconsistencies usually rises along with the project’s age. You might have found some in forms of snake_cases in a CamelCase-based language, or mixed architectural patterns between MVC, MVVM, or VIPER… or Massive View Controllers for iOS projects ūüėĒ. Along the way, I realized that none of these projects has standards set for them.

In my humble opinion, every new project should have a standard set before the development. If you’re using Git as your source control, you could put the list of standards in a README.md file. Git-based hosting sites (e.g. GitHub, BitBucket) normally show the README content on the project’s home page, allowing visitors (and new contributors) to read the standards before jumping to the code. Here’s a list of standards that I have set in projects I have led:

  • Architectural pattern. Should we use MVC, MVVM, or VIPER? If there’s a modification to the pattern, kindly specify it in the README file. For example, our iOS team usually uses MVVM along with Krzysztof Zablocki’s FlowControllers.
  • Project structure. How should we structure the folders? Which folder should we choose to store a certain type of class? Our iOS team usually laid out the folders based on business domain first, then type as subdomain (e.g. Views, ViewControllers).
  • Style guide. Referring to the sample code above, each person has different coding style. If not specified, a project could end up with inconsistent writing style or wasted time on useless debates. I recommend every project to have a writing style guide to keep consistency and increase readability for maintainers. If you’re using Swift, you could use GitHub’s Swift style guide. Ray Wenderlich’s style guide is a good choice, too.
  • Contributing guide. What’s the branching strategy for this project? How should contributors add new features or bug fixes to the codebase? If any, how much code coverage should be achieved? Who should review each pull requests?
  • Dependency manager.  What are the preferred dependency manager to use for the project? How to install the dependencies? What are the rules when someone want to add a new one?

This practice seems pedantic and unnecessary, but it has helped our team to onboard new contributors with minimum supervision. It also helped us to have a “single source of truth”, which frequently referenced when we’re reminding each other. I have found that every minute shed in making this standard has paid off multiple times.

Continue reading “Commit #7: Useful practices for leading an Agile team”

Commit #6: Unwrapping Swift optionals

Update 12 Oct ’16:¬†I’ve updated the code in this post and the Xcode Playground blog post version¬†to Swift 3! Thank you for the wait¬†ūüėĀ

As an iOS developer, handling empty value cases in Objective-C is never easy. Let’s suppose we’re making a function that return NSString¬†instance out of a NSDictionary:

/// Will return @p NSString representation of user's token from passed @p payload, or @p nil if there's no user token in it.
– (NSString *)userTokenFromJSON:(NSDictionary *)json
{
return json["user_token"];
}

view raw
SampleStringMethod.m
hosted with ❤ by GitHub

Everything seems fine, isn’t it? The¬†method’s logic is pretty clear – it returns the value in user_token¬†key of the JSON. If the key exists, it will return the string. If not, it will return a nil value… dead simple, right?

No.

I left out a sanity check there, but ¬†let’s continue our example for now.

Suppose that the returned string will be encrypted and stored by C++ library. And for that, we need to cast our NSString to C string:

– (void)storeUserToken:(NSString *)userToken
{
if (nil == userToken) {
return;
}
const char * rawString = [userToken UTF8String];
// Further code that uses rawString here…
}

Where’s the problem, Do? Everything looks fine…

Right. The method above looks good – it stopped the process early if passed userToken¬†is nil. Both of them will work correctly, until¬†somebody from the server side single-handedly pass null value in response¬†JSON’s user_token key, instead of omitting it.

Let’s run through the code once again. If the passed JSON is made from NSJSONSerialization process, the user_token key will store a¬†NSNull¬† instance. Thus, the result from userTokenFromJSON:¬†will be a NSNull instead of a nil or NSString – which will allow it to pass through storeUserToken:‘s early sanity check code (since it’s not a nil), and¬†break the whole app, since NSNull doesn’t have UTF8String method.

Let’s hope this case will never happen in production servers. And yes – I’m looking at you, cowboys.

Due to this issue, nil-checking alone in Objective-C isn’t sufficient. We also need to ensure¬†whether an instance is the right class using isKindOfClass:¬†method. It doesn’t always work well either – for example, if the server on the example above returns a number for user_token¬†value,¬†there’s a chance that it’ll read as _NSCFString¬†(Apple’s private API)¬†instead of a NSNumber.

That’s why after a few month working with Swift, ¬†I grew appreciating the Swift Team’s decision to include¬†Optionals. I believe they made¬†this as an answer to Objective-C’s tedious¬†sanity check. The documentation clearly says that:

You use optionals in situations where a value may be absent. An optional says:

  • There¬†is¬†a value, and it equals¬†x

or

  • There¬†isn‚Äôt¬†a value at all.

If I declare a variable to be a String?¬†(read: String Optional), it would either be a String value¬†or a nil. Not a NSNull,¬†not other class type, and not another Apple’s private API. So, userTokenFromJSON:¬†above could be rewritten in Swift into this:

/// Returns `String` optional representation of user's token from passed `json`.
func getUserToken(json: [String: AnyObject]) -> String? {
return json["user_token"] as? String
}

And yes, this method will an Optional – either ¬†String¬†or a nil.¬†ūüôā But the process isn’t ended here – we need to take the available String¬†value out of the Optional. The term is usually called as¬†unwrapping in Swift development –¬†and there are several ways to do it!

Wait, it seems I¬†had¬†enough rant above… this post started to feel edgy. Let’s change the mood, shall we?

In this post, I’ll list the ways for unwrapping Swift’s Optionals that I have found so far. For the sake of the post,¬†let’s assume we got a new function that needs a String input and an Optional variable:

func createGreetings(sailorName: String) -> String {
return "ūüĎģ Ahoy, \(sailorName)! Welcome to S.S. Salty Sailor, arrr!"
}
var name: String?

view raw
SailorGreeting.swift
hosted with ❤ by GitHub

Now, we need to unwrap the name (since it’s a String optional) to pass it to the createGreetings(sailorName:). There are several ways to do this:

Continue reading “Commit #6: Unwrapping Swift optionals”

Commit #2 : Export your *.xcarchive to *.ipa via terminal!

December last year, several Ice House clients asked for Christmas update on their app.¬†There’s a strange case that occurred when our team tried to send old projects to the iTunesConnect using Xcode 6’s Organizer, just like this image :

Screen Shot 2015-01-09 at 17.12.22

Our supervisor, Didiet, said this issue might be caused¬†by¬†the project file. The project was built on¬†Xcode 5.1 and we’re¬†trying ¬†to publish it from Xcode 6. Since we don’t have much time left, we ended up using xcodebuild‘s exportArchive¬†command from terminal to export the *.xcarchive from Organizer to *.ipa :

Continue reading “Commit #2 : Export your *.xcarchive to *.ipa via terminal!”