GNOME 3.0 Final Verdict

After GNOME 3.0 was released, I gave in and decided to take the plunge. I packed up my .xinitrc and .xmonad/ and decided to give it a fair shake. I used it for about a week of real work, as well as the usual recreational activities (surfing, coding, wine).

The Good

Overall I was impressed at how effective I became with GNOME 3.0, although it’s a far cry from Xmonad (as I’ve mentioned in the past, but I’ll try not to get into tiling evangelism here). I’m not as keyboard-centric as I’d like to be, so already I have my hands on the mouse more than necessary. Getting back into the drag and drop paradigm wasn’t hard. I will admit I used the drag-to-side half vertical tile functionality built into mutter a *lot* and, for the most part, I was content with it. Vertical tiles are by far the most common layout I use, and even though it was restricted to a 50/50 split (and sometimes I like a 70/30), it was nice.

The gnome-shell bar took a little getting used to (it’s hard not looking at the top right corner for a time), but the status icons contained in it were very sleek and their menu options were very useful. These little icons were one of my favorite changes in 3.0. Particularly on my laptop where the network manager icon is very useful.

As I’ve mentioned before, I love the keyboard friendly additions. Like the built-in run dialog with completion, and the ability to type two letters of a program name from the activities view and see it pop up in the icons. I like that even more than I like my Xmonad dmenu, which is saying something. I haven’t figured out whether you can easily address the “favorites” on the left hand sidebar, but the new use case is very nice. Also, I was able to make the transition a bit easier from Xmonad by binding some keys from the keyboard controls (like Alt+F2 to open a terminal, Alt+F3 to open the run dialog, Alt+1,2,3 to switch desktops). These worked well, although I would have liked the ability to Alt+Shift+1 to send a window to a desktop.

Everything with my usual work went fine (with some caveats in the next section), surfing was no problem. Multimedia worked just fine, sound with pulseaudio was no issue (although I’ve been using pulse for awhile even outside of GNOME). I was pleased that running things like smplayer fullscreen on my TV was handled just fine and didn’t interfere with working on the other monitor. I guess problems with using 3D and video at the same time have been worked out long ago, but I was concerned with the new desktop. My only qualm with that was that when someone switched to the activity view on the main screen, the full screen movie was shrunken a bit and enumerated like all the others (so it’s hard to use the main desktop without jarring the people watching the movie on the other screen. At least it’s consistent though and, because the movie was still playing in the slightly smaller window and with sound this is only a minor nitpick.

My wife actually really likes the new interface. She’s running it on her netbook and also on our “family” machine (RAID box), which is where I did the movie testing. GNOME is more her style of usage, being the type that uses a web browser and the media players most often. I was pleased that her little netbook had no trouble with the graphics either (it’s by far the lowest spec machine we have, unless you count phones).

Lastly, our Wine Diablo 2 sessions went very well. I found that if we run in a desktop, GNOME properly treats it like any other window, and it smart enough to full screen it on restore and hide its window bar. I attempted to run in unmanaged, full screen mode and it works. The bar was still shown for some reason, but that appears to have been fixed in the interim as I can’t reproduce now. The one issue that I had was that running unmanaged, if I accidentally hit the windows key, I had no idea how to get back to the Diablo 2 screen. If I hit windows key again, it would automatically take me back, but if I had focused another window it was a mystery.

All in all, I was happy with what amounts to the initial rough cut of the 3.0 interface. I’m really looking forward to seeing where it goes. I think that if I’m ever able to finish up my current side project, I might start taking a look at contributing some improvements. However, for now, I have some definite WTFs.

The Bad

Multiple Monitor Desktops

GNOME 3.0 has pretty decent support for taking advantage of more than one screen. As I mentioned above, playing a movie on one and working on the other works fine. The main problem is that, by default, your secondary screen can only have one desktop on it. Now this might be a sane default (i.e. switch tasks on the primary screen, keep static things like IMs / email / multimedia on the second screen), but it’s not how I want to use my monitors.

There is a gconf setting to allow the desktop to basically span both screens (so switching to desktop 2 changes both monitors) but after I enabled it, support was buggy. Things like closing empathy would cause windows to warp onto my primary desktop for no apparent reason. I guess there’s a reason this is hidden in gconf. Although I have no clue why it would still be a gconf key, as I though they were switching to dconf, but I could be wrong.

Anyway, ideally I’d like to see Xmonad style multiple monitor support. I.e. you have one desktop apiece and can change them independently. Xmonad enumerates them all and allows you to show any two, but I’d settle for having a per-screen desktop stack since that seems like it would fit the GNOME 3.0 paradigm.

Empathy / Integrated Messaging

I’ll admit, I was excited about the integrated messaging. It seems so useful and one of my nits about XMonad is that I always have to switch back to my IM windows, or send them to the desktop I’m working on.

This feature is entirely broken on release though. Empathy is just not ready, and neither was the integration. For example, you get a nice notification on a new message (or, configurably, on contacts going online / offline). You can even click that message and respond inline. Cool! But what you can’t do is focus another window and keep that inline chat window open. I want to hold a conversation while surfing Reddit with the inline window hovering on my desktop. I like to be able to read the last four or five lines of my conversation, not just see the next response show up for an instant in a notification and decide whether I want to respond.

In addition, the interaction between the integrated bar and the “traditional” empathy chat is absolutely bizarre. For example, if you have a real empathy chat window open (which you almost always will because of the inability to keep the integrated window open), and you receive a new message, you get a notification and a little chat blurb on your notification bar, but no new chat window in the actual empathy window. Some sort of foibling is required to get it to open there, and I’m not quite sure what.

The “traditional” empathy contact list is also underfeatured, like not being able to change the order of contact groups. It also doesn’t remember your status setting on return (just setting you to “Available”, whereas pidgin will automatically reuse that last status). Finally, because it supports some form of LAN messaging that never seems to connect the contact interface is constantly spinning as if it’s loading.

The last thing, and the true deal breaker for me using GNOME 3.0 is that the notification bar fails to show you urgent flashing notifications. I walked out of the room for a moment and missed a message. I had *no idea* I had missed anything until I randomly displayed the notification bar and say the empathy icon flashing and a two-hour-old message from my boss asking for an email. That doesn’t work ladies and gentlemen. I can’t take two hours to respond to a message. That’s ridiculous. Especially since I was sitting at my computer the whole time. Hell, I’ve even missed notifications because I was looking at my other screen.

I thought GNOME 3.0 was designed specifically for this workflow. I guess I was wrong.

Conclusions

Nobody argues with the fact that the GNOME 3.0 interface needs work. I was pleased with using it for awhile, but it’s sorely in need of improvement with a handful of things. Especially the chat and notification features, which are effectively broken.

The upshot though is that nothing is so wrong with the concept or the execution that these bugs couldn’t be fixed very quickly. These are not problems that should require heaps and heaps of code to fix. In fact, I wouldn’t be surprised if distros officially packaging GNOME 3 have already addressed and patched some of them.

NOTE: All of the above judgments were made using the current (as of 19 April) Arch GNOME 3.0 packages from gnome-unstable and testing. Particularly the gnome, gnome-extra, and telepathy meta-packages. Arch is great, but I’m assuming these packages are basically packages as-is, with only minimal distro integration patches.

Posted in software | 2 Comments

Evince: So close, yet so far.


EDIT: Suddenly my Evince 3.0.0 (according to Arch 3.0.0-3) has started naming bookmarks with the current / first new section on the page. Kudos to whoever fixed that, although the help still claims there’s no such thing as a bookmark =). 7 May 2011

Let it be known that I’m a bit of a PDF power user. Not because I wanted to be, but because my job suddenly started entailing reading 1000 page specs that are held together with nothing but blinding seas of jargon. Being that they’re usually new CPU user manuals and SoC programming references, they’re also extremely useful… when you can find the information that you need.

So, it was with open arms that I embraced Evince’s new 3.0 feature: bookmarks. It’s only been recently that I’ve started to need this feature, but a quick Google indicates people have been WTFing over Evince not supporting bookmarks since it was created. The F1 help (which as of this writing on Arch Linux still says that bookmarking isn’t supported) notes that you can use annotations as bookmarks, but it seems to me that they’re fundamentally different things and, even if they weren’t, the PDFs I’m reading seem to have hundreds of blank annotations. I’m not sure if that’s Evince’s fault (not all PDFs have it), if the annotations are real, or if the person generating the PDFs is just using a crappy PDF generator.

After installing Evince 3.0, I decided to give bookmarks a spin. I scrolled to a useful page in one of my specs (a page describing the minutiae of some bits in a hardware table that I’ve been using recently). Seeing the new “Bookmarks” menu, I simply clicked “Add Bookmark” (Ctrl+D would’ve sufficed as well). Then, clicking the same menu, I got a bookmark listed: “Page 250″. Right clicking it had no abilities, there was no apparent way to edit the bookmark. Gah. “Page 250″ is almost worthless as a bookmark, especially since I had like 10-15 other bookmarks I wanted to make. Bookmarks shouldn’t force a user to shuffle through them all just to figure out what they are.

Bad Bookmark

But wait!

But I didn’t give up there. The “Bookmarks” menu makes it totally non-obvious, but in the Evince sidepane (hit F9 or View->Sidepane) you can now select a “Bookmarks” selection from the pull down. From that list of bookmarks, you can right click and actually rename / remove your bookmarks.

Menu with real options

After renaming, they then show up properly in the “Bookmarks” menu.

For shits I decided to try it out on some other, non-work PDFs from random places on the internet. No dice for the bookmarks. Not that it tells you why it can’t create bookmarks, but from the look of it, Evince can only bookmark PDFs that support embedding them. I can’t be too disappointed because it doesn’t look like FoxIt or Acroread can do it either. Both of them seem to think “bookmarks” are chapter and section headings which is stupid. Nonetheless, I was hoping for a [gd]conf / ~/.config/evince solution that would work generically with all PDFs and versions.

So, in the end, the new feature is nice … after you learn to use the sidepane for it, and only if the PDF you’re using happens to support it.

For reference, the failing PDFs were (for some reason) all PDF 1.4, optimized, with no security and the work PDFs were 1.6, optimized, no security. I’m guessing that it comes down to the PDF version, but I could be wrong.

Posted in software | Leave a comment

Xmonad backed by GNOME 3.0

My previous post criticized modern desktop environments (like gnome-shell and KDE 4.6) because they lack anything resembling efficient window management. It’s not a surprising view coming from someone that’s been spoiled by Xmonad’s beautifully easy mouse-free window management and dynamic layouts.

I’m not going to talk about window management today though. I installed a fresh copy of the libraries from Arch’s gnome-unstable repository and, instead of giving gnome-shell another whirl (not yet at least), I merely restarted Xmonad with the usual suspects running in the background (gnome-settings-daemon, gnome-keyring-daemon) and continued to use my typical GTK apps.

I have to say that I was pleasantly surprised that the GNOME beta functioned well as a drop-in replacement and, aside from the different theme and widget style everything worked identically. The VNC client still remembered my passwords too, so I interpret that as the keyring being intact. I even like the new default font and anti-aliasing choices. I’m sure some people will complain that it looks muddy (as critics of anti-aliasing almost always do), but to each their own.

Overall I’ve been pleased with some of the non-shell improvements of GNOME 3. The control center is a good replacement for the system menu of traditional GNOME and on par with Windows and KDE. I probably appreciate it a little more than average considering that I don’t have the system menu under Xmonad and it’s easier to remember to invoke gnome-control-center than it is to remember which little GNOME subapp to use to tweak some behavior of the GNOME applications.

One thing that surprised me was dconf-editor. I’ve heard throughout the GNOME 3 bashing blogs, that a lot of the configuration was hidden in dconf-editor and that really sucks because it’s basically regedit. That may be true, but GNOME has always essentially had a registry (gconf) and dconf-editor has to be the nicest registry editor I’ve ever used. Not that it’s a passable replacement for a control center option, but as a developer and desktop explorer it’s nice to see a full on description of each possible toggle and tweak in the registry.

I understand that this is a very small subset of GNOME that I’m using, but it’s nice to know that even if the GNOME desktop’s next full release is the Linux desktop apocalypse, everything will still just work.

Posted in software | 3 Comments

The Sad State of Mainstream Window Management

No doubt you’ve all been keeping (or have been kept depending on how you read the news) up on the GNOME 3.0 / gnome-shell / Unity stuff that’s been going on. In short, the new major version of the typical GNOME desktop, 3.0, has reinvented the way that you interact with your desktop.

Initially I was excited to hear the news because the new release is supposed to be much more keyboard friendly than “classic” GNOME, and I am all about efficiently using the keyboard. That said, I am wary of any sort of broad scale change like this because I haven’t been fully convinced this is a good idea. Gnome-shell takes some good ideas, like the concept of per-task workspaces and the aforementioned keyboard friendliness, but it falls short. I’ve been trying to compose this entry for awhile since I compiled the gnome-shell ecosystem and even tried the gnome3.org liveCD, but it wasn’t until I read this post about eliminating minimize/maximize that it finally struck me. What the mainstream DEs are missing now is decent window management.

I’ve been an Xmonad user for years now and that one fact has really kept me away from using GNOME or KDE (in it’s vanilla form) for about as long. It’s just unwieldy to move windows with the mouse and painstakingly arrange windows to be productive. It’s this sort of task that software should make simple. For the uninitiated, Xmonad arranges all windows on a workspace in a dynamic layout. If you have one window, it takes up the whole screen. Two, and it’s divided between the two, three and it’s divided between the three and so on. The layouts are very advanced, ranging from simple splits to spirals, to circles. Sending windows to another workspace, switching workspaces, switching layouts, all of these can be accomplished with simple keystrokes. I don’t know how I’d survive without it anymore, I just have too many active terminals and applications to juggle with a mouse.

To be clear, I’m not advocating that GNOME start using Xmonad (although Xmonad integrates beautifully with GNOME 2.x). Also, I am aware the latest gnome-shell builds support a rudimentary tiling by dragging a window to the left or right edge of the screen, but it’s just not enough. KWin (KDE’s window manager) recently added basic tiling support as well but its efforts are just as primitive and laughable.

If the GNOME devs want to improve the way we interact with our windows, like gnome-shell purports to do, we need way more control over them both automatically (like dynamic layouts) and with user interaction. Basic concepts like “maximize” and “minimize” cease to make sense when the user has so much more power over how windows are shown by default. Want to work with your windows like a stack of papers (all fullscreen)? There’s a layout for that. Want to have a desktop with a browser and a news reader split 70/30? There’s a layout for that. Floating desktop for something like GIMP? There’s a layout for that. Decide the current layout no longer works for your workflow? Change it and the windows are automatically rearranged. Any conceivable, efficient way to view your windows can be chosen and dynamically used by a window manager. Using layouts makes dragging windows with a mouse feel like stone age technology or a child’s puzzle.

Additionally, the technology is entirely backwards compatible. If developers are worried about scaring new users with their layouts (although since gnome-shell is already a radical departure that doesn’t make too much sense) then just make the default layout behave like the current default (floating). Meanwhile, the rest of us looking for a better way can benefit. Perhaps best of all for the GNOME community, the people looking for that level of efficiency are also usually developers.

In short, there needs to be a powerful set of keybinds with a powerful set of window actions (send to desktop n, switch to desktop n, change layout, give window layout focus, etc.). If a major DE like GNOME got behind the tiling/dynamic layout paradigm, that would truly be a leap forward. Until then gnome-shell will be, at best, a marginal improvement over 2.x or, at worst, a KDE 4 style debacle. For now, all of us Linux users have to choose between a desktop with A+ integration (like GNOME 2.x — although in reality it’s probably more in the B-/B range) and a desktop that gets out of your way and lets you manage your tasks efficiently.

Posted in software | 2 Comments

New Machine

This is my first post for a topic not intended for a larger audience =). I’m building a new machine. I ordered the parts from Newegg and they should be here on Monday. Although… they are here in TX already (yes, I have the tracking number stats open in my browser right now, did you think I wouldn’t?), so I might be making a roadtrip this weekend just to have something to do other than dream about hardware.

Needless to say, I’m looking forward to it. The last computer I built in 2008 was primarily for media (our RAID box), so disk read performance was paramount over any sort of gaming etc. Juliette uses it as a Sims 3 box (via PlayOnLinux), and Scarlett plays her PBS/Disney/Nickelodeon flash games on it, so it works pretty well for that and serving up media to the PS3. But it’s an unorganized mess and even Juliette playing the Sims beats the shit out of the video card (a 7300 SE / 7200 GS I picked up for $30 just to be able to attach a monitor to the machine), so I decided to pick up an identical 460 GTX for it as well. I can’t tell you how hard I wanted to keep it a secret and SLI my box, but the Sims stop cranking the box and being able to use the HDMI output to the TV might cut the PS3 transcoding step out of watching media if I can figure out sound.

Just for shits though, I decided to lookup the benchmarks. Ouch. According to videocardbenchmark.net which is run by “Passmark” who I’ve never heard of (but also have no reason to doubt their relative numbers) the card that’s in there (7300 SE / 7200 GT — according to lspci) got a 66, and is ranked 656 of all of the cards they ranked. To put that in context, the Geforce TI 4400 I bought when I was… geez… a sophomore in high school (2002) got a 216 and is ranked 349. I couldn’t believe it. I mean, I knew it was a $30 card and it wasn’t going to impress anybody by any stretch of the imagination, but *damn*, being a third as powerful as a card I bought 6 years previously. Goddam. Now, I’m not sure how this benchmark really works, nor do I really care, but the 460 GTXs got 2296 for an overall rank of 7. And that’s vanilla (mine are overclocked) and with an unspecified amount of RAM (either 768M or 1G, mine are 1G).

So, quite a hefty upgrade for the RAID box. Assuming that the benchmark scales linearly (which might be a bad assumption), that means the card I’m putting into it is 35x better than the POS I’m taking out. Hope you enjoy actually being able to play the Sims, honey =).

Anyway, the stats: 3.0Ghz Core i7-950 (Bloomfield), 4GB of Kingston DDR3 1800 RAM, an overclocked Gigabyte GTX 460 video card, a Western Digital 1TB SATA 3Gb/s drive, a USB 3.0 compatible ASUS Sabretooth motherboard, a 750W Corsair PSU and a full size heavy-as-balls Antec case. Topped off with dual ASUS 24″ 1920×1080 widescreen LCDs.

Posted in personal | Leave a comment

Using Decorators for Flexible Prompts

As a general rule, anything that you’re going to need to do many times should be abstracted to be made easy. When you’re coding something with a prompt, adding commands definitely falls into that category. With Python introspection and decorators make a new text prompt can be as simple as writing a function and defining a simple format for it. Like this:

    @command_format(("terms","listof_uint"))
    def sumstar(self, **kwargs):
        print sum(kwargs["terms"])

Which is safe, clear, and working. This method has a number of advantages:

  1. It easily allows for features like automatically prompting for missing arguments and argument defaults.
  2. The decorator for each command function doubles as documentation since it both simply lists the names of the keyword arguments as well as their types.
  3. Cleanly separates the function of the command from the validation of its arguments.
  4. Ideal for allowing users to write pluggable commands because actual command functions use native objects instead of strings, and they automatically receive the benefits of prompting, listing, defaults, etc. Plus, there’s only a single line of overhead when the validators are pre-defined.
  5. Allows validators to easily use each other so multiple minor variations of the same type of validation can be expressed simply.
Table of contents

The command_format Meta-Decorator

def command_format(*types):
    def cf(fn):
        def cfdec(self, **kwargs):

            rem = kwargs["args"]
            realkwargs = {}

            for kw, validator in types:
                validator = getattr(self, validator)
                valid, result, rem = validator(rem.lstrip())
                if not valid:
                    log.debug("Couldn't properly parse %s" % kwargs["args"])
                    return

                realkwargs[kw] = result

            return fn(self, **realkwargs)
        return cfdec
    return cf

It’s not every day that you see a triple nested def, but it’s pretty standard meta-decorator, where *types is a list of string tuples like [("keyword","validator")]. Where each keyword is the name of the keyword argument the parsed object will be passed as to the final command function and each validator is a string-reference to a method of the class this command resides in. If you’re operating outside of a class, this validator could easily be a function reference as well.

This meta-decorator is applied to every function that embodies a command. We’ll get to that later. For now, let’s look at what these validators look like.

A Simple Validator

Validators are passed one argument: the entire unparsed portion of the string you’re parsing, which can be ""/None. It returns a three tuple of objects. A boolean value whether the validator passed and, if it did, the resulting object and the remaining, unparsed portion of the string. Let’s take a look at a simple validator that will take a positive integer.

class MyCommandHandler(...)
    ...
    def uint(self, args):
        terms = args.split()
        if not terms:
            return (False, None, None)

        try:
            ret = int(terms[0])
        except:
            log.error("Couldn't parse %s as integer!" % terms[0])
            return (False, None, None)

        if ret < 0:
            log.error("Argument must be > 0")
            return (False, None, None)

        return (True, ret, " ".join(terms[1:]))

Extremely simple, it grabs the first whitespace delimited argument from the string, attempts to parse it as an integer and makes sure it’s >0 before returning that the arg passes validation.

Let’s put our command_format and the int validator to use by writing a simple sum that will take a string argument, attempt to parse out two integers and print the sum.

sum Example

class MyCommandHandler(...)
    ...
    @command_format(("term1","uint"),("term2","uint"))
    def sum(self, **kwargs):
        print kwargs["term1"] + kwargs["term2"]

No need to do any extra validation on either argument, we know both that they exist and they’re integers, so we’re safe.

At this point, with a little wrapping code we can do the following:

jack@arpeggi:~ $ ./basicsum.py
sum 12 16
28

sum 1 b
Couldn't parse b as integer!
Couldn't properly parse 1 b

But that’s not very exciting. Let’s look a little harder and see how we can leverage these.

More Useful Validators

Automatic Argument Prompting

The first thing that pops to mind as being a useful addition to a command prompt is being a little more tolerant to missing arguments. Let’s make our uint validator prompt instead of bailing on an empty string.

class MyCommandHandler(...)
    ...
    def uint(self, args):
        if not args:
            args = raw_input("uint: ")

        terms = args.split()
        if not terms:
            return (False, None, None)

        try:
            ret = int(terms[0])
        except:
            log.error("Couldn't parse %s as integer!" % terms[0])
            return (False, None, None)

        if ret < 0:
            log.error("Argument must be > 0")
            return (False, None, None)

        return (True, ret, " ".join(terms[1:]))

NOTE: One of the attributes of the command_handler resulting decorator is that the arguments passed to each validator are stripped of leading whitespace so we know that if not args will work on any empty string passed to the validator.

Now, again with a shade of wrapper code, we have a bit more functionality.

jack@arpeggi:~/blog $ ./promptsum.py
sum
uint: 13
uint: 14
27

sum 13
uint: 20
33

sum 14 15
29

Function on Lists of Arbitrary Types

So, at this point, we’ve basically got a sum2 function and, even though it’s nice (=P), it’s pretty inflexible. Let’s write another validator that generates a list of uints and work on that, with another appropriate function. Better yet, let’s write a validator that will make a list of *any* consistent type.

class MyCommandHandler(...)
    ...
    def listof_(self, prompt, val, args):
        l = []
        if not args:
            args = raw_input(prompt)

        while args:
            v, term, args = val(args.strip())
            if v:
                l.append(term)
            else:
                # If you wanted to be really fault tolerant, you could
                # remove the first term and try again. We'll be really
                # strict here though.
                return (False, None, None)
        return (True, l, "")

    def listof_uint(self, args):
        return self.listof_("uints: ", self.uint, args)

There we go. As you can see, the listof_ function will attempt to use any given validator on the input until it’s used up. A smarter implementation might not use up the whole input, but expect lists to be bracketed by symbols, or a certain length. This also includes the arbitrary prompt that we used before. Let’s put it to use implementing sum*.

    @command_format(("terms","listof_uint"))
    def sumstar(self, **kwargs):
        print sum(kwargs["terms"])

Done. Now we have a much more flexible sum* command. As evidenced using starsum.py.

jack@arpeggi:~/blog $ ./starsum.py
sum*
uints: 4 7 8
19

sum* 3 8 10 11
32

sum* 4 5 6 a
Couldn't parse a as integer!
Couldn't properly parse  4 5 6 a

Closing Notes + Source

The above examples use positive integers (and yes, I’m aware that *sum* works on negative integers a well =P) because they’re a convenient type that everybody knows. One of the advantages of the system is that it doesn’t matter what sort of return object the validator gives, the command functions can just assume everything is all right because it never gets called if the args don’t parse correctly. I wrote a system very much like this for the new version of my side project Canto (an RSS reader) that allows users to give a list of story indexes, which are then converted from simple integers to actual story objects by the validators (listof_items) and passed to the corresponding function.

Also, this code is easily extensible to use any sort of input format (obviously raw_input isn’t exactly the most useful way to get a string from the user if you’re graphical or running ncurses, like I always am). Canto uses this via a Textbox class from a curses window.

The examples used in this write-up are available as executable .py files (used for the output sections).

Basic sum2 validating prompt: basicsum.py
Added missing argument prompting: promptsum.py
Added sum*: starsum.py

These were tested on Linux with Python 2.6, but should work on practically any platform with any relatively modern Python. It’s also under public domain, if you actually care about the licensing of blog snippets =).

:wq

Posted in programming, python | Leave a comment

Calm Down!

I’ve been ditching a lot of code lately. The first thing was my side-project Canto’s old codebase*. The second was this blog, which is now obviously a WordPress blog instead of a quirky but fun-loving git based CMS I wrote before. All together, I’ve shed thousands of lines of code and it feels great. But as I toss this code to the wayside, I can’t help but wonder “How did things get this way? Where did I go wrong?”

One thing that I’ve learned over the course of my programming travails is that design is more important than implementation. As I maintained and extended and improved Canto over the two or three years since I first started it, I learned a lot about showing foresight. A lot about how getting a feature into a codebase right is a better long-term strategy than getting a feature into a codebase quick.

Programming is a tough task. It requires a lot of concentration and thought and, as if that wasn’t bad enough, it’s generally done under a lot of pressure. Either from deadlines from a boss, or just expectations of your users (or your perception of either). A lot of choices I’ve made in the last couple of years have been wrong because they’ve been twisted by having the perception an audience. If someone sends you an email and they’re in distress because of a bug you feel as if they’re waiting for your response, constantly refreshing their mail client or feeling frustration with your software the whole time the flaw goes unpatched. You feel as though there are a thousand other users that have run into the same bug and just never reported it only to move on to greener pastures. You see the 10 day (or more!) turnaround time on your packages in repositories. The fact that Ubuntu is now actively serving up a broken version to its users and there’s nothing you can do but fix it for the next iteration (Salacious Salamander or whatever) six months later. Suddenly it’s as if everyone using your software is secretly unhappy with it.

It’s hard not to face these troubles and feel an urgency beyond reality. Feel the need to find it, fix it, and push it to the repo and make a release before anybody else reports the same problem. But, unless you’re dealing with a critical bug and your software is immensely popular it’s probably not as urgent as you imagine. Most likely, the user reported the bug and moved on with their lives. They either uninstalled your software, will use something else in the meantime, or will patiently wait for a fix. If you’re lucky, maybe they included a patch. The point is, what the user does is what the user does, it’s up to you to take your time and really analyze a problem before you fix it. There are plenty of potential users out there and for any user you lose over a single bug there’s another who will try your software after it’s patched. That’s why it’s important to find the right solution instead of the quick solution because the right solution will keep you from getting into this situation again (or make it easier to fix correctly when you do) and the quick solution increases the probability that you’re going to feel that sort of pressure, and lose another user over essentially the same bug.

Coding is all about trying to maximize the time you spend writing features and feeling rewarded, and minimize the time you spend bug fixing and feeling like your users are searching you out with machetes. Anything you do to sway that balance in your favor should be done without hesitation. But what can you do? I might not be the best person to ask, but these are some improvements I’ve been trying over the last few weeks and so far so good. I call my new philosophy “Calm The Fuck Down

  1. Start over. Either on the project, subsystem, or feature level. Even with recognition of the fact that the current implementation has become unmanageable, it’s always hard to look at functioning code and say “This is crap! Tear it out!” but sometimes that’s the only thing to say. Coders tend to look at their own code and not see its utility, or its elegance, but the weight of all of the obstacles they’ve overcome, or the bugs they’ve ironed out. To be passionate about good code, you have to be dispassionate about your own code. As you gain experience you see the error of your ways and have to re-evaluate practically every decision you’ve made in the light of new information and the easiest way to do this is to start over. It’s not always the right thing to do, but when you suddenly realize that your code has turned into a chain of hacks then you have no other path forward. Some developers believe they can just do a quick stub-out of code, or a quick and dirty narrow implementation now and return later. Maybe you can. I can’t. My thought is that if you can’t take the time to do it right, it’s time to hold off and give it a bit more thought.
  2. Put everything on paper first. This is something that I find helps alot, particularly if you’ve really got a good handle on the language you’re using, because it helps you layout your data structures beforehand and anticipate your needs before you even open your editor. Sometimes it doesn’t work out (I actually just rebased out of existence a commit that I had planned out on paper but had fallen victim to a number of unexpected twists), but most of the time an hour of planning can save you a full day of coding. If you get into the habit of putting everything on paper first, your first step in responding to a feature request or a bug report is grabbing a piece of paper and a pen, instead of impulsively taking a hatchet to your codebase.
  3. Don’t let the phantom specter of imagined users fleeing over bugs or missing features rush your design decisions. I’ve fought this battle for so long that it’s become meaningless. There’s always another feature, always another bug. If you rush to fix a bug, you’re probably simultaneously laying the groundwork for the next one. Getting a fix or a feature out means nothing if it bites you in the ass down the line. So unless people’s boxes are being enslaved into a malicious porn spam botnet because of a security flaw, it can wait.

As for all of that code I’ve scrapped over the last few months, I chalk it up to one thing: practice. If the wise men of yore are to be trusted, that apparently makes perfect…

Reddit tl;dr : Regardless of perceived pressure, calm the fuck down and take your goddam time.

*Tangentially, Canto 0.8.x is much stronger and in alpha for harder-core IRC lurkers.

Posted in programming | Leave a comment