Rapture In Venice, LLC

:: Freelance iOS Development & Team Augmentation

Clients: Getting a Better Project Price…from a Denver iPhone Developer

My experience as a technical consultant has taught me what the best projects to pursue are, how to smell a rat, and how to come up with the highest bid that wins. I don’t know, maybe I bid low, or too high, who knows, but I’ve got a great conversion rate on getting contracts signed so I’d like to think I’m doing a good job with it.

But why just share my insight with other developers? What about the other side of the coin? So, all you potential clients and entrepreneurs out there, here are some tips for getting the best fixed rate on a project from a consultant.

Introduce Yourself and Your Idea Well

I get a fair amount of email from prospective clients, that I’ve never worked with before, who’ve found me on Google. Sometimes they have a contract in mind, and other times it’s a partnership offer from some kid who thinks they can make a million-dollar flashlight app. For every email I get, I have to decide if I will potentially devote a handful of hours to phone calls, requirements gathering and ultimately a formal proposal. Every time I bark up the wrong tree, I lose a half-day or more of work time that will set me back on my current projects — so I have to choose wisely.

My advice if you’re looking for an iOS consultant is, when you write to that developer, take the time to introduce yourself, explain clearly what you’re looking for, and if you are company-backed — say so. This is important. When you tell me you are a manager at a company looking to build a project, you get instant credibility as a good lead. Is that unfair to independent venturists, yeah probably. That’s business, however, and if you have the advantage of a corporate backing then by all means flaunt it.

One of my best clients almost never was because I initially didn’t even respond to his first inquiry. Here’s the first message I ever got from him:

Hi –

I have an idea for an app I’d like to make what are our next steps?

– Some Guy I Never Heard Of

Ask yourself, how much time would you take from your work day to chase this lead down? I didn’t even bother. It took future emails and even then, when I had to cancel a chat due to the flu, I totally forgot about the person afterwards because in my mind it was likely never going to amount to anything. Boy was I wrong. But was it my fault? Hardly.

What he had failed to realize is that I get many messages that look like this from clients who aren’t looking to pay for work. In fact, the email is borderline spam. :-) Now, assuming that a developer does respond to this kind of message, you must remember that it really is true: first impressions matter. Over the course of correspondences, that developer will remember how things started and carry a shred of distrust. Perhaps a shard! So OK, with this particular client, I didn’t fully trust them until we first met some weeks later. Without trust, a developer may up their bid to cover the risk involved with that lack of trust and you may not even realize it.

It matters that much, yet only takes 5 minutes to write a solid opening correspondence. Put in the effort and it will be well worth it.

Know What You Want

This is a biggie. When a customer comes to me with a project in mind the first thing I do, of course, is ask about their idea (generally under NDA). Most customers have an idea, but a handful don’t. In many cases, that client is looking to me for guidance. (I am a consultant after all.)

But is that optimal? I can say that the more unsure the prospective client seems to be about what they want to build, the higher my bid will be. Why? Simple:

  • The more unsure a client is, the more change will be introduced later. The more change, the more net work.
  • It’s easy to envision that I’ll be spending many hours working with the client to nail down their requirements.
  • All of this produces risk that my bid will end up being too low. To be sure I don’t lose money on the deal, the bid must be increased to offset said risk.

I once had a client who I spent about 7 months with exchanging phone calls, emails, IM’s and what have you answering questions about what’s possible on iPad and working with them to formulate their requirements. I took calls on the road, while walking to the train, at work…everywhere. I even wrote a little demo app for them to show their own client. In total, I probably spent 12 hours of my time on all of this before any phase of the project had even begun. Clients like this do themselves a disservice because as a developer it’s easy to see huge warning flags in this behavior.

Contrast this with the clients I come across who have requirements, and even wireframes, in hand. These are the clients that clearly articulate what they want and they just need you to build it. I can confidently estimate the time needed to do it and am able to give a confident fixed price. Most importantly, that price is generally coming out lower than normal because I don’t feel pressured to charge for risk and perceived change. In addition, I don’t want to lose out to another consultant: I *want* this client.

My advice is to be these clients.

Be As Responsive As Possible

Finally, your developer is in butt-in-seat mode and product is being built. You’ve taken all the advice above to heart and have a solid deal signed and now you just have to wait for the work to be delivered. Alas, you’re not done! Fixed-bid contracts (as well as hourly) can crumble right underneath you if you hang the developer out to dry. It’s up to you to prevent that.

Let’s take a fixed-bid contract to start. Let’s say you agree to a $20,000 contract with the developer. With that, the developer has an understanding of the work needed to be done and the timeframe. Now let’s say that the project progresses and your developer is pinging you with questions and clarifications on what the app should do. If you aren’t responsive, the developer is liable to be (A) stuck or worse (B) continuing forward with an incorrect understanding.

You *have* to be responsible. No, responding within a day is not sufficient. Within an *hour* is. This might be inconvenient at times, but the quality of your app will suffer if you push the developer off. And it gets worse…if that developer is constantly having to wait a day or two to hear back from you, they will get irritated because it’s likely increasing their time expectations of the product and, if they are having to do rework, it’s increasing the expected work involved. What does this mean? It means the developer, in order to avoid losing money, will cut corners that will ultimately hurt you down the road.

Even worse, the developer will stop contacting you. That may make you happy, but realize that this means the developer is unsure of what to do but is uninterested in asking you. You’re going to get the wrong thing.

Is it fair? Actually, yes. If you don’t display the care for your app your developer expects, why should they care? A lazy customer suggests to me that they don’t expect the polish I was willing to put the extra effort into. It’s a natural human reaction that if you don’t care, I don’t care. This is best described by the Broken Window Theory and you should take the time to read it as it’s incredibly eye-opening.

So care. You’ll be rewarded. :-)

Conclusion

To get the lowest rate, and the best product possible, you don’t have to be worried about the above if you keep the following axioms in mind:

  • Be credible.
  • Be trustworthy.
  • Be dependable.

That’s it. I can’t speak for all developers but I’m sure I am when I say that we *love* customers like this. Not only will I give my most competitive bid for these customers, I’ll prioritize them above all others because I know I can rely on them and I want their business again in the future. And the bottom line is that if you’re the client, this is what you want your developer to think.

Now that we’ve got this understanding, let’s improve the relationships we have and get to work!

  • Print
  • Facebook
  • Twitter

An Open Letter to Apple: Please Kill Synthesis in iOS 6!

And John Blanco penned an open letter to Apple…

Dear Apple,

The gig is up. I see what you’re doing. You’re trying to fix one of biggest follies of iOS development that the mainstream doesn’t know about but us developers do. You want to kill Objective-C.

It’s obvious. No no, it’s not that you added properties and then blocks. Those are awesome language features. The problem is that you already knew they were awesome language features because all other modern languages have them. No, it’s what you silently did with much less fanfare:

You removed the need to define ivars for synthesized fields.

A lot of iOS developers still don’t realize this. For example, this compiles and works:

@interface Foo
 
@property (assign) fooNumber;
 
@end
 
@implementation
 
@synthesize fooNumber = fooNumber_;
 
...
 
@end

Indeed, we no longer have to declare fooNumber_ as an ivar. And thank you for it. It’s one less place I have to replicate a field name in order to add one. You recognize that to add a field to a class prior to this, you had to declare all of the following:

  • The ivar.
  • The property.
  • The synthesizer.
  • The deallocation.
  • The memory management on the setter (if applicable).

Five places! Six if you count the getter, but I’ll give you a pass. FIVE PLACES. But, then you eliminated one:

  • The ivar.
  • The property.
  • The synthesizer.
  • The deallocation.
  • The memory management on the setter (if applicable).

Now, iOS 5 has come out, along with the ARC system. And lo and behold, you got rid of the deallocation. And this glorious thing happened:

  • The ivar.
  • The property.
  • The synthesizer.
  • The deallocation.
  • The memory management on the setter (if applicable).

Yes, I might still need to write a setter, but if I do I don’t have to manage the memory. And, if I override the setter, it’s no different than any other language. The synthesis will do it for me if I don’t.

But now I have a demand.

Please make @synthesize implicit!

I know you can do it. You did ARC and ARC is inserting code for us even though it’s not there. Why not do the same for properties? How about letting this code fly:

@interface Foo
 
@property (assign) fooNumber;
 
@end
 
@implementation
 
...
 
@end

How glorious! I can define a field in ONE place! Here’s how it’d work:

  1. Every property is automatically synthesized.
  2. The property name is set to fooNumber_. It’s OK to assume, that’s what you’ve told the developers to do.
  3. If I want to override a setter or getter, I can just do it.

I am racking my brain and I can think of no reason why this can’t be done. And you know what? You’re gonna do it. Come iOS 6, this will be how it is. I know it! So please, just do it. You gave us ARC and are already making our brains meld to the new form. So, just end the misery. Let’s make this the new list and rejoice:

  • The ivar.
  • The property.
  • The synthesizer.
  • The deallocation.
  • The memory management on the setter (if applicable).

PS – Sorry about Steve. :-(

  • Print
  • Facebook
  • Twitter

RIV Announces RaptureXML for iOS!

I’m so pleased to announce a new project that’s now on GitHub called RaptureXML. It was born from the sheer aggravation using any of the current XML frameworks has caused me — and I’m sure every other iOS developer out there!

The beauty of RaptureXML is the ability to use query paths, which leverage a concise API, to write code like this:

[rxml iterate:@"players.player" with: ^(RXMLElement *e) {
    NSLog(@"Name %@", [e child:@"name"]);
}];

XML processing is not only ridiculously easy with RaptureXML, it’s actually FUN! When’s the last time you said that about XML?! The JSON iOS libraries are getting a little jealous.

The GitHub project has all the documentation you need to get started with RaptureXML right now! Go for it!

  • Print
  • Facebook
  • Twitter

, , , , , ,

The Ruby Version Manager

If you’re doing Ruby and not using RVM, you simply need to be. There’s not only a big difference between Ruby 1.8.7 and 1.9, but you’ll likely want some different gemsets to use different Rails versions, including the new 3.x series. Here’s the most concise guide possible for setting up RVM. (Mac OS X instructions only)

  1. Uninstall any ruby installs from brew or ports. You can leave the system ruby alone, it feels good to keep it there. :-)
  2. Install RVM: bash < <(curl -sk https://rvm.beginrescueend.com/install/rvm)
  3. You may want to restart Terminal now to make sure your path is right.
  4. Run: rvm list known
  5. Install a Ruby. Here’s how you’d install 1.9.3: rvm install 1.9.3
  6. You can install other Rubies if you want. Pick the one you want to use with: rvm use 1.9.3
  7. Did it work? which ruby

Find out more here.

  • Print
  • Facebook
  • Twitter

InnerBand Tutorial Part 2: Core Data Quick and Easy!

This is the second part of a multi-part series on the InnerBand Framework. Previously, in InnerBand Tutorial Part 1: Introduction and Functions, I reviewed what the InnerBand Framework is and the basic mechanics of its macros.

The various Apple frameworks are hit and miss. Some of them, such as UIKit, are spot on in their design and its consistency makes UI development simple and easy. Core Data, the persistence framework of iOS, is sadly not so gifted. The SDK is clumsy, easy to get wrong, and worst of all requires a lot of boilerplate code to manage your data.

Until InnerBand, anyway. :-)

The CoreDataStore is the featured player in InnerBand when it comes to wrapping the CoreData framework. I conceived of this layer after completing my first Core Data-based project. During a post-mortem review, I was disgusted with all of the low-level, hard-to-understand code that was the result. When I write my persistence code, I expect it to be focused on logic and my app’s data structures, not the silliness I was forced to add. Maybe you feel the same way? NSPersistentStoreCoordinators, NSManagedModels, and NSManagedObjectContexts — OH MY!

Let’s see how the CoreDataStore fixes everything.

Initializing and Clearing Core Data

There is only one requirement to use Core Data, and the CoreDataStore, in your project: include the CoreData framework in your project! That’s it. In fact, I recommend not even clicking the “Use Core Data” checkbox when setting up your project. If you do, you’ll want to delete all the Core Data boilerplate that you’ll find in your App Delegate. You won’t need it.

(And by the way, Apple, you shouldn’t be putting that code there…that was a poor choice on your part. Shame. Shame!)

Ready to see how you initialize the CoreDataStore?


Wait, where’s the code? There is none! Once you start using CoreDataStore, it will automatically create your persistence store it if it hasn’t been already. I told you it was going to be easy. :-)

Now, here’s a bonus. Many frameworks don’t make this available, but if you ever wanted to erase all your data so that you can start fresh again, here’s what you do:

[[IBCoreDataStore mainStore] clearAllData];

This is really handy during unit testing when you want to erase any persisted data between tests.

Inserting Data

CoreDataStore supports two styles of API:

  • ActiveRecord Style – This is the preferred API which lets you operate directly on your Core Data objects in the style of the ActiveRecord pattern. It does require you generate your CoreData objects with their entity names. Since this is already common and a best practice, you’ll most likely be using this style.
  • Factory Style – This style doesn’t require generating Core Data objects and requires the client code to specify entity names as an NSString. It works exactly the same, but is less intuitive and prone to errors since it’s not type-checked.

I’ll show both styles. First, we’ll review ActiveRecord Style. You should generate all your Core Data entities as classes being sure the class names match the entity names. This is usually accomplished via XCode, but I highly recommend the mogenerator utility since it uses a better design pattern for generating the classes as two per entity.

Here’s how you create a new object:

Customer *apple = [Customer create];
apple.name = @"Apple";
 
[[IBCoreDataStore mainStore] save];

Here you can see that we create the Customer object directly by calling -create right on it. We save to something called the mainStore. This is an important concept. The mainStore is considered the default NSManagedObjectContext for all operations. For most apps, it’s all you’ll need. It’s essentially using a single database handle for your entire app. One situation where you might want to create your own context is when you want to handle a set of operations that you can rollback at a given time. If you want to perform the same creation with a custom context, the code would look like:

IBCoreDataStore *customStore = [IBCoreDataStore createStore];
 
Customer *apple = [Customer createInStore:customStore];
apple.name = @"Apple";
 
[customStore save];

All of the CoreDataStore methods support this syntax to let you choose a custom CoreDataStore to perform your operations, but the default always is the mainStore. You’ll likely only need this context.

Now, if you’re not generating your objects, you create data another way:

NSManagedObject *apple = [[IBCoreDataStore mainStore] createNewEntityByName:@"Customer"];
apple.name = @"Apple";
 
// always remember to save!
[[IBCoreDataStore mainStore] save];

As you can see, you need to pass the entity name as a string to create the object. Otherwise, the syntax is similar. Note also that you still have the ability to create your own context rather than use the mainStore.

Deleting Data

Deleting data is the same in either style:

[myObj destroy];

Remember, you’ll need to save, too. I won’t show this code anymore, but review the previous section to see how it’s done.

Querying Data

There are many ways to query using CoreDataStore. Here are a series of examples that should be easy to understand. (If they weren’t, InnerBand wouldn’t be doing its job now would it?)

// all methods
NSArray *allCustomers = [Customer all];
NSArray *allCustomers = [Customer allOrderedBy:@"name" ascending:YES];
NSArray *activeCustomers = [Customer allForPredicate:[NSPredicate predicateWithFormat:@"active = 1"]];
NSArray *activeCustomers = [Customer allForPredicate:[NSPredicate predicateWithFormat:@"active = 1"] orderBy:@"name" ascending:YES];

// all methods -- custom data store
NSArray *allCustomers = [Customer allInStore:myDataStore];
NSArray *allCustomers = [Customer allOrderedBy:@"name" ascending:YES inStore:myDataStore];
NSArray *activeCustomers = [Customer allForPredicate:[NSPredicate predicateWithFormat:@"active = 1"] inStore:myDataStore];
NSArray *activeCustomers = [Customer allForPredicate:[NSPredicate predicateWithFormat:@"active = 1"] orderBy:@"name" ascending:YES inStore:myDataStore];

// first methods
UserSettings *settings = [UserSettings first];
Customer *apple = [Customer firstWithKey:@"name" value:@"Apple"];

// first methods -- custom data store
UserSettings *settings = [UserSettings firstInStore:myDataStore];
Customer *apple = [Customer firstWithKey:@"name" value:@"Apple" inStore:myDataStore];

Use whatever you need. There should be no question about what the methods do. The -all methods return all data that matches the query, if there is any. The -first methods simply return the first match. In most situations, you should expect only one result. So, you should be attempting to match singleton data (such as user settings) or a specific match with a unique name.

Summary

The goal of CoreDataStore is to give you access to Core Data without all the ugly boilerplate you’d normally need. I think it does that well, what do you think? In Part 3, I’ll review the Core Data Store, a handy set of methods that make using Core Data much easier!

In Part 3, I’ll introduce the Message Center, a replacement for the NSNotificationCenter that adds the ability to insert code between posting and receiving messages.

Where Do We Go From Here?

In Part 3: The Magical Message Center I’ll review the Message Center and how it makes real-world application flows super simple!

  • Print
  • Facebook
  • Twitter

, , ,

Previous Posts Next posts