20050605

I must be crazy

I must've clocked 24 klicks on my bike today. Not even close to the 40 klicks the "Tour de l'Île" people do, but that's the point--I'm not ready to do the tour-de-l'Île, and I want to be ready for next year. Whether I'll be able to maintain my shape during winter is another story, I guess...

I should've picked a less busy street than Viau to go down to the Maisonneuve park, though. I think I breathed in a lot of hydrocarbons. Down with cars! Hurray for bicycles! (except in winter, of course)

It was a good workout for myself, but also for the bike. I had ridden to the metro so far, but never farther than that. There are a few problems with the derailer that I'll need to look into, but besides that, it's a sturdy, reliable workhorse so far.

Anyhow, I'm sure I'll sleep extremely well tonight. And hurt all over tomorrow...

20050503

Why Free Software matters

No, I haven't turned into Richard M. Stallman.

I'm not in the habit of linking to trade press articles; most are trite. This one, however, summarizes my whole take on proprietary vs. free. Proprietary licenses give rise to abuses of power more often than not. That is why, as a general principle and if possible, they should be avoided. I don't care how much of the economy rests on them; a lot of the economy used to rest on strip mines, and those are still seen as harmful and as needing very strong regulation.

Now, in the bitkeeper case, it's a bit more complex, because one could argue that there was no good substitute at the time. And I can understand Linus' position of wanting to use the best tool. However, what I find unfortunate is how Linus and Larry reassured everyone that exactly what happened would not happen. Whose fault it is, doesn't matter. The fact remains: a proprietary program gives all the power to the author, and none to the customer. If you're going to use a proprietary program, make damn sure you freeze the license at least for the version you're using, so that conditions don't get changed retroactively. Better yet, if you have a free software alternative that fits the bill with minimum customization, just bite the bullet or hire someone to do it for you. It may cost more up front, but in the long run, it may actually be a safer proposition.

I know it's cliché, but would you buy a car with the hood welded shut?

(Interestingly enough, while there is a move for software to become more transparent, cars are actually becoming more opaque, but that's a whole 'nother can of worms...)

This said, take the time to read RMS's writings, instead of just putting him in the "communist" box. What he says is very similar to this. Some claim his arguments are "moral" rather than "practical" (and some discuss the morality of what he says). I contend that there is no difference; what is morality for, if it's not meant to help figure out praticalities?

20050501

On the limitation of ORM systems

Lately, I've been wondering why so many ORM systems tend me to throw up my hands in disgust and hope I'd just written straight SQL.

There's the Object-Relational impedance mismatch, of course. That alone is a big killer. The fact that relational systems support declarative rather than object-oriented data is a big problem. Another is that relational systems discourage encapsulation; you should know, when designing a database, exactly what you're going to store, because it dictates relationships. In OOP, refactoring objects to move state data around is no big deal. After all, what's one more pointer dereference? Especially when it's as likely that the refactor causes one less pointer dereference.

In relational systems, where the data is is one of the most important decisions. It dictates index structure, how many joins you need to make, how easily you can access the data from different parts of the system, etc.

Whatever ORM system you want to use, it must truly address this concern. Lazy-loading is not an answer. Neither is select n+1. You need something that can anticipate object queries (maybe from hints as to what objects are related when you pull an object graph) and collapse large joins into a normalized object graph.

But that's not the only problem. Another is the "garbage generation" problem.

This is a problem, mind you, that is mostly specific to garbage-collected languages where objects are very heavyweight (i.e., Java, C#; Python objects are heavyweight, but so are primitives, so I don't count Python in there). Even if you collapse large joins, each query will generate a lot of temporary objects. This is fine if you're actually going to do something with them. But what if you're only trying to display them to the user?

For such situations, a simple query with queries on column names may work better; especially since you can use limit/offset to tabulate the data. However, it's extremely annoying to lose the ability to query a typed object; working with string column names is annoying, it makes it hard to refactor, you don't get code completion, etc. Admittedly, all those things are crutches and aren't especially necessary to programming, but it'd be nice if you could have them.

But if you try to generate objects from a large query, you generate a lot of garbage. All that for a simple table display! A table display that is, in most business applications, very likely to be much more frequent than table updates...

The ideal interface, to me, would be to get an iterator that returns a single table row object graph at the time. Unfortunately, very few ORMs offer that.

The last problem is that many ORMs really, really want to provide your database schema. They'll work with custom schemas, but it's always a big problem. It's, to be fair, a really hard problem.

That said, I think Hibernate really handles many of those things well. So does iBATIS SQL Maps, although it does different things well. I'd like to have a combination of both, that is, the power of Hibernate with the ability to write custom queries. Or I'd settle for an iBATIS extension that makes it easier to handle multiple database dialects, and a way to have it iterate over result sets rather than populate lists. Or maybe iBATIS already does this; if anyone knows how, please drop me a line.

UPDATE: iBATIS has queryWithRowHandler(), which probably works the way I'd like it to. It's probably better than an iterator, because people forget to close result sets. Should have checked before starting to write this. All that's really missing is the custom database support. And, according to the todo file, they have no support for BLOBs yet (I know a few applications where this can be a problem). Still, overall, it looks like an interesting solution when you have to recycle an existing schema.

20050429

Bitmapped fonts in xft applications

A couple of months back, I moved to using XFce 4.2 and the os-cillation Terminal application. I liked the Terminal application mostly because it had the features of gnome-terminal, but didn't require gnorba and other silly libraries. When all you want is a competent multi-tab terminal, it's annoying to require all sorts of extra stuff.

The only annoyance is that Terminal uses client-side font rendering. For some reason, client-side apps weren't able to see bitmapped fonts on my system. Which is not normally a problem; however, I really like the "terminus" font for terminals and editors and such, and it being a bitmapped font, I had to make do with Andale Mono, a font that I never found as clear.

I got fed up and did a quick google search. Turns out that on Debian systems with fontconfig installed, there is something that can be done. I went into the /etc/fonts directory. There was a conf.d subdirectory, in true Debian fashion. When in there, found a file named yes-bitmaps.conf, while the file no-bitmaps.conf was symlinked. The symlink contained the "debconf" word, which led me to think that it was a configuration option below my normal debconf level.

dpkg-reconfigure fontconfig, and voilà.

So, for those of you who want to use terminus in Terminal (or any GTK+ 2.0 application, as most use client-side font rendering thanks to pango) under a Debian system, hopefully this post was of some use.

20050415

Positively non-humbling

Looking at my old entries, I found something about a so-called humbling experience. Well, turns out that isolating the lookup from the rest of the system was a really good idea, because somebody's trying to use it outside the application framework...

At this rate, my head won't pass well through door frames very soon.

Hey, I'm entitled to brag once in a while like everyone else, ain't I?

20050413

I really, really hate computers...

Stupid computers.

This week-end, my computer's hard drive started showing up bad sectors. Well, that gave me an excuse to go buy a bike (I got a retro bike--it looked cool, and was cheaper than the cheapest hybrid; bit heavy, though) and enjoy it for some of the week-end.

But still, I had to get the darn computer to work.

Scrambled to get data out on CDRs. Degradation was really quick, which surprised me; usually, you get a few bad sectors, not a whole whack with a bunch more following in hours' time.

Bought a new disk, was pleasantly surprised that Maxtor 8 MB cache models come with a 3-year warranty, so if it goes bad like the last one, I'll have some way to recover my losses. If I don't lose the bill, of course.

Installed the OSes. For the record, I dislike installing Windows. On the plus side, the new installation seems much snappier logging in; I must've done something wrong the first time. I also installed Debian from the latest Sarge netinstall CD, and it went extremely well. Took a bit of time to get used to the GRUB, but besides that, I had almost nothing to do. Recalling my original Debian install, it was such a pain at the time--especially the ALSA drivers that would not enable any channel by default. The new ALSA init script does enable the PCM channel to a sane value, so it works really well.

Monday, came into work, and expunged my woes by expressing them to our sysadmin. His rather cryptic reply: "It's springtime." Say what?? Apparently, humidity changes due to Montrealers having to heat their houses in winter (otherwise we'd be frozen solid in a matter of minutes during winter) and abruptly stopping in spring wears out the rubber seal that keeps the vacuum in the drive. Once vacuum is lost, the drive surface oxydizes. It's worse if your heating is electric, as mine is (most modern constructions in Montreal are, since electricity isn't that expensive up here and it's much more convenient than putting water pipes or air ducts all over the building's walls). There's a small circle on the drive that pops up when vacuum is lost, and sure enough, when I checked, my former drive's is popped up.

Bummer. This means, next winter, I'll have to humidify the damn computer room. This means work--the humidifier I have needs cleaning every day. Maybe I'll just put a bowl filled with water next to the heater instead.

On the same day, one of my co-worker's new work computer showed signs of instability. It's one of those eMachines with integrated nforce chipsets. Another co-worker has the exact same model, which exhibits no stability. Granted, the stable machine runs Arch Linux and the other, Debian GNU/Linux, but I don't see how that could be the problem; we did compile X.org by hand on the Debian box. Stability is good for a while, then the co-worker will copy-paste something, and poof--back to the gdm screen. This is driving me nuts.

So, to close:

I hate computers!

(with apologies to Christian ;-)

20050329

Long time no post

Time I waste sometime airing my thoughts to a non-existing audience.

First, promises I made. Fanfic not advancing at all, I'm afraid. Been busy with taxes and lots of other stuff. Xenosaga II is advancing. I'm in the sidequest part, and I dislike doing those on second playthrough (I'll just play a second time with a lot less annoying things to do), so it can be a bit tedious. Though a lot of them are no worse than those in FF X-II, and probably no worse than the stuff in FF VII (I suspect that although I did those ten times, I'd balk at doing it again at my age). Beard is still off, for practical reasons and because I got used to it. And there's no way I can screw up shaving activities in this state.

Reminds me of the best way to keep things clean: own as few things as you can manage. Works OK so far.

Other things... got federal tax return back, so working on taxes instead of fanfic paid off, I guess. In an élan of non-geekiness, I bought a 30$ D-Link router instead of hacking one from leftover computer parts. The amount of power eaten by all those moving parts in regular computers made me balk. D-Link's not really hackable, but they get major good points for giving it a plain HTML interface. I don't know how solid the device is, but it's not being used for anything critical (my laptop isn't connected to it all the time), so even if it dies, it's no big deal.

Been following the Hacker's Diet's exercise program once more, reached rung 20 without too much trouble yesterday. I feel overall more alert. I recommend this program; its main attraction, to me, is that I cannot make excuses to skip an 11-minute routine, and since it's supposed to be daily, I can't think stuff like "I'll do it tomorrow..."


In my current conceited state of mind, I decided to commit to the electronic medium my thoughts on the rules every programmer should know. OK, so they're the rules I know, and they may not apply to every programmer; but I've been toying with the idea of writing some stuff on this someday, and, well, now's as good a time as any.

So, here it is: BGE's Killer Programming Rules... Of Justice.

If it ain't tested, it probably doesn't work
This can be seen as a corollary of the second law of thermodynamics. Code, left alone, "rots". Of course, this sounds silly; the code doesn't change, so how can it rot? Well, everything around it is changing; new OS, new libraries, new runtimes, even the code around it may make that code malfunction. There are only two ways to ensure the code remains OK: active maintenance, which is not always practical (codebases tend to become really big!) or periodic testing. And "testing" does not mean send it to a client and hope it works. That's exactly when it won't (and that part's a corollary of Murphy's law)
Just say no to protected data members
Protected data is t3h 3v1l. There is no telling what derived classes will do to it. Unless you want to be condemned to leave your base classes with the same implementation until the end of time (and that's not really feasible, because of the first principle, above), you should never use protected data. That's right, never. I'm usually not that drastic, but I've never seen protected data being used in a sane manner. And this is coming from the guy who things Multiple Inheritance can be very useful at times. If you think of the implications, protected data makes your base class less reusable and unable to evolve, which kind of goes against the grain of object-oriented programming principles.
Overriding concerns should not be abstracted away
Overriding concerns are things like transactional semantics and resource clean-up. Somebody, somewhere, is going to have to make a decision on the transaction boundaries or on the clean-up time. It very likely should be code that has a wide enough view of the problem to make an intelligent decision, usually some top-level or near-top-level method. I've ranted about this before.
Keep resource ownership sane. Don't transfer it implicitely.
This means several things, namely:
  • DON'T allocate a resource in a method to clean it up in another function at the same level;
  • DON'T have objects allocate resources and expect the caller to clean it up if something bad happens (note that if your object has a "close" function of some sort, it's really the object cleaning up; what I mean here is don't expect the caller to call a method to get said resource and clean it up by hand);
  • DON'T program as if exceptions cannot occur in any block, and DON'T try to catch every exception to force cleanup in catch handlers. This is extremely brittle. See Herb Sutter's Exceptional C++ for more details;
  • DON'T transfer resource ownership if you can help it;
  • DO try to give any limited resource a finite scope in a single method, if possible;
  • DO wrap the resource in an object with a close() function (or a destructor in C++) if the lifetime of the resource cannot be determined by the code allocating it.
Respect the computer and the OS; it's more often right than wrong.
Surprising to many who know me, I do apply this piece of advice to Windows-family OSes as well. In my experience, 98% of the time when I thought the compiler/OS/computer was being stupid, I found out that it was a coding error (not always mine, but always within the programming group). There are some exceptions to this: kernel panics and such should not happen through a programming error, period. But I'm talking of more subtle cases, where you wonder why the heck the code stopped working, why the OS is returning an error there, etc. Don't just throw up your hands in the air at the stupidity of the OS, even if, yes, it is stupid sometimes. But you'll probably find with times that if it's not necessarily entirely your fault, it's at least partly your fault, because what you're doing is a bad idea and that's why the OS is being difficult. Of course, OS programmers are human, and so are computer designers; but they have several hundred thousand programmers who bang on their code everyday, and that doesn't count users doing all sorts of nasty things to their nice piece of software; they are therefore tested very widely. OSes are pretty mature these days, and except for, say, exploits and such, if your code acts weird, it's pretty much certain that it's your fault.
Try to listen to what the machine is trying to tell you.
This is related to the previous point. If you have to do something really cumbersome, or scary, or brittle to get things to work, it's likely that somebody is trying to tell you something. Namely, that your semantics are muddled, that you're using the wrong approach, or that you're trying to do something that's not really allowed. Virus writers want to do the latter, but industrial programmers don't; it always causes huge problems in the long run, when it stops working with compiler XYZ and OS Gamma. Another nice way to test whether it's a boneheaded idea is to try to explain it to somebody. If you feel silly explaining it, or you can't explain it clearly, it's probably because you're a bit confused about what you're supposed to do or how you can achieve it. Try to take a different tack.
Sometimes, it pays to trust your intuition.
I've been known to really dazzle co-workers by looking at some code, pointing at a line saying it's not a good idea to do that, and, of course, it ends up being that line that causes the problem they're trying to fix. Now, if you can't really prove that this is the problem, intuition is worthless. But it's easy enough to throw test data at said method/class and check.
The brilliant lone programmer is a myth.
Well, I can't claim that I'm a perfect authority on the subject. But I've known programmers who started out as loners. Sure, they are more brilliant than some more social programmers. But they always reached their full potential only after becoming more social. Programming is about ideas; if you don't exchange them, you can miss something really obvious, or paint yourself in a nice little corner, or constrain your mind to a nice little box of your own making. It is unfortunate that the myth of the lone, incredibly brilliant scientist is so pervasive in our culture; I guess it's because everyone likes heroes. But, as Isaac Newton allegedly said, "if I have seen so far, it is because I have been standing on the shoulder of giants." (Aside: it's interesting Newton, of all people, said that, as there are rumours that he was not really the most cooperative scientist, nor one who shared his results very often). Now, this doesn't mean that I think one should ignore more introverted programmers; rather, one should try to make them feel comfortable in the team, so they start sharing all those insights. Being an introvert myself, I know it's not easy to bring out one, but it's not completely impossible either.
Keep commented-out code out of your source files.
Yeah, yeah, I know, maybe you'll need it someday. Just like protected member variables right? :-) Seriously, you should use source control. If you use source control, there's no reason to keep this cruft around. If you're really worried that you may need it, apply a source control label to the tree before removing it. The reason? Dead code breaks the flow of the code around it, makes plain-text searches find false positives (I know good IDEs make plain-text searches less frequent, but they still happen sometimes), and by the time you'll need it again, it probably won't be any good anymore; it'll have suffered bit rot. If you really must keep some code commented out in the source file, at least be polite and move it to the end of the file with a comment giving a hint where it came from. This way, people looking at it will figure out immediately that it's not something that was left commented out by mistake. But I really think it should be ditched rather than commented out; the latter idea is a lousy compromise at best. Just use source control. Comments are for explanations, not for executable statements.
Avoid doing things that disgust you, especially if the rest of the code already does.
Your objective, when touching a piece of code, should be to improve it, not worsen it. Adding a feature can be seen as an improvement, but it's not necessarily an improvement for the code quality; it's just a feature. Going through the code and resisting the temptation to copy-paste a segment is an improvement. Nobody will pay for such things, and you're always short of time; I know, I've been there. But when I stopped making excuses for myself, I realized that in many cases, I could find a solution that, if it didn't improve the code much, at least didn't make it worse, implemented the feature properly, took less time to debug because it was easier to understand, and (that's the part that surprised me quite a bit) didn't take more time, overall, to do than the quick-and-dirty solution would have taken. In fact, every time I was forced to take the quick-and-dirty solution, when I redid it properly later, I was always really annoyed somebody had forced me, because the proper way hadn't been any longer and wasn't really riskier. Code will worsen on its own; you should always strive to lessen its entropy, not add to it.
Avoid doing things "just in case."
This is the infamous YAGNI (You Ain't Gonna Need It) principle from Extreme Programming. By all means, think of a design that will accomodate "just in case" (just don't take that too seriously nor waste too much time on it). But don't bother implementing it unless you have an immediate use for it. You'll just be adding to the complexity, with no benefit, and you'll have added code that will rot eventually from disuse and lack of testing.
It's not because there's a class that it's object oriented.
I've seen many cases where people would create bunch of classes, each implementing bunch of interfaces... And who, in the end, created a spaghetti-like mess. OOP does not mean you should forget structured programming; it's still there, within your classes. And it's not because you replaced your globals with singletons that you don't have globals in your project. And it's not because your class implements an interface that it's swappable, especially if all the code ends up using the exact class because of missing stuff in the interface. I could go on, but I think you get the point.
Be really, really careful when designing and changing persistent data formats.
Those are always a bitch to upgrade. Your internal code can change somewhat more easily, so internal code organisation is only important for your next maintenance release; if it's not ideal, there's the possibility to fix it later. But broken persistent formats can be a real pain to fix. Even more so if you're signing the data or encrypting it in some way; you may not be able to re-sign or re-encrypt it after you've converted it. Bummer. Changing formats should be done carefully as well, because there's always trouble with conversions or with people who want to use old versions with new data. And no, it's not because you're using XML that you're safe from any of those problems. You can have problems with XML-based formats, too; you only avoid (some) parsing problems, not semantic problems.
Don't go ape with design patterns.
I sometimes think that software design teachers are encouraging students to look for ways to apply patterns when they teach their course. This is exactly the wrong way to teach patterns. Patterns should be a solution to an existing problem: you have a piece of code that needs to do such-and-such thing, so such-and-such pattern will help. You should never, even be given a pattern and asked to apply it in your program. The reason I think this is what's happening is because I've seen a trend in code written more recently that it's filled with pattern mush, often in places where it doesn't make sense. Extra factories where a simple function would do; composites where the composite's properties are not being used; and so on. This is extremely annoying because it can make the code hard to follow, especially if the person applying the pattern didn't really understand it. Also, I find that a few patterns in the GoF book aren't all that useful; Flyweight is rarely applied correctly, and I always found Visitor to be a bit cumbersome (yes, I know what it's supposed to solve, but I've usually found different ways to solve this particular problem, and they tend to be easier to read for maintenance programmers).
Make objects minimal-state.
That is, objects should maintain the bare minimum of the state they need. Never add a member variable just to avoid passing a parameter between two member functions; it may look like a good idea at first, but it's really not--you're adding extra state to the object for no good reason. Would you add a global to your module just to avoid parameters in structured programming? Well, adding a member for that reason is like adding a semi-global, and it's not a good idea.
Avoid the construct-and-call-setters anti-pattern.
I've seen this very often, and it makes me feel a bit sick every time. You have an object with an empty constructor, which must have its setters called before you call any method. IoC is bringing back this way of doing things (so is struts, to some degree), and it really distresses me. What if you forget to call a setter? What if you call them in the wrong order somehow? What if somebody calls a setter after calling a method, thus violating some invariants? By turning an atomic operation (object construction) into a non-atomic one, you're asking for trouble. Strive to keep your objects in a sane state, always. It should not be possible to put it in an insane state from the public interface, especially not by forgetting to call a method... Note that you can always prevent such problems by adding manual checks, but that's brittle; it's better to make it impossible to put the object in an incorrect state in the first place.

Well, that ran a bit longer than I thought, and it contains some stuff that's a bit lower-level than what I initially wanted to write. But there it is; I hope it was somewhat useful to you, at least. It's by no means complete, but it's a start. I may complete this list from time to time when things come to my attention. I may also strike out some items or modify them, as I've been known to revise my ideas on some things.

20050316

It's gone, Gone, GONE!!!

Had an argument with my beard trimmer yesterday around 00:30, which resulted in me shaving the whole thing off, including mustache. Morale: don't shave at 00:30.

Hadn't seen my face whiskers-free for ten years. It looks weird.

Not sure whether I'll let the beard grow back yet. I look less intimidating without, which may have some benefits overall. But my face looks wider and my chin sort of disappears in my neck visually, which I don't find that aesthetically pleasing. But maybe I'm just not used to it. I'll probably give myself a few weeks, and then decide. Probably depending on how many of my friends laugh at me.

I have to get a picture up of The Beardless One, just for everyone's amusement. Stay tuned...

20050308

A-25 Redux

The mayor of the Anjou borough has a half-page on every "Ville d'Anjou" leaflet we get once every month.

On the whole A-25 issue, he has to say that it will improve the pollution situation by putting pressure off A-40, and that the complaint about lack of collective transports is silly since he asked Transport Québec to put reserved lanes for buses on the bridge, otherwise it was a no go.

He also mentions that the bridge won't really make urban sprawl worse, because people are already sprawled all the way to St-Jérome, and that's way farther than the sphere of influence of the new bridge. As he points out, people don't sprawl because a bridge becomes available--they sprawl because they can't find affordable and calm spaces in the city boudaries. Anjou could provide that, especially if it were less isolated from a transportation point of view. The A-25 bridge won't help that, particularly, but as I mentioned in a previous post, I'm worried that no bridge will also mean no metro, no commuter train and no A-720 extension.

Needless to say, I agree with much of what he says. I don't know about the pollution situation, though; A-13 was supposed to help, but didn't in the end, because it only allowed people to settle way further. A-25 won't be as bad since it won't reach all the way to the north shore, but it could still have unexpected effect. I think a longer A-720 would be a better choice if one wanted to make the "less pollution thanks to the highway" argument.

Still good points. Too bad he's preaching to the choir; he should write for the Plateau or Outremont regional newspaper. Still, I have some hope--the president of the chamber of commerce of eastern Montreal wrote an editorial in a major newspaper about the whole transportation infrastructure situation. Hopefully it's been heard.

Keeping my fingers crossed... At the very least, if that bridge has a cycling lane, I could cycle to Laval, and that would be, as they say, Way Cool.

20050302

Added to developers' whiteboard

String b = "some string";
StringBuffer sb = new StringBuffer();
sb.append("a" + b + "c");
sb.append("a").append(b).append("c");

'Nuff said.

Note to future language designers: make sure "+" is an efficient operation, maybe by having it return some sort of temporary "not concatenated yet" list of strings and resolve the catenation at the very end. This would be possible to pull off in C++ given the powerful type system and pass-by-value semantics (and it would literally rock if move constructor made it into the language!). It's not possible in Java, so we have to tell people to be careful. And for some reason, there are a some people who aren't.

Reminds me of the equivalent problem in Python:

b = 'some string'
sb = 'a'
sb += b
sb += 'c'

sb = ['a']
sb.append(b)
sb.append('c')
sb = ''.join(sb)

But notice that it's more a problem of incremental appending than one of usual concatenation. At least, 'a' + b + 'c' will not produce a temporary "string buffer" object on top of the extra temporary strings. Besides, Python does not have pretensions as being the new systems programming language...

Some would argue that neither does Java, but I disagree; witness the number of client apps being written in that language because that's what graduates are taught, and because people can't handle language where the GC does not come by default (make no mistake, the Boehm GC is available for C++ and works very well).