Tag clouds look better sorted!

October 31st, 2007

I like the idea of tag-clouds and tags in general, but I had problems making them look good in becontrary.com. I experimented with changing the relative size and blending colors, as well as with the huge number of visual tweaks you can do with CSS, but the amorphous blob of words just didn't seem to fit with the nice neat columns I had. Until, that is, I sorted the tags by popularity, which made it a lot neater and enhanced the effect of blending the font size / color. I don't know why it didn't occur to me before. I don't see many sites doing this, most tag clouds are sorted alphabetically.

The image below shows a tag-cloud sorted by popularity (left) and just alphabetically (right). Which one do you think looks better?


(Click for a larger image.)

Update: A few people have commented that without alphabetical order it is difficult to pick out a tag you are looking for. Personally I have never used a tag cloud like that, its usually just a starting off point to explore the site. If I wanted something specific I would use the search function. Even if the tag-cloud is used to scan for specific tags, it becomes redundant if you have so many tags that you can only show a subset, which is the case for becontrary.com. So I chose form over function, consequences be damned!

Creating debates open to everyone

October 28th, 2007

I've added the ability to becontrary for users to add their own debates. The debate regarding Python templates was quite successful so I hope Pythonistas will take advantage of this new feature to discuss Python-related topics. There's no restrictions on topics though, so feel free to create a debate on any topic. I think it is a great way of gathering opinions.


Is there a CSS expert in the house?

October 28th, 2007

I've noticed that links in becontrary.com that have have a fragment (i.e. something after a #) don't always go to the exact location of the named anchor. I figured this was a Firefox bug originally, but I see the same thing in other browsers. I believe I have figured it out though. The browser changes the scroll position after the html is read, but before the stylesheets have been read. Once the browser has the CSS information the page updates, but because the CSS contains the dimensions of some elements, the named anchor changes position -- but the scroll position doesn't update accordingly. At least thats my working theory.  The only solution I can think of for this is to make all my style sheets inline -- but that would mean I wouldn't have the cache-related benefits of having them external. I can't be the first developer to be irritated by this. Can anyone offer a solution?


You heard it here first!

October 20th, 2007

They say that in every day, you will use at least one sentence that has never been uttered before. I think this may be true of the Internet as well. According to google, the phrase 'telepods of doom' was used on the Internet for the very first time by me! Now if only I could somehow get it in to common usage and be immortalized... Telepods of doom you later!


BeContrary out of Beta

October 20th, 2007
BeContrary.com seems to have been well-received. There hasn't been a huge amount of visitors, but I do have some loyal regulars that have made some great arguments. The site was on a few of the social bookmarking sites, which caused spikes in traffic. Annoyingly though, not all social bookmarking sites are created equal in terms of getting visitors. Visitors from Stumbleupon for example had a high bounce-rate because of its random site button. Other sites like metafilter.com and the Dilbert Blog brought more genuinely interested visitors.

The site was also the subject of a bit of vandalism. One user was repeatedly posting page after page of garbage text. Another user posted an argument where he professed his desire to perform fellatio (in slightly different terminology), which was kind of off-topic. So I hurriedly had to implement some anti-jerk technology to prevent flooding. I also had to add the ability to the admin page to completely wipe a users arguments / comments, something which I had naively thought I wouldn't need. The truth is though, that this type of site is vulnerable to vandalism, and if somebody wanted to make a nuisance of themselves then it wouldn't be difficult. All I could do is retroactively clean up the mess. I've had no problems with spam so far, because I implemented a number of anti-spam measures that using javascript to present different content to users than would be seen by a bot. It would be quite easy circumvent, but I can change the technique if spam becomes an issue -- or implement a captcha solution.

Turbogears and Webfaction hosting have consistently performed well, even when traffic spiked. I suspect that the number of visitors has never even come close to critical mass though, so perhaps my optimizations were a little premature. The content is mostly text-based and the largest page (the front page) takes up a meager 64.1K -- I've written emails bigger than that!

The XML or Text for Python Templates debates was quite popular for a while and has many compelling arguments for either site. I think I will try to include a number of Python / geek related debates. Some of the arguments in other debates people come up with are very funny. The following are two of my favorites:

" I would no more use a "Telepod of Doom" for transportation than I would a "Bus of Pain", a "Rickshaw of Destruction" or a "Personal Time Capsule of Discomfort". - In Telepods of Doom.

" Women are financially insolvent breeding mules. To expect that mewling milk spouts could afford the sort of meal required to flatter them is sheer fantasy. " In Going Dutch.

I have officialy declared the site non-beta, although I imagine I'll be tinkering with it for several weekends to come. Now I'm thinking about promotion. I really don't want to spend money on advertising, so I'd appreciate any suggestions of how to get more visitors!


XML or Text for Python Templates

October 15th, 2007

There are a number of (very good) templating systems and languages available for Python. They fall in to one of two camps; either they are XML based, like Genshi, or they are text based, like Mako. Most programmers favour one or the other, but there is far from a consensus over which is better.

I'd like to use this debate to gather reasons for using one over the other in the context of web development. I suspect there will be no clear winner, but it should serve as a useful resource for those faced with the decision!


Timed Caching Decorator

October 14th, 2007

Here's the caching decorator I mentioned in my previous blog entry about optimizing the front page of becontrary.com. It is pretty simple to use, you supply the same parameters to it as timedelata. So @timed_cache(minutes=30) would cache the result for half an hour. It is thread safe, so you can happily use it in the context of a web application, such as Turbogears. For many things it is a magical one-line speed-up, but there are some issues to be aware of. You can't use it to cache anything where the return value is context sensitive, such as SQLObject class instances -- because they are tied to a database context that wont exist at the second call. If you do want to cache such objects, then you should copy the information you need to a dictionary. Genshi templates make the difference completely transparent, so it is not much of a problem. Another issue is that parameters must be immutable, because they are used as keys in a dictionary.

from datetime import datetime, timedelta
from copy import deepcopy
from threading import RLock

def timed_cache(seconds=0, minutes=0, hours=0, days=0):

    time_delta = timedelta( seconds=seconds,
                            days=days )

    def decorate(f):

        f._lock = RLock()
        f._updates = {}
        f._results = {}

        def do_cache(*args, **kwargs):

            lock = f._lock

                key = (args, tuple(sorted(kwargs.items(), key=lambda i:i[0])))

                updates = f._updates
                results = f._results

                t = datetime.now()
                updated = updates.get(key, t)

                if key not in results or t-updated > time_delta:
                    # Calculate
                    updates[key] = t
                    result = f(*args, **kwargs)
                    results[key] = deepcopy(result)
                    return result

                    # Cache
                    return deepcopy(results[key])


        return do_cache

    return decorate

if __name__ == "__main__":

    import time

    class T(object):

        def expensive_func(self, c):
            return c

    t = T ()

    for _ in xrange(30):
        t1 = time.clock()
        print t.expensive_func('Calling expensive method')
        print "t - %i milliseconds"%int( (time.clock() - t1) * 1000. )

There are some other things to be aware of. Naturally it will use up more memory, because a copy of the result is stored for each combination of parameters. And the standard disclaimer applies, that you should check if there is actually a speed-up before using it in production code.


Caching Aggregated News Feeds

October 13th, 2007

Did some work on becontrary.com today. The front page was a little dull and had a bounce rate of 49.8% according to Google Analytics, which means that almost half of the visitors that land there don't go any further. Previously the front page just displayed a news feed and some recent arguments and comments, I change it so that the feed in the main column aggregates the content from the debates so that in addition to news, it also displays new debate topics and arguments. The result is that it the front page should contain much more interesting content that will tempt visitors to explore the site.

I also made the BeContrary aggregated content available as an RSS feed, which makes it very easy for me to keep an eye on activity in the site. Hopefully it should be entertaining for visitors as well. Turbogears makes it laughably simple to add news feeds with the FeedController class. You simply derive from it and supply a method that returns the feed content. The controller does the work of producing the XML and serving it with CherryPy.

Because the changes would increase database access, I wrote a caching decorator for methods that return site content which doesn't need to update very often. If the decorated method is called within a definable period of time, the decorator returns a cached copy of the return value rather than building it again. Using this decorator I was able to reduce the database calls for the front page to zero for most requests (it updates every half an hour). This should come in handy if I get Slashdotted, Reddited or Dugg. Come to think of it, I could use the cache decorator on most of the site content. Even if the cache time was set to one minute it would be worthwhile for serious traffic. If I were to get 10 requests in a minute, it would reduce database access to one tenth! I'll probably blog the decorator at some point.

I seem to be finding a lot of time for my blog and hobby projects lately, because my TV broke! Rest in peace, my widescreen friend.

Update: I blogged the decorator code.

I Sold Out!

October 10th, 2007

I have officially sold out, by enabling adverts on becontrary.com. I think I have made them quite subtle by using the same color scheme as the site and fitting them in to existing column sizes. There is a fine line between collecting some revenue to pay for expenses and scaring away the people that provide the content, so I would be interested in hearing peoples opinion on adverts in general.


Convince Me to Be Contrary

October 10th, 2007

I just came across a site that is remarkably similar in concept to becontrary.com, called convinceme.net. I don't think it existed when I started work on my site. Like becontrary.com, they have dual columns for arguments and voting, but it is more competitive than my debating concept, which about arguing purely for the hell of it. They also have a slicker looking design, obviously created by a real web designer rather than a coder working on it in his living room. Oh well. I guess competition isn't necessarily a bad thing!

Search for Posts
© 2008 Will McGugan.

A technoblog blog, design by Will McGugan