My building, like many here in the fair City O' Fog, has a door entry system which calls a phone number - I can then buzz the door open using the hash pound octothorpe key. This is handy because even when I'm not home I can let people in. Or if I forget my keys then at least I don't have to wait around outside. The disadvantage is that I have to have reception. Ironically the worst place for reception is in the apartment. Also, quite often either I or my flat mate are abroad so if you phone one of us then it might well be silly-o-clock where we are. So what I want is use something like Grand Central or maybe an install of Asterisk or Adhearsion set up with a phone number that calls multiple mobile phones when we're buzzed. However, there could also be a motion detector (or something that detected our phones connecting to the wireless) in the apartment so that it would also add the land line. Furthermore it could check our Dopplr feeds and work out if either of us were out of the country and then remove them from the "to call" list. Because, you know, having a door entry system you have to debug rather than just fricking work sounds like a wonderful idea.
And ooooooooooooh, the music puns get worse and worse. So, at work we stumbled across an interesting Perlism. Well, interesting if you're a huge nerd which, must as it pains me, I'm going to have to concede. Anyway, so Perl has the concept of a DESTROY method which gets called on an object when it's, err, destroyed. Also, in Perl, objects can be any kind of a blessed scalar value - usually it's a hash reference but it could be a blessed array, or a bless sub routine reference. Which is where we join the story. Observe this:
my $foo = Foo->new;
$foo = undef;
package Foo;
sub new {
my $class = shift;
return bless sub { print "Hello from Foo\n" }, $class;
}
sub DESTROY {
my $self = shift;
$self->();
print "Destroying Foo\n";
}
1;
We'd expect it to print
Hello from Foo
Destroying Foo But it prints nothing. How weird. However if we do this (note the $class in the print statement):
my $foo = Foo->new;
$foo = undef;
package Foo;
sub new {
my $class = shift;
return bless sub { print "Hello from $class\n" }, $class;
}
sub DESTROY {
my $self = shift;
$self->();
print "Destroying Foo\n";
}
1;
We get both statements printed. Freaky, ne c'est pas? So the reason, as far as I know is that DESTROY is only called when all references to the object are destroyed. Presumably for optimisation reasons, the anonymous subroutine in the first case is invariant and the new subroutine takes a reference to it and so the DESTROY is not called until the new goes away which it won't because the symbol table isn't wiped. So the reason why the second one works is that by referencing the $class variable the anonymous sub is upgraded to a closure and a closure gets a new copy for every instantiation and thus gets DESTROYEDed. It all makes sense if you squint at it askance but it's still the sort of thing that will trip you up.
After my last bit of Calendar fiddling I was left slightly disgusted by the state of the code. In my defence it was written over the course of a hungover Sunday afternoon but there was CGI and DBI code mixed up together, no DBI place holders and all sorts of other perversions and sickness. At least it was all templated, which is something. So I ripped out all the DBI code and put that in an abstraction layer and did the same for the handling stuff and then just generally had a cleanup which also ended up with it gaining a config file rather than hardcoded values, marked everything up as hCalendar and made it multiuser in the process. Because the DBI stuff was abstracted out it was pretty easy to add another provider which could read from iCalendar files both locally and remotely. To be honest, I was vaguely shocked when I plugged in my Dopplr feed url and lo and behold my trips showed up. So far so good. A neat, tidy, clean and simple to install calendar system that, whilst it only has the concept of all-day events, can read and export iCalendar (and copes with recurring events through that). Although I've also got code lying around for a more complicated calendaring system I've been using this system for the last 5 years and it works just fine. Two small bug bears I'm wrestling with. The iCalendar exporting is fine but I'd like to make it more flexible to output different formats, it's all a bit complicit at the moment. I'd also like proper caching. Oddly enough with this it's not the caching code that's the problem - it's the config file. Well, sort of. In concept it's very simple. At the moment we have two types of provider: DBI and iCalendar. Actually, if we look skewiff at it then we have 3 types: DBI, iCalendar and the one that takes the input from multiple providers. A cache would just be another provider and either sit after the multiple provider or in between the multiple provider and one of the other providers (probably a remote iCalendar provider since local iCal and DBI are fast enough). So far so easy but I'm trying to think of an easy way to shim this into my config scheme which is currently .ini file based and looks something like
[providers]
default = dbi
birthdays = ics
dopplr = ics
[default]
dsn = dbi:SQLite:calendar
user = username
pass = password
[birthdays]
# local file
file = birthdays.ics
[dopplr]
# remote url
file = http://dopplr.com/user/uid.ics I'm also not in love with the fact that providers' names are in there twice. I have pondered something like this
providers = default birthdays dopplr
[default]
dsn = dbi:SQLite:calendar
user = username
pass = password
type = dbi
[birthdays]
# local file
file = birthdays.ics
type = ics
[dopplr]
# remote url
file = http://dopplr.com/user/uid.ics
type = ics And then I could change it so that
[simplecache]
cache_dir = .cache
[dopplr]
# remote url
file = http://dopplr.com/user/uid.ics
type = ics
cache = simplecache which is doable but involves more complicity and blurs the abstractions since some classes are treated differently. It's kind of vexing that it's not the coding that's the problem, it's designing a clean architecture. It really interrupts your rhythm.
Last week I did a big refactor of some Java code, massively simplifying the flow and making things clearer, faster, more extensible and more secure. In general I'm hugely happy with it and I'm also pretty happy with my Java. It was a long time ago when I last did Java professionally and so this past year I've always been a bit wary that my code wasn't idiomatic. Idiomatic code, like patterns, is interesting. Sometimes brevity or whatever can and ought to be sacrificed for clarity. If nothing else then idiomatic code makes the next maintainer's job easier. And that could well be you. Remember, you always code for three people - you now, you in the future and the person who comes after you. And idiomatic code tends to integrate better with with external libraries (as long as they're largely idiomatic of course). Plus, they're usually idioms for a reason. So, the first cut at refactoring went incredibly quickly and I excised all the old baroque, rotten code that had built up as new wrinkles in underlying libraries came up and as old assumptions had been discredited and new requirements had come up. Not that the old code was bad it just needed a spring clean and a new wardrobe. I then rebuilt the functionality in a much saner way working to a general plan in my head and filling in the details as I went along. That went incredibly quickly - I had working code by the end of the first day and had filled out the details by the end of the second day. All in all, about a 5000 line diff. So far so good. Then I took a step back, sketched my class diagram on a white board and started thinking about making things more idiomatic. And in Java that means Interfaces. To paraphrase The Rhyme of the Ancient Mariner - "Interfaces everywhere and all the compilers did shrink. Interfaces everywhere and not a drop to drink. Because they're doing my head in and I have a powerful thirst for some alcohol". The debate about multiple-inheritance versus interfaces has been done to death elsewhere and by better, wiser and more scarily obsessive people than me. I've come across a few occasions when I could really have done with multiple inheritance but mostly I've been able to work around it and I can understand the arguments against it so we'll just leave it at that. But I'm beginning to wonder if I made a mistake. Should I just have left it at the old code with the leaky abstractions? Has separating it out into interfaces tricked me into over engineering things, made me jump through conceptual hoops which, whilst correct in a very 'pure' way have actually made things worse. A while back I was talking with someone about writing a book - "Java for Scripting Language Programmers". One of the things we talked about was the fact that programmers who are frolicking in a language which isn't their normal one will find warts that habitual users of the language never come across, in much the same way that a user can find a bug in 30 seconds that the programmer of an app hasn't come across in 6 months of testing - there's an underlying conceptual model and you instinctively steer away from doing stuff wrong "The bug happened because they tried to add a Frob to a Bleep! Why would they ever do that?!" [1]In short I'm wondering if my issue is because I'm trying to program Java like Perl. Or I expect Java to be like Perl and then get upset when it's not. Or maybe it's just that Bondage and Discipline languages are just annoying (although Piers Cawley once remarked "Perl let's you program in a Bondage and Discipline style ... it just lets you have safe words". I've often thought that programming is like Architecture - it's not for nothing that we stole the concept of a pattern language off Christopher Alexander's books "The Timeless Way of Building" and "A Pattern Language . Building a whole system is like building an estate with roads and parks and shops and places to live. You need some discipline because otherwise people just swarm everywhere and it's annoying to get everywhere but, ideally, adding new functionality in the form of a new building or communal area should be an easy task with an obvious course of action. However if the system is irritating to use you start getting ugly brown marks across the middle of your parks as people take short cuts across the grass. Sure you can then pave that path to prevent further damage but that screws up your design aesthetic and really it should have been obvious that was going to happen and the situation should have been dealt with in advance. In short I think you should accept that your users are going to occasionally want to do stuff that you never dreamed that they'd want to do. Or that occasionally breaking the rules will be necessary and should be prepared to deal with that. Give the programmer a mechanism to do it and at least let them know what the consequences are. More than once I've had to do #define private public
#include <somelibrary.h>which is obviously bad and wrong and has horrific long term consequences. Much nicer if I could that within a tight scope in much the same way Perl allows you to do {
no strict 'refs';
*$sub_name = sub { print "Hello World\n" };
}In short, trust the programmer and let him, her or it have enough rope to shoot themselves in the foot if they really want to. They may have a damn good reason and it's not up to you to second guess them, only to give them a warning then let them get on their merry way when they brush you aside. Actually, what I should be doing is finishing off this code instead of procrastinating about it on LJ. But there you go. [1]Apparently it's not uncommon for tourists to blunder into riots happening in cities whereas natives subconciously stay away, warned off by environmental clues. A little trivia for you there. Read "Sources of Power" by Gary Klein. It's really good.
Que geek! That overwhelming urge to automate your life using nothing more than a rag tag collection of Perl scripts, RSS feeds, chewing gum and lollipop sticks. I'm convinced that if I had children they'd be read bedtime stories using a combination of Festival and Project Gutenberg. Hmm, thinking about it - maybe that's why I was subjected to compulsory sterilisation by the state. Anyway, I present tv2feed which turns a list of TV programs into an Atom feed of when they'll next be on. Shouldn't be too hard to augment it to put in season and episode number and the scour various torrent sites a day or so after and start downloading them. Not that I'm advocating such a thing. I'm just saying. TV piracy is bad and wrong.
I finally got to do a bit of hacking this evening and noodled around with Net::Social. I'm not entirely sure on the name but this module will probably go nowhere since it's mostly just satisfying my curiousity. I currently have plugins for LJ, Vox, Flickr and Dopplr working. If the underlying CPAN modules weren't horked then I'd have Orkut and Gmail too. I'm waiting on some clarification on one of the Jabber modules and then I'll have Jabber Roster support too. And Paul Mison contributed a Twitter plugin. I think del.icio.us, MySpace and FaceBook support will probably be next. Net::Social doesn't really do anything clever - each plugin defines what parameters it needs passing in to do its work and then exposes a friends() method that returns a list of hash refs which contain information about each of your friends. At the moment the plugins only populate a 'user' field but I can see stuff like 'real_name', 'private', 'mutual' being filled in. Then, on top of that, I'd build a DB backed Web App which would use Net::Social to populate its tables when the user adds their credentials for each site. It's all a bit hacky but its been a fun few hours and its exposed the rather parlous state of web API authentication. I should clean the code up, add some docs and maybe write some coherent thoughts on what I've learnt but for now I'm going to have some hot chocolate and try and wind down in the hope of getting a decent night's sleep tonight.
Social networks. Kind of like Pokemon - gotta catch'em all, ya know. Same people, same faces, different website. LJ, Vox, Dopplr, Flickr, Twitter, Facebook, MySpace, LinkedIn, Orkut. Wouldn't it be handy if there was some tool for managing them all? It was supposed to rain yesterday and it was the London leg of the Tour De France, the British Grand Prix and Wimbeldon - perfect conditions for a solo hackathon. Except it was sunny so I went and hung out round the river instead. However, when I thought it was going to rain I started thinking about hack projects. Rather than sensibly looking at an existing project - applying outstanding patches, fixing bugs and adding new features is so passe - a conversation a few days ago prompted an idea. A site where you can input all your known aliases at various different web sites (LJ, Twitter, Flickr, MySpace, Facebook, Jabber) etc etc and it goes off and fetches your friends from the various sites and then correlates them and then suggests which of your friends on one site is a member of another site but isn't your friend there or suggests people that you may like to befriend. For some sites it can even auto add friends for you. To be honest, it seems a fairly easy task so it should have been easy enough to do in an afternoon. I may still work on it this week anyway. I have some questions to ask of the LJ lazyweb first though -
- Ideas for names - unfortunately also.at, alsoknown.as, the.se (so you can be <whatever>[at]the.se) are all gone. Bonus points for TLDs that don't charge 400 USD per annum and also for domains that don't have vowels missing.
- Ideas for features - beyond the ones mentioned above, OpenID and FOAF file generation are the obvious suggestions. Someone's already suggested XFN.
- Probably should have put this first actually - this idea seems way too obvious. Surely there's a site out there that does this already. Please find it and force me to do the right thing and finish one of my other projects.
At first I was was going to make it possible for a person to add in other peoples' aliases without them ever signing up but, on reflection, that seemed like a bad idea. Another issue - if you add you@twitter.com but don't want to associate that account with your more professional life as you@linkedin.com. I think a fairly broad solution would be to sign up for multiple accounts - a professional and a personal one but I'm pondering on whether it'd be better to have a more complicated structure which allows you to have multiple personas tied to one account instead.
Mon, Mar. 27th, 2006, 01:10 pm Long time gone
It's true, I probably haven't done any hacking for 2 months and 11 days.
I'm not sure if this is because I haven't had any good ideas or because I'm mildly burnt out again or because ... because of some unknown reason. I mean, I've noodled around getting London.pm's website moved to a new system and given it an RSS, Atom and iCalendar feed but that was probably a whole 10 minutes work.
Gripping.
I've added a couple of features to Woohoo but nothing big.
Maybe I'm losing my mojo. Again.
Mon, Mar. 27th, 2006, 01:00 pm Abusing Google
brad was working on Brackup and in the comments of his LJ someone mentioned that a Gmail target would be cool.
Python has had an extension that lets it access Gmail including storing files on there (using a certain amount of trickery) which someone used, along with FUSE to create a Gmail File System
Perl had no such ability to store and retrieve files simply from Gmail. Clearly this had to be rectified. Hence Net::FS::Gmail. What's nifty is that it was trivial to create it as a versioned filesystem.
From there it was a relatively minor hop skip and a jump to create Brackup::Target::Gmail. Now if only Brad would write the restore bit of Brackup so I could test it ...
I'm now pondering a Filesys::Virtual backend. Because it's nice to be doing some hacking, ANY hacking, again.
After my last excursions in AJAX and DHTML I feel slightly more confident about hacking together the last bits of EventQueue to make it full functional.
However, before I release it I really want to make it so that it can have multiple backends (mod_perl 1 & 2, cgi, static) which shouldn't be too hard but means that it's become suspiciously Framework like.
*shudder*
Framework - the verboten word.
A Module::Pluggable::Fast appeared on the scene - which purports to do immediate instantiation which is needed for Class::DBI::Loaders.
To be honest I'm not sure what to feel about this. Flattered in one way but I think the features he wants could have been rolled into Module::Pluggable.
It would have been nice to have a mail either way.
I used the opportunity to do some nice speed ups to Module::Pluggable and I'm thinking of hacking in immediate instantiating just to be spiteful ;)
I've also been thinking of spinning off the code that will tell you all the inner namespaces in any given namespace. I just want to make sure that I'm not doing bad things and that nobody else has done the same.
|
|