Beware the IDEs of July

Well, it’s not March, is it?
I’ve been evaluating Boa Constructor.  To be exact; I’ve spent much of the last two days deep within it, using it in anger since there is no better way that I know of to see how well a development environment works.  And it’s nearly wonderful.  Nearly but not quite, almost[1].

What it does have going for it is its completeness; in the one package you get Python and ZPT syntax highlighting, Zope and filesystem browsing, edit-run-debugging and most anything else you could want.  For yanking Zope files off the server, hacking them about in a decent editor with an understanding of syntax, it’s excellent.  The source Explorer is brilliance in a tabbed window, the self-building UML and Hierarchy views do just what they say on the tin.  Much kudos to the developers.  If I did wxWindows development, I’ll warrant I’d find it even more useful; perhaps one day.

But where it falls down, it falls down hard.  I mean, the sort of thing that will make you scream and use words that get you Looked At by your loving spouse.

Let’s start with the keybindings.  There may be a rationale behind their choice, some abtruse phiosophical system requiring unique insight of a shaman on peyote, or an open, uncluttered, left-field perspective that an old hacker like me is never going to have… but I suspect not.  Okay, I can live with someone deciding that, say, the Gnome keybindings are the be-all and end-all of keyboard conventions, but BC isn’t even self-consistent.  And what’s worse, it’s dangerous.  Take Ctrl-U.  In Python mode, it’s unindent.  Unconventional, perhaps, but there it is – Indent is Ctrl-I (I for Indent, I assume) which matches the more common Tab.  But in HTML mode (or more exactly, Zope Page Template mode), it’s “convert selection to lowercase”.  If, like me, you’re someone who keeps HTML indented to track the various levels of tag and subtag, then you’re likely to select a block of text and do Ctrl-U to “unindent” it.  The silent conversion of every uppercase character to lowercase is so visually subtle that you miss it, and then wonder what the heck[2] it was that messed up all your lovely mixedCaseScriptNames.
And whilst I’m on about indenting… call me awkward, but I rather like to use two-space indents for complex code.  BC is unforgiving in this respect – you follow its rules and be grateful, baby, leading to muttered curses while you struggle to work out how you can fix the jagged indentation in what was, before editing, a perfectly good method.
I could go on about it… how the effect of selecting whitespace and hitting tab is never quite what you expect, how Ctrl-Q is used for closing files (how charmingly quirky) or the bindings that the debugger uses for step into/out/over are dissimilar to every single other package I’ve ever used, but hey, that would be tedious, and this blog is tedious enough already.

Debugging is… odd.  Let’s assume you’re working with a Python application.  You set up the command line (an option in the File menu, naturally, where else?) and click Debug Application.  Let me take a moment here to note the way in which BC relies heavily on toolbars full of icons.  Untitled icons which (and I say this with all due respect and acknowledgement of my own lack of artistic skills with a crayon) are often so abtruse in their visual cues as to be hieroglyphic.  But that’s okay, because if you float your pointer over them, they pop up a tooltip to remind you what they do.  As long as the window they’re in has the focus… so you find yourself clicking on title bars, then floating your pointer over icons and WAITING.  Mystery Meat Navigation at its finest.
Anyway, let’s assume you wish to debug.  You click Debug Application.  That, sort of, starts the debugger.  The pointer (we’re on Windows here, to give some context) changes to the arrow-with-hourglass to tell you to hang on.  And you wait.  Eventually you move the pointer and find that it changes back to an arrow – looks like you didn’t have to wait after all.  But your debugging has not yet started.  Now you must go over to the Debug window and either Step or Run the code (again, using the appropriate icon).  Now you’re debugging.

And so a trackback occurs (happens to even the best of us, don’t take it personally).  You get the full and detailed error in a tiny little panel at the bottom of the Debug window.  Well, you do as long as it’s less than about twenty characters.  There’s an Errors tree-control type thing in another panel but don’t worry about it, nothing happens when you click on it.  Oh, and to get an interactive shell a la Pythonwin when you’re at a breakpoint, you need to click the Eval In Shell icon.  No, I wouldn’t have guessed that either.

And so on, and so forth.

It would be easy to get me wrong here – I’m still using it and probably will keep on doing so, but with that continuing sense of dislocation and awkwardness as I pause before hitting F8 to step and wonder if I’m remembering the BC, VB or Pythonwin conventions.  Where it’s good, it’s very good – a model of the sort of integration to which any IDE can aspire, a flagship of what free software can be.  But when it’s bad, it’s horrid.

[1] http://www.shriekback.com/lyr_JamSci.htm (Achtung).  Memories of my college days…
[2] Take it as read that the word I used was dissimilar to “heck” in the first two letters.

Bags and Objects

Someone (who remained anonymous) was kind enough to point out, following my last entry, that there’s an equivalent to Bag built into Zope; the Products.PythonScripts.standard.Object class[1].  It, too, initializes from keyword parameters and also emulates dict semantics (which, interestingly enough, I’d added to Bag before reading the comment).  Where I ran into problems in trying it out is with iteration.  There’s debug code in my Zope site that does something like:

&ltspan tal:repeat="key myBagOfStuff"&gt
 <p>Key is <b tal:content="key">key</b>, value is <b tal:content="myBagOfStuff/?key">value</b>
</span>

to iterate over the keys.  Objects can’t do that, nor can they support the more basic iteration style:

&ltspan tal:repeat="item myBagOfStuff"&gt
 <p>Item is <b tal:content="item">item</b>
</span>

But as long as you don’t need iteration (and given a decent implementation of __str__, I don’t need to), Object is a Good Thing, not least because it’s usable from within PythonScripts where classes can’t be defined.

Anyway, I still found it interesting to build something that (when completed) had keyword initialization, dict-semantics emulation[2] and key iteration, so here it is.

class Bag(object):
    def __init__(self, **kw):
        """Initialise, and set attributes from all keyword arguments."""
        self.__allow_access_to_unprotected_subobjects__=1
        self.__members=[]
        for k in kw.keys():
            setattr(self,k,kw[k])
            self.__remember(k)

    def __remember(self, k):         """Add k to the list of explicitly set values."""         if not k in self.__members:             self.__members.append(k)

    def __getitem__(self, key):         """Equivalent of dict access by key."""         try:             return getattr(self, key)         except AttributeError:             raise KeyError, key

    def __setitem__(self, key, value):         setattr(self, key, value)         self.__remember(key)

    def has_key(self, key):         return hasattr(self, key)

    def keys(self):         return self.__members

    def iterkeys(self):         return self.__members

    def __iter__(self):         return iter(self.__members)

    def __str__(self):         """Describe only those attributes explicitly set."""         s = ""         for x in self.__members:             v = getattr(self, x)             if s: s+=", "             s += "%s: %s" % (x, `v`)         return s

[1] It’s not actually a class, it’s a method Object() that returns objects of class _Object so that Zope security paranoia rules can be observed.  Just to be clear 🙂
[2] As much as I needed it, anyway – there’s no iteritems or itervalues support.

A Useful Pot to Keep Things In

Snippet time, with appropriate thanks to Pooh Bear.  I liked this ASPN Python recipe that initializes an object from the parameters to __init__, but thought it was a bit all-encompassing (not to mention a bit too clever with sys._getFrame).  I happened to be in need of something similar for Zope development – a way to return a collection of associated data from an External Method, so I knocked this up:

class Bag(object):
     def __init__(self, **kw):
         """Initialise, and set attributes from all keyword arguments."""
         #This is a bit of Zope magic to allow access from ZPT code.
         self.__allow_access_to_unprotected_subobjects__=1

        #Set an attribute for every keyword argument.         for k in kw.keys():             setattr(self,k,kw[k])

I can create and initialize it all in one go, and use it as a sort of struct equivalent.

See, Zope allows you to pass dicts back from Python to ZPT and access the elements with the usual ZPT “/” based syntax; so if I have a dict:

{ 'id' : 'eric', 'title' : 'Eric the Object' }

I can access it from ZPT with stuff like

<p tal:content="thedict/id">goes here</p><br>
<b tal:content="thedict/title">and the title goes here</b>

which gives me

eric
Eric the Object

But if I need to invoke Python, then I need to remember that the dict is accessed via [‘id’] (etc).  ZPT hides that distinction, which means that it’s easy to forget.  Using a Bag to keep the data in means that the notations are consistent – “/” in ZPT, “.” in Python.

Now I shall go and work out a reason for putting a BurstBalloon in one…

One Tiny Drop Of Truth From SCO

Pure silliness 🙂  Rupert Goodwin’s Diary this week contains this summary of the SCO/DaimlerChrysler spat:

“A SCO customer has to divulge the list of ‘authorised CPUs’ on which the software runs.
DaimlerChrysler, having not run the software for the best part of a decade, quite reasonably replied with ‘There are nil CPUs’.
‘Aha!’ said SCO. ‘Nil is not a list. You owe us a list. We’ll see you in court.'”

If we, in true Spinal Tap-style, translate DC’s comment into a Python-esque “There are None CPUs” then we can see that SCO are right.  None is not a list.  In fact

>> None is list
False
>>> isinstance(None, list)
False

So there you are.  SCO are right 🙂  DC should have said “The list of CPUs is []”.

Told you it was silly.

Fat Lady Chokes

It seems that Opera and  Zope don’t always play together nicely.  The textarea bug I can live with, for now.  However, I’ve had some very odd behaviour within the ZMI – copying objects from one folder to another, the Paste option isn’t visible in the target.  Looks like it might be caching, or it might be cookie handling, but whatever it is – it’s sufficiently unsafe to stop me doing my Zope work in Opera.  Which is a pain, because Opera’s tabbed browsing is excellent for stacking up code next to representation and seeing the results of edits.  Ah well.

Cue The Fat Lady

There wasn’t one final straw that made me flip back to Windows from Linux for my day-to-day work (that’s desktop, not server), it was more an accumulation of straws, like being slowly smothered by a haystack.  Call it the Death Of A Thousand Annoying Little Incompatibilities.  The world (which, as we all know, is a den of wickedness in many respects) insists on remaining Microsoft-centric and for someone who makes a living through a computer connected to the Internet the friction, caused by the mismatch between my Linux/StarOffice/MultipleBrowsers/KDE/Gnome environment and the assumptions that tended to be made, got too much.  I gave in.  You don’t know the Power of the Dark Side.

But actually, it’s ok.  I like Linux; the day that I convert the various servers under my control to a proprietary OS that costs money and needs actual stupid per-client licenses will be the day that I do it for a huge fee as a consultant because I will have resigned, baby.  But in my extremely humble opinion it’s just not there on the desktop for me, as yet.  The effort required to keep a Windows XP setup secure and comfortable is probably about the same as required to overcome the friction between Linux and an MS-oriented world – different tasks, but same effort.  But the homogeneity of the environment is much better; key combinations work across programs, copy and paste don’t fail in odd ways, embedding just… works.  I never liked being a pawn in the Linux game of my-solution-is-better-and-compatibility-sucks.

On the other hand, there are times when Redmond’s unique combination of arrogance and misplaced self-belief gets to me.  Like with the latest IE flaw, as yet unpatched.  So after reading yet one more review of FireFox and Opera, I thought it might be time to give another browser a try.  So I installed Opera and, as a test, pointed it at the Zope API reference.

The Zope site has a comment system that combines minimum usefulness with maximum annoyance.  Make a comment (via the partially fixed comment pages whose help texts refer to invisible or not-yet-implented features) and it gets added to the page.  Permanently.  No way to edit.  No way to retract.  And nobody involved in running the site who has authority to edit comments ever seems to read and prune the un-necessary ones…. anyway, to hide or reveal comments, you click a button, whereupon a huge and hidden Javascript engine creaks into action and rewrites the page, bigtime.  On IE, this can take ten seconds (on deeply commented pages).  On Opera it just happened.  Click.

But the last thing the world needs is another “I Saw The Light And Changed” review, whether blogged, magazined or posted on a forum.  It’s not useful; the sort of people who’d read it can make up their own mind.  But what it made me think about is how much is involved in taking a step away from the mainstream.

Firstly, there’s perception of the need to change.  In my case, it was sparked by a recent security flaw; yet none of the non-techies in my family were aware of that (and yes, I asked a sample), or even of flaws in IE in general.  To them, nasty stuff on their PCs is just something that happens.  It’s life, and when Ben comes round, ask him to take a look at it.  Thus they see no need to change.  Many geeks do.
Secondly, there’s awareness of the existence of alternatives.  One or two have heard of Netscape, but think it’s long dead.  Nobody’s heard of Opera.  Geeks have.
Thirdly, there’s the ability to make the decision, not in some philosophical sense of adopting-an-intentional-stance or the like – just the level of control over the computing environment that’d let them do it.  If it’s a work PC, then chances are that no change will be allowed.  If it’s a home PC – well, changing the browser might affect more than just one person.
Fourthly, there’s the technical ability needed to make the change.  I kept a record of the configuration changes I’ve made to get Opera to where it is now – default browser with imported bookmarks, etc.  There are a lot of them; in some cases I had to go digging into preferences.  Not everything is obvious.
Finally, and here’s the most interesting one to me, there’s the courage to make the change.  You’re shifting something deep in the way you look at the online world.  IE isn’t just an application to most people, it’s an environment in which cool stuff happens.  When you make a change of that magnitude and move to something that doesn’t come with the computer, you risk being out on a limb, you risk failing to get it to work, you risk having odd incomptibilities with things that “work fine for everybody else”.

Think of it like limiting friction; the pull of gravity is not enough to get the stone to roll.  It also needs a heck of an initial push.