Monday, December 5, 2011

Setting Up a Folder Action

The Automator application on OS X gives a good drag-and-drop way to have the computer take over some repetitive tasks for us. Things that Automator can be good for are:

  •  combine a bunch of PDFs into a single PDF
  • rename a whole bunch of files
  • run a script (bash/ruby/php)
  • manipulate some images (resize or watermark)

If you think you will actively be working with files (dragging them around) then set up an Application automation. If some other task might be creating the files you are starting with then you might want to set up a folder action. In other systems the folder action is called a "hot folder". This quick tutorial is going to set up a folder action to take any file or set of files I dump into the folder and then add a timestamp to the filename and move the item to a folder on my hard drive called "Finished".

First we will open Automator and select a New workflow from the File menu. We are going to make a workflow of type "Folder Action" so we select the proper icon and click the "Choose" button.

By choosing a folder action, we are asking Automator to watch the folder at all times, and whenever we add any file, group of files or folders to the folder, we want the workflow to begin.

The first thing Automator will want is an answer to "Folder Action Receives files and folders added to". We need to choose what folder is going to have this action attached to it. For the purposes of this demo, we are going to create a new folder called "StampTasks" and place it on the desktop.

The next step is to add the timestamp to each file that gets dropped into the folder. In the Automator, there is a library. The library has two types of actions: those supplied by the system and those supplied by third party applications. Pixelmator gets a shout out here for some of the really useful automator actions they have supplied.

For this tutorial, we are just going to use the action in "Files and Folders" called "Rename Finder Items". We do this by just dragging the Action from the list of actions to the main workflow window. When we first drag the action, we will get a dialogue box asking us if we want to work on the original files or if we want to make duplicates of the files and work on those.
For my purposes, I don't mind working on the originals, so I click Don't Add for this tutorial. Now we are presented with the second step in our workflow. For renaming purposes, Automator provides us with a few different choices for how we want to rename our files. 

Today we are just going to "Add Date or Time" and using the drop down menus I am going to insert the current date after the name of my files.

Now we need another action to move these files out of the folder and place them into their final resting place. So I use the "Move Finder Items" and then navigate to the folder I want to place the items into. "Move Finder Items" can be a little confusing, but basically it is saying "take the file that you did an operation on in the previous step and move it".

Finally, just to show off we can add a "Show Growl Notification" (this action is under Utilities if you have Growl installed). Here is what the final workflow looks like.

At this point you may be excited to run your new folder action but you will see that the "Run" button gives you an error. This is because the workflow starts when you drop a file into the folder, so we need to save the workflow first (NB: with Lion, I have gotten lazy about saving things, but if you don't explicitly save, Lion will happily not save a workflow and it doesn't give you the "Save As..." or other indication that it didn't save). It just won't run your workflow and you will say bad words.

If you have created the workflow and saved it, you should now be able to drop a file into the "StampTasks" folder and wait a few seconds and see it appear in the "Finished" folder with a Growl message. Here is a link to a zip copy of the workflow I created for this tutorial. In general, Automator will place files in the ~/Library/Workflows/Applications directory. (NB: In Lion I notice that the Library folder for the user is not invisible, so you may need to use "Go to Folder" from the "Go" menu in Finder to get at it.

The biggest issue with using the Automator is that debug info and errors are hard to work with. For instance, using the working tutorial above, delete the "Finished" folder. Then when you run the workflow you will get no error, but it won't run either.

Working with Scripts:
Any bash or ruby script can be run in automator using the Run Shell Script command. By default you can run shell scripts in your favorite flavor of sh as well as perl, python or ruby. The shell scripts should be expecting to get the files or text they are to work with just as if they were set up to get things from the command line. The shell script will be run once for each file in the folder.

Tuesday, November 8, 2011

Devices for Testing iOS Software

For the next few months at least it's going to be a pain to test in iOS. Recently I had to test an app on 4 different devices and it behaved differently on all four. So, here is the set-up I used to try to get the best coverage.

Old Devices
The oldest devices I'm willing to support (or that my clients ask to support) are running iOS 3.1.3. These are second generation iPod touches as well as iPhone 3G devices. Thankfully, these are the last devices are the last ones that don't do OS signing with Apple, so it is pretty trivial to upgrade them to 4.2.1 (the highest OS they support) and then back to 3.1.3 (a common OS because it runs faster). For maximum coverage, I have one device at one OS version and one at the other. Switching OS versions is easy but time consuming. I have an iPod Touch and an iPhone 3G for this testing. I decide which one to set at which version depending on if I need the camera for my app or not. These devices require armv6 code.

Less Old Devices
Apple is currently selling iOS 5 installed on iPhone 3GS, iPhone 4 and iPhone 4S. All of these devices are armv7 So, I'm treating this hardware as interchangeable for now. I have an iPhone 4 running 4.3.5 and I have an iPhone 3GS and and iPhone 4 both running iOS 5. Apple has made it really hard to upgrade/downgrade without jailbreaking, so I have to have big stickers on my 4.3.5 device to make sure I never upgrade it by accident.

I have an iPad (1) and and iPad2 that are both running iOS 5. Because the iPad is a newish device, I have assumed that everyone has upgraded or is upgrading soon away from iOS 3.2. I test with 4.3 in the simulator and test on the devices in 5.

What else?
In my experience, the biggest change as far as the OS breaking things happened between iOS 4.2 and 4.3 which corresponds to the 3G devices and the 3GS and above. Apple made lots of changes to the video, and graphics libraries during that time. Because the 3G and the older iPod Touches only go up to 4.2.1 (and even then don't support multi-tasking) we need to keep testing with those devices for a while. If an application doesn't require the new features in the newer OS'es then it seems like a poor decision to cut out the older devices, those people still have iTunes accounts and can still give us money.

My Wish List
Google has a really nice chart of what OS versions in what volume are hitting its App Store each week. This can help a developer make good guesses about what OS should be the minimum. Apple should be able to provide this data. I wish they would. It's one thing for me to gather data about my current customers (which I can do using Flurry or similar analytics) but that information is only about my small part of the customer base, not about the entire population.

Tuesday, October 25, 2011

iOS 5 Support for dismissModalViewControllerAnimated

Fixed an odd bug today and submitted v1.3 of Caroline's Cat Game to the store. Turns out that calling dismissModalViewControllerAnimated: for the [self parentViewController] basically stopped doing anything. When Apple makes changes that cause crashes that is bad, but at least we get some kind of alert. This just makes a button stop doing anything. No crash, no error, no nothing.

Anyway, if you are here because your calls to parentViewController have stopped working, here is the code we are now using. It appears that we need to use "presentingViewController" as well as a new call to dismissViewcontrollerAnimated. This all seems to be related to storyboards in iOS 5. Here is a link to the updated UIViewController documentation that talks about parentViewController and presentingViewController and the new dismissViewControllerAnimated. Right here below, is how we have set up our button to respond to being clicked. In the old days (last month) the method just had the   [[self parentViewControllerdismissModalViewControllerAnimated:YES] line but we have to add a little more now.

    if ([[self parentViewController] respondsToSelector:@selector(dismissModalViewControllerAnimated:)]){
        [[self parentViewController] dismissModalViewControllerAnimated:YES];
    } else {
        [[self presentingViewController] dismissViewControllerAnimated:YES completion:nil];

We have wrapped the whole call into an if statement so that we can still use the old way when on an older phone. The respondsToSelector: test is a good way to deal with using old and new code together. Trying to test for a specific version of iOS by name is pretty brittle; always use the respondsTo method instead.

Friday, October 21, 2011

Setting Up Xcode to Support Old iPhones

The iPhones from v1 to v3G all use the armv6 architecture
The iPhone 3GS and above all use the armv7 architecture (this is why it is not a really big deal that Apple has decided to continue to sell the iPhone 3GS)

The phones that run the armv6 are mostly on iOS 3.1.3. It is possible to pus 4.2.1 on an iPhone 3 but it runs so….very…..slowly….that most people have downgraded back to 3.1.3 or else bought a new phone. The 3GS runs iOS 4.x and 5.x pretty well so there is no reason for people with a 3GS or above not to be on 4x or 5x. The 3GS had some issues with iOS 4.0 but those speed issues have been addressed and any 3GS you purchase today will have IOS 5 on it.

As is their general theme, Apple hates supporting old things so the defaults in Xcode 4 (and 4.2 which is the current version) assume that everyone is running iOS5 and that they have a 3GS or better device. That is a reason the simulator only has options for 4.3 and 5.0 software. If you read this article from Apple Insider you will get a nice graphic showing how hard Apple is pushing iOS 5 and on what devices it runs.

To make your Xcode compile code for an old iPhone you have to do two things:
In Build Settings for your target, change the "Compiler for C/C++/Objective-C to LLVM GCC 4.2 (this is not the default)
In Build Settings for your target, change the "Architectures" from "Standard (arm7)" to "armv6 armv7"

You should also check these two settings since Xcode is going to want to have the Deployment Target be the latest version of the OS by default.
In Build Settings for your target, make sure that "iOS Deployment Target" is set to "iOS 3.0" or whatever the minimum you will support is
In Build Settings for your target, make sure that "Base SDK" is set to "Latest iOS (iOS 5.0)"

Now, you should be able to install and compile things on the old phones. The above settings are for ALL projects you create where you want to support older devices.

Update: Others are having this problem and posting similar fixes. I think I like this fix for the armv6 issue over at Retro Dreamer better.

Thursday, August 25, 2011

Supporting TextExpander in My Application


With version 2.0, the Massage Therapist Notebook now supports TextExpander snippets. A great deal of information about a session can be recorded just by dragging stones onto various parts of the body images. However, notes are handy as well. Because of the way that the iPad deals with special characters (like colons and semi colons that are hidden on an auxiliary keyboard) we realized that entering a lot of notes was going to be a big problem. Additionally, when customers want to create an expansive narrative either for themselves or for an insurance claim, the MTN would stand in the way rather than being helpful.

For the first version, we added a single text macro of .SOAP. that will create the text of
in any note field. This boilerplate text is to help those practitioners who use the SOAP method to document their sessions. However, the CARE method is also in use and in other languages, neither of these is used widely. We realized that we needed a way for anyone to be able to create a series of sentences or paragraphs that they could call up from the application.

That just happens to be the primary function of the TextExpander application.

Setting up TextExpander:
On a desktop computer it is simple to have one program that makes itself available to all other programs. However, on an iOS device (like an iPad) this is much more difficult. The application providing the service has to be written in a particular way and any application that wants to consume the service must also be written in a particular way. Fortunately, to set up TextExpander for sharing a customer just needs to change one setting in TextExpander. They need to turn "Share Snippets" on.
The Massage Therapist Notebook is always checking to see if TextExpander is running. If Text Expander is running then the Massage Therapist Notebook lets it monitor all of the notes as they are typed. When a macro snippet is typed then TextExpander will immediately replace it and even provide a nice whooshing sound to let you know a change has been made (it would be nice if autocorrect did something like this).

Making a snippet:
To make a snippet in TextExpander, we just need to decide on a character sequence we will type and the words that will replace the sequence. Here we have made a snippet in TextExpander to describe neck injuries. For longer paragraphs and phrases, TextExpander supports copying and pasting from other locations. For those people who have the desktop version snippets can be created and shared even faster. If you create a lot of snippets, it would be wise to create a naming convention so that you don't accidentally type one when you don't mean to and so that you can remember all of them.

Adding the snippet to a Note:
Type the Macro
For our example snippet of nkinj1 we add the snippet just by typing. As soon as we type the last character of the macro name (as soon as we type the 1) we hear the whooshing and the new phrase appears. Woosh!
Using the SDK:
Following along with the sample application in the SDK that Smile! provides couldn't have been easier. We simply added a few calls to our delegates for the note taking screens. We were even able to preserve our little .SOAP. macro because as soon as TextExpander does its thing it hands control right back to our program. We are so excited about this integration. We hope our customers find it as valuable as we think they will.

Wednesday, August 24, 2011

Massage Therapist Notebook 2.0 Submitted for Review

We have submitted the latest version of the Massage Therapist Notebook to the store for review. Hopefully it will get approved without requiring any major changes.

There are three big, new features of this app. The first is support for Text Expander. We are excited about this and the SDK that Smile provided made this really easy. In essence, Text Expander will let you type out words, sentences or even whole paragraphs and then assign those to a set of keystrokes.

In the first versions of the app we rolled our own macro (go ahead and type .soap. into any of the session notes, stone notes or clients notes). However, we realized that this was going to be a never ending issue. Thankfully we found Text Expander.

The next is a change in how we draw the stones. When a stone has an associated note (do a long press on any stone to add a note) it will now get a little halo instead of the stripes icon. We have done this because we are working on setting up a symbol editor in a future version so the therapist can add any symbol they desire to the stones. We are also considering letting a therapist edit the colors of the stones themselves, but one thing at a time. We have also added enough new colors so that there is more variety.

We have added a PDF export of any session as our final big feature. This will create a pdf with the body figures and their stones, all of the stone notes and session notes as well as any client notes. This was by far the hardest new feature to add. Once the PDF is created it attaches itself to an email. In future versions we will probably have to rework this part the most so that it is more usable.

There were some other minor bug fixes and UI enhancements. The most common question we got over these past few months was "how do I delete clients". The functionality has always been there but now we've made it more obvious.

What didn't make it into this version:
Client intake forms. This is going to take some thought since there are lots of different ways to make intake forms and lots and lots of questions that might be specific to a single practice.
Multiple body figures. We want to have the ability to have just hands or feet and different body figures with pressure points and other markings. It just wasn't ready.
Stone editor. As mentioned above, we are shooting to have more customization over the stones.
Universal (iPhone) version. We want the product to settle down just a little before we go adding this.

Wednesday, July 27, 2011

Chakras in Massage

Some of our customers of the Massage Therapist notebook use chakras in their practice. For them, the three stones are not enough to represent all of the different chakras as well as other interest points. We are incorporating these new stones
The New stones for the Massage Therapist Notebook
into the app for the next release. In order to represent the chakras correctly we need to have each of the seven colors of the rainbow. We have enjoyed finding lots of different textures to use for the stones themselves. We decided to look for textures from nature, so butterfly wings, flower petals, moss, and fruit images are used for many of the new stones.

Thursday, July 14, 2011

Our Philosophy on Apps for Kids

Caroline's Cat Game hasn't even been in the App Store a whole day and we already got our first complaint: why are you charging money for this app?

We don't believe that apps aimed at children should contain advertising.

Saturday, July 9, 2011

New Podcast We're Listening To

We've started listening to British Mac. Our favorite section is definitely the Pussycat Club section. Where we have learned the new toast "Chin Chin". This podcast is more of a computer user level and less of a developer/nerdy cast. Very entertaining. It makes us remember that there are different perspectives.

Wednesday, June 29, 2011

Using the Facebook API and Contemplating Seppuku

A lot of our TapLynx and related work requires us to get RSS or Atom version of content. For classical blog platforms this is a pretty easy thing. Even if the authors do not have RSS explicitly enabled, platforms like Drupal and WordPress have nice, RESTful ways to get a feed from the blog postings.

Then there's Twitter and Facebook. Facebook has been the worst recently as they keep changing how they want requests formulated. Until recently anyone who could formulate a request correctly could get a Facebook wall as a JSON feed as long as the content was public. Recently, an oAuth token became required even for "public" data. Granted, this is becoming a more common event. Unfortunately, we either weren't watching the right Forum posts or it wasn't announced when the change happened. So, we found out about the change after customers started to complain that the applications were broken.

Things are working for us now, but the documentation isn't totally clear and the system is likely to change again. It makes us nervous.

Wednesday, June 22, 2011

Greek Financial Crisis

In light of the recent events in Greece it seemed like a good time to add a Greek Coin to Carter's Coin Flip. So, version 2.2 has been approved by Apple and will hit the App Store on Thursday, June 23 2011. We had actually chosen this particular coin earlier in the year for its pretty design. We moved it up in the release order because of the world news. Here is a preview of the coin we are using. This is the Greek 10 Drachma coin from 1973. This is actually a rare design. We originally chose the coin because we were looking for a coin with a horse on it at the request of one of our younger members of the "focus group".

The 10 Drachma coin is about the same size as the Swiss 2 Franc piece (about 26mm in diameter). All of the coins in Carter's Coin Flip are proportionally sized to reflect how they appear in the real world.  Also, the coins was minted in "medal alignment" which is why the tails view is upside down. Other coins in Carter's Coin Flip with medal alignment are the British Pound and the Canadian Quarter). Medal alignment means that a coin's faces are both the same orientation. This is great if you are wearing the coin on a necklace as it will always be the right side up, no matter which side is facing forward.

The Phoenix had appeared on the coin since 1971 but the Pegasus was not on the coins for long. As with many of the older coins we use in the app, inflation and the Euro have decimated the monetary value of the coin. 10 Drachmas was equal to just 0.02 Euros in 2001. This particular coin from 1973 was part of the "Hellenic Republic" movement. Greece was marking it's departure from the monarchy of King Constantine II. In 1976 all of the coins were again replaced with new designs.

If you don't already have Carter's Coin Flip, maybe you would like to buy a copy. Also, we are setting up a email newsletter type of list we want to use to expand our focus group. If you want to have the opportunity to vote of the next coins or give input on features we can use to enhance the entertainment value or the educational value of the app please sign up and check that you are interested in Carter's Coin Flip.

Monday, May 23, 2011

Back to the Cat Game

A little girl is having her 10th birthday next week. What she wants for her birthday is for the cat paper doll app we've been tinkering with for a year or so to be in the App Store. This will be a hard deadline to meet. We have 7 days.

The sticking point has always been and continues to be this problem: if you let the user resize the cat with a pinch motion, how do you also resize the cat's collar, bow and hat. That is a simple geometry problem but is made more complex by the fact that the collar, bow and hat need to respond to touches so that they can be repositioned. We have solved this problem about 10,000 different ways over the last year but always end up finding a fatal flaw in one of the edge cases that makes us scrap the design.

Tuesday, May 17, 2011

Making Screen Shots

We sell out apps in countries where the primary languages are English, French, German, Japanese, and Spanish.

Localizing the buttons and the text in the app is something we've always done. Now, we can localize the screen shots and splash screens. This is proving to be a big headache. However, we're pretty positive that when a non-English speaker reads about our app in the app store of their country and then sees that we didn't translate the screens it gives them pause.

Monday, May 9, 2011

Quote from Today's MacTech Magazine

"you may find yourself struggling to achieve something, and then later find that there's a Cocoa class that does it for you." - Edward Marczak

Story of my year so far.

Thursday, April 28, 2011

The Long Tail of the App Store

Today, there are 1321 iPad Apps in the US App store in the Business category. Massage Therapist Notebook is in the top 200 ranked by popularity and by Gross. At times this month it's been in the top 100. The chart below is the chart for the US based on Gross.
Here is how we know that the tail is long, very long. We have settled down to between 2 and 5 purchases in the US per day and have not yet sold 100 copies in the US. Still, we are ranked higher than over 1000 of the apps in our category (we are easily in the top 20%).

In some countries where we have sold only a handful of copies, a single purchase can move our app store ranking by almost a hundred points.

We're not disappointed by our adoption rate yet. We have found a few customers who have reached out to us offering improvements. We knew that the app was not feature complete when we released it. The strategy is to release the app and then reward early adopters by adding features they want while slowly raising the purchase price for later adopters (once you buy an app in the App store, the developer cannot charge you for upgrades to that app).

Tuesday, April 26, 2011

Google Translate Saves the Day!

The Massage Therapist Notebook has been selling in other countries and we have been getting it translated into German, Japanese and some other languages. A different post on that process. Today we got this in our ticketing system:
He adquirido la aplicación, y desconozco como poder borrar un cliente una vez se ha creado. Podrían indicarmelo por favor.
Since we don't speak Spanish we were a little nervous. Thankfully, Google Translate has gotten very good over the years. So, we were able to see that the person wanted to know how to delete clients. This is actually the third time we've been asked this question, so we need to improve that part of the UI clearly.

Then we typed out our answer to the question and sent it back
Busque en los nombres de cliente pulsando en el botón 'Clients'. A continuación, deslice el dedo hacia la izquierda en el nombre del cliente. El botón 'Delete' debe aparecer.
Yo no hablo español muy bien. Por favor, hágamelo saber si tengo que hacer un video o algo más para ayudar a explicar.
One trick we use is that we always translate to the language and then open a separate Google Translate window and translate it back to English. It is a good way to catch idiom mistakes.

Wednesday, April 6, 2011

MapKit Custom Images and Offset Issues

Much thanks goes to user Georg who sent us this image of how he was trying to use our TA_MapKitPlugin for TapLynx in his app. He noticed that if we zoom out to a world view, that the custom pin images are no longer in the correct positions.
Georg's Map Showing the Pin Error
The pin he has highlighted actually points to a location in California (Colton) though if we zoom out, it appears to be pinned to a location out in the Pacific.
After we stopped panicking we did some testing and discovered that if we used the system supplied pin images the pin was on the map in the correct location. In the TA_MapKitPlugin the default iPhone pin images will appear if there is no entry for the pinImage key in the NGConfig file. This meant that the location is correct, but there was something wrong with the image.
Next we went over to the Apple documentation and demo code to look at how they implemented custom images. We noticed that that code also has this issue. When using Apple Map Callout demo code, if you zoom all of the way out, the custom pin will appear offset from the proper location.

The Original Pin graphic with lines to show center.
We finally realized that the MapKit code CENTERS the custom image on the map location. So, we added some padding for our custom pin images and, voila, they now stay in the correct location.
Improved Pin graphic with lines to show center.
While initially confusing, this now makes clear something we have always misunderstood: pin shadows. Since the image for a pin is actually much larger than it appears, adding a shadow (or any other shading to improve the 3d effect) to the image is quite easy to do with image editing software. We were always confused by this as we thought it would throw off the pin location in the graphic. However, now that we know the image center is the pin location we understand.
We have updated the TA_MapKitPlugin in github with new versions of the graphics. Additionally, we have found and fixed a bug in the rendering code that sometimes caused a crash, so if you are using an older version of the code, please update.

Tuesday, March 29, 2011

Amazon Cloud Storage and S3

Today, Amazon announced their new Cloud Drive service. With that they are offering 5GB of free storage forever. Amazon has been for a while offering 5GB of their S3 storage service for free for 12 months.

These have to be the same on the back end don't they? So, wouldn't the better deal be to get the Cloud Drive? I think that the top end of S3 is probably better than Cloud Drive but for a small organization like us, it's a lot of space. We currently have about 3GB on dropbox that we use for backup and sharing.

Friday, March 25, 2011

Taking the XCode 4 Plunge Again

We have a few days between coding jobs and a new version of XCode 4 has been released, so we are downloading the 4.0.1 version and planning to reinstall today. It's times like this that we would like to have more than one computer at work. The show stopper for us before had been that some of our XCode 3.x projects would not open without crashing XCode 4.

Wednesday, March 16, 2011

Making Screencasts for iPad

Making screen casts is not as easy as one might hope. We are using the SimFinger project from github and that is helping a lot, but our scripts aren't great and though we always knew we had a face for radio, it's the voice that's key. Perhaps instead of thin and reedy our voice sounds calming?

Here is the playlist so far. We decided that instead of one, long video it would be better to make lots of short videos. We thought about online tutorial, but can't quite see how it would fit into the app itself.

Monday, March 14, 2011

Meta Thoughts on MTN

No technical notes here. Just us thinking about what we think about this app and some of the marketing and business challenges we think lie ahead.

What is Making Us Nervous
We are not a Massage Therapist. This app came out of an unsatisfying few sessions with a therapist who could not remember from one month to the next what our preferences were or where we were injured. We thought that if she just had some way to take five seconds and jot down a few things so that she could pretend to remember us next time we would be happier customers and her tips would have been bigger. So, we are nervous because it is possible that we just had a bad therapist and the market for this app is tiny. We are nervous that Massage Therapy isn't classified as medicine for a lot of regulations, but it might be something where people are uncomfortable using the iPad to keep client data. We are nervous that the American Massage Therapy Association only has about 60,000 members.

Where We Want to Go Now
The camera on the iPad 2 and the possible release of Duke Nukem Forever really spurred us to finish this thing and get it out there. We think that if a massage therapist can take photographs of client intake forms she would find that really valuable. We think that integration with the iPad calendar so that appointments would pop up session data in the app is important. As Massage Therapy moves more into the arena of being covered by insurance and regulated by states, we think the ability to spit out reports of client visits and therapy regimens in a state's requested format could be the bees knees. We think that having a small group of therapists be able to share client information (within a practice for example) or having the session data sync with an iPhone or desktop application to help run the business.

If we implement all of those features, we think this will be a robust and valuable tool for the Massage Therapy profession.

Where We Don't Want to Go
We don't want to replace Quicken or Billings, or QuickBooks. We don't want to deal with salesforce integration. We want the start to finish interaction with this app to be 5 minutes. Some quick notes about a client after a session or a quick review of trends before starting a session.

Who is This For
We find it helpful to envision the core customer when writing software. You can make decisions better and you can think through use cases. During the development of this application our core customer was Ginger. She is a middle-career massage therapist who sometimes works out of a studio but also does in home visits. She carries her big, green massage table on one shoulder and she has a duffle bag of linens and creams on the other. The town where Ginger works has a number of seasonal residents, so there are people in her practice that she might see only three times a year. There is no way to really advertise to these people since they are not local so word of mouth from current clients is her best way. Since she started using the app, Ginger has been doing a good job of sending follow up emails to clients a long with a little note based on some snippet of their conversation that she had recorded after the session. These emails just happen to have her contact information so that they have it for their reference. Ginger processes client intake forms and generates SOAP notes after her initial meetings with a client but often has to leave them at the office when she makes her calls (that duffle is almost stuffed full already). Though she checks her iPad when the client is scheduling their appointment, she always takes the few minutes between when she first greets a client and when she starts the session, Ginger checks her iPad again to go over their records. She really likes that she can flip through all of their past sessions and see what areas need special attention. Ginger likes to use the different colored stones in the app to signify different kinds of issues. She uses the orange stones to denote surprise areas that the client didn't realize were issues but which caused them to really yelp when she worked them. Ginger also keeps notes in the app about whether a client is chatty or quiet and what kind of music they like. As she's cleaning up Ginger makes a few notes in the iPad or might even schedule the next session with the client.

Massage Therapists Notebook: Lots of Firsts for Us

The App Store image for the app.
At the risk of jinxing the app approval process we wanted to get some of our thoughts down while we are still on the post-submission-adreniline high, before reality sets in.
Some Firsts

  • This is our first iPad application for ourselves
  • This is the first (non-contract) app we've written that is specifically for bringing revenue to the firm
  • This is our first large Core Data integration
  • This is the first time we've spent more than 20 hours strictly on "polish".

Tools We Used

What We Learned
Read the Apple Documentation. In general, especially if one of the system apps does it, the iOS SDK has lots and lots of functionality. At the beginning of this project we relied only on Google searching and to get over each hump or past each block. However, by the end, we would take one or two hours each day to read through one of the Apple guides. Very often, we discovered a built in piece of code or SDK function that let us go back an rip out whole methods, or even views.

Use a bug tracker or at least a timer. We feel like our productivity shot through the roof after we implemented FogBugz. Being able to write down all of the tasks and then being able to close them out was so satisfying. Also, having FogBugz record how much time we spent on each ticket was a real eye opener as to how bad we are at time estimations.

Use Version Control. Sometimes we went down a rabbit hole and couldn't get out for weeks. Initially we just used the XCode snapshot feature. This made us hesitant to ever roll back because we would have to roll back the whole project. Once we started using Mercurial and could roll back each file as well as see the differences, we did much better. Additionally, near the end, we were tired and prone to typos. Being able to see in the version control that we had accidentally deleted an extra line or semi colon kept us from going completely insane.

Just ship something. Honestly, the substantive changes we have made between what was submitted to Apple today and what we had on our hard drive last Summer are not that great. The code is cleaner, we are a better programmer now, and there is much more polish. However, the functions are largely unchanged. We could have shipped this a long time ago and then iterated with actual user feedback.

Downgrading XCode

OS X BSODphoto © 2007 Manu Contreras | more info (via: Wylio)
With the release of XCode 4 into the App Store, we thought it was finally safe to put it on our primary development machine. Sadly, after 3 days and many crashes, we are taking it off. It's cool and all, but there are some projects that it works with fine and others that it just won't run for long with out crashing....and crashing.

We're reinstalled a few times and done all of the tips and tricks recommended after our Google searching. Things had gotten better but certain client projects still just crashed and crashed and crashed.

All of our client code is in Kiln or github so we will be able to reconstruct. It's just that losing the hours of productivity isn't billable.

We are trying the nuclear option for XCode 4 of typing
sudo /Developer/Library/uninstall-devtools --mode=all
. If that doesn't work, it's back to XCode 3.2 for a while.

Saturday, February 26, 2011

Updating the MapKit plugin for TapLynx

Map of 1905 Lewis and Clark Centennial Expositionphoto © 2009 Oregon State University Archives | more info (via: Wylio)
Our MapKit plugin for TapLynx seems to be well accepted so far. We've noticed a few bugs that have been fixed and are excited that two applications already incorporate the code. The Albuquerque Journal (who also use our Citizen Reporter plug in) and another client who has not yet had their app approved. We'll update the name when it is approved as we don't want to jinx anything.

New buttons
It was when we were working with our other client that we discovered the need to add a scrollable list to the plug-in. That application has about 30 pins in the map and so expecting a user to tap one each one was not a good experience for the user. So we have added a button to the interface and now display a list of the places (in alphabetical order) that a user can tap to scroll to and display the callout for that place.

As usual, we are using the excellent glyphish icons. However, we had to build a listing icon since there is not a simple list included in that set. We were worried about getting in trouble with Apple if we copied their list icon too closely, so we have four bars instead of three and we space our bars closer together.

As with our other TapLynx plug ins please use these in your projects and let us know if we can help out. The TA_Mapkit plugin for TapLynx can be found on github.

The Problem With IPv6

ipv6photo © 2010 Aldon Hynes | more info (via: Wylio)
For "normal" people, the move to IPv6 should be mostly uneventful. The creation of the DNS system shields users from having to memorize the actual IP addresses of servers they want to use. Without DNS you wouldn't browse to rather you would head on over to to read about the latest events. Because of DNS a regular user doesn't care that soon will be something like FE80:0000:0000:0000:0202:B3FF:FE1E:8329 or FE80::0202:B3FF:FE1E:8329 in the collapsed form.

But, System Admins and us technical types routinely think about machines in a network by their IP address. Ask any of your IT friends to name an IP number of a machine they use or their favorite IP subnets and guaranteed, they will be able to give you one, or lots. It may be the IP for the main router of their NAT network (often 192.168.something.something) or it might be the IP of one of the big DNS services ( is Google's). These are numbers that can be kept in someone's head and actually used.

IPv6 numbers, not so much.

Thursday, February 24, 2011

Alternative to DimDim

Now that DimDim has been taken out by Salesforce, we are looking for an alternative. The issue for us really is that we need screen sharing capability with our clients and our partners. We don't really need a lot of the other premium features that people want us to pay for. It is for that reason that we can't justify purchasing a solution like GoToMeeting ($50/month) or FuzeMeeting ($30/month).

Skype screen sharing so far has been the best option if people have a Skype account. We are also looking at the free version of (the paid version of $30/month isn't for us). The thing that makes all of this tricky is that we don't want to share what is on our screen. We want to share what is on the customer's screen. So, far that has been the killer issue that makes solutions difficult to find.

Why are we being so cheap? Well, we might have need to share a screen once or twice a month for about an hour at most. Also, we might share a screen to solve a single problem and don't want to have the other party have to install a bunch of software (sometimes that is beyond them). We are willing to pay for a solution but would rather something a la carte since we cannot project usage.

Any other ideas for us?

Wednesday, February 23, 2011

App Rejected for Not Being Useful or Entertaining?

/dohphoto © 2008 hobvias sudoneighm | more info (via: Wylio)
Building iPhone apps for other people always has the risk that the app will be rejected. We work really hard to make sure that there are never rejections for bugs or crashes. Today, however, one of our clients got the dreaded reason 2.12 rejection:
2.12 Apps that are not very useful or do not provide any lasting entertainment value may be rejected

If you would like to share your app with friends and family, we recommend you review the Ad Hoc method, on the Distribution tab of the iOS Developer Portal, for details on distributing this application among a small group of people of your choosing.

It's hard to figure out how to respond to that (after the initial shock wears off). We wonder if the fact that the niche for this particular app is not American and therefore probably not known to the reviewer has any bearing.

While we ponder our next move, we are looking at hybrid/Dashcode web apps and trying not to think about all of the apps we know about that are in the store and are way less entertaining than this one would have been.

Saturday, February 12, 2011

Stackoverflow and Altruism

We are closing in on a reputation score on Stackoverflow of 400. We now feel compelled to find questions we can answer to get the score up. The creators of that site have really hit on a valuable combination with their reward system.

In some ways the site is like a real-time quiz show. I can go there anytime and be presented with infinite programming questions that need an answer. If I answer correctly I get points.

Two odd things about the site: often the answer is easily found by searching the official documentation for the language; and most every question we've ever had has already been asked, so is there an upper limit to the number of questions that the site should support?

Friday, February 11, 2011

icicle and savedInstanceState are examples of geek humor

iciclesphoto © 2006 liz west | more info (via: Wylio)
Have to keep remembering that at the core, computer geniuses like a joke as much as the next person. Today's example: by default, the bundle variable for an Android class is called "savedInstanceState". However in most examples, you will see it called "icicle". Icicle seems to have become common like "foo" or "x" in examles as a generic variable name. This is because it is shorter to type than "savedInstanceState" and because in earlier versions, the method definition for "savedInstanceState" was called "onFreeze".

Wednesday, February 9, 2011

MapKit Lat/Long "Errors" and Decimal Precision

Benchmark DX1095photo © 2008 Chuck Coker | more info (via: Wylio)
After the recent release of our MapKit plugin for TapLynx we got an email from someone who wanted to know why every point on their map was about 2 miles (3.2 km) to the East. After we got over the initial panic and fear that every developer gets when a piece of code they released to the public might have a bug we started to wonder about what could have caused the issue and why things looked fine on our machine.

As we looked at it more, we wondered if decimal precision was the issue.

I found this that talks about translating each decimal place of precision into meters of offset.

Here are some test we ran modifying the precision for the location of Elvis Presley's Graceland mansion. The address we fed into was 3765 Elvis Presley Blvd, Memphis TN 38116. This caused geocoder to give us a decimal latitude of 35.045988, and a longitude of -90.024982. When we plug these numbers into our MapKit plugin we get a nice pin right at the front gates.

Next we made a number of duplicates of the entry and for each one took off one decimal place (e.g. 35.045988, 35.04598, 35.0459, 35.045, 35.04, 35.0). To make it easier to see the effect we did latitude separately from longitude. For each one of these maps, we have six pins drawn. In both cases, the first few pins are effectively in the same place so we know that -90.024982 and -90.02498 are pretty precise measurements for an address. However, -90 is pretty far over to the East. Similarly, as we decrease the precision of the latitude measurements, our pins head South down Elvis Presley Boulevard and 35.045988 is pretty far from 35.
Changing Longitude
Changing Latitude

So, at least to us, this says, five or six decimal places are needed for a good street address. Fortunately, MapKit uses double float numbers for the latitude and longitude values. That means we have plenty of decimal places to work with.

Since the Earth isn't a perfect sphere and since some location points will be unaffected by added precision (i.e. 35.5 = 35.50000000) we expect that changing precision has different impacts on map points depending on the location of the map point.

Friday, February 4, 2011

Using FogBugz in Eclipse and Elsewhere

Time Managementphoto © 2010 Ryan Hyde | more info (via: Wylio)
We started using Kiln and FogBugz in December. When we did January's invoicing it was AMAZING how much better things went. We are sold on FogBugz. We love it. We use "Working On" all of the time. Also, we just saw the new "Mobile Site" in FogBugz (Look under the Extras menu) and it looks great on our iPhone.

For meetings, admin, business development, etc, we have created a project called Tyree Apps and cases as "Schedule Items" for those random things. That way we can use Working On, to track all of our time.

Though the website and web app are powerful, we like things to be integrated. Today we set up EclipseBugz as we started to set up Eclipse. We're going to need Eclipse as we try to figure out whether it's going to be better to learn how to program in Android or just make a partnership with a good Android programmer who needs a good iPhone programmer.

How We Set up EclipseBugz on our Mac
As with other things on Sourceforge (or maybe just because we're inexperienced in Eclipse), in order to get EclipseBugz to work you need to do a few things:

  1. In Eclipse go to the Help -> Install new Software menu
  2. Add a new location by clicking on "Add" and then entering as the location.
  3. Follow the prompts to install the packages.
  4. Go to Eclipse preferences and find the EclipseBugz entry
  5. Enter the main url of your fogbugz installation (for Tyree Apps, it's
  6. Apply the settings and close out of preferences (you might get asked for your FogBugz credentials here, if so, enter them)
  7. Still in Eclipse, go to Window -> Show View -> Other and find the EclipseBugz entry and click on it to open the Eclipsebugz window.
  8. And there are your cases!

Pretty cool. We've just got it installed in Eclipse so haven't figured out the advantages over the web view. Basically, we need to be able to change time estimates and to do "Working On".

Thursday, February 3, 2011

App Store Market Research with Numbers

App Storephoto © 2008 Cristiano Betta | more info (via: Wylio)
Our renewal notice for our Apple Developer license arrived the other day. It got us to thinking about what happens to the apps when someone doesn't renew. Surely the app goes away, right? That made us wonder about the longevity of apps so we did a little counting.

A coin flip app like Carter's Coin Flip is a relatively uncomplex piece of software. In our case, the app serves the purpose of letting us focus on the mechanisms for marketing, compiling and updating software. It also gives us an app that lets us test using the iTunes Connect features. 99% of our revenue from software comes through writing things for others. So, it is nice to have something of our own where we can experiment so that when it comes time to work with the customer, we have more experience.

To look at competition for Carter's Coin Flip, we did a search on "Coin Flip" in the app store. Then we counted and tallied all of the results:
Price, apps in the set were between Free and 3.99 in price.
Free: 39
99c: 45
1.99: 7
3.99 1
4.99 1
So, this tells us that our recent experiment to raise our price from .99 to 1.99 was doomed ever before it began. At 1.99, we had 0 sales for the month (the price is going back to .99).

Category, apps in the set were divided among Entertainment, Education, Games, Productivity, Utilities and Lifestyle. Carter's Coin Flip is currently an "Education" app.
Entertainment: 49
Education 2
Games: 23
Productivity 3
Utilities 13
Lifestyle 3
This one is hard to think about. Clearly, in Education, we must stand out but perhaps there just isn't as much traffic there. We are going to change our "primary category" to a few of these others and see if it has any effect.

Last Update, this is the date that the app was last updated in the store.
2008: 4
2009: 23
2010: 58
2011: 7
Since we're writing this in Jan/Feb of 2011 the fact that 60~ apps were updated in the last year seems to show that people are still active, or coin flip apps are a good "first app". It will be interesting to see if any of the 2008 apps are still in the store next year. They are: CoinFlip (.99), iChoose(FREE), iFlip the Coin (.99), RPG Dice(.99).

We think the list that the store provides is sorted by search term match but we aren't sure. Regardless, our app is about halfway down (unfortunately, "below the fold") the list. It has sort of hovered at that point in the list the entire time it has been on sale.

Also, interesting. When we took these measurements last week, there were 93 results to the search term "Coin Flip". Tonight there are 96...a vibrant market.

Wednesday, January 26, 2011

MapKit Plugin for TapLynx

Today, we have released our newest contribution to the open source community in the form of the TA_MapKitPlugin for TapLynx. The current source can be obtained on GitHub.

Basically, this plugin lets someone add a list of places and information about those places into the main NGConfig.plist file of a TapLynx application. TapLynx is a framework for iPhone and iPad that will let a content provider create applications just using configuration files. The user of the application can then see the places, tap on them to see detail information and even display their own location to see what is near to them.

Each point is represented by a latitude and longitude setting as well as textual information about the location. We considered offering address geocoding but it turned out to be too difficult to implement reliably for the United States, and nearly impossible for the entire world. There are lots of websites that will geocode an address. The iPhone takes decimal numbers for location points (not degrees, minutes etc.).

As with the other Tyree Apps' plugins, this one is designed to give some flexibility in presentation. When creating an application with this plug in, the icons for the pins can be changed (and multiple icons can be used to designate different points). Also, the detail information page for each pin is an html file so that can be customized and additional links can be added.

Configuration instructions are maintained in the Readme file that can be found in the github repository as well as in the project files. As always, please let us know if you find the plugin useful and if you have any comments or feedback we would love to hear about how you use the plugin. If you like this and our other plugins, please remember that we are available to build custom applications for your company.

Thursday, January 20, 2011

Giving the Customer What They Want

Our two biggest challenges with being in this business are embodied in the exchanges that we paraphrase below:

Customer: "I know this feature will be really easy for you to do"

- and/or -

Customer: "I really wanted X but I didn't ask you for it because I figured it would be too hard"

In the first case, the customer has already decided that the change will be easy because it looks simple from their end. It's often something like "add a field", "combine these two things and roll them up", "move this data from the other screen" or similar. Because they think it's easy it seems like they have a corresponding low price and effort expectation. Often, there is a good reason why the change will take longer than they think and sometimes the change is nearly impossible given the current architecture of the system.

In some ways the second case is much worse. The customer believes a feature will be hard so they don't bother to ask. Often, it turns out that the feature is easily accomplished or is no harder to implement than other features. However, since we were unaware of the desire, we couldn't deliver.

In both cases we have a hard time meeting customer expectation so customer disappointment is a real risk. I think that getting in front of the second issue is addressable by asking lots of questions and by getting the customer to dream a little during discovery. However, we have yet to figure out how to get in front of the first issue.

Wednesday, January 12, 2011

Carters Coin Flip 1.9

We are working through CCF 1.9 trying to get it off our to-do list. The biggest change will be the inclusion of REALLY HIGH RES photos for the Retina displays. We are also trying to figure out the best way to make this a Universal (iPhone/iPad) application.

As we play with the high res photos we are ashamed of the crappy quality that our current customers are enduring. These new images are really neat. You can really see the detail in the coins if you have an iPhone 4. Also, because we can display so much more, we are moving around the backgrounds a little bit. So, the iPhone 4 gets a slightly different view of home plate or the turf than an older iPhone.

The iPhone 4 is pretty smart in how it deals with images. When you load an image like this:

[UIImage imageNamed:[NSString stringWithFormat:@"%@_heads.png",self.coinName]]

You only reference the lo-res version of your image. Then when any device (like an iPhone 4) that can handle the higher resolution sees that code it goes looking for a file that is the same name but has a slight variation. So, in our example above, it looks for something that has "_heads@2x.png" in its name. This way we don't have to code around what image to display and what resolution etc. When the iPhone 4 doesn't find a high res version of the image, it simply doubles the size of the old image. This is why images can look jagged on the iPhone 4. They are blown up to 2x size.

In an app like CCF, we are always bumping up against size limits because the image files are so big. So, to save space we are taking advantage of this runtime trick of the iPhone 4. Each flipping coin animation is made up of four images: heads, tails, heads at an angle, tails at an angle. The two 'at-an-angle' photos are to make up the illusion that the coin is really rotating. So, giving users a jagged image for those two isn't a problem since they aren't the focus of the animation and since they are only visible for .03 seconds.

When CCF ships later this month it will contain six images for each coin: two for the heads, two for the tails and one each for the at-an-angle view. All together this is about 800K of images per coin. If we had included high res versions of the at-an-angle views that would have added another 4ooK per coin. When the animation happens, the iPhone will pick and choose which graphics it should display and all will be well. We hope you like it.