Sunday, June 22, 2014

QA and Devs Working Together

In our latest experience report, Tearing Down the Walls, Stephanie Savoia asks us to,
“Imagine a wall. Now imagine a developer creating code and throwing it over…[where] it lands on the heads of the Quality Assurance (QA) or Test team. This is where the code is tested in various ways. If the development team does unit testing, then many of the tests QA are creating/executing are duplicative. If there are no unit tests, QA are left to test as much of the affected code as they can.”
Now imagine a more efficient world where QA and Devs work together much more closely. That’s where Stephanie is today. This report recounts her journey from being a member of a separate QA group, to being a valued member of a unified XP team that includes both Developers and QA. Pairing on her team is not only Dev/Dev but also QA/Dev. It happens daily. And the whole team takes responsibility for code quality.
Stephanie Savoia has been working in quality assurance for 12 years. Currently, she is a Technical Lead in QA at Marchex, Inc. Prior to that she worked at LexisNexis. Before that, she created the quality control process for deliverables at Applied Discovery, a legal software company, and verified the data that would be sent to opposing counsel and government entities such as the Securities & Exchange Commission and the Department of Justice.
The Agile Manifesto says,
“We are uncovering better ways of developing
software by doing it and helping others do it.”

Monday, June 16, 2014

How much does it cost to make an app?

“How much does it cost to make an app?” As a developer, this is the most common question I am asked. This is like asking “How much does it cost to build a house?” Following the house analogy, are you looking for a mansion or a shack? Do you want a house made of straw, sticks, or brick? Do you want a custom home or a tract home? Just like a house, the variables in developing an app are endless.
Develop a Storyboard
The first place to start is defining what you want your app to do. I normally recommend our clients storyboard their app (the technical term is wireframe). The wireframe is like the blue print in the house analogy. The goal for developing a wireframe (or storyboard) is to capture functionality and flow. This is not the time to worry about the actual aesthetics yet. It’s important to start from the beginning though, when a user first launches your app. Think about what’s the first thing they will see? On the home screen, if they tap the first menu selection, what happens next? And so on.
To create our wireframes, our designers use a design tool called Balsamiq. I send our clients a PowerPoint template where they can either use PowerPoint’s drawing tools or they can even print it out and hand draw it.
Other Factors
Beyond the storyboard, other factors that will impact the development and cost are:
  • Integration to an existing backend / Development of backend: Most of the apps we develop now either need to talk to an existing backend or we have to create a backend to support the app.
  • Integration to third party vendors: A lot of features that typically used to be expensive to develop can now affordably be added by leveraging third party vendors. Examples are push notifications and mobile commerce.
In addition to the wireframe, if you’re app requires extensive integrations to third party vendors, you may need to put together an architectural diagram.
Getting a Quote
For the most part, a developer should be able to provide you a quote to develop your app based on your wireframe (and architectural diagram). You can find reputable U.S. based developers at iphoneappquotes.com and theymakeapps.com.
You can also find freelancers and offshore teams at elance.comguru.comodesk.com; Just beware. I’ve talked to clients that have used developers from these sites and it’s a mixed bag. I’ve talked to a few people that have had good experiences and I’ve heard of some horror stories.
If you feel like your app concept is the next Uber, it’s okay to ask the developer for an NDA (Non-Disclosure Agreement) or to ask them to sign your NDA. When you go through this process, you’ll find a vast range for the quotes. My recommendation is to look at other when selecting a developer.
(Shameless plug – we also would, of course, be happy to provide a quote for your project. Just visit us at Apptology.com)
Alternatives
App development, like most technology has become commoditized to some extent. If you have little budget for app development, you may consider DIY (Do It Yourself) App services like ibuildapp.com or seattlecloud.com. There is also a middle ground where a developer can create a robust but cost effective solution based on templates. Apptology offers a cost effective app development solution using templates (called ReadyBuilt). Mobile Roadie is another developer that uses template. Apps based on templates are primarily used to promote a business or to provide content and are typically a fraction of the cost of developing apps from scratch.
Final Thoughts
My answer to the question, “How much does it cost to develop an app?” is “It depends.” If you are thinking about developing an app, I highly recommend taking a little time to create a storyboard or wireframe. This step will help you flush out your concept and greatly assist a developer in providing a solid quote for your app.

Wednesday, June 11, 2014

i​OS 8

Ask anyone, and they'll tell you: WWDC 2014 was one of the most exciting in recent memory. It was, first and foremost, a developer event, with nary a hardware announcement to upstage the latest software & developer tools.
And boy howdy, was there a lot to be excited about.
The announcements from iOS 8 & OS X Yosemite alone would have made 2014 a bellwether year for the Apple platform, with Extensions, Continuity, SpriteKit enhancements, SceneKit for iOS, Metal, Game HealthKit, HomeKit, Local Authentication, and a brand new Photos framework. Not to mention the dramatic improvements to Xcode & Interface Builder, a revamped iTunes Connect, TestFlight, Crash Reports, and CloudKit. And oh yeah—Swift.
The kicker? Apple has graciously relaxed its NDA for new technologies, meaning that we don't have to wait to talk about all of the shiny new toys we have to play with.
This week, we'll take a look beneath the headline features, and share some of the more obscure APIs that everyone should know about.
From here on out, NSHipster will primarily write code samples in Swift, with the occasional Objective-C throwback where appropriate. By the end of the summer, we hope to have all of the existing code samples ported to Swift, with the option to toggle between languages.

NSProcessInfo -isOperatingSystemAtLeastVersion

Forget [[UIDevice currentDevice] systemVersion] and NSFoundationVersionNumber, there's a new way to determine the current operating system in code: NSProcessInfo -isOperatingSystemAtLeastVersion
import Foundation

let yosemite = NSOperatingSystemVersion(majorVersion: 10, minorVersion: 10, patchVersion: 0)
NSProcessInfo().isOperatingSystemAtLeastVersion(yosemite) // false
Keep in mind, however, that a test for capability, such as with SomeClass.class orrespondsToSelector:, is preferable to checking the OS version. Compiler macros in C or Swift can be used to conditionally compile source based on the build configuration of the target.

New NSFormatter Subclasses

One of the features most sorely lacking in Foundation was the ability to work with units for quantities like mass or length. In iOS 8 and OS X Yosemite, three new classes were introduced that fills the gap: NSEnergyFormatterNSMassFormatter, & NSLengthFormatter.
This effectively doubles the number of NSFormatter subclasses in Foundation, which was previously limited to NSNumberFormatterNSDateFormatter, &NSByteCountFormatter.
Although these new formatter classes are part of Foundation, they were added primarily for use in HealthKit.

NSEnergyFormatter

NSEnergyFormatter formats energy in Joules, the raw unit of work for exercises, and Calories, which is used when working with nutrition information.
let energyFormatter = NSEnergyFormatter()
energyFormatter.forFoodEnergyUse = true

let joules = 10_000.0
println(energyFormatter.stringFromJoules(joules)) // "2.39 Cal"

NSMassFormatter

Although the fundamental unit of physical existence, mass is pretty much relegated to tracking the weight of users in HealthKit. Yes, mass and weight are different, but this is programming, not science class, so stop being pedantic.
let massFormatter = NSMassFormatter()
let kilograms = 60.0
println(massFormatter.stringFromKilograms(kilograms)) // "132 lb"

NSLengthFormatter

Rounding out the new NSFormatter subclasses is NSLengthFormatter. Think of it as a more useful version of MKDistanceFormatter, with more unit options and formatting options.
let lengthFormatter = NSLengthFormatter()
let meters = 5_000.0
println(lengthFormatter.stringFromMeters(meters)) // "3.107 mi"

CMPedometer

Continuing on iOS 8's health kick, CMStepCounter is revamped in the latest release. CMPedometer is a strict improvement over its predecessor, with the ability to query from discrete points in time, track both steps and distance, and even calculate how many flights of stairs were climbed.
It's amazing what that M7 chip is capable of.
import CoreMotion

let lengthFormatter = NSLengthFormatter()
let pedometer = CMPedometer()
pedometer.startPedometerUpdatesFromDate(NSDate(), withHandler: { data, error in
    if !error {
        println("Steps Taken: \(data.numberOfSteps)")

        let distance = data.distance.doubleValue
        println("Distance: \(lengthFormatter.stringFromMeters(distance))")

        let time = data.endDate.timeIntervalSinceDate(data.startDate)
        let speed = distance / time
        println("Speed: \(lengthFormatter.stringFromMeters(speed)) / s")
    }
})

CMAltimeter

On supported devices, a CMPedometer's stats on floorsAscended / floorsDescended can be augmented with CMAltimeter to get a more granular look at vertical distance traveled:
import CoreMotion

let altimeter = CMAltimeter()
if CMAltimeter.isRelativeAltitudeAvailable() {
    altimeter.startRelativeAltitudeUpdatesToQueue(NSOperationQueue.mainQueue(), withHandler: { data, error in
        if !error {
            println("Relative Altitude: \(data.relativeAltitude)")
        }
    })
}

CLFloor

CLFloor is a new API in iOS 8 that ties the new features in CoreMotion with Apple's ambitious plan to map the interiors of the largest buildings in the world. Look for this information to play a significant role in future hyperlocal mapping applications.
import CoreLocation

class LocationManagerDelegate: NSObject, CLLocationManagerDelegate {
    func locationManager(manager: CLLocationManager!, didUpdateLocations locations: AnyObject[]!) {
        let location: CLLocation? = locations[0] as? CLLocation
        if let floor: CLFloor? = location?.floor {
            println("Current Floor: \(floor?.level)")
        }
    }
}

let manager = CLLocationManager()
manager.delegate = LocationManagerDelegate()
manager.startUpdatingLocation()

HKStatistics

As a framework, HealthKit covers a lot of ground, with dozens of new classes and constants. A good place to start, in terms of understanding what's possible is HKStatistics.
HealthKit manages your biometrics from all of your devices in a single unified API. Statistics on things like heart rate, caloric intake, and aerobic output can be tracked and aggregated in powerful ways.
The following example shows how statistics summed over the duration of the day can be grouped and interpreted individually:
import HealthKit

let collection: HKStatisticsCollection? = ...
let statistics: HKStatistics? = collection!.statisticsForDate(NSDate())
for item: AnyObject in statistics!.sources {
    if let source = item as? HKSource {
        if let quantity: HKQuantity = statistics!.sumQuantityForSource(source) {
            if quantity.isCompatibleWithUnit(HKUnit.gramUnitWithMetricPrefix(.Kilo)) {
                let massFormatter = NSMassFormatter()
                let kilograms = quantity.doubleValueForUnit(HKUnit.gramUnitWithMetricPrefix(.Kilo))
                println(massFormatter.stringFromKilograms(kilograms))
            }

            if quantity.isCompatibleWithUnit(HKUnit.meterUnit()) {
                let lengthFormatter = NSLengthFormatter()
                let meters = quantity.doubleValueForUnit(HKUnit.meterUnit())
                println(lengthFormatter.stringFromMeters(meters))
            }

            if quantity.isCompatibleWithUnit(HKUnit.jouleUnit()) {
                let energyFormatter = NSEnergyFormatter()
                let joules = quantity.doubleValueForUnit(HKUnit.jouleUnit())
                println(energyFormatter.stringFromJoules(joules))
            }
        }
    }
}
NSHipster will be covering a lot more about HealthKit in future editions, so stay tuned!

NSStream +getStreamsToHostWithName

In many ways, WWDC 2014 was the year that Apple fixed their shit. Small things, like adding the missing NSStream initializer for creating a bound stream pair (without resorting to awkwardly-bridged CFStreamCreatePairWithSocketToHost call). Behold: +[NSStream getStreamsToHostWithName:port:inputStream:outputStream:]
var inputStream: NSInputStream?
var outputStream: NSOutputStream?

NSStream.getStreamsToHostWithName("nshipster.com",
                            port: 5432,
                     inputStream: &inputStream,
                    outputStream: &outputStream)

NSString -localizedCaseInsensitiveContainsString

Also filed under: "small but solid fixes", is this convenience method for NSString:
let string: NSString = "Café"
let substring: NSString = "É"

string.localizedCaseInsensitiveContainsString(substring) // true

CTRubyAnnotationRef

If you're a linguistics and typography nerd, this new addition to the CoreText framework may have you standing up on your chair and cheering. "What's with Jim? Is it me, or has he been acting kind of weird since his trip to San Francisco?", they'll say, looking at you atop your desk as you tear your clothes off your body in a frenzy of pure ecstasy. "Yeah, remind me not to stay in the Tenderloin for next year's conference."
...oh right. Ruby. No, not RubyRuby. It's used to display the pronunciation of characters in certain Asian scripts.
@import CoreText;

NSString *kanji = @"猫";
NSString *hiragana = @"ねこ";

CFStringRef furigana[kCTRubyPositionCount] =
    {(__bridge CFStringRef)hiragana, NULL, NULL, NULL};

CTRubyAnnotationRef ruby =
    CTRubyAnnotationCreate(kCTRubyAlignmentAuto, kCTRubyOverhangAuto, 0.5, furigana);
Admittedly, the documentation isn't entirely clear on how exactly to incorporate this into the rest of your CoreText drawing calls, but the result would look something like this:
ねこ

New Calendar Identifiers

What's even nerdier than Ruby annotations? The new calendar identifiers added to iOS 8 & OS X Yosemite. This update brings Foundation up to the latest version of the CLDR:
(Sadly, the French Republican Calendar is still but a twinkle in the eyes of NSHipsters everywhere)
  • NSCalendarIdentifierCoptic: a.k.a Alexandrian calendar, is used by the Coptic Orthodox Church.
  • NSCalendarIdentifierEthiopicAmeteMihret: Ethiopic calendar, Amete Mihret (epoch approx. 8 C.E.)
  • NSCalendarIdentifierEthiopicAmeteAlem: Ethiopic calendar, Amete Alem (epoch approx. 5493 B.C.E.)
  • NSCalendarIdentifierIslamicTabular: A simple tabular Islamic calendar using the astronomical/Thursday epoch of CE 622 July 15.
  • NSCalendarIdentifierIslamicUmmAlQura: The Islamic Umm al-Qura calendar used in Saudi Arabia. This is based on astronomical calculation, instead of tabular behavior.

NSURLCredentialStorage

The Foundation URL Loading System has remained relatively unchanged since last year'sNSURLSession blowout. However, NSURLCredentialStorage has been given some TLC, with new functions that get and set credentials for tasks in asynchronous, non-blocking fashion.
import Foundation

let session = NSURLSession()
let task = session.dataTaskWithURL(NSURL(string: "http://nshipster.com"), completionHandler: { data, response, error in
    // ...
})

let protectionSpace = NSURLProtectionSpace()
NSURLCredentialStorage.getCredentialsForProtectionSpace(protectionSpace: protectionSpace, task: task, completionHandler: { credentials in
    // ...
})

kUTTypeToDoItem

Looking through the latest API diffs, one might notice the large number of new UTIs constants. One that caught my eye was kUTTypeToDoItem:
import MobileCoreServices

kUTTypeToDoItem // "public.to-do-item"
As a public type, iOS & OS X now provide a unified way to share tasks between applications. If you happen to work on a task management tool (and, let's be honest, the chances are extremely good, considering how damn many of them there are in the App Store), proper integration with this system type should be put at the top of your list.

kCGImageMetadataShouldExcludeGPS

Most users are completely unaware that most pictures taken with phones these days include GPS metadata. Countless individuals have had their privacy breached because of this small detail.
New to the Image I/O framework is a convenient new option for CGImageDestination:kCGImageMetadataShouldExcludeGPS, which does what you'd expect.
@import UIKit;
@import ImageIO;
@import MobileCoreServices;

UIImage *image = ...;
NSURL *fileURL = [NSURL fileURLWithPath:@"/path/to/output.jpg"];
NSString *UTI = kUTTypeJPEG;
NSDictionary *options = @{
                          (__bridge id)kCGImageDestinationLossyCompressionQuality: @(0.75),
                          (__bridge id)kCGImageMetadataShouldExcludeGPS: @(YES),
                          };

CGImageDestinationRef imageDestinationRef =
CGImageDestinationCreateWithURL((__bridge CFURLRef)fileURL,
                                (__bridge CFStringRef)UTI,
                                1,
                                NULL);

CGImageDestinationAddImage(imageDestinationRef, [image CGImage], (__bridge CFDictionaryRef)options);
CGImageDestinationFinalize(imageDestinationRef);
CFRelease(imageDestinationRef);

WTF_PLATFORM_IOS

#define WTF_PLATFORM_IOS has been removed from JavaScriptCore. It will be missed.

WKWebView

UIWebView is dead. Long live WKWebView.
WKWebView offers Safari-level performance to your own app, and further improves on UIWebView with preferences and configurations:
import WebKit

let preferences = WKPreferences()
preferences.javaScriptCanOpenWindowsAutomatically = false

let configuration = WKWebViewConfiguration()
configuration.preferences = preferences

let webView = WKWebView(frame: self.view.bounds, configuration: configuration)
let request = NSURLRequest(URL: NSURL(string: "http://nshipster.com"))
webView.loadRequest(request)

NSQualityOfService

Threads have been systematically de-emphasized from the conceptual foundation of Apple frameworks. This has been a good thing for developers.
Following this trend is a change to NSOperation in the latest APIs. A new qualityOfService property replaces the threadPriority. These new semantics allow an app to defer non-critical work to ensure a consistently great user experience.
The NSQualityOfService enum defines the following values:
  • UserInteractive: UserInteractive QoS is used when performing work that is related to graphically intensive work such as scrolling or animating.
  • UserInitiated: UserInitiated QoS is used for performing work that has been explicitly requested by the user, but does not require millisecond accuracy like animations. For example, if a user requests an email app to check for mail right now.
  • Utility: Utility QoS is used for performing work that has been requested by the user to happen automatically. For example, an email app may be configured to automatically check for mail every 5 minutes. It is not a problem if the email check is deferred by a few minutes if the system is extremely limited in resources.
  • Background: Background QoS is used for performing work that the user may not even be aware is happening on their behalf. For example, an email app may use this to perform indexing for a search.
Quality of Service is used throughout Foundation in iOS 8 & OS X Yosemite, so be on the lookout for opportunities to capitalize on this new feature.

LocalAuthentication

Finally, one of the most anticipated features of iOS 8: LocalAuthentication. Ever since TouchID was introduced with the iPhone 5s, developers have been salivating at the prospect of using that in their own app.
Imagine: with CloudKit and LocalAuthentication, nearly all of the friction to creating a user account is gone. Just scan your fingerprint, and you're in.
LocalAuthentication works in terms of an LAContext class, which evaluates a specified policy, and gives a thumbs up or thumbs down on user authentication. At no point is any biometric information made available to the application—everything is kept safe on the hardware itself.
LAContext *context = [[LAContext alloc] init];
NSError *error = nil;

if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
                         error:&error])
{
    [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
            localizedReason:NSLocalizedString(@"...", nil)
                      reply:^(BOOL success, NSError *error) {
        if (success) {
            // ...
        } else {
            NSLog(@"%@", error);
        }
    }];
} else {
    NSLog(@"%@", error);
}

Although it seems like all that anyone can talk about these days is Swift, it'd be a shame if we ignored all of the neat things iOS 8 & OS X Yosemite allow us to actually do with this new language.
If you're feeling adventurous, dive into the iOS 7.1 to 8.0 API diffs to really appreciate the magnitude of new technologies to discover. Granted, of the 4000+ new APIs, at least half of those are slight changes to Accelerate functions, or methods becoming properties, but still... Have at it!