Arrrgghh writing GUI programs is tedious

Last week I thought it would be a good idea to write a small GUI front end to virt-resize.

After two days, I nearly have the first tab (out of four) working.

Granted, maybe the first tab is the hardest one:

The job of the first tab is to ask the user for the source (disk image or libvirt guest). It then fires off a background job to open that guest and inspect it for operating systems. Based on the outcome of that (opened OK, found OSes, no OSes found, etc) it has to update and enable the other tabs.

Also the user can preselect a guest on the command line. We also have to deal with connecting to libvirt asynchronously to read the list of guests (and this might also fail in a number of ways).

So far, 1600 lines of code, and the first tab is by no means complete.

One part of the problem is there’s a certain “impedance mismatch” between functional programming in OCaml and writing Gtk. Gtk is heavily mutable and object based. OCaml prefers (but does not require) immutability, and objects in OCaml are obscure and not widely used, and the Gtk bindings are written in a very hard-core object OCaml style.

Another part is just that it’s tedious. It would be tedious if I was doing this in C or Python too. You’ve got asynchronous actions going off here and there which update bits of state. Every control or input could potentially affect every other control or output, resulting in a kind of O(n2) mess of wiring up signals and callbacks.

Is there an easier way? I don’t know …

About these ads

13 Comments

Filed under Uncategorized

13 responses to “Arrrgghh writing GUI programs is tedious

  1. smizrahi

    You should use glade to generate all the biolerplate stuff for you. And use python to clean up the rest. It’s should save you a lot of time.

    • rich

      Glade doesn’t solve the wiring/logic problem at all. In fact, glade is solving a non-problem. [Edit: I should add “when glade works …”, which is not that often. It’s a crashy, buggy poc which changes its output format in every release.]

      In addition, Python is a terrible language for writing programs. I don’t know how people deal with the complete lack of safety. (And yes I’ve got experience here, hacking virt-manager).

      • Disclosure: given that our employer pays me to work on Python, I have an obvious bias here (and this is my opinion, not my employer’s, etc)
        Caveat: it’s been a while since I’ve done GUI coding.

        I second the “use glade and python” comment; your response seems rather strange to me.

        You assert that Glade is solving a non-problem. Looking at the screenshot, it’s clear that you’re constructing the widget hierarchy “by hand” i.e. in code. The reason I say that is to give you a taste of your own medicine (see e.g. your GNOME 3 rants).

        One of the issues with UI development is that it’s far too easy to criticize a GUI compared to actually fixing that GUI, compared to that ratio for non-graphical programs. This can be very dispiriting.

        So here comes my criticism: your GUI is ugly. You should use a graphical tool for this; it’s far easier to refine the look that way. You might want to look at gazpacho: it’s a reimplementation of glade that may or may not be more stable (I don’t know if that project is still alive, but back when I worked on GUIs in was). BTW, don’t use Glade’s code autogeneration feature, always just use libglade to turn the XML layout file back into widgets, and a graphical tool to create that layout file.

        Glade _does_ solve at least part of the wiring problem: see e.g.:

        http://www.pygtk.org/docs/pygtk/class-gladexml.html#method-gladexml–signal-autoconnect

        This makes it trivial to wire up widgets to e.g. Python callbacks to specific UI events. This doesn’t solve the other half of the problem: dealing with the events from the VM being inspected/modified. The reference to O(n^2) in wiring suggests to me a need for the Mediator design pattern (from the GoF book); I’ve successfully used this in the past to simplify the interactions between multiple UI elements: all of the interactions go through a “mediator” object, leading to O(n) wires.

        You declare that you’ve found it really hard to do in OCaml, then assert that “Python is a terrible language for writing programs”. I’d argue that all you’ve demonstrated is a deficiency in OCaml, not in Python.

        In terms of the “complete lack of safety”, presumably you are referring to the lack of compile-time type-safety. The normal response to this is an automated test suite; e.g. see Bruce Eckel’s ” Strong Typing vs. Strong Testing.” blog post, which now seems to now be archived at https://docs.google.com/View?id=dcsvntt2_25wpjvbbhk&pli=1

        Unfortunately, that can be hard to do with an interactive graphical program. My first thought here is to mock out the internals of asynchronously querying the VM for its various properties, so that you can easily exercise the various event-handling cases in an automated way. A poor-man’s version of this might be to fuzz-test: have an internal component that randomly emits all of the different state change messages that the VM-interaction code can emit. Or you could look at e.g. Dogtail (though, again, it’s been a while since I worked on this).

        Then again, programming language choices seem to be a highly personal thing: different languages fit different people’s brains better. From my reading of your blog, you seem to have an intense dislike of Python.

        Was GUI programming your first exposure to Python? That might explain why you dislike Python; that was mine, and I wasn’t keen on what I saw. My opinion changed after tackling some other problems with it, and when I came back to GUI programming, I found it was significantly easier.

        [and yes, I’m more than aware of Python’s various deficiencies, and am working on fixing them…]

        Hope this is helpful.

  2. At some points, GObject property bindings could help to make this less of a pain:

    http://developer.gnome.org/gobject/unstable/GBinding.html#g-object-bind-property

    You might see support for this in Glade somewhere in the next months (I worked on it for GSoC).

  3. d.

    I’ve heard of Adobe using a tailored language to describe their GUIs and more importantly tell in a descriptive way how each GUI item influences the others.

    Could reactive programming help in that regard?

    • rich

      I’ve never really got into FRP despite trying to explain it a couple of years ago. The idea is straightforward enough, but it’s still a wiring problem.

      How is it different from Gtk signals? Signals at least have helped me in guestfs-browser so that now everything is wired together in a single place, which is better than distributing the wiring all around the program.

      I don’t think this is an OCaml problem. I think it’s a GUI programming problem.

      Also interesting: http://stackoverflow.com/questions/2672791/is-functional-gui-programming-possible

      • d.

        I entirely agree Richard! This is a deep GUI programming problem. When I programmed the GUI a demexp (OCaml program) years ago I faced similar issues (days to develop very simple GUI) and was deeply disappointed by the different technical solutions (being OCaml or others like Qt).

        Regarding the Adobe approach I was mentioning:

        http://stlab.adobe.com/group__asl__overview.html#asl_overview_intro_to_adam_and_eve

        “””
        The property model library consists of a solver and a declarative language for describing constraints and relationships on a collection of values, typically the parameters to an application command (a function). When bound to a human interface (HI), the property model library provides the logic that controls the HI behavior. A property model is similar in concept to a spreadsheet or a forms manager. Values are set and dependent values are recalculated. The property model library provides facilites to resolve interrelated values, but is not a general constraint system.
        “””

        They mention constraint system. Maybe logic languages that integrate constraint systems like GNU Prolog could help (thinking out loud).

        Best regards,
        d.

      • Adrien

        Yes, it *is* possible and FRP can help I think.

        It’s not a silver bullet however and you can use it like you use functional programming in OCaml: for the big picture. Mutability is better sometimes. A mix of both should work out well.

        As for you O(n²) wiring, I definitely agree. I’m almost ready to make a preview release of lablgtk-react and, after a lot of design changes, I’ve settle for something quite simple which gets it down to O(n) (2*n actually): you get a central interface which you send data to, and which feeds it again to the whole interface. You get n sources which send signals and data to only one element “X”, which then sends data to n sinks. This element “X” can do pure computations and use all the nice stuff we’re used to in FP.

        Release date: when I get 4 to 8 hours free and can write the examples. IMHO, knowledge on FRP is enough for the first applications today but the GUI libraries haven’t necessarily kept up. A few short changes to lablgtk2 give what is needed, but these changes required some knowledge of glib and lablgtk2 along with the will to spend some time on it.

      • rich

        Looking forward to it.

  4. One suggestion I have is to consult a UX person/team on the GUI approach you’re taking. It seems odd to have a single tab requesting information from the user and then enabling other tabs. That’s not quite the typical tab pattern.

    The Gnome HIG team is working on an updated version that includes things like patterns but we’re not quite at the point where it would be helpful to most people. In lieu of this you might consider asking for input on the right approach for your GUI.

    As an example, if the first tab is needed to be filled out before the rest of the tabs are useful, it feels more like a prompt than a tab. Or you might consider a Wizard-style approach if you want to walk the user through some steps.

    In terms of actually creating the screen, I’d suggest mocking it up rather than actually building it, even in things like glade. You might start with paper, as it is easy to explore ideas and throw them away if they suck. For more refined (and shareable) mockups I like Inkscape for example, and find it quick and easy to throw together screen ideas for review with other people or for discussion. It is less costly than trying something in Glade/code and then tweaking it.

    Writing GUI programs may be tedious, but the GUI is a large contributor to an application’s success, so it should be given the same amount of thought and exploration that code-based problems often are (IMO).

  5. In nearly 20 years, I haven’t found a better way to write a GUI than Tcl/Tk, either forking Unix commands to do the work in the background, or linking it to C or other compiled code (Tcl’s intended use) . For the sort of async stuff you want to do, -textvariable with an event loop is perfect.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s