Paul Brown

Failure to Learn

Easy Grade for Mac Released

Easy Grade on iOS has been doing great for the past couple of years, and now I’m happy to announce that I’ve just released the Mac version of Easy Grade. Why the Mac, you say? There are a number of reasons to not bother with the Mac version (mainly that most teachers have a school-issued Windows laptop), but there are other reasons for doing it.

As of this year, Apple merged the developer programs into one, so I don’t have to pay the extra $99/yr to have a Mac developer account. Also I know iOS programming, and the Mac frameworks are quite familiar to me because of that. Despite having written the iOS version in Objective-C, I wanted a good little project to learn Swift, and Easy Grade was perfect.

As you can see from the screenshots here and in the App Store, I practically ported my design from iOS over to the Mac, with slight modifications where appropriate. I also took some design cues from with the vibrancy (besides, Easy Grade is a calculator, right?).

So if you are a teacher (with a Mac), grab it on the App Store now! If you know a teacher with a Mac, this would be a great gift idea. For more info, click the Mac App Store badge below or visit the Easy Grade for Mac.

Sometimes Freemium Works

Looking at the variety of ways to make money in the App Store is always a fascinating discussing to me. In Freemium is hard, Marco reflects on Shuveb Hussain’s experiment with taking a paid app freemium:

Freemium is hard. Its effectiveness depends on where you can put that purchase barrier in your app. Many app types simply don’t have a good place for it.

I’ve thought about this a lot with my app. I’ve got one app that has been through the same two revenue models that Shuveb went through. In my situation, though, it went the opposite way.

I released Easy Grade as a paid app in July 2012. It was selling a handful of copies a per week. I think for those first 6 months it made a couple hundred bucks. I don’t know what actually made me think to do this, but I decided to take a chance on a freemium model.

My app had (and still has) a feature that distinguishes it from the other EZ-Grader apps in the store – it can calculate grades based on half-points partial credit (back-story here). I decided to put an ad at the bottom, and the In-App Purchase would remove ads and enable the half-points feature. I released this in January 2013.

This new freemium app did extremely well. To give you a visual, here’s the comparison:

Being free boosted downloads by an order of magnitude, and by the end of 2013, I was even seeing noticeably more In-App Purchases than paid app downloads. The scales had tipped to the point that I eventually decided to pull the paid version in January 2014.

There was one major victory in this switch that I was not expecting. My app is used by teachers to calculate grades. They set the app the way they need it and prop it next to them while they grade papers. The average Easy Grade session time is 12 minutes. This is huge for an app that uses advertisements. You can debate the ethics of using ads in apps (_David had a great discussion of this on his podcast). At least for now, I think ads are an acceptable revenue stream.

Marco is absolutely right, though. Freemium is hard, and it doesn’t work in every situation. I think his execution of the freemium model in Overcast is perfect. It works for my app. But it certainly doesn’t make sense for everyone.

Side-note: About a year ago, after seeing Jury’s Cingleton talk, I thought it’d be fun to double the price of the In-App Purchase and see what happened. To my delight, I have seen roughly the same number of purchases, thus my IAP revenue has doubled.

Problems With the Scribd iPhone App as an Audiobook Player

I have a moderate commute (moderate for Atlanta standards), so I listen to a lot of podcasts and audiobooks. I found out recently that Scribd offers a fairly large selection of audiobooks for a reasonable price, so I signed up for a trial to give it a shot. The user experience with this app has been so bad that I felt compelled to write up a list of its shortcomings here. Hopefully they can continue to improve this app as time goes on, but for now these reasons are keeping me from continuing my trial into a paid membership.

  • Don’t leave your wifi’s range before the audiobook is finished downloading. I did this and when I paused, it wouldn’t restart because the file wasn’t locally available
  • The touch target for the audio scrubber must be tiny. I haven’t run this thing through a jailbroken phone and a view debugger to see the exact pixels (I think that’s possible), but it is almost impossible to get it the first five tries.
  • Several times the app has been playing along and suddenly skipped to the next chapter. Then you have to go back to the previous chapter and use the impossible scrubber to find where you were.
  • The app cannot reliably remember where you are in an audiobook. Many times I have hit play at the start of my morning commute and found mself listening to the last chapter I listened to.
  • A couple of times I have reached the end of a chapter and the audiobook paused. Sometimes it will start back on its merry way once I launch the app, and sometimes I have to hit play to get it to continue playing.

I know writing apps is not easy, but to me it looks like the problems with this app could be fixed with a couple months of solid iOS development time. Scribd has a good foundation built, and a rock solid iOS experience could really provide a good option in the audiobook subscription marketplace.

Side-note: Insurgent is kind of boring.

UPDATE (Aug 30, 2015) – I submitted this post to Scribd in a support ticket, and they admitted problems and told me they were working on the problems. I received another response when version 3.11 was released, and they very generously gave me some extra time on my account for free. I listened to another 1.5 books these last few weeks, and I will say that the experience is much better! However, there are still problems:

  • The app cannot remember what playback speed you are using between sessions
  • On several occasions, I would reach the end of a chapter and playback would just stop. This is infuriating when you’re driving down the interstate.

Making Free/Busy Work in a Hybrid Exchange Environment

Over the last month or so at my day job, we ran into an unnecessarily tricky scenario trying to get free/busy working between our on-premises Exchange environment and a federated hybrid environment. My main purpose in writing up this experience is because I hope people can find it via a web search and not have to commit hours upon hours of time with Microsoft solving it.

The problem was that when a user in the cloud went to invite an on-prem user to a meeting, the Outlook client (desktop client or OWA) would show an error: “The recipient’s server could not be determined”. Not entirely helpful, as that’s extremely generic.

We looked at the IIS logs on the Exchange front-ends to see if that revealed any clues. Whenever we attempted to view an on-prem user’s free/busy info from the cloud, the log would show something like this:

2015-04-09 18:33:02 POST /autodiscover/autodiscover.svc/WSSecurity &CorrelationID=<empty>;&cafeReqId=be5979f1-ed29-04b9-a131-254aeff795a4; 443 - ASAutoDiscover/CrossForest/EmailDomain//15.01.0130.019 - 401 0 0 140

Notice the HTTP 401 error at the end of that line. It seemed like the cloud server was not authorized to view information on the on-prem server. At this point, we opened a ticket with Microsoft. (side-note: this was frustrating… we had an engineer working with us up to this point. Why did he not have the tools to troubleshoot, or at the very least do the research and get back to us?)

The new support engineer first delegated us to a TMG engineer, who then proceeded to tell us it wasn’t a TMG problem (the request was making it all the way to our front-end – TMG was not getting in the way). We got another on-prem Exchange support engineer, and after doing the typical Microsoft support case song and dance, he finally sent us this link:
Free/busy lookups stop working in a cross-premises environment or in an Exchange hybrid deployment

The problem was revealed by the Test-FederationTrust cmdlet, which produced this output similar to this (I’ve replaced the irrelevant RunspaceID GUIDs):

> Test-FederationTrust
RunspaceId : <guid>
Id         : FederationTrustConfiguration
Type       : Success
Message    : FederationTrust object in ActiveDirectory is valid.
RunspaceId : <guid>
Id         : FederationMetadata
Type       : Error
Message    : The federation trust doesn't contain the same certificates published by the security token service in its federation metadata.
RunspaceId : <guid>
Id         : StsCertificate
Type       : Success
Message    : Valid certificate referenced by property TokenIssuerCertificate in the FederationTrust object.
RunspaceId : <guid>
Id         : StsPreviousCertificate
Type       : Success
Message    : Valid certificate referenced by property TokenIssuerPrevCertificate in the FederationTrust object.
RunspaceId : <guid>
Id         : OrganizationCertificate
Type       : Success
Message    : Valid certificate referenced by property OrgPrivCertificate in the FederationTrust object.
RunspaceId : <guid>
Id         : TokenRequest
Type       : Success
Message    : Request for delegation token succeeded.
RunspaceId : <guid>
Id         : TokenValidation
Type       : Error
Message    : Failed to validate delegation token.

The key problem was the TokenValidation. That url referenced above suggested that the metadata information in our environment had become stale, and it proposed that we run

> Get-FederationTrust | Set-FederationTrust RefreshMetadata

in our Exchange powershell. Magically, after we ran this, the cloud users could then retrieve our free/busy information.

As I mentioned above, I hope this write-up helps someone down the road. We searched high and low for a solution to this problem, and for whatever reason we never came across the article that our support engineer linked us to. Maybe it’s because we searched for this related to our HTTP 401 error on the Exchange front ends. That article doesn’t mention anything like that – just that our metadata was stale.

What makes this situation more ridiculous is that Microsoft suggests in the article to set up a Scheduled Task to run this cmdlet regularly. If they know this is a problem, then why can’t that run as part of some process under the hood of Exchange? I digress…

Finally, I should also add that this is probably one of a hundred different problems you could encounter while making free/busy work between cloud and on-prem environments. Even still, I hope this helps someone.

Minimizing Twitter

Life has changed a lot for me recently, this being the best example of that. I’ve thought a lot about what is actually important to me, and how I spend my time. Even though I wouldn’t consider myself a heavy user of Twitter, for a while I’ve realized that I should probably cut back on the time I spend consuming this stream of consciousness from the internet.

Going to China helped, because internet was so spotty there, and because for those first two weeks we had our daughter, I obviously had significantly more important things to do than stick my face into a screen. Then we got home, where the internet was actually usable, and I realized I didn’t want to model that behavior to my child. In addition to that, though, I was finding my mind continuously distracted by my Twitter stream.

So I “quit”. I put that in quotes because I do still check it, but in a vastly different way now. I deleted my Twitter clients for a few days and didn’t check it at all. This was extremely refreshing.

In an effort to stay connected, though, I created a Twitter list of the people whose tweets I definitely want to see. Right now it’s only 22 people who are either close friends in real life, or people whose tweets are infrequent and have a high signal-to-noise ratio.

I’m not knocking the high volume twitterers – these users post a lot of good content. I just don’t need that distracting me all day every day. When I really do have time to just sit back and relax, I’ll intentionally go look at those users’ streams and skim through.

All in all, I’m extremely happy with this decision, and I don’t see myself turning back. My mind stays much more focused on my tasks, and I’m able to spend more quality time with my wife and daughter.

A final sidenote: It was satisfyingly coincidental hearing Marco discuss his withdrawal from Twitter on last week’s Accidental Tech Podcast:

Twitter is a tricky balance between whether it makes your life better or worse overall, and I’ve been questioning what the value of it is for me recently, and whether it is a net gain or a net loss.”

If you listen to their full discussion, he explains it further, and his reasons for pulling back are more related to the constant negativity on the internet, which is understandable. I’m not enough of a Twitter-celebrity to see a lot of that, nor do I seek it out, of course. We’ve seen enough damage done to people recently on the internet, and we could all benefit from rediscovering our priorities away from social networks, whether it’s to avoid the negativity or just to spend more time with those close to us.

Books I Read in 2014

I didn’t make a blog post about the books I read in 2013, probably because I only read 8 books (see my Goodreads profile.) 2013 was also a hectic year – I should have blogged about that, but in short, I finished grad school, bought a house, sold a house, went on a mission trip to Guatemala, and started a company. I picked up the reading pace again in 2014, so I thought I’d continue the tradition of posting my books.

Guns, Germs, and Steel: The Fates of Human Societies by Jared Diamond
This was on Bill Gates’ list of recommended books. I personally thought it was really dull, but it was very well-researched.

The Connected Child: Bring Hope and Healing to Your Adoptive Family by Karyn B. Purvis
We are adopting, and this was required reading for the educational part of the adoption process. I think every parent should read this.

The Lamb and the Fuhrer: Jesus Talks with Hitler by Ravi Zacharias

Dandelion Wine by Ray Bradbury
I remember Fahrenheit 451 being great, so I thought I’d get a different taste of Ray Bradbury. I didn’t care much for this book, but I do think I’ll re-read Fahrenheit next year.

One Way Love: Inexhaustible Grace for an Exhausted World by Tullian Tchividjian

Last Night in Twisted River by John Irving
My favorite book (in my current recollection) is A Prayer for Owen Meany, by John Irving. Irving is a fantastic writer, but Twisted River turned into a meta-story about Irving himself, which got old (I mean, c’mon, a writer writing about a man becoming a writer?)

The Grace Effect: How the Power of One Life Can Reverse the Corruption of Unbelief by Larry Alex Taunton
Another great adoption-related book

Wish You Happy Forever: What China’s Orphans Taught Me About Moving Mountains by Jenny Bowen
An amazing story of how a now very successful orphanage program in China got its start

The Reason for God: Belief in an Age of Skepticism by Timothy Keller

A Separate Peace by John Knowles
Not nearly as good as I remembered it from high school

The Power of Habit: Why We Do What We Do in Life and Business by Charles Duhigg

Divergent by Veronica Roth
It’s like Hunger Games meets Twilight, and not in a good way. I’ll probably continue the series, though.

Forgotten God: Reversing Our Tragic Neglect of the Holy Spirit by Francis Chan

Bonhoeffer: Pastor, Martyr, Prophet, Spy by Eric Metaxas
What a story of a great man’s life.

Which books did you read in the last year?

Again, like I mentioned in my 2012 post, I noticed that books that have been published in more recent years tend to have a Title:subtitle format. I guess it makes sense, but when you list out books like this, it makes it noticeable.

Full disclosure: The links above are Amazon Affiliate links, which means I get a small percentage of money from sales made by clicking them. If you don’t want to support that, go directly to Amazon/Google and search for the books.

Hearts Scoreboard - the Best Hearts Score Keeping App for Your iPhone/iPad

In June, I went to a condo with some guys for a weekend as a sort of preliminary bachelor party getaway. These particular friends love the game of Hearts. In college, when I was playing Spades multiple times a week, they were probably playing Hearts twice as much. I wasn’t surprised when I got sucked into a game of Hearts during this weekend at the beach.

As we were getting set up, we of course needed to get a scoresheet, which made me think “There’s gotta be an app for that” sound familiar?. And let me tell you… I found one. But it was so bad I couldn’t put myself through that misery. There was a pretty good generic scorekeeper app, but considering the way Hearts points typically add up, I thought a Hearts-specific scoring app would be nice. A thus was born the idea of my new app:

Hearts Scoreboard

I’ve used my Hearts-playing friends as a sounding board, and I think it covers all of the elements you need while playing the game:

  • Keeps track of which direction you pass the cards in each turn
  • Keeps track of the dealer
  • Has multiple buttons for assigning points, suited to Hearts scoring
  • New style and Old style Shoot the Moon scoring
  • Rearrange/rename players

If you’re a Hearts player and want a better way to keep score, I think you’ll love this app. Download it by hitting the App Store Badge below, or search in the App Store.

As a side-note, my wife and I are in the process of adopting a little girl from China. When you use this app, you are contributing to that process. Read more about that here

OS X Caching Server Does Not Support the iOS 8 Update

With the release of iOS 8, yesterday was an eventful day in the iOS universe. I thought it’d be an interesting experiement at work to set up a Caching Server (part of OS X Server), particularly to see if it would work for the iOS 8 update. At some point yesterday, Apple provided the quick answer to that question in a support doc.

The Caching service of OS X Server doesn’t cache the iOS 8 update. The service continues to cache iOS content including apps, books, iTunes U course materials, and OS X updates.

I only found that doc this morning, but yesterday proved as much to me. Here are the stats from our Caching Server a couple of hours after release:

Before Apple released the update, we already had a couple of gigs of cached data. Within the hours that followed the iOS release, I know we downloaded the update at least 4-5 times on multiple devices, The cache numbers seemed to stay stagnant, thus indicating the Caching Server was playing no role in the update. My company probably has more than 1000 iPhones/iPads. I suspect many would have updated to iOS 8 yesterday, especially considering our internet speed at Tech is easily more than 10x the average employee’s home speed.

This isn’t all bad, though. Today, we’ve got 14 GB of data cached. Plus, the server has sent ~22 GB while it has only received ~17 GB. I take that to mean there has been a decent amount of users who have pulled app updates from the server. And during a time when Apple’s servers are being hammered, this has to help a little bit at least.

Screenshots from 2014-09-18:

Now we can just hope that before the next wave of iOS updates come, Apple will update the Caching Server to support OS updates. It would be a win-win for everyone.

Final Note: Fraser Hess has written a lot of great articles about OS X’s Caching Server. He has a post about not supporting iOS updates here, but if you’re interested you should check out his other posts too. Also check out Nik Fletcher’s blog post about Caching Server.

Programmatically Reading and Converting Database Sizes With Exchange 2013 Powershell

For quite a while I’ve had automated PowerShell scripts that monitor our Exchange database sizes. I set this up so we could see weekly/monthly/annual growth patterns for different departments in the company. We weren’t really concerned about running out of space on the backend servers, but it would be good to have a rouch idea of the trajectory. And more data is always better, right?

To start, here is how you get the database size in Exchange PowerShell:

> Get-MailboxDatabase -Status <databaseName> | select DatabaseSize

8.063 MB (8,454,144 bytes)

That size format is a bit odd, but in Exchange 2010, PowerShell would let me convert that to gigabytes, using the ToGB() function on the DatabaseSize property. So, I set up a script to iterate through all of our databases, convert each DatabaseSize to GB, and then enter that data into a database.

ForEach ($db in $arr) {
  Get-MailboxDatabase -Status $db | select DatabaseSize | ForEach {
      $size = $_.DatabaseSize.ToGB()
      $query = "INSERT INTO ``sizes`` (``timestamp``, ``database_id``, ``size``) VALUES (DATE(NOW()),(SELECT id FROM ``databases`` WHERE db_name LIKE `'$db`'),$size)"
      Write-Host $query
      $Rows = WriteMySQLQuery $conn $query

The WriteMySQLQuery at the end is just a function defined elsewhere that executes the MySQL query.

After we upgraded to Exchange 2013, these scripts stopped working. I tried running the script manually so that I could see errors, and I saw a bunch of these:

ForEach : Method invocation failed because [System.String] doesn't contain a method named 'ToGB'.
At C:\exchangescripts\db_sizes.ps1:99 char:58
+     Get-MailboxDatabase -Status $db | select DatabaseSize | ForEach {
+                                                             ~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [ForEach-Object], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound,Microsoft.PowerShell.Commands.ForEachObjectCommand

I don’t know the exact reason, or I at least can’t find any documentation indicating that Microsoft changed anything. However, in my search for a solution, I found this forum post, which gave me the fix. I inserted these two lines at the top to load the Exchange Data dll:

$dll = "C:\Program Files\Microsoft\Exchange Server\V15\Bin\Microsoft.Exchange.Data.dll"

Then I used a ByteQuantifiedSize object to hold the DatabaseSize property, like so:

[Microsoft.Exchange.Data.ByteQuantifiedSize]$obj = $db.DatabaseSize

Working this concept into the original script above, it now looks like this:

ForEach ($db in $arr) {
  Get-MailboxDatabase -Status $db | select DatabaseSize | ForEach {
      [Microsoft.Exchange.Data.ByteQuantifiedSize]$rawSize = $db.DatabaseSize
      $size += $rawSize.ToGB()
      $query = "INSERT INTO ``sizes`` (``timestamp``, ``database_id``, ``size``) VALUES (DATE(NOW()),(SELECT id FROM ``databases`` WHERE db_name LIKE `'$db`'),$size)"
      Write-Host $query
      $Rows = WriteMySQLQuery $conn $query

This is how I got my data out of Exchange. I also set up a task in Task Schedular to run this every night. Over time this generates a nice bit of data that can be charted. Once I have a bunch of data, maybe I will come back and edit this post with some of those visulations.

How I Track Which WWDC Videos I’ve Watched

It’s that time of year again, when Apple developers around the world get back home from WWDC (or are still at home and well-rested, like me) and start trying to soak up all they can from the session videos. I always have intentions of watching ALL THE VIDEOS, but inevitably I just catch the ones that are pertinent to what I’m doing. If you write iOS and Mac apps for a living, though, you probably watch more than me.

One problem I have with the session videos is that sometimes I forget which ones I’ve actually watched, especially if I watch them sporadically. My solution to this is to create an Evernote checklist with all of the sessions listed and I check them off as I go. As stupidly simple as this sounds, it’s very effective, so I thought I’d share my WWDC 2014 checklist. You can download the file below. Enjoy! And please send any suggestions for improvement.

Update (2014-07-25): I’ve now created a similar Evernote file to track NSConf 6 and UIKonf 2014. I may also add one for Çingleton.

WWDC 2014 Evernote note file – just import it into Evernote
NSConf 6 Evernote note file
UIKonf 2014 Evernote file