How to one best avoid writing bloated GUI code

guirefactoring

I find whenever I work with GUI code, the code tends to bloat faster then other kinds of code. It also seems harder to refactor. Whereas in other kinds of code I can refactor pretty easily — I find I can decompose a larger class into smaller pieces of functionality — with most GUI frameworks I'm often bound to a framework that requires my widget/control/whatever class to implement a lot more things more directly in the widget/control/whatever. Sometimes this is due to needing to either (a) inherit off of some base widget/control/thing or (b) need access to protected methods.

I typically also have to, for example, respond to a large variety of inputs via signals/events/whatever from the framework to implement all the modes of interacting with the user. I might need in one GUI widget/control to handle a large variety of input/output that might include:

  1. a right click/context menu
  2. reacting to selections from the context menu — which may be many
  3. a special way to paint the GUI
  4. react to keyboard input
  5. buttons, checkboxes,
  6. etc etc

… all the while manage the classes under the GUI representing business logic.

A simple straight-forward GUI can have its code grow pretty quickly, even when seperating out buisiness logic and using MVC, I find GUI code is a big magnet for change.

Is there any way to manage GUI code in a sane way and avoid letting it become a broken window? Or is a mass of random event handlers/overridden methods really the best we can do for GUI code?

Best Answer

The thing to remember about GUI code is that it is event-driven, and event-driven code is always going to have the appearance of a mass of randomly organized event handlers. Where it gets really messy is when you try to shoehorn non-event-driven code into the class. Sure, it has the appearance of providing support for the event handlers and you can keep your event handlers nice and small, but all of that extra support code floating around makes your GUI source seem bloated and messy.

So what can you do about this, and how can you make things easier to refactor? Well, I would first change my definition of refactoring from something I do on occasion to something I do continuously as I code. Why? Because you want refactoring to enable you to more easily modify your code, and not the other way around. I'm not simply asking you to change the semantics here, but asking you instead to do a little mental calisthenics in order to see your code differently.

The three refactoring techniques that I find I use most commonly are Rename, Extract Method, and Extract Class. If I never learned a single other refactoring, those three would still enable me to keep my code clean and well structured, and from the content of your question, it sounds to me like you will probably find yourself using the same three refactorings almost constantly in order to keep your GUI code thin and clean.

You can have the best possible separation of GUI and Business logic in the world, and still the GUI code can look like a code mine has been detonated in the middle of it. My advice is that it doesn't hurt to have an extra class or two to help you to manage your GUI properly, and this does not necessarily have to be your View classes if you are applying the MVC pattern - although frequently you'll find the intermediary classes are so similar to your view that you'll often feel an urge to merge them for convenience. My take on this is that it doesn't really hurt to add an additional GUI-specific layer to manage all of the visual logic, however you probably want to weigh up the benefits and costs of doing so.

My advice therefore is:

  • Do nothing directly behind your GUI except to invoke and define how the GUI will hook into the View (or an intermediary layer).
  • Don't try to shoe-horn every view related thing into a single class - or even a single class per GUI window - unless it makes sense for you to do so. Your alternative is to create lots of little and easy to manage classes to manage your GUI logic.
  • When your methods are starting to look a little larger than a 4-5 lines of code, examine if this is necessary and if it is possible to extract a method or two so that you can keep your methods lean, even if this means a class with many more methods.
  • If your classes are starting to look really large, start by removing ALL of the duplicated functionality, and then see if you can logically group your methods such that you can extract another class or two.
  • Think about refactoring every time you write a line of code. If you get a line of code to work, see if you can refactor it to avoid duplicating functionality, or to make it a little leaner without changing the behaviour.
  • Accept the inevitable, that you will always feel that one part or another in your system will start to feel a little bloated, especially if you neglect refactoring as you go. Even with a well-factored code base, you can still feel as if there is more that you could do. This is the reality of writing software, that you will find yourself always feeling that something more could have been done "better", so you need to strike a balance between doing a professional job, and gold-plating.
  • Accept that the cleaner you try and keep your code, the less bloated your code will seem.
Related Topic