Thursday, July 24, 2008

Django: Error while importing URLconf 'django.contrib.admin.urls': No module named urls

(permalink)
I didn't see a lot on google about this error so I thought I'd post something. If you're getting it, it's likely you updated to the latest Django SVN release, and haven't upgraded your admin site's configuration.

Read more here: http://code.djangoproject.com/wiki/NewformsAdminBranch

Thursday, July 03, 2008

One button sign up (continued)

(permalink)
There have been a number of comments about my previous post a one button sign up. I thought I'd re-post them here and clarify.

OpenID is easier: http://openid.net/

OpenID is easier and it's not mutually exclusive to what I'm suggesting here. OpenID or not, many websites will still need to collect additional information. The idea is not to force the user to give you that information in order to use basic site functionality.

If a user sees an auction ending in 1 minute but is then required to jump through some hoops before bidding - thats just as bad an experience.

You're right - so maybe eBay should require accounts just to browse listings? Obviously, that idea doesn't make sense. You shouldn't force the user to sign up early just so that in the off chance they want to bid on an item that's ending soon, they can.

Instead, I'm suggesting you give the user as much access to the site as possible, as soon as possible. Prompt the user for additional information with messages like "Update your address for quick bidding." If your users decide to wait, that's their decision - don't make it for them.

I want to feel involved. Plus, if I'm using a website to the extent that I'm going to want a username and password I pretty much expect that I may have to fill out more information upon registration so it is not as bothersome.

I disagree. Long and tedious registration forms are a horrible way of involving the user. The less information a user needs to enter for the same functionality, the better.

By giving people random user names, you force them to do more work long term.

Step 1: Click the one button and get my user name Step 2: Go write it down somewhere Step 3: Cookie expires/is cleaned - now user forgets the random user name or email. Step 4: Go look it up, enter info


The user should never actually see (or need to remember) their random username. What I was referring to is simply a unique backend identifier. Tracking a user without a username isn't that radical - even Amazon does it.

Amazon (and other stores) do one button sign ups

When I first visit Amazon, the site gives me as much functionality as possible. I can look at products and even add them to my cart - without logging in. Like I was suggesting - Amazon does upsell for more information, prompting you with messages like "Sign in to turn on 1-Click ordering."

After I've visited a product page, I'm in Amazon's database. In this example, simply viewing a product is the equivalent of "signing up" - even though the user doesn't realize that. That's great. Sign up buttons don't always have to be big and green. Ideally, the first step of the sign up process should occur transparently.

Every time I return to the site, Amazon recognizes who I am and suggests similar products to ones I've already viewed:



Now, if I choose (or am required) to create a login, Amazon seamlessly associates it with all my previous "anonymous" data. For example, I still have my previous browse history:


By making it as easy as possible to start using the site, creating a "transparent user" to track my history, and up-selling to gather more information in order to gain additional functionality, Amazon is doing almost exactly what I described in the previous post.

But why limit this process to online stores which by their nature must collect most user information during checkout? Every site should collect as little information as feasible and do it as late in the user experience as possible. That's the whole premise behind one button sign ups.

Wednesday, July 02, 2008

One button sign up

(permalink)
I've stumbled across a new sign-up process: one button. That's it. From now on, the user will only have to click a button on all of my new projects to sign up.

"But Sam," you might ask, "How will you collect user information?"

Easy. Ask for it when you need it. If you only ask for the user's address when the user wants to do something that requires their address, then you have a carrot to encourage the user to give you that information.

If you ask for the address up front, then not only does the user have little incentive to give it to you, but you discourage the user from signing up at all

Take, for example, ebay's registration form:



Does ebay really need my address if I just want to watch an item? Requiring me to fill out all this information just to preform basic actions (like watching an item or searching closed auctions) discourages me from using the site at all.

Why not not create a "one button" sign up with a default user account and random username? Allow me to use as much of the site as possible, while asking for (but not requiring) information to gain additional access.

"But Sam", you counter again, "what if the user forgets their random username?"

That's easy, authenticate with cookies and/or a unique URL (see craigslist). At the same time, prompt the user (maybe at the top of every page) for a unique username or email address for logins.

EDIT: I've continued this discussion in my next post, One button sign up (continued)

Monday, June 23, 2008

Free Mohammed Maree

(permalink)
By now, you've all probably heard of James Buck - a university student jailed in egypt. After twittering that he was arrested, friends, journalists, bloggers and many in the online community rallied for his release.

While it's nice to see the world unite behind such a good cause it's unfortunate that James' friend (Mohammed) hasn't received the same level of attention.

Needless to say he's still in some Egyptian jail, having endured several weeks of torture: http://jameskarlbuck.com/


Interested in helping? Check out James' blog

Labels:

Wednesday, June 18, 2008

Well I cancelled embarq... and I now have a new ISP

(permalink)
My new ISP
My new ISP,
originally uploaded by odiosam.
I've had embarq for about 2 years, and I think I'm fed up with them. I was paying ~$200/mo for business class DSL with a few static IPs. For that price, the connection should be FAST and rock solid.

It wasn't.

After about a weekend of downtime (which caused a permanent 35% decrease in BluWiki's traffic) - I was done. Here's my solution: I'm hosting my servers on slicehost for ~$130 / month, and for my personal internet, well, I'm using my friends' connections :)

In the attached photo, you see what I came up with to facilitate doing that.
Parts include:
- DLB 2300 Deliberant AP (no longer sold, had this laying around)
- Buffalo WHR-G125 (not sold in the US, you have to buy it off ebay)
- U.FL to RP-SMA adapter (for the buffalo's antenna)
- Hawking Hi-Gain Directional Corner Antenna 15db
- Yagi 2.4GHz 14.5dBi
- 4 port switch
- Power strip
- Cheap tripod

Basically, I followed the instructions over at i-hacked (www.i-hacked.com/content/view/261/42/), except I substituted the WHR-G125 for the router and the 90 degree corner antenna instead of the yagi. This setup will scan within a 90 degree radius for the strongest open network.

I then use the DLB 2300 in WISP mode to aim the Yagi antenna at the network and repeat it on the switch.

I've decided against repeating the network wirelessly to eliminate any WIFI interference.

It works pretty well :)

Wednesday, June 04, 2008

Error creating thumbnail: /path/to/wiki/bin/ulimit.sh: xrealloc: ../bash/subst.c:514: cannot reallocate 512 bytes

(permalink)
MediaWiki's software was giving me this error, and I couldn't find a solution on google. I thought I'd post one.

I was able to fix the problem by moving the bin folder to bin.bak, downloading a new copy of mediawiki, and copying the bin folder from the new installation.

I suspect that the error occurs when you set the permissions on ulimit.sh to global read-write (777). The ulimit.sh in the new bin directory was set with limited permissions:

total 20K
-rwxr-xr-x 1 root root 88 Jun 5 04:18 svnstat
-rwxr-xr-x 1 root root 52 Jun 5 04:18 ulimit-tvf.sh
-rw-r--r-- 1 root root 53 Jun 5 04:18 ulimit.sh
-rwxrwxrwx 1 root root 53 Jun 2 01:54 ulimit.sh.bak
-rwxr-xr-x 1 root root 48 Jun 5 04:18 ulimit4.sh


Correcting the error may be as easy as changing the permissions, but if that doesn't work, you can follow the steps I outlined above.

Labels: , ,

Tuesday, May 27, 2008

a quick tip: the disk "name-here" is in use and could not be ejected

(permalink)
Under Leopard I seem to get this error relatively often when I'm trying to eject my external disks. Even after quitting all my applications, the error doesn't go away. I never want to disconnect my drive without unmounting it (maybe it's an OCD thing). Here's my solution:

First, get the device name of the drive: Disk utility > Select volume > Click Info > Then note the disk identifier.

Open up terminal to check which applications are using this drive (substitute your drive name):
lsof /dev/disk2s10


Quit (or kill) all the processes that are using the resource. If nothing is returned (as is frequently the case with me), then force umount the drive (substitute your drive mount point):
sudo umount -f /Volumes/Backup


I'm adding this because the man page on umount doesn't document the force (-f) option.

Labels: , ,

Saturday, May 17, 2008

Extending the user model: profiles in Django

(permalink)
I think the documentation about using profiles & the get_profile() function isn't as clear and/or elegant as it could be. The problem with django's recommended implementation of profiles is that when a user is created, a user's profile isn't automatically created - it's not part of the same model. Managing the two can be tricky - if you mess up, you're bound to get ObjectDoesNotExist errors.

My solution was to never use get_profiles() directly - but instead add a helper method where any ObjectDoesNotExist errors are caught and resolved:


First, create a profile class in models.py:
from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
    karma = models.IntegerField(default=1, core=True)
    url = models.URLField(default="", core=True)
    user = models.ForeignKey(User, unique=True)

Note, if you want to be able to create profiles using the Django admin interface, change the last line to the following:
user = models.ForeignKey(User, unique=True, edit_inline=models.TABULAR, num_in_admin=1,min_num_in_admin=1, max_num_in_admin=1,num_extra_on_change=0)


Add this line to settings.py:
AUTH_PROFILE_MODULE = 'core.UserProfile'

(change your line to 'appname.ModelName' - note, do NOT include your project name or anything else. Just your application name and model name (the model name is UserProfile, unless you change it).

Finally, add to views.py:
from django.contrib.auth.models import User
from project.core.models import UserProfile
from django.core.exceptions import ObjectDoesNotExist

def get_or_create_profile(user):
    try:
        profile = user.get_profile()
        except ObjectDoesNotExist:
        #create profile - CUSTOMIZE THIS LINE TO OYUR MODEL:
        profile = UserProfile(karma='1', url='http://example.org', user=user)
        profile.save()
    return profile


Now, in views.py, to access a user's profile, you only need two lines:
user = User.objects.get(pk = user_id)
user.userprofile = get_or_create_profile(user)


And, say if you wanted to change a value:
user.userprofile.karma += 1
user.userprofile.save()


Easy, eh?

Labels: , ,

Wednesday, May 14, 2008

SICP and promises

(permalink)
A few days ago I blogged about be working through SICP in ARC. I was going to track my progress on bluwiki.

My personal goal was to make some progress every day. That hasn't happened.

I'm thinking about abandoning ARC, and just working through SICP in scheme. Scheme & ARC are remarkably similar, it seems the only difference is semantics. It'd be a lot easier scheme, since I wouldn't have to translate all the problems. Also, the language is more mature - so I suspect the libraries are more robust.

We'll see - I'm going to take a crack on SICP 1.2 and 1.3 this weekend, and I'll make a decision after that.

Labels: ,

Tuesday, May 13, 2008

One concrete tip for the self-employed programmer (that procrastinates)

(permalink)
I just read an article about procrastination that I found interesting (mostly because I agree with it). Procrastination is great - as I explained in the comments:
... procrastination paid my way through school. When you don't start studying for tests until a few hours before, you suddenly find yourself with a lot of time on your hands.


Procrastination teaches you how to work efficiently under pressure - a very important skill to have. The experienced procrastinator becomes a pro at putting out fires, and ironically, quickly getting things done. So why do procrastinators fail at life? Partially because there isn't enough that absolutely needs to get done. Procrastinators need pressure.


So what's a procrastinator to do? Start fires.


In software development this translates to setting artificial deadlines. Make promises - and judge your performance by whether you keep them. Here are some examples:

  • Promise your mom that you'll blog at least once per week (I do).
  • Promise a new feature on your website by a specified date.
  • Make promises on your blog, to whomever will listen (if you don't keep your promise, publicly apologize too).
  • Promise your clients you'll have respond to their emails within 12 hours.


And here's my favorite example: find someone important to you and make them your boss (I've chosen my girlfriend). At the beginning of every week spend an hour with that person and explain to them what you're going to do in the next week. Make promises. Then, check in with them throughout the week, and at the end of the week, conduct a "performance review." It helps if you can create some sort of incentive to meet your targets (you can be creative here... ).

Labels: ,

Monday, May 12, 2008

My first attempt at a python/django application

(permalink)
You know that "a-ha" moment when yo finally get something? I think I might've just had it today. I've built my first (working) python / django application - and I think I'm actually starting to understand django & OO programming. I still have a long way to go, but it's a relief to get the hang of things.

Here it is: b l a c k l i s t e d - it's a fun little search box that will tell you if your name appears on a government watch-list. Pretty basic, but hey, what do you expect?

Labels: ,

Saturday, May 10, 2008

Now using DISQUS for blog comments

(permalink)
I've switched this blog to DISQUS for the comment system. Going forward, you might want a disqus account to post a comment (but it's not required!). For posts previous to this one, you'll be able to add comments either through Blogger or disqus.

Labels:

Thursday, May 08, 2008

(re)discovering IRC

(permalink)
Analog IRC
Analog IRC,
originally uploaded by thowi.
I've rediscovered IRC. I love doing this, there's a wealth of information on there. It's so much easier to get help if google isn't giving you any love. One word of caution: just don't abuse those who help you, and try to help others when you can :)

Here are the channels I currently hang out on, feel free to stop by & say hi:

#bluwiki
#elc
#startups
#python
#django
#arc
#gentoo
#debian
#bash
#rubycodejam
#lighttpd (these guys are especially friendly)
#friendly-coders
#gcj

If You Put That Picture On The Internet I'll Call My Lawyer

(permalink)
Awesome. I hope somebody recognizes this guy and tells him he's all over the 'net.

how to dive into web programming

(permalink)
I'm just starting to get serious about web programming, and I've done a decent amount of research about how to master it. I quickly articulated this advice in an email to a friend, and I thought I'd post it here:


Her question:
From: AM
To: Sam Odio
Subject: hi i'm curious..

Hi,

I saw that you're doing SCIP - so then I looked up what a functional programming language was, and according to wikipedia functional languages "have largely been emphasized in academia rather than in commercial software development." But it notes that you can use it for commercial use as well. So are you doing it just to learn or is to serve some future practical purpose?

I was just wondering b/c I always want to know what the best language to learn is (not that I have much of an intention of learning any sort of functional programming after getting extremely confused by your progress tracking on bluwiki) and I also know that this is all based largely on personal preference, but i'm still curious....

AM.


My response:
From: Sam Odio
To: AM
Subject: Re: hi i'm curious..

my suggestion:

1) learn an object oriented language & framework (I'm doing pything w/ djano, you can also do ruby/rails or php/symfony)
2) learn functional programming w/ SICP if you want to get good (CLisp, scheme, arc)

#2 will take a lot of time, and yield few direct results. But it'll help you understand what is capable w/ programming. Long-term results, not short-term. If you want ONLY short-term results, learn php/symfony. PHP is not completely object oriented, but quick & dirty.

-s


What does everyone think? did I give her the right advice?

Labels: , , , , ,