Tuesday, the 11st of December, 2007

Dependency injection: I'm not going back

InfoQ carried an article about dependency injection, with the title "Does Dependency Injection pay off?".

Answer: it does.

You learn something useful from most languages, frameworks and libraries you get to know. One of the more surprising revelations the Java world had for me, after working in it for the best part of a decade, came in the form of Spring. It's a huge pile of stuff, but in the center sits a pretty good idea. It's not an original idea, but Spring is where I got to know it. It's dependency injection. It's about classes not instantiating their dependencies or looking them up from some sort of global scope, but exposing them as constructor arguments or properties.

In Spring, you define the dependencies in an XML file and let the framework set things up. It works well enough, but I've been merrily using the same design in non-Java environments ever since getting to know it without any of that angle bracket noise and haven't really missed it; you get by just as well with a piece of code that creates all the objects, hooks them up and presses play.

Everything is so much cleaner and simpler than it used to be and as an extra bonus, it's suddenly a lot easier to test, too. The cleanliness DI brings to your design has the quality of being self-supporting: once you start building the system with it, the path of least resistance is to keep on using it instead of letting the dependencies spread. It also makes using singleton a lot less tempting (it's easier to just instantiate an ordinary class and give that instance everywhere it's needed), which is another big plus.

Someone in the InfoQ article invokes YAGNI. It's a false argument. You have to set up the dependencies anyway somewhere. You are going to need that. So the question is, should you do it in one place or scattered throughout the system? Which is cleaner? Another question you can ask is the old OO design principle, whose responsibility is it anyway? With the benefits DI brings, it's an easy decision to make.

@ 19:38 +0200 [ ] archived

Saturday, the 8th of December, 2007

Using SSH from the Gnome menus

Some time ago I wrote in a SSHMenu related blog posting's comment thread that I found the Gnome panel's menu combined with gnome-terminal's profiles feature sufficient for my SSH needs. As a followup, I got a email a couple of days ago by someone asking if I knew how to do the same thing except opening Nautilus windows for the remote hosts. I replied, but apparently the email could never be delivered, so here's a quick recap.

Below, I'll use foo as the remote host name. Replace it with the name of whatever host you want to use.

Steps:

  • Open the menu editor, either by right-clicking on the menu or from System > Preferences > Main Menu.
  • Click on New menu to create a new submenu, call it "Remote hosts" or something.
  • Select the new menu, click on New Item to create a new menu item.

For terminals:

  • In the Launcher Properties window that opened after clicking New Item, set the launcher type to Application, give it a descriptive name like "ssh foo" and the following command: gnome-terminal --window-with-profile="Remote foo". You can also give the launcher an icon. I usually like to give an icon that I use also for the gnome-terminal profile. See below.
  • The launcher won't do much useful yet, beyond opening up a new terminal, so now you have to create the gnome-terminal profile "Remote foo".
  • Open up a gnome-terminal window.
  • If you value your screen real estate, you probably have hidden the terminal menu bar. You have to make it visible to access the new profile creation functionality, so bring up the context menu with the right mouse button and select Show Menubar.
  • In the gnome-terminal menu, select Edit > Profiles. Click on New to create a new profile and give it the name "Remote foo". Click Create.
  • In the General tab, you can give the profile an icon. As I said, I like to use an icon here and in the menu, but that's up to you. You can also specify host specific colors in the Colors tab.
  • In the Title and Command tab, check "Run a custom command instead of my shell", and specify ssh foo as the custom command.

Now you are set, and selecting ssh foo in your new Remote hosts should open up a new terminal window that prompts you for authentication information for foo.

Turns out using this for Nautilus is even less work. Assuming things work out.

  • In the Launcher Properties window, instead of specifying gnome-terminal as the command, type in nautilus ssh://login@foo .

Replace login with your login on foo.

That's it. No extra steps needed.

Now, if gnome-vfs does its magic, you'll get a new Nautilus window when you select your new menu entry, showing the contents of your home folder on foo. The other option is that you get a Nautilus window showing nothing, which seems to happen to me for some hosts. No idea what that's all about.

@ 09:55 +0200 [ ] archived

Monday, the 3rd of December, 2007

Shuffling the stack: first faltering steps on Factor

In my neverending quest of avoiding actually getting any of my projects ready, I started playing with Factor. In four years, Slava Pestov and the other folks hacking on Factor have created an extremely impressive language, beating many other dynamic languages like Python and Ruby in speed and providing an environment that doesn't make the Factor 2.0 goal "Best interactive development environment of any programming language" sound like an impossible idea.

But it does have a steep learning curve. The concepts of the language aren't difficult — in many ways it resembles other dynamic languages — but it feels like I'm clumsily trying to perform mental gymnastics instead of actually being productive. See, it's a Forth-style stack shuffling concatenative programming language. There are named variables (dynamically scoped, which feels weird, but that does have its uses when used sparingly) and these days there are even lexically scoped named locals, but depending on those instead of getting used to stack manipulation would be cheating, no? So now I'm slowly dupping, overing, tucking and swapping my way through simple algorithms, trying to switch my head into the right gear.

@ 18:33 +0200 [ ] archived

Thursday, the 8th of November, 2007

This is how all software should be

 $sudo -u couchdb /opt/couchdb/bin/couchdb 
 couch 0.7.0a572 (LogLevel=info)
 CouchDB is starting.
 CouchDB has started. Time to relax.

It's a bit like having a dictionary with the words "Don't panic" printed on the cover in big, friendly letters.

@ 18:09 +0200 [ ] archived

Sunday, the 7th of October, 2007

Resin: Javascript in JSPs?

Am I missing something here? JSP Templates vs.

/test.jsp:1: 'javascript' is not supported as a JSP scripting language.

1:  <%@ page language="javascript" %>

That's what Resin 3.1.2 tells me.

Update: Right, now I noticed this in Resin 3.0.0 release notes:

Since the JavaScript for JSP was used by too few users, it no longer makes sense to continue support.

Arf.

Apparently Tomcat, Jetty and Glassfish all support only Java in JSPs, not any javax.script implementations. Now I'm trying to figure out how to use EJS from scripting.dev.java.net. Any other Javascript templating options for servlets? I know Helma, but I'm interested in the front-end code (templates, value objects, possibly controllers) only.

@ 13:05 +0300 [ ] archived

Sunday, the 23rd of September, 2007

Cirque du Soleil's Delirium: meh

We went to see Cirque du Soleil's show Delirium, now in Helsinki on their tour of Europe, yesterday. It was the first time I've seen any of their shows live. It wasn't exactly bad, but not what I was hoping for. The most important part seemed to be the music and the video stuff, and the acrobatics were a bit of an extra. Trouble is, the acrobatics were what we went there to see.

The music was an A-Z of genres with no carrying theme, going from rock with guitar heroics to Africa flavoured world fusion to soul to pop to salsa to tango. And few of the songs were all that great, either, basically sounding like filler tracks on a pretty ok album. A different album in each case, of course.

The video show was amazing, mostly computer generated and in all cases heavily processed, with two big screens on each side of the stage, one behind it and a translucent one part of the time in front of it.

And occasionally somewhere there were a few acrobats. They were mostly extremely impressive, too. At least when you could see and concentrate on them. Too often, though, even if they were there, there was the huge A/V show going on all around them, drowning them with its volume, both in terms of sound and screen area. And as if that wasn't enough, sometimes they had the translucent screen in front of the stage showing water or something, forcing you to squint to see the people who you thought were supposed to be the most important part of the whole experience.

According to the official web site, "For the first time Cirque du Soleil created a show where melodies, musicians and singers are the driving force". I guess I'll just have to keep that it mind when deciding which show to go see next time.

@ 10:12 +0300 [ ] archived

Monday, the 27th of August, 2007

Glade-3 toolbars

This note is here so I can grep or Google for it the next time I spend ten minutes clicking around the Glade-3 window, trying to remember what the trick was: Glade-3 has put the menu and toolbar editors behind an edit button below the the properties notebook.

@ 19:21 +0300 [ ] archived

Saturday, the 25th of August, 2007

Python-style enumerate for Nemerle

So instead of just whining about Nemerle, here's a something potentially useful. I found I missed Python's built-in enumerate function. It wasn't too hard to implement in Nemerle:

public class Enumerator['a] : IEnumerable[(int * 'a)] {
    private e: IEnumerable['a];

    public this(e: IEnumerable['a]) {
        this.e = e;
    }

    public GetEnumerator(): IEnumerator[(int * 'a)] {
        mutable i = 0;
        foreach (elem in this.e) {
            yield (i, elem);
            i++;
        }
    }
}

Usage:

foreach ((index, item) in Enumerator(list)) {
    System.Console.WriteLine($"index for $item: $index");
}

The naming might not be optimal, with potential confusion with the standard libraries, but I don't care at the moment. Use and enjoy.

@ 12:50 +0300 [ ] archived

Tuesday, the 21st of August, 2007

Flow 07: Sunday and Regina & Husky Rescue at the Huvila Festival Tent

Sunday was a whole lot better at Flow than Friday. Everything worked better and the music was lovely. Kudos to the organizers for seeing the problems and acting to correct them.

Highlights:

  • Risto is the king of the world.
  • Tuomo played just the kind of music you'd love to hear on a sunny Sunday afternoon.
  • Korpi Ensemble was easygoing and fun.

On the not quite as good front, it was the first time I had heard of Jenny Wilson and wasn't really very impressed. Nice enough, but didn't really generate any strong feelings. Bebel Gilberto was better, but she arrived late on the stage and I don't think she really captured the audience. We left in the middle of her set.

Monday evening we went to see Regina and Husky Rescue at the Helsinki Festival Huvila Tent. Both were excellent, even though Regina would have clearly worked even better in an envinronment where people wouldn't have been sitting down — the tent doesn't really encourage you to move your ass.

All in all, you get the feeling that Finnish music is doing pretty well.

@ 18:45 +0300 [ ] archived

Saturday, the 18th of August, 2007

Flow 07: Friday done

First day of Flow is behind. This year, we bought tickets for Friday and Sunday, we'll skip Saturday. I have a few not-so-great photos online.

The good:

  • The artists. Pepe DeluxĂ© was good, sometimes great. Terry Callier was brilliant. No complaints about the other stuff, but those were the only two complete sets we heard. Well, CocoRosie was, er, slightly too weird for my tastes.
  • The location, the old Suvilahti power station. The outdoor space isn't quite as excellent as last year, but it is pretty nice anyway. And even closer to home. And having the club space in the same place justifies the move pretty well.

The bad:

  • Queues. Queues everywhere. One of the main attractions of Friday for us was Nicole Willis and The Soul Investigators. We spent the time they were on stage in the line outside the festival area, waiting to get in. Partially a timing problem (starting the first set at six o'clock on a Friday evening is just too early), partially a organizational problem (why does it have to be so slow to let people in?) Time to get a beer from the bars next to the main stage: 20-30 minutes. And of course the bar areas are fenced and you aren't allowed to go buy your drinks from another bar and take them to the main stage. Queues to the toilets, too.
  • The main reason causing the queues: too little staff. They would have probably doubled their sales if there was actually enough people staffing the bars. When they opened the club space, there was apparently one person staffing the three bars, serving a couple of hundred potential customers.
  • No schedules anywhere. If you didn't print out the schedule yourself, too bad.
  • Too small venues. The main stage was ok and we didn't really go to the club hall except right when it opened, so no idea how that was later on. But the tent where The Five Corners Quintet, Jukka Eskola, The Stance Brothers and Timo Lassy were the last acts was woefully small, with horrible crowding. We couldn't stand it so had to skip them, which meant that with Nicole Willis missed earlier, we didn't see half the acts we were trying to see.
  • The hot dog stand ran out of buns before hotdogs and gave out all the hot dogs to people when there were still others in the line. Thanks. We would have paid for those. After that, the only food left was a small piece of dry lasagna costing ten euros. This looks like a pretty good business.
  • The beer was Fosters. The cider was Upcider. The wines were JP Chenet.

If we hadn't already bought the tickets for Sunday, we might seriously reconsider our plans: good music, but they made it way too difficult to enjoy it.

@ 12:28 +0300 [ ] archived

Sunday, the 12nd of August, 2007

Slightly disappointed in Nemerle

I've been coding with Nemerle a bit during the last couple of months. I've discovered that I had set my expectations too high. It doesn't quite live up to them. Might be as much my fault as Nemerle's, but that doesn't really change anything.

I was hoping for a experience closer to OCaml (only with better cross platform library support) than I got. With OCaml, once your code compiles, you know you are doing pretty good. With Nemerle, not so much. First of all, it feels like you get to fight a bit more with the type inferer than in OCaml. This is probably partially due to the maturity of the implementation, partially due to the fact that with OCaml, I didn't use as serious class hierarchies as I do with Nemerle, thanks to the .NET standard library and heavier Gtk+ usage.

The second problem I've encountered is that when you interface a lot with C# code, you don't really get much mileage out of the functional stuff in Nemerle. When you have a List generated in C#, you don't get to fold over it. While Nemerle does have the ICollection interface extending System.Collections.Generic.ICollection with all the functional iteration tools, there are no wrapper classes and no standalone functions. If you want a foldable List, you'll have to copy stuff. Not nice.

And third, while the variables are by default non-mutable, which is nice, and when you define your types in Nemerle you can do matching and get the safety that brings, you end up interacting so much with .NET code that you have to do the normal null checks all over the place anyway.

In short, the benefits of Nemerle over the current features of C# are feel pretty limited. Maybe it would be better if you were working with pure Nemerle projects, but at least interacting with C# eliminates most of them.

@ 16:16 +0300 [ ] archived

Thursday, the 17th of May, 2007

Making Emacs understand ncc errors

Add this to your .emacs or equivalent to make Emacs' compilation-mode make proper links out of the Nemerle compiler's error messages:

(setq compilation-error-regexp-alist 
    (append compilation-error-regexp-alist 
            '(("^\(.+\):\([0-9]+\):\([0-9]*\):\(?:[0-9]*\):\(?:[0-9]*\):" 
            1 2 3))))

Update:

Or even better, using rx (thanks to this hint for reminding me about it):

(setq compilation-error-regexp-alist 
      (append compilation-error-regexp-alist 
              `((,(rx line-start 
                      (group (1+ (not (any ":"))))
                      ":" 
                      (group (1+ digit)) 
                      ":" 
                      (group (1+ digit)) 
                      ":" 
                      (*? digit) 
                      ":" 
                      (*? digit) 
                      ": ") 1 2 3))))

@ 14:27 +0300 [ ] archived

Saturday, the 28th of April, 2007

C# export for Gaphor

Gaphor is the best free UML tool for X I've seen yet. It's far from finished but at least it produces pretty graphs. I started writing a C# export plugin for it. The first somewhat working version is available. This has been developed with 0.10.4, no guarantees of it working with any other version. No guarantees of it working with that version either, to be exact, but at least it works for me.

Extract it inside Gaphor's source directory, in gaphor/data/plugins.

@ 10:47 +0300 [ ] archived

Friday, the 27th of April, 2007

Python, Queue, Pygame and the GLib mainloop

The GLib mainloop is what you're probably running in your Python program when you are using PyGTK or GStreamer.

Sometimes you want to integrate other event sources to it. The documentation for this is a bit thin; all I've seen is GLib's page on the main event loop, GSourceFuncs section and test-source.py in pygobject. Here I'm presenting two snippets displaying how to do it with two systems I've needed to work with. No guarantees on their correctness, but they do seem to work. Both are parts of larger modules, so they aren't usable by themselves and aren't really tidied up to look like proper examples. However, they should give you the general idea.

Here's how to do it with Python's Queue:

class QueueSource(gobject.Source):
    def __init__(self, queue):
        gobject.Source.__init__(self)
        self._queue = queue
        self.logger = loghelper.get_logger(self)

    def prepare(self):
        return False

    def check(self):
        return not self._queue.empty()

    def dispatch(self, callback, args):
        self.logger.debug("dispatch called, callback: " + str(callback))
        if callback is not None:
            self.logger.debug("dispatch calling callback: " + str(callback))
            v = callback(self._queue.get(), *args)
            self.logger.debug("dispatch returned " + str(v))
        return True

    def finalize(self):
        self.logger.debug("finalize called")


m = QueueSource(self._queue)
def my_callback(command, *args):
    self.logger.debug("my_callback: args: " + str(command) + ", " + str(args))
    self.logger.debug("my_callback: thread: " + str(threading.currentThread()))
    if command == self.PLAY:
        self._player.play()
    elif command == self.STOP:
        self._player.stop()
    elif command == self.SKIP:
        self._player.skip()

m.set_callback(my_callback, mainloop)
m.attach()

And here's Pygame:

class PygameEventSource(gobject.Source):
    def __init__(self):
        gobject.Source.__init__(self)
        self.logger = loghelper.get_logger(self)

    def prepare(self):
        return False

    def check(self):
        try:
            pygame.event.pump()
            p = pygame.event.peek(
                [KEYUP, KEYDOWN, VIDEOEXPOSE, VIDEORESIZE, NUMEVENTS, QUIT,
                 ACTIVEEVENT, USEREVENT])
            return p
        except Exception, ex:
            self.logger.error("Caught an exception while checking for events",
                              exc_info=True)

    def dispatch(self, callback, args):
        if callback is not None:
            try:
                e = pygame.event.poll()
                v = callback(e, *args)
                return v
            except (KeyboardInterrupt, SystemExit):
                self.logger.warn(
                    "Caught a terminating exception while dispatching to the "
                    "callback, re-raising", exc_info=True)
                pygame.display.quit()
                raise
            except Exception, ex:
                self.logger.error(
                    "Caught an exception while dispatching to the callback",
                    exc_info=True)
        return True

    def finalize(self):
        pass

def my_callback(self, event, *args):
    if event.type == QUIT:
        sys.exit()
    if event.type == KEYDOWN:
        self.logger.debug("my_callback: keydown: event.key: " + str(event.key))
        if event.key in (K_q,):
            sys.exit()
        elif event.key in (K_n, K_SPACE):
            self._player.skip()
        elif event.key in (K_p,):
            if self._player.playing:
                self._player.stop()
            else:
                self._player.play()

    return True


def start_mainloop(self, mainloop):
    self.logger.debug("Starting mainloop")
    if not self._started:
        s = PygameEventSource()
        s.set_callback(self.my_callback, mainloop)
        s.attach()
    return

@ 19:26 +0300 [ ] archived

Saturday, the 14th of April, 2007

One of Those Things You Don't Know If You Should Post in Your Blog Or on TheDailyWTF

From Rails, or more specifically, ActiveSupport's json.rb:

# When +true+, Hash#to_json will omit quoting string or symbol keys
# if the keys are valid JavaScript identifiers.  Note that this is
# technically improper JSON (all object keys must be quoted), so if
# you need strict JSON compliance, set this option to +false+.
mattr_accessor :unquote_hash_key_identifiers
@@unquote_hash_key_identifiers = true

@ 13:43 +0300 [ ] archived

Friday, the 9th of March, 2007

AudioFormat 0.4 released

After a longish break, released a new AudioFormat when I noticed how aggravating the current version was :-)

The new version, 0.4, allows you to add files to the list of files to convert via a file selector or by dragging. It also should handle and report errors a bit better. And maybe it'll even recognize Vorbis files? Although I suspect it'll get very confused if it encounters something like Ogg Tarkin files. Will have to work on that a bit more.

Enjoy.

@ 23:44 +0200 [ ] archived