$210,542

No, that’s not my revenue (I wish!)

It’s what SLOCCount estimates Quick Brown Frog cost to develop. I’ve always felt that SLOCCount tends to exaggerate development cost. Either that or I’m vastly underpaid.

7.6 months and $210K seems way high for this app, even with the salary is set to a rather low $56K default.

Still, it’s quite the ego boost for a solo programmer. I’ve only been developing this typing tutor for about 6 weeks so far, and this feels kind of like a pat on the back.

SLOC	Directory	SLOC-by-Language (Sorted)
3688    typing          java=3688
3183    gwtstore        java=3183
196     mystore         java=196

Totals grouped by language (dominant language first):
java:          7067 (100.00%)

Total Physical Source Lines of Code (SLOC)                = 7,067
Development Effort Estimate, Person-Years (Person-Months) = 1.56 (18.70)
 (Basic COCOMO model, Person-Months = 2.4 * (KSLOC**1.05))
Schedule Estimate, Years (Months)                         = 0.63 (7.61)
 (Basic COCOMO model, Months = 2.5 * (person-months**0.38))
Estimated Average Number of Developers (Effort/Schedule)  = 2.46
Total Estimated Cost to Develop                           = $ 210,542
 (average salary = $56,286/year, overhead = 2.40).
SLOCCount, Copyright (C) 2001-2004 David A. Wheeler
Please credit this data as "generated using David A. Wheeler's 'SLOCCount'."

This also goes to show that the cost of software development does not necessarily have anything at all to do with its worth.

Posted in Business/Marketing | Leave a comment

Quick Brown Frog Typing Tutor is launched!

After lots of helpful feedback from beta testers and Hacker News, my typing tutor app “Quick Brown Frog” is live and open for business!

Some of the things I changed in response to feedback include:

  • price reduction from $29.95 -> $9.95
  • support both Google Checkout and Paypal options for payment
  • stats reporting (WPM/Accuracy improvement over time)
  • report on frequently mis-typed keys after practice lessons
  • allow automatic single/double spacing after end of sentences (very frequently requested)
  • implemented crawlable Ajax links for SEO
  • plus many bug fixes for cross-browser compatibility

I consider this an MVP-level release, which means that it still needs lots of work and polish (in particular, the look-and-feel of the UI).

The important thing is to get it out there, and start getting feedback from actual customers. Absent that, I’d just be spinning my wheels.

Posted in Technical | Leave a comment

Measuring Typing Accuracy

It turns out that measuring typing accuracy (how accurately you hit the intended keys) is non-trivial. A quick survey of the online typing courses out there shows that there is considerable confusion over how to correctly measure typing accuracy. One site actually gives a negative percentage if you backspace too many times!

This was kind of surprising to me. I figured it would take me perhaps 10 minutes to implement. It ended up taking a day and a half of my time, $10 spent on an ACM article, and some quality time with a recent CS grad’s PhD thesis. No joke.

Well, to be completely honest, in the end, the implementation was in fact fairly trivial. What was hard was figuring out what to measure. It’s more of a human problem than a technical one.

Why is this hard?

Your intuition might be to simply measure the ratio of correct characters to total characters typed. At first glance this seems OK, but consider the following case:

intended: The quick brown frog jumped over the lazy fox.
actual  : The quck brown frog jumped over the lazy fox.

If we match up the typed characters with what was expected, the accuracy of this typed statement is a very low 15 %. But looking at it from a human perspective, what were the actual errors here? The typist missed the “i” character in the word “quick”, and as a result the rest of the line was offset by one.  It seems like there ought to be a way to more accurately capture the fact that the user made a single typo. There is.

Edit Distance

Edit Distance is the number of operations required to transform one string into another. The operations include insertion, deletion and substitution. In this example, it requires only a single edit- ‘insert an i’.

Soukoreff’s thesis describes a Minimum String Distance Error Rate as the Edit Distance divided by the maximum of the lengths of the presented vs typed text, times 100%. For our “off by one” example above, the error rate is a mere 2%, i.e. 98% accurate. That seems more reasonable!

So for a while I was using the Levenshtein Distance algorithm to compute the edit distance, and hence the accuracy. This certainly worked better than my initial naive algorithm, but it still had a problem- What if the typist made lots of errors, but was fastidious about backspacing over the mistakes and correcting them? His error rate would be zero in this case, with an accuracy of 100%.

While correcting all your mistakes is admirable, it seems wrong to award a “100% accurate” rating to a typist sporting a bruised backspace key. Somehow, we’ve got to take the mistakes into account, even if they’ve been corrected.

Text-Entry Taxonomy

Soukoreff’s PhD thesis again provides a solution. Classify each of the keystrokes into one of the following categories:

  • C – Correctly typed
  • IF – Incorrect, but Fixed
  • INF – Incorrect, Not Fixed
  • F – Fixes, i.e. backspace or cursor movement used to correct mistakes

Using these classifications, he proposes a Total Error Rate defined as:

(INF + IF) / (C + INF + IF) * 100%

So, going back to our “off by one” example, if the typist noticed immediately that he missed the ‘i’ in ‘quick’, and backspaced to correct it,

The quc⌫ick brown frog jumped over the lazy fox.

the breakdown would be C: 47, F: 1, IF: 1,. INF: 0, for a total error rate of (0 + 1) / (47 + 0 + 1) = 2%, or 98% accurate. Same as using the Edit Distance alone, in this example.

But what if the user didn’t notice the mistake until 10 characters later? The input stream would look something like this:

The quck brown f⌫⌫⌫⌫⌫⌫⌫⌫⌫⌫ick brown frog jumped over the lazy fox.

What’s the error rate now? C:47, F:10, IF: 10, INF: 0, or (0 + 10) / (47 + 0 + 10) * 100% = 17.5%, or roughly 82% accurate. Aha!

I plugged this formula into Quick Brown Frog and watched the error rate go up and down while typing. Finally, it seemed to be doing the right thing- rewarding accurate, deliberate typing, and taking off points for outright mistakes as well expensive corrections.

Yet another example of why it’s hard to estimate software schedules- sometimes the ‘trivial’ is anything but.

Posted in Technical, Typing | Leave a comment

Quick Brown Frog featured on StartupLift!

I’m happy to report that StartUpLift.com, an awesome new site for promoting new startups, is featuring Quick Brown Frog.

http://startuplift.com/quick-brown-frog-learn-to-touch-type/

Posted in Business/Marketing | Leave a comment

how to resolve App Engine timeouts when parsing web.xml

For a few weeks now I’ve been plagued with timeouts while updating my App Engine apps. At first I thought it was a problem in the Intellij EAP beta I was running, but today I spent some time digging into it.

It seems to be unrelated to the EAP, as I get the same behavior with the App Engine command-line tools- timeout failure parsing web.xml roughly 75% of the time. It looks like this:

Nov 17, 2010 4:32:54 PM com.google.apphosting.utils.config.AbstractConfigXmlReader readConfigXml
SEVERE: Received exception processing /Users/armhold/work/git-mega-repo/mystore/out/artifacts/Typing_Web_exploded/WEB-INF/web.xml
com.google.apphosting.utils.config.AppEngineConfigException: Received IOException parsing the input stream for /Users/armhold/work/git-mega-repo/mystore/out/artifacts/Typing_Web_exploded/WEB-INF/web.xml
at com.google.apphosting.utils.config.AbstractConfigXmlReader.getTopLevelNode(AbstractConfigXmlReader.java:210)
at com.google.apphosting.utils.config.AbstractConfigXmlReader.parse(AbstractConfigXmlReader.java:228)
at com.google.apphosting.utils.config.WebXmlReader.processXml(WebXmlReader.java:142)
at com.google.apphosting.utils.config.WebXmlReader.processXml(WebXmlReader.java:22)
at com.google.apphosting.utils.config.AbstractConfigXmlReader.readConfigXml(AbstractConfigXmlReader.java:111)
at com.google.apphosting.utils.config.WebXmlReader.readWebXml(WebXmlReader.java:73)
at com.google.appengine.tools.admin.Application.(Application.java:105)
at com.google.appengine.tools.admin.Application.readApplication(Application.java:151)
at com.google.appengine.tools.admin.AppCfg.(AppCfg.java:115)
at com.google.appengine.tools.admin.AppCfg.(AppCfg.java:61)
at com.google.appengine.tools.admin.AppCfg.main(AppCfg.java:57)
Caused by: java.net.ConnectException: Operation timed out
After some digging around, it seems to be related to a timeout deep in the bowels of Java’s XML libs while trying to validate the DTD for web.xml.

The fix is simple: elide the DTD declaration from the top of your web.xml:

<!DOCTYPE web-app    PUBLIC “-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN”    ”http://java.sun.com/dtd/web-app_2_3.dtd”>

Posted in Google App Engine, Technical | Leave a comment

Implementing a keyboard in CSS

The predictive keyboard in QuickBrownFrog has gone through three major iterations so far. At first, I really didn’t expect to be able to implement a functional keyboard in GWT (i.e. Javascript+CSS), so I set about drawing the keyboard using Omnigraffle.

Round 1 – Static Images

static keyboard image from Omnigraffle

static keyboard image from Omnigraffle

It was fairly easy to whip up the initial design. But then in order to implement key selection I had to create about 100 variations of this with all the different keys selected. That was painful.

GWT provides a way to bundle image resources, and that helped keep the image size in check, but it was still a bit slow on the client until all the images were cached. Unfortunately this also meant that I had to create a mongo ImageResources.java interface, which listed every foo_key() foo_keyShifted(), etc.

So this clearly wasn’t optimal, but it worked for a while. Then when I decided it was time to change the “selected” color, and I had to manually re-color every single PNG. Obviously, this was not going to scale, and it was time to re-think my approach. So I set about experimenting with ways to programmatically generate the keyboard.

Round 2 – SVG

First up, I went with SVG. The SVG Canvas is not natively supported in every browser, but the GWT-Graphics library gracefully uses VML in Internet Explorer, making it effectively cross-platform. This worked pretty well, and after a day and a half tweaking the layout, I had a functional SVG keyboard. And finally I was able to change the look of the keys (color, shape, etc) very easily with a couple lines of code. I was thrilled!

Unfortunately VML on IE was still kind of slow, and also had some occasional rendering problems. Still, this was far better than a huge set of static images, so I stuck with SVG for a while. When it came time to re-design the website with a new color scheme I was really thrilled to not have to update 100+ keyboard images in Omnigraffle again.!

Round 3 – CSS

With launch-time approaching, the speed issues with VML have really started to become a problem. Clearly, a predictive keyboard needs to be faster than the typist using it, and my keyboard was not keeping up. That led me to my third iteration- CSS.

Since my SVGKeyboard.java was created as an AbsolutePanel subclass, it was fairly straightforward to re-implement it in regular old GWT. Instead of an SVG rect, each key is now simply an AbsolutePanel, with InlineLabels for keycaps.

Implementing the “selected” coloring is as simple as adding and removing a CSS style that specifies the color and background-color. I was even able to make the keys look rounded with the following bit of CSS magic:

-moz-border-radius: 4px;
 border-radius: 4px;

It’s perhaps not as pretty as my original Omnigraffle drawing, but that seems a small sacrifice to make for ease of maintenance, should I decide to tweak the design in the future. Plus there’s the performance improvement- typing really flies now!

CSS Keyboard

final keyboard design, rendered entirely via CSS

Posted in GWT, Technical | Leave a comment

Introducing Quick Brown… Frog?

I’m working on a new consumer-oriented webapp for touch-typing lessons. I’ve been very much inspired by Patrick McKenzie of Bingo Card Creator fame, so you will find some obvious similarities between our approaches and target audience. This blog will document both the technical and business aspects of bringing Quick Brown Frog to market.

So, why typing software?

Typing software has been around forever, and there are some excellent, well-known packages for learning how to type. But most of them are shrink-wrap products that you have to physically purchase and install from CD. The idea that you need to have a round piece of plastic shipped to your home in order to install a piece of software is really an anachronism in 2010.

Yes, there are some decent typing tutors on the web, but the ones that actually work half-decently are Flash or Java apps. I think I can do something in the modern browser, and without resorting to any plugins.

Tools

Additionally, once I’ve had a chance to go back and clean up and refactor my code, I hope to take the nuts-and-bolts scaffolding from my app and turn that into a product- a quick-starter way to create all the common things a consumer-oriented webapps needs, such as account creation, secure password hashing, “Buy Now” links, expiring downloads, etc.

Stay tuned for more news on that front, as well as some “how it’s built” type posts.

Quick Brown… Frog?

“Quick Brown Fox” was the obvious choice, but alas, there’s already an (iPhone) app by that name. QuickBrownFrog.com was unique and available, so there it is! It’s still quite heavily under construction, but feel free to visit and leave me some (much appreciated) feedback.

Posted in Business/Marketing, Typing | Leave a comment