Mike Eng User Experience Designer 401-234-4611
m@mike-eng.com
me on github

Digit Decoder Update #4

Sep 26, 2013

Screenshot showing Load and Save buttons

Part of an ongoing personal project. Here are all posts on the subject. Also, here’s the code at this stage and the working demo – which is now much more useful since you can save and load your work.

This is beginning to take the form of a real (yet simple) application. I implemented the ability to save one’s work, which is going to be crucial in order for this tool to be useful. I am starting to see the light at the end of the tunnel with this project, which is both exciting and pre-emptively disappointing to think that I will soon put away this labor of love and let it stand on its own. In that case, the good news is that I’m not there yet.

Saving

As I started solving more of the message, I wanted to be able to save my work and come back to it. I was hoping to keep the solution to this as simple as possible. I had become quite comfortable working on the front end and achieving everything I needed to do with jQuery and CSS. All the DOM manipulation as one solves the message is done in jQuery. My initial approach was to first encode all the HTML in the element that contains the message (including the original message in digits, the letter options for each digit, the solved words, the cursor, and the select element and next button at the position in which they appear) to a string using the handy window.btoa method, which I just discovered. Then, I wanted to append that string to the URL after a hash and show it on screen for someone to copy or bookmark and come back to. Encoding the elements to a string worked, but appending that string to a hash or even logging it to the console either didn’t work or took about two minutes. I discovered that the string was over 600,000 characters long.

At this point, I was fretting about how to make that string shorter. I thought I might have to separate out the solved words and the position of the cursor and select element (all the things that the user manipulates) apart from the initial message. This would involve some fairly heavy parsing on both the saving and loading (from a saved message) ends.

There was one other approach though – rather than trying to move that 600,000+ character string around with JavaScript, I might be able to save it to a database. This would require a lot of complexity I was hoping to avoid (MySQL, another PHP script, AJAX), but If it worked, then it would be worth it. I created a local database using PHPMyAdmin, hardcoded some fields into a MySQL query and used a jQuery AJAX call to write that string to the database. It worked like a charm. I have a new deep and abiding respect for MySQL.

One wrinkle I discovered when revisiting MySQL for the first time in a while is how much we as users of software take for granted what happens when one clicks “save”. We expect that action to create a new record if there isn’t one already, but if there is a record, we expect it to update that existing record. It is incredibly not-straightforward to do this in MySQL since there are two separate commands to achieve this: “Insert” and “Update”. One thing smooths this development process over quite a bit though is the “Insert… on Duplicate Key UPDATE…” method.

Loading

This part was pretty straightforward. I created a “load” button that took that 600,000+ character string from the database and decoded it back into HTML. For loading, I let the server do the heavy lifting for once – I did this in PHP using base64_decode.

The way I structured the data meant that the initial message and the user input were wrapped up in each other. This has implications for the future. If I discover a typo in the initial message and then fix it, this would invalidate any saved data. I thought about trying to separate it out, but this kind of bound relationship actually makes sense here. If the initial message originally said “43556”, and the user input contained “HELLO”, then I changed the initial message to “43574”, I would want to invalidate that user input. If I wanted to get fancy, I could be smart about which sections need to change and highlight those portions for the user to correct, but I’m not ready to get that fancy yet. This will just stress the importance of proofing the initial message that I input. I am considering crowdsourcing that proofreading to Mechanical Turk or the like since I can’t think of anyone I know who would be willing to subject him/herself to such drudgery as a favor.

Authentication

I have perhaps an overly optimistic hope that there may be someone else as crazy as I am about figuring out what this message says. To that end, I set out to allow multiple users to save their own versions of their messages. This required authentication.

I didn’t want to deal with the security liability of storing people’s passwords, so I set up authentication using OpenID. I used the LightOpenID PHP library, which worked smoothly in the included example code and was straightforward enough to modify. For now, I am only using the authentication with Google. After authenticating, I am storing the user’s email address in a session variable and then using that as the “username” in the database if the person chooses to save or load.

Lessons learned

It was interesting finding a path when navigating the JavaScript, the PHP, and the database. Initially, it was disorienting like being dropped into a wide open field. For example, I could implement the log out process asynchronously using AJAX or I could do it synchronously using PHP. First, I thought it would be nice to preserve the message on logout, so this pointed toward doing the logout asynchronously. As I walked through the process though, it seemed odd to be logged out but have my message still visible on the screen. This would be especially strange if people were sharing a computer and someone else came up to it and started from this leftover message.

Also, at the moment, there is a “load” button and a “save” button. This made sense when there was only one user, and these actions had to be explicit. However, now that there is authentication involved, it seems to make more sense to have “load” happen implicitly on login and remove the “load” button since it’s of no use after that initial load.

Next steps

Based on the above, I plan to couple loading with login and couple clearing the saved message on logout so that the ability to view one’s stored message corresponds with being logged in.

If someone begins solving the message and then proceeds to register, I want to preserve the person’s work and then reload it once login is complete. This means implementing a lazy registration pattern. This would need to create a new database row to store the message if someone has input data and then clicks “log in”. Then after login is complete, it would associate the user’s email address with that row that was just created and reload the message from the database.

I need to create a “message saved” confirmation and perhaps a “logged out” confirmation as well.

And I still need to implement the ability to erase a word.

Reply