I love how little design decisions can make a huge difference. The tangible changes may not be big, but the impact is enormous. Here are two examples of good design and bad design:
Evernote Login: Remember Me
I’ve recently been checking out Evernote (watch the video) recently and it seems pretty cool so far. If you want an invite, I have 10 of them :). It’s a pretty handy piece of software to keep track of random crap you encounter.
The login page looks pretty standard, username, password, remember me and submit. The beauty in the design here is subtle, but extremely useful. If you want to click the “Remember Me” button, you don’t have to click the tiny, tiny box. If you click the text, it checks the box too. This essentially quadruples the area that you can click!
It may sound obvious. It’s pretty logical to have the text be clickable, yet so many websites don’t let you do it. I don’t know how many times I’ve had to chase down that little checkbox just to select it. Making the text after it clickable is very simple to write in code; there’s really no reason it shouldn’t be clickable.
iPod Touch: Layout
A couple months ago, it was finally time to retire the iPod I had since high school. I had been waiting for a touch screen iPod to finally replace my old one. So far, I’ve been back and forth whether I really like it or not. Overall, though, I’m fairly happy with it. A lot of it has to do with it being gorgeous
One thing that has annoyed the bejeesus out of me is the placement of one of the buttons. It wouldn’t be such a big deal if it had more than two buttons. The iPod is shown below:
Now, this is a big problem when I want to do something craaaazy, like … put it in my pocket. The big problem is: which side goes down?
On/off button - wrong. If it goes down first, it can potentially continually turn on and off whenever I sit down or even when I’m walking. I’m pretty sure there were a couple of times my iPod died much earlier than it should’ve because of this
Earphone jack - also, wrong. This causes the base of the earphones I use to tear. Exhibit A:
If they were on the same side, there would be no problem!
For anyone who has known me for more than, I don’t know 10 minutes, would know that I am really lazy. I very much believe in the converse of the physics law “things in motion tend to stay in motion.” ie. if I’m sitting my ass in a chair, pretty be damn good to get me out of it.
However, recently, I’ve been oddly productive. I don’t mean at work either, but like in real life. What I’m referring to is some of the side projects I’ve been working on (exhibit a and exhibit b). Now, here’s a revelation I’ve come upon: It feels good to do stuff.
How does this relate to missed opportunities?
Muxtape.com has been getting some buzz around the net. It’s a pretty cool concept, upload a few songs, and be able to play the songs as well as link it with your friend. Simple problem, simple solution. Not trying too hard at all. It’s one of those ‘Web 2.0 startups’ that are bound to be bought out by a Google or Yahoo-types.
A few years ago, I had started develop this site called “hearphone”. Simple idea: upload a few songs, be able to play it, share the link with friends. Sound familiar?
I think part of the reason why I’m, you know, doing things is that it sucks that you miss an opportunity like this because you’re lazy. If you have a good idea, why not go with it? It sucks to regret not putting in the extra little bit to keep going.
Updated (05/08/2008 @ 9:37 AM): my thoughts about other “Mixtape” websites here.
For the two (rss) readers of this blog (according to my feedburner), exciting z0mg 1337 soop3r h4z0r n3wZ!! THERES A NEW BWONG.NET.
Yeah, I know, I don’t care either.
But I’m going to talk about it anyway. So the other day I thought “instead of sitting on my lazy ass, maybe I’ll do something productive,” which lead to the new bwong.net. Over the years, I’ve had grandiose ideas of what bwong.net would be. I could have a lot of things like projects I’m working on, books I’ve read, pictures, videos, A WINDOW INTO MY SOUL, peanuts, music, tiny kitten, and the like. Then, I realized that was all ridiculous. Why would I need a whole complicated website for myself? I have at most 3 things that are interesting about me, and those could be summed up in 1.734 sentences.
So I opted for a simple, straight to point design (if you can even call it a design). It has all I really care to share about me on the internet, and points you to places where you can browse if you’re intruiged. The only thing that is a bit interesting about the page is the “I currently dig” thing. It has nothing to do with digg, but is kind of a weird love child between digg, twitter and my tumblr.
So I wrote a quick little script in PHP do keep these little snippets of things I’m interested in, links I’ve found, categorized with little tags. The script only took an hour or two to write and couldn’t help thinking of DHH’s post about the Immediacy of PHP. Anyway, if anyone is interested in how I did it, it might be fun to write up, but only if anyone cares.
Anyway, that’s all. Enjoy, and I don’t care what you think, I think its pretty.
Since my last post (3 hours ago), I felt like the data in Unihan was great, but basic. Most Chinese “words” consist of more than one character. For example, the word “adult” is “大人”. And what do you know, there’s a database for that too! It’s called CEDict (wikipedia entry) and surprise surprise, its a flat file like the Unihan database is. This time, it’s a bit nicer to use:
Traditional Simplified [pin1 yin1] /English equivalent 1/equivalent 2/
中國 中国 [Zhong1 guo2] /China/Middle Kingdom/
I’ve written a(nother) quick python script that’ll convert this file into a(nother) sqlite database. Enjoy!
#! /usr/bin/python## A script to parse the CEDICT file into a sqlite# database.## Author: Benny Wong <bwong.net># Date: 2008.04.27importrefrom pysqlite2 import dbapi2 as sqlite
columns = ['Traditional', 'Simplified', 'Pinyin', 'Definition']
f = open('cedict_ts.u8', 'r')
p = re.compile('(.*) (.*) \[(.*)\] /(.*)/')
conn = sqlite.connect('Cedict.sqlite')
cursor = conn.cursor()
cursor.execute("DROP TABLE IF EXISTS Cedict")
cursor.execute("CREATE TABLE Cedict (" + ", ".join([i + " TEXT"for i in columns]) + ")")for line in f:
ifnot line.startswith('#'):
tokens = p.match(line)
traditional = tokens.group(1)
simplified = tokens.group(2)
pinyin = tokens.group(3)
definition = tokens.group(4).replace('/', '|')
cursor.execute("INSERT INTO Cedict (" + ', '.join(columns) + \
") VALUES (?, ?, ?, ?)", \
[traditional, simplified, pinyin, definition]);
f.close()
conn.commit()
Once upon a time I wrote an extension for Firefox where you could highlight Chinese characters and be able to right-click and “Pinyinize” the characters. It would then take the characters into Pinyin, the phonetic representation of those Chinese characters.
Now, the only way I could do that was to pretend to make a request to pin1yin1.com and parse the HTML page that comes back. That’s a silly way to do things. There should be a way/service where I could make a query, and have the results come back in a known schema, in JSON or XML or otherwise.
I haven’t been able to find one (if you know, let me know ) so I thought I’d see if I could make my own. I haven’t gotten that far, but I found out what database they were using. pin1yin1.com uses the Unihan database. The problem with that is is that its a flat text file where the lines look like:
<Chinese Character> <Key> <Value>
like:
U+340C kDefinition a tribe of savages in South China
It’s totally unusable in most situations so I decided to write a quick python (thanks Hila!) script to do this:
#! /usr/bin/python## A script to convert/pivot the Unihan.txt file into a sqlite# database.## Author: Benny Wong <bwong.net># Date: 2008.04.27from pysqlite2 import dbapi2 as sqlite
charmap = {}
keys = set()
keys.add('Character')
f = open('Unihan.txt', 'r')for line in f:
ifnot line.startswith('#'):
tokens = line.split()
key = tokens[0].replace('U+', '')ifnot charmap.has_key(tokens[0]):
charmap[tokens[0]] = {}
unichar = tokens[0].replace('U+', '0x')
unichar = unichr(long(unichar, 16))
charmap[tokens[0]]['Character'] = unichar.encode('utf8')
charmap[tokens[0]][tokens[1]] = " ".join(tokens[2:])
keys.add(tokens[1])
f.close()
keystring = ", ".join(key + " TEXT"for key in keys)
conn = sqlite.connect('Unihan.sqlite')
cursor = conn.cursor()
cursor.execute("DROP TABLE IF EXISTS Unihan")
cursor.execute("CREATE TABLE Unihan (key TEXT, " + keystring + ")")whilelen(charmap)> 0:
key, values = charmap.popitem()
columns = ",".join(values.keys())
cells = '","'.join(values.values())
sql = 'INSERT INTO Unihan (key, ' + columns + ') VALUES ("' + key + '", "' + cells + '")'.encode('utf8')
cursor.execute(sql)
cursor.execute("CREATE INDEX key ON Unihan(key)")for key in keys:
cursor.execute("CREATE INDEX " + key + " ON Unihan(" + key + ")")
conn.commit()
I haven’t worked with python much, so if this code is crappy, let me know and how to fix it I’m seeing when I’ll have time to actually create the service (if anyone’s interested!) but yeah, here’s the basis that I’m going to be using.
You can easily port this database over from SQLite to MySQL, PostgreSQL, etc. by using “.dump;”
Tie Domi’s total number of penalty minutes in his NHL career according to his wikipedia page, comes out to 3515 minutes. A quick Google of “3515 minutes in days” yields:
“2.44097222 days”
Two and a half days of Tie Domi’s life was spent in the penalty box.
My brother had told me this and I couldn’t believe it!
It’s been a beautiful weekend, not only because of the weather, but also because of the badassery of the Rangers eliminating the Devils. The Devils had no chance whatsoever because they suck and the Rangers are awesome (this is not an objective blog :-P). Why, you might ask? Well, for one, our very own Sean Avery provoked the nhl to change their rulebooks:
“An unsportsmanlike conduct minor penalty will be interpreted and applied, effective immediately, to a situation when an offensive player positions himself facing the opposition goaltender and engages in actions such as waving his arms or stick in front of the goaltender’s face, for the purpose of improperly interfering with and/or distracting the goaltender as opposed to positioning himself to try to make a play,” Colin Campbell, the NHL director of hockey operations said in a statement. sportsnet
Haha. Seems like a silly rule right? Who would do that? Well…
The fact that they had to make a rule because of this guy shoot him up a few notches in my book and proves Rangers == Awesome. A role model to kids across the country. No clowns at my next birthday party, I’m going to bring a Sean Avery.
Anyway, these antics went on throughout the series. Definitely very entertaining to watch. The Devils goalie, Martin Brodeur was so pissed by the end of the series that he refused to shake Sean Avery’s hand (video).
And how did Avery respond?
“Everybody talks about how unclassy I am, and fatso over there forgot to shake my hand”.
Yeah its been a while, but hey, its what i do. A lot a lot has happened since the last post (I’m apparently not a loser, who knew?) but I’m going to be lazy and leave you guys hanging and talk about random crap.
So recently, I’ve been on a total nerderiffic mood recently. “But benny, aren’t you always a nerd?” Good point, but believe it or not its even worse than usual.
Anyway, after listening to him talk, some reading, and messing around with git, I’m convinced its the right vcs for me (and you) and I havent even tried it!. Here are two points really stand out to me and just make sense:
Distributed and relatedly Local Commits - description here. Now, not having a central repository might seem weird at first, but if you think about it a bit, it kind of makes sense.
Having a centralized respository, as with subversion or CVS, means that any code you want to track will reside there. Thats all fine and dandy and I like that because there is a central place where my code resides. But what about the situation when you’re messing around with your own code and experimenting, but also want to keep track your changes. In svn or cvs, you would have to create a branch, track your changes there, and somewhere down the line, merged it all back together.
That, to me, seems very silly. I don’t see the need for my experimental changes, which I may very not use in the future, to be forever reside in the central repository. It dirties the repository and wastes space. I should be able to branch on my local repository, track my changes, and when the time comes, decide whether or not to merge them into my main branch.
But what if you want a “main” public repository that will have the de facto version of the code? That is also possible (and easy!) in git. If you do a quick google for “git public repository“, you find help in no time.
Linus also makes a valid point that if you’re disconnected, ie. on an airplane, there’s no reason why my revision control software shouldn’t be able to keep track of my code changes. Isn’t that the whole point of a VCS! In svn/cvs, the only way to commit changes is if you can access the repository, which can be extremely inconvenient. I want my vcs to track my changes, no matter where/how connected I am. period.
Separate orthogonal changes - have you worked on a project where you were making two independent changes? No? Well, that’s ridiculous
Anyway, for the rest of the 99.9% of people who have, a problem with most VCSs is that it is either: an atomic commit of the working tree, or atomic commits based on files. Let me explain.
In svn, if you do a svn status, it shows you all the files you have changed. If you have more than one logical change, like a new feature and a bug fix, you have to commit them at the same time (as far as I know, let me know if not!). So all the changes that you’ve made, whether they’re related or not, is committed. This doesn’t seem very logical to me. What if I wanted to put in the bug fix first before I polish the new feature a bit. I’m not sure how I would do it with SVN without some manual fiddling around. I stand corrected. I guess I haven’t used subversion (or forgot it :P) enough. whoops
This is partially solved by other VCSs, such as Perforce (what we use at work). In Perforce, there is an idea of “Changelists”. Changelists are lists where you can separate the files that you want to commit. Like in the example above, the files that are affected by the bug fix can go into one changelist, while the new feature can go into another one. Then I can commit the bug fix without having to commit the changes I made for the new feature.
But yes, there is even a problem with that! What if those two changes affect the same file? How can you commit the changes for the bug fix, without partially submitted some changes associate with the new feature? File level commits aren’t good enough.
Git to the rescue! Git allows you to pick and choose what content, not files you want to commit to the repository. Git lets you pick the changes you want to add to your index (which is like a changelist) before committing them. Controlling what content is committed, rather than the file, is much more logical to me.
There are many more things about git that are really pretty great, but those are the two that are most iimportant to me. Git’s popularity has been gaining momentum since Linus’ talk so I’m sure if you lookaround, you’ll find that a lot of people love a lot of different aspects of git, so I suggest you at least take a look at it if you’re using any type of source control.