February 2010 (1)
September 2009 (1)
May 2009 (1)
April 2009 (1)
March 2009 (4)
January 2009 (3)
November 2008 (2)
October 2008 (2)
September 2008 (1)
August 2008 (5)
July 2008 (3)
June 2008 (1)
May 2008 (5)
April 2008 (8)
March 2008 (3)
February 2008 (1)
January 2008 (2)
December 2007 (2)
November 2007 (4)
October 2007 (17)
September 2007 (9)
Sunday, March 22 2009
The other day I was reading Ryan Tomayko’s blog and I got inspired.
Ryan wrote the Kid templating library which drives this blog, and is quite the Python/Ruby hacker. He also has a very minimalist design. Its principles are outlined here.
With hypertext, the information itself is the interface. The content takes center stage while the chrome and tool areas are placed in the back-seat. This inversion of priorities has created as big a leap in interface innovation as the first graphical user interfaces did to the terminal based applications before them.
And yet, these fine attributes of hypertext are regularly subverted. Since the web’s inception and subsequent boom, people have been trying to get around hypertext’s “limitations” as an interface medium: first with Java Applets and Active X controls, later with Flash sites, and today with Rich Internet Application (RIA) platforms. There was a time when sites were authored with the goal of preventing the vertical scroll-bar from ever appearing! The goal is always the same: invert the web’s superior content-oriented interface back to the GUI era and allow for the types of administrative debris so common and accepted in desktop applications.
I have applied them over on my other channel. (I also made a bunch of other improvements, like per-tag RSS feeds, and better 404 handling.)
I often have rude things to say about other people’s usability, so it feels good to get my own house in order. I am interested though in whether there such a thing as best practice design for blogs. For example, are “recent comments” widgets useful? Should you have whole articles rather than excerpts on your home page, and if so, how many? I don’t know, but I’d like to.
Naturally, this blog is still untouched and looks like pus; in fact owing to changes made for the other channel, it’s worse than before. This will not be the case for long.
Tags: usability ~ burble ~ ryan tomayko ~ catalyst
Monday, October 22 2007
A few weeks ago I set out to write myself a blogging engine, which I have dubbed “Burble”. The motivation was partly to get off Blosxom, which I’d been finding pretty limiting, but mostly so I could come to grips with developing Python web applications.
And now I’m done. It was surprisingly easy. I’m even running on my own tiny frameworklet, which I have called Whisky, after WSGI. I’m going to put the code online soon, not because it’s ready for other people, but as an example (or a warning).
It’s pretty damned zippy too, even with all my old content from the other site. Network latency is by far the biggest factor in Burble’s performance. I’ve done my best to tweak that by turning on compression in Apache and minimising the markup. I have found YSlow invaluable for this.
(It’s worth a post on its own, but by judicious use of mod_deflate and mod_expires, guided by YSlow, I managed to get one of our indispensible extranet apps at work loading in less than 5 seconds, down from about 20, rendering it far, far more usable.)
Now I have to find something else to do. I think the Ruminator is next. I have plans to use some stemming software and a bit of Bayesian analysis and a better visual representation that indicates links between stories.
Tags: burble ~ web development ~ yslow ~ apacheUsability, or, Physician, heal thyself
Tuesday, October 16 2007
Burble has a nifty comment spam preventer, the details of which need not detain us here. But anyway, the spam-resistant comment process does require an extra step. This is partly to fool robots which mindlessly submit and then go away, and partly so I can do some magic.
I had Iabelled the buttons for the three steps Preview → Save → Confirm. That matched my mental model and the labels I had given these steps in my head.
A little log file inspection revealed that a couple of people had abandoned comments at the Save step. And I realised that by using the word “save” I had given the impression that the user’s comment was already persisted at the second step (it isn’t).
I have fixed the button labels to reflect what’s really happening. They are now Preview → Confirm → Save. And lo, now I have comments.
Tags: burble ~ usability ~ web developmentA tiny WSGI framework in an hour or two
Sunday, October 14 2007
I’m not sure whether the first story here is meant to encourage or dissuade, but I am writing my own WSGI framework to support Burble. Colubrid is holding me back, and its replacement Werkzeug is overkill for what I want. (To be fair, Colubrid has been a great help to me in getting started.) I’m really getting into the educational aspect of doing things from scratch where I can.
It turns out that putting together a very lightweight WSGI framework is very easy indeed, especially having made a small compromise by using a few pre-built things from Ian Bicking’s Paste. (Yeah, I contradict myself. I am large, I contain multitudes.)
It’s so easy that I’m almost done, so I present a tiny, noddy framework for your reading pleasure. It implements a regex-based URL dispatcher a la Web.py.
#!/usr/bin/python
from paste.request import parse_formvars
from paste.response import HeaderDict
import re
def attrsfromdict(d):
"""From Python cookbook s6.18 p 280"""
self = d.pop('self')
for n,v in d.iteritems():
setattr(self, n, v)
def simplerepr(obj):
d = obj.__dict__
members = ', '.join([n + '=' + v.__repr__() for n,v in d.iteritems()])
return '%s(%s)' % (obj.__class__.__name__, members)
class NoMatchingControllerException(Exception):
pass
class Request(object):
def __init__(self, environ):
self.environ = environ
self.fields = parse_formvars(environ)
class Response(object):
def __init__(self,
status_code='200',
response_phrase="OK", body="",
headers=HeaderDict({'content-type': 'text/html'})
):
attrsfromdict(locals())
def __str__(self):
return simplerepr(self)
def __repr__(self):
return self.__str__()
def status(self):
return ' '.join([self.status_code, self.response_phrase])
class Dispatcher(object):
"""
The Dispatcher maintains an internal list of regexes and controllers.
The Dispatcher accepts strings, and tries to match in turn against
the regexes. As soon as a match is found, the corresponding controller is
invoked.
"""
def __init__(self, regex_app_tuples):
self.dispatch_list = []
for k, v in regex_app_tuples:
p = re.compile(k)
self.dispatch_list.append((p, v))
def dispatch(self, request):
"""
Expects to call a Controller's instance method GET or POST
with the request and the groups obtained from the regex
as arguments.
"""
path_info = request.environ.get('PATH_INFO', '')
method = request.environ['REQUEST_METHOD']
for pat, app in self.dispatch_list:
mo = pat.match(path_info)
if mo != None:
args = [request]
args.extend([i for i in mo.groups()])
if method == 'GET':
return app.GET(*args)
elif method =='POST':
return app.POST(*args)
raise NoMatchingControllerException, "No match for %s" % path_info
class WhiskyApp(object):
def __init__(self, dispatcher):
self.dispatcher = dispatcher
def __call__(self, environ, start_response):
request = Request(environ)
response = self.dispatcher.dispatch(request)
start_response(response.status(), response.headers.items())
return [response.body]
class NoddyController(object):
def GET(self, request, id):
r = Response(body="Noddy got %s" % id)
return r
class BigEarsController(object):
def __init__(self):
print "in init"
def GET(self, request, arg1, arg2):
r = Response(body="Big Ears got %s and %s" % (arg1, arg2))
return r
if __name__ == '__main__':
from paste import httpserver
dispatch_list = [
(r'/noddy/(\d+)/?$', NoddyController()),
(r'/bigears/(.*?)/(\d+)/?$', BigEarsController())
]
dispatcher = Dispatcher(dispatch_list)
app = WhiskyApp(dispatcher)
httpserver.serve(app, host='127.0.0.1', port='8080')
That’s pretty much all I need, to be honest. I’m happy using Beaker for sessions, and I’ll probably pull in cookie stuff from Paste. I bodged up an Etag cache manager for Burble, which I want to integrate. I want to write a nice base class for controllers. And that’s it. Whee!
Tags: python ~ burble ~ wsgi ~ paste ~ programming ~ web developmentSunday, October 07 2007
It’s cutover time. I don’t think Burble is fully baked yet, but I need usage to smoke out bugs. This makes me anxious.
The old site is still around, but vital.org.nz is now backed by the same Burble instance that’s serving this.
Things I now have which I didn’t have with Blosxom:
not quite ready for prime time
Saturday, October 06 2007
A few things are still causing me headaches with Burble.
So near, and yet so far. It’s frustrating.
Tags: burble ~ mod_rewrite ~ hostingFriday, October 05 2007
I think I did it. (update: I changed the path when I finally cut over, so I’m fixing it here too.)
But I’m going to be a little cautious and leave the full cutover until tomorrow. Because I’m just a wee bit too tiddly to be wrestling with mod_rewrite at this time of night.
Mind you, given my normal experience with mod_rewrite, being totally trollied first might actually help.
Tags: mod_rewrite ~ burble ~ vital.org.nzWednesday, October 03 2007
I’m committed now to using Burble for two sites. I’m about halfway through refactoring to make this possible, and I’ve discovered that my choice of framework is making this a tedious chore.
Colubrid is by the authors’ own admission based on a misapprehension about how best to use WSGI, and they recommend that you use Werkzeug now instead. Unfortunately, I didn’t realise this when I started using it.
The fundamental problem is that various important thingies are set up and torn down with each request, and various things done after instantiation, such that your init methods break. So I am forced to cut and paste where inheritance would be better, or monkeypatch.
So my very next thing to do is get off Colubrid. It would be top of the list now, but I really am desperate to get vital.org.nz off Blosxom and on to Burble. I just like my own blogging tool so much more.
Tags: burble ~ python ~ colubrid ~ wsgiSaturday, September 29 2007
In my day job, we have a client who is in many ways a delightful chap, but who is frustratingly unable to make his mind up about what he wants. We make changes and then undo them. We implement features he asks for, and he hates them. We make suggestions, and he ignores them, and then two weeks later he demands they be implemented immediately. Naturally, this causes stress. In my weaker moments I find myself feeling a certain amount of resentment. Which he doesn’t deserve, since he cheerfully pays for everything, and I admire his perfectionism.
So anyway I’m finding it unnerving that I’m doing the same thing myself, on my own personal project. Suddenly, it is imperative that Burble be able to serve multiple sites (so I can use it for bazombo.com and vital.org.nz without running multiple instances) and ordinary non-blog pages (since what is a blog but a specialised CMS that focuses on a content asset’s date metadata? Might as well deal with other kinds of asset while we’re at it.) It is vital that I be able to turn comments on and off, even though I have never felt like doing that in four years of blogging. And maybe I should be instrumenting pages for dynamic usage statistics. And so on… anyway, it feels weird when your own hobby project has scope creep.
I pretty much have non-blog pages licked. I can create arbitrary pages and pick templates for them and build a search engine-friendly URL out of the title. I don’t have much use for them on bazombo.com though. They’re really for my content from vital.org.nz.
My ultimate plan is that vital.org.nz stay as my purely personal site, for trivia and babbling and news for Stephen’s Inner Circle; bazombo.com is meant to be a platform for various projects and schemes I’m cooking up, and technical, factual, informative blogging. But I’m discovering that Burble is so much nicer for me to use than Blosxom (which drives vital.org.nz) that I have to have it on both sites.
Tags: burble ~ scope creep ~ the bazombo media empireFriday, September 28 2007
When importing all my old content, I hit a snag. A lot of vital.org.nz has pretty broken markup in it. Burble’s templating system is strict XML under the hood, so any post or comment that contains broken markup causes burble to barf.
I discovered that there is a lovely Python wrapper for HTML Tidy. And there’s even an Ubuntu package. Problem solved.
>>> import tidy
>>> html = 'some <b>horrible<i> soup</b> which is nasty & yukky'
>>> options = {'show-body-only':'y', 'output-xhtml':'y', 'enclose-block-text':'y', 'enclose-text':'y'}
>>> body = str(tidy.parseString(html, **options))
>>> body
'<p>some <b>horrible <i>soup</i> which is nasty & yukky</b></p>\n\n'
Thursday, September 27 2007
I have whipped up a script that imports all the content from vital.org.nz into burble.
I wasn’t really planning on migrating that site over. Burble was meant to be a platform for some other things I’m cooking up, not a replacement for Blosxom. I just wanted to feel confident that burble would work well with a reasonable volume of entries and comments — and it does. Well enough that I’m wondering if maybe I shouldn’t go the whole hog and run everything on burble. That’d be kind of cool.
I’ve also fixed a little problem with Etags.
This is what my to-do list looks like for Burble:
Write query to retrieve posts by tag
refactor sql methods in model to do substitution and avoid SQL injection properly (see http://initd.org/pub/software/pysqlite/doc/usage-guide.html#executing-sql-statements )
Write template and handler for posts by tag
OpenQuestions
ComponentisedTemplates
Write query to retrieve posts by date
Write template and handler for posts by date
Refactor response so we can redirect
Write comment functionality:
– get sessions working
– design CommentProcessFlow
– design CommentDataAttributes
– write CommentAndCommentDAO
– merge CommentController and SingleEntryController (GET and POST)
– write CommentFormTemplate
– investigate turning forms into Entries.
– implement CommentProcessFlow
– implement AntiSpam
– retrieve comment count for entries
– hyperlink comment author names
– make anchors for comments
– we shouldn’t allow comments on nonexistent ids
– clean up session after comment post.
EtagManagementAsADecorator?
ArchiveCalendarWidget
TagCloudWidget
AdminAuthenticationDecorator
AdminConsole
BlogRollWidget
Tags should be able to have spaces
RecentCommentWidget
NonBlogPages
RSSFeed
implement TitleController
SetupOnTextdrive
Move methods out of model.EntryDAO into services
ImportOldContent from vital.org.nz
CachingStrategy
You can see there isn’t much left to do.
Tags: burble ~ softwareWednesday, September 26 2007
More progress: Burble now has an Atom feed. This proved surprisingly easy to implement. It’s just another template to pump a list of entries into.
Tags: burble ~ python ~ syndication ~ atom ~ templatesMonday, September 24 2007
Tweaked css so the top paragraph didn’t butt up against its containing div.
Sessions are now persisted in dbm instead of memory, and are properly disposed of after.
Started thinking about how to abandon Colubrid, which appears to be abandonware now, and whip up a micro-framework myself.
Tags: burble ~ colubridSunday, September 23 2007
I’ve learned about Apache bugs. I’ve learned about Etags. I’ve learned about Python.
This post won’t be sticking around for long — I’ve a lot more work to do on this first — but this will be taking over as my publishing wotsit soon.
Tags: burble ~ python ~ testing ~ i did it my wayRendered at 2010-03-13 08:55:22