Why Software Is So Expensive
I started on a project for a client today and was reminded of why software is so expensive. I’ve had people say “it’s just a little bit of functionality, it should be quick to implement.” Well, sometimes it is, but frequently there is a bunch of stuff that you have to handle under the hood. So today I implemented a simple login screen, the kind any app is going to have. This is an iPad app, and due to later screens it needs to be in landscape mode.
This is about as simple a screen as it gets, and there is already a bunch of things that need to happen:
- The Login button actually should be disabled until it would make sense to login. (Of course, you could just pop up an error dialog if the input is not valid, but that is poor user interface practice. You should make it impossible for the user to make mistakes if at all possible.) This requires that...
- Every time the text in either the username or password changes we need to enable or disable the button, as appropriate.
- Of course, we need to remember to disable the button initially.
- And we need to disable the button whenever the screen appears, because if you logout and come back to the screen the button should be disabled again.
- Which reminds me, we need to clear the password field when we press the button.
- And we should disable the button while we are waiting for the response from the server. (Oops, I actually forgot to do this today.)
- Oh, wait, clearing the password field should do that.
- Oops, no, it doesn’t, because password.text = "" is not a keystroke, okay, put that back in.
- Actually, clearing the password field when we press the button looks like we send an empty password to the server. It looks a lot better to clear it after we get the response back. (I actually forgot to implement this today, and discovered this one when I added it to the code just now.)
- If we wanted to be really user-friendly, we would not clear the password if the problem was a server error (server not available, internal server error, user is in airplane mode, etc.), although that’s getting to be pretty edge-casey.
- You know... it’s kind of a pain typing in the username all the time on that touch keyboard, especially if it’s an email address, so maybe we should save the last username? Except that’s actually a security risk because someone could pick up the iPad and now they know one out of the two pieces of information. But, probably, who cares. Certainly not users! We could give the user the checkbox to save their username, but let’s be real, what user is not going to turn that button on first thing? Great, well that’s settled, add in some code to save the username and code to read it back in when the app first starts.
- Now once we push the button, we can send the request to the server—but wait: first we need to unhide and animate the activity spinner that tells the user that something is happening. Oh wait, did you put that in at the beginning? No? Ok, time-out: add the spinner, figure out how to get it halfway between the bottom of the password field and the top of the button so it looks good. Time-in: now we unhide and animate the spinner when the button is pushed. Then, when we get the response back from the server we need to stop the spinner and hide it. (Unless it hides automatically when it’s not spinning, but iOS’ spinner does not do that.) Make sure that the spinner stops if there’s an error, it’s easy to put the code in the if statement instead of out it.
- Speaking of errors—oh, we need a text label to display the
error. Ok, time-out—add the text label, hide it (or make it
empty), color it red—all right, time in. Hang on, this app will
also be released in the Chinese market right? (OMG, if I just had
one dollar from each Chinese person I’d be $$$rich$$$!!! Gotta go for the Chinese market!!!) Isn’t
red a lucky color in China? Uh, how about yellow for
warning? No, that’s not very visible on the white
background. Uhh, fire off an email to marketing asking about
it. They’ll probably forget, but China has stop lights with red
for stop right? They’ll probably understand. Hmm, what about
an icon in addition to the color? Well, now we’ve got to position
the icon next to the text, that’s a lot of work. Maybe there’s an
error icon in Unicode that we can just prepend to the text? Well,
there’s the WARNING symbol, but shoot, it’s yellow not red. Maybe
the NO_ENTRY symbol would work? Kind of looks like the iOS delete
icon, though. Hey, look at all these symbols they put in! Who’s going to use RECYCLING_SYMBOL_FOR_TYPE_6_PLASTICS?! Seems
like a waste to put that in all my fonts. What?! FUNERAL_URN? DIVORCE_SYMBOL?! I didn’t even know there was
such a thing! INVERTED_PENTAGRAM? Ha, Apple didn’t implement
that one in their font, it’s just a question mark in a box. They
did implement CHRISTIAN_CHURCH and SHINTO_SHRINE, though. Hmm,
you’d think the Unicode people would have included PAGAN_TEMPLE, given
how careful they were to have DOUBLE_MALE_SIGN, DOUBLE_FEMALE_SIGN,
MALE_AND_FEMALE_SIGN, even NEUTER_SIGN (to be inclusive of eunuchs, I
take it?). Right-ho, back to work, then. Uhh... let’s stick
with red for now.
[Aside: you could just throw up a dialog if something goes wrong.. You could even say “Error!” if you wanted to infuriate your users. Let me implore you, once you go down that dark path, forever does it dominate your users’ and coworkers’ destiny and they will will curse your name (or your unknown name, in the case of your users). Not only does the dialog disrupt your flow and require a tap, to acknowledge, it is completely unnecessary because you could just display the error in a label as described above and save everyone that annoyance. And good error messages will help you, because I assure you, you’re not going to get that login code right on the first try, or your wifi router is going to decide to stop giving you a connection three days from now after you’ve forgotten about the login screen, and you won’t notice until it fails, or the server team will forget to restart the testing server, or something and those error messages will save you a bunch of time. Trust me. And you’ll really thank me when your test users encounter a weird error and instead of the UI mysteriously not working, they give you a specific error and you go, “whoops, yeah, that’s right here” and you fix it in five minutes instead of going back and forth over two days trying to figure out how to reproduce it.]
- Whew, that was a surprising amount of work for something so simple. Oh, hey, the Chinese and German translations came back. Bother, the username and password text is in the wrong place. The Chinese is 1/3 of the size of the English so the right side of the text is a long way from the text edit, and the German translation is full of long words like “Donaudampfschiffahrtsgesellschaftskapitän” and runs on top of text edit, which aside from looking bad means that you can’t tap on the text edit because the label is on top of it and ignores the tap. The experienced developer will always right justify their text labels that are next to inputs to avoid this problem. (Hopefully you don’t need “Danube steamship company captain” in your German UI, because it’s probably going to go off the left margin no matter what you do.)
- Oh no! The iPad keyboard covers the text boxes, even on the iPad Pro (but only one in that case). Probably should have seen that one coming, but it’s easy to forget about while you’re typing on a keyboard. A quick fix is to make the “Return” button on the username start editing the password, and to press the login button if currently editing the password, but that’s not really a solution. Some googling around and some reading of Stack Overflow indicates that you need to listen for UIResponder.keyboardWillShowNotification and UIResponder.keyboardWillHideNotification, which you can use to get the height of the keyboard and scroll the view up whatever amount is necessary so that the text boxes are visible.
Despite being a software developer for about twenty years at this point, I still forgot about four of these today. And all this is just for simplest screen you’re likely to have...