Week 1 Recording – I Don’t Want to Grow Up

November 4th, 2009

It’s early. Last week I said I would post a recording before midnight on Nov 5th and it’s the fourth, but I had no choice. I’ve got a pretty bad chest cold and am losing my voice (I sound like a pubescent kid at some parts of the recording :) ). If I’d waited till tomorrow to record it, there’s a good chance it couldn’t have happened.

That being said, I’m happy with the way things turned out. I played the song from beginning to end without any lyric sheets or other visual aids infront of me! The day I posted my intention to learn the song my friend Bill Love sent me the following collage he’d made as a joke. Thing is, it worked! Very well too. Within a couple hours, I could play the song without even needing visual aids. Thanks a lot Bill!

So, anyway, without further ado, here’s a link to the recording: http://www.machete.ca/wp-content/uploads/2009/11/I don’t want to grow up.mp3.

So to keep myself honest, again I declare that the next recording will be out by the stroke of midnight on November 14th EST.

I haven’t decided what song to do you yet, so suggestions would be welcome. I’ll decide by this Saturday what I’m doing and edit this post accordingly.

Thanks for tuning in :)

General, Music , ,

Becoming a Better Musician…

October 30th, 2009

Next blog entry in this series can be found here.

I don’t typically post personal blog entries on my blog, as evidenced by the fact that I didn’t have a category by that title until now, so I hope you’ll forgive me for posting this one.

For the last 4 years or so I’ve been keeping busy with work and family. So much so that I haven’t made time to play the guitar and was too wise to try while the kids slept (anyone who’s ever seen a 3am child induced evil eye will understand what I mean). Now that my kids are sleeping better, it’s time to break out the 6 string again.

I have an admission to make though: I don’t remember lyrics. Ever. Not popular camp fire songs, not even Oh Canada. To make it even more embarrassing, I don’t remember the words to songs that I’ve written myself, including my wedding song (though to be fair, I can make my way through more than half of it from memory).

So, how can I fix this? Practice of course, but how can I make sure that I follow through with the practice? This blog, and the subsequent ones are my attempt. If it doesn’t work, this is going to be, gulp, awkward.

As a disclaimer, I have played before. It’s just been a while since I’ve done so at a level I’m happy with. I play guitar and I sing. Since I was paid 50 bucks once to play at a bar, I guess you can say that I’ve even done so professionally. But even then I was never able to do it without my idiot sheets in front of me.

So, here goes…

I pledge to post a recording of myself playing a song from memory once a week for the next 5 weeks.

First song will be posted by midnight on November 5th, 2009 and will be “I don’t want to grow up” by Tom Waits. I chose that one because I like it and I’d really like to know the words by heart.

If you don’t know the song have a look, and you’re welcome in advance:

So, tune in next week for this weeks exciting conclusion…


Edit: My friend Bill Love just sent me the following picture as a joke, but it might just be the perfect mnemonic for me! I can “see” the picture in my mind and follow along with it! Thanks Bill! It’s my desktop background for the rest of the week.



General, Music, Personal , ,

Hello world, now what?

October 16th, 2009

So, you’ve learnt your first programming language and you’re feeling pretty comfortable with its syntax. What should you learn next?

A couple years ago I’d have recommended you pick up the gof patterns book and learn as many software patterns as you could. This is like learning to play the piano by learning how composers think. I honestly didn’t think you’d be able to apply most of what you’d learn, but i thought being exposed to higher order development ideas would raise the quality of your own.

Boy was I wrong. If a developer isn’t ready for them, patterns just make them over-architect everything. Unless a developer has a problem that would benefit from the application of a particular pattern, they’ll never internalize it. The problem must preceed the pattern before the pattern is seen in future problems.

These days I’d flatly point them towards Test Driven Development (TDD for short). Now, before you think that I’ve jumped on the agile bandwagon because it’s trendy, you should know that I was a hold out. I thought that applying TDD was a waste of programming time. I now think that it uses only slightly more time than an ad-hoc approach, but that time is better spent and the resulting software is of better quality for it.

So, why TDD for novices? It’s simple. By trying to write software that is testable, you end up requiring patterns. You can get away with not knowing them (for a while), but your ignorance causes you in pain; The perfect catalyst for true learning. Eventually one of three things is likely to happen:

  1. you give up, finding the problem too hard
  2. you search for and find an existing pattern (there are so many now that the chances of you not finding one are quite small)
  3. you solve the problem by reinventing the wheel and then possibly discover a name for it later

I think all 3 are good things.

If you give up because you found the problem too hard, then you’ve just discovered that you aren’t cut out for solving technical problems for the rest of your life. At least you won’t be just another miserable coder. Go paint, go write, at least you’ll be happier for it.

If through your research you discover a pattern that solves your problem exactly, the act of refactoring things (changing your code for the better) will make you perceive the beneftis of the pattern anyway. The need for a solution will make it that much sweeter when it’s received.

If you’ve reinvented the wheel… at least you own that wheel and the act of carving it out has made you better at thinking through similar problems in the future. I wouldn’t belittle a carpenters brand new chair simply by saying that he could have bought one for less at Walmart. Plus, should you discover a name for it later, you will always understand it better than had you just read about it.

TDD done right can be a hard thing to do well. It’s more subtle than at first it appears, allowing beginners hit the ground running, subtlety be damned. Long time TDDers will often say crazy things like “It’s not about the tests” and If you’re into that kind of high brow thinking, which I am, you’ll appreciate the sentiment. But for a beginner, TDD can be all about the tests. Eventually by becoming better at the practice of testing, they’ll start to appreciate the higher order lessons that it is revealing. If not, so what, they’ve still learnt a new skill. They may never be masters, but they won’t necessarily be bad at it either.

So, what should you learn after TDD?

It’s very simple, there’s only one thing worth learning and you’ll have have to discover it for yourself. But when you do, would you please write an opinionated blog post about it for me.

Thanks.

Agile Development, Programming , , ,

Social Networks: A boon for business, but not for users.

August 17th, 2009

Forgive the rambling nature of this post, but there are few things that make me spout more jibberish that a strong opinion.

Except for a couple of sites which exist solely because they are social networks and always have been, I’d say that most sites out there are trying to grow social networks for all the wrong reasons.

Most sites that are implementing social networks are doing so because they wish to go viral and grow their user base (which I think is a fundamental misunderstanding since sites don’t go viral, content does). Rarely is it because it provides a significantly better user experience for their customers. There are lots of benefits that could be had with a social graph that don’t require inviting (read pestering) friends as StumbleUpon demonstrates, but since they don’t improve a sites uptake they are rarely executed.

Anyone who’s suffered through Facebook’s latest incarnation will get a feel for what I’m talking about. Facebook apps are almost entirely terrible. I’ve yet to meet anyone who doesn’t wish there was a way of disabling the apps completely. Rare is the application that uses the social graph in a way that makes it better than its old school equivalent. I can’t possibly be the only one who clicks “Skip” when it asks me to notify my friends about my latest victory at some pointless game.

That’s not to say that I don’t like social networks when done right, it’s just that I see a lot of value going untapped because it’s more about virality than providing value to users.

One whole class of social applications that’s completely under represented is one that mines the social graph (relationships between users and their relationships to content) but doesn’t actually force it’s users to interact with other users. StumbleUpon, the site I mentioned earlier, does it perfectly, though recently it seems that they’re pushing the social part of it further. There was a time when you could use it without even being aware that it was a social network. You’d just happily click the button and get your digital pellet.

I think it’ll be a long while before this becomes a dominant approach to improving web apps since it doesn’t lend itself to going viral, but honestly, I think it’s the only one that won’t piss off most people tired of getting bitten by zombies, or getting an invite to yet another social network.

Rant over.

If you read this far… what’s wrong with you? :)

General ,

Neural Networks for Business Analysis

August 5th, 2009

First let me say that this idea isn’t quite flushed out yet, but it’s one that I hope you’ll find interesting.

First off, a little about what neural networks do:

1. They are approximate mappings from a set of inputs to a set of outputs
2. They can be trained with real world data
3. They handle fuzzy inputs pretty well

When you’re applying Neural Networks to a problem, you need to state the problem as a mapping.

For example, if I were trying to predict profitability of a factory, I’d decide on some things to measure about the factory and then relate those to its known profitability.

So for example, I might choose to measure # of employees, avg throughput per month, min throughput per work day, utilization, etc. and relate those things to the profitability of the factory as a measure between 0 and 1.

Now, one interesting thing about this is that some problems with my choices of measurements will become apparent during the training process.

If no matter how many samples I give it to train on or how many neurons the network has, it never seems to be any good at predicting profitability, then it means the things I’ve chosen to measure don’t matter.

If instead of wisely choosing things to measure, I’ve just measured every possible aspect of the factory, I’ll likely get something that predicts profitability, but that takes eons to train. Given that situation, I could start culling measurements and retraining, if the results don’t get worse and it takes less time to train it, then I can safely say that that particular measurement isn’t essential to the prediction (Think # of vending machines in the cafeteria). Repeating the process should lead to the minimum essential measurements and is essentially an automated form of Occam’s razor.

It is possible that no matter how hard I try, the thing won’t train. There might be no relation between inputs and outputs, though I think that for most problems the human beings chosing what to measure would rarely pick measurements that didn’t matter.

Anyway, like I said, this isn’t a finished thought, but i’m curious to know what other think about this approach.

General , ,

More powerful CSS with Preprocessing

June 22nd, 2009

This post is a follow up to my previous post entitled Less annoying CSS using PHP Preprocessing. It’s a refactoring of the original code that’s evolved through various projects I’ve thrown it at.

I’d like to think that the quality of the code is higher since I now consider it far more maintainable. Strikingly, it now is implemented as a class since I never liked having the guts of the implementation visible through all of its helper functions and callbacks.

It is not, mind you, an attempt to make it faster, just more maintainable and powerful, so caching is absolutely necessary on a high traffic website (when is it not though).

So, the complete feature set is now:

Allows for nested selectors
The following is valid code:

#navbar {
  border: 1px solid black;
 
  h2 { background-color: black; }
  li { text-decoration: none; }
}
Constants
Constants may be defined, and may be overridden like CSS rules.

//Example:
 
[Background Color=#000]
body {
  background-color: [Background Color]
}
Imports are performed
CSS imports are now expanded inline with some restrictions. They need to be relative paths, and they need to be relative to the “$base_path” specified while calling the processor. Also, because I didn’t want to fiddle with the Regex anymore, I’ve made it require double quotes around the path. If a file can’t be imported, it’s treated as an empty CSS file.

For example, the following piece of code would perform the imports and then perform preprocessing:

@import url("header.css");
@import url("content.css");
@import url("footer.css");
Single Line Comments
I found this too annoying to allow. I found myself using single line comments (of the double forward slash variety) and getting CSS errors. Never again
Minification (Compression)
I’m stripping everything out that I think isn’t necessary and doesn’t seem to affect the final rendered page (whitespace, empty rules, etc). I haven’t yet encountered anything that’s troublesome, but please let me know if you do.

Without Further Ado… he’s the code (css.php.txt):

<?php
 
// For the purists who don't like enforcing Object Orientation onto the general public
function renderCSS($raw_css, $base_path) {
  $cssProcessor = new CSSProcessor($raw_css, $base_path);
  return $cssProcessor->process();
}
 
class CSSProcessor {
  private $base_path = '';
  private $constants = array();
  private $content;
 
  public function __construct($content, $base_path) {
    $this->content = $content; 
    $this->base_path = $base_path;
  }
 
  /**
   * Processes CSS so that:
   * 1. imports are expanded inline
   *      @import url("testing.css") would be loaded in place 
   *      and any imports it has would also be imported
   * 2. constants may be defined.  For example [Background Color=#000]
   *      would allow for the use of [Background Color] instead of the hard coded #000
   * 3. Single line comments are allows ala //this is a comment style
   * 4. The following is stripped out: comments, unnecessary whitespace, empty rules (a {}) 
   * 5. Nesting of CSS rules. 
   *     For example #navbar a { ... } could be rewritten as #navbar { a{ ... } }  
   */
  public function process() {        
    $this->expandImports();
    $this->expandConstants();
    $this->fixNesting();
    $this->minify();     
 
    return $this->content;
  }
 
  private function expandConstants() {
    $css = preg_replace_callback(
      '/\[([^\]]+)=([^\]]+)\]/', 
      array($this, 'extractConstantsCallback'), 
      $this->content);
 
    $css = preg_replace_callback(
      '/\[([^\]]+)\]/', 
      array($this, 'substituteConstantsCallback'), 
      $css);
 
    $this->content = $css;
  }
 
  private function extractConstantsCallback(array $matches) {        
    $constant = $matches[1];
    $value = $matches[2];
    $this->constants[$constant] = $value;    
    return '';
  }
 
  private function substituteConstantsCallback(array $matches) {       
    $constant_name = $matches[1];
 
    if (!isset($this->constants[$constant_name])) 
      throw new Exception("Reference to unknown CSS Constant: $constant_name"); 
 
    return $this->constants[$constant_name];    
  }
 
  private function expandImports($max_depth = 10) { 
    $cssText = $this->content;
    $imported = $cssText;
    $import_depth = 0;
    do {
      $import_depth ++;
 
      $cssText = $imported;
      $imported = preg_replace_callback(
        '#@import +url\("([a-z0-9_\-]+\.x?css)"\);?#', 
        array($this, 'importCallback'), 
        $cssText);
    } while ($imported != $cssText && $import_depth < 10); 
 
    if ($import_depth == $max_depth) {
      $this->content = '/*Recursive import problem*/';
    } else {
      $this->content = $cssText;
    }
  }
 
  private function importCallback(array $matches) {    
    $filename = $matches[1]; 
 
    return file_get_contents($this->base_path.'/'.$filename);  
  }
 
  private function fixNesting() {
    $result = array();
    $pieces = split("{", $this->content);
 
    $selectorStackIndex = 0;
    $selectorStack = array();
 
    $currentPieceIndex = 0;
 
    for ($i = 0; $i<count($pieces); $i++) {
      $piece = $pieces[$i];
      while (($closeBracketPos = strpos($piece, "}")) !== false) {
        if ($closeBracketPos > 0) 
          $result[] = substr($piece, 0, $closeBracketPos);
 
        $result[] = "}";
 
        $selectorStackIndex--;
 
        if ($selectorStackIndex > 0 ) {
          $result[] = $this->fixNestingSelector($selectorStack, $selectorStackIndex);
          $result[] = "{";
        }
        $piece = substr($piece, $closeBracketPos+1);
      }
 
      if (trim($piece) === '') 
        continue;      
 
      // Inner Rule
      $endOfLastProperty = strrpos($piece, ";");
      if ($endOfLastProperty !== false) {
        $result[] = substr($piece, 0, $endOfLastProperty+1);
        $piece = substr($piece, $endOfLastProperty+1);
      }
 
      if ($selectorStackIndex > 0) 
        $result[] = "}";      
 
      // Whole piece is the selector
      $selector = $piece;
 
      $selectorStack[$selectorStackIndex++] = $selector;
      $result[] = $this->fixNestingSelector($selectorStack, $selectorStackIndex);
      $result[] = '{';
    }
 
    $this->content = join($result);  
  }
 
  private function fixNestingSelector($selectors, $depth) {
    $newSelector = $selectors[0];
 
    for($j = 1; $j<$depth; $j++) 
      $newSelector = $this->fixNestingBuildSelector($newSelector, $selectors[$j]);    
 
    return $newSelector;
  }
 
  private function fixNestingBuildSelector($outer, $inner) {
    $outerPieces = split(",", $outer);    
    $innerPieces = split(",", $inner);
 
    $resultPieces = array();
    foreach ($outerPieces as $o) {
      foreach ($innerPieces as $i) {
        $resultPieces[] = trim($o) . " " . trim($i);
      }
    }
 
    return join(",", $resultPieces);
  }  
 
  /**
   * Minifies the CSS content by removing things that are unnecessary
   */
  private function minify() {
    // remove single line comments, like this, from // to \\n
    $data = preg_replace('/(\/\/.*\n)/', '', $this->content); 
 
    // remove new lines \\n, tabs and \\r
    $data = preg_replace('/(\t|\r|\n)/', '', $data);  
 
    // remove multi-line comments 
    $data = preg_replace('/(\/\*[^*]*\*\/)/', '', $data);  
 
    // remove multi-line comments
    $data = preg_replace('/(\/\*[^\/]*\*\/)/', '', $data);
 
    // replace multi spaces with singles
    $data = preg_replace('/(\s+)/', ' ', $data);
 
    //Remove empty rules
    $data = preg_replace('/[^}{]+{\s?}/', '', $data);
 
    // Remove whitespace around selectors and braces
    $data = preg_replace('/\s*{\s*/', '{', $data); 
 
    // Remove whitespace at end of rule
    $data = preg_replace('/\s*}\s*/', '}', $data);
 
    // Just for clarity, make every rules 1 line tall
    $data = preg_replace('/}/', "}\n", $data); 
 
    $this->content = $data;
  }
 
}

CSS, PHP ,

Making iBatis Type-Safe(r)

March 31st, 2009

iBatis recently came up as a near perfect solution to one of my problems. Its level of data abstraction is exactly right for what I’m doing and it provides out of the box caching. I’d previously tried Hibernate in this context but because my objects are long lived, I’d inevitably need to reconnect the objects to the active session anytime I wanted to do something interesting, like lazy loading.

But, and its a biggie, the interface when using iBatis is not type-safe; meaning I found myself with lots of error prone code resembling:

List<Product> products = (List<Product>)sqlMapClient.queryForList("getAllProducts");

When what I really wanted to do was write code like this:

List<Product> products = productDAO.getAllProducts();

Now, there are existing iBatis DAO options, but it seems to me they don’t solve this specific problem. Their approach to DAOs is a coding convention more than a framework, so you end up encapsulating the type-safety problems, but you still write the code.

With that in mind, I’ve written a utility library that very thinly wraps the iBatis library in a (mostly) type-safe way that doesn’t require me to implement all the access code myself.

I’ll start by providing some example code that makes use of it, and then drilling down into the code that makes it possible.

First off I define my model classes:

public class Product {
  private int id;
  private String name;
 
  public void setId(int id) {
    this.id = id;
  }
 
  public int getId() {
    return id;
  }
 
  public String getName() {
    return name;
  }
 
  public void setName(String name) {
    this.name = name;
  }
}

And the DAO’s interface:

public interface ProductDAO {
  public List<Product> getAllProducts();
  public Product getById(int id);
}

And the actual usage would be something like:

DAOFactory daoFactory = new DAOFactory("path/to/ibatis/config.xml");
ProductDAO productDAO = (ProductDAO)daoFactory.buildDAO(ProductDAO.class);
Product product = productDAO.getById(1);
List<Product> products = productDAO.getAllProducts();

You’ll notice that line 2 does involve a Cast, but this is the only one required to work with the DAO, as opposed to normal iBatis usage which requires you to cast on practically every call.

And the magical class that makes it all possible:

public class DAOFactory {
	private SqlMapClient sqlMap;
 
	public DAOFactory(String configPath) throws IOException {
		Reader reader = Resources.getResourceAsReader(configPath);
		sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);
	}
 
	public Object buildDAO(Class<?> daoInterface) {
		assert (daoInterface.isInterface()) : "buildDAO only works with interfaces";
 
		String namespace = extractNameSpaceFromDaoClass(daoInterface);
 
		InvocationHandler handler = new SqlMapInvocationBridge(sqlMap, namespace);
 
		Object dao = Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] { daoInterface }, handler);
 
		return dao;
	}
 
	private String extractNameSpaceFromDaoClass(Class<?> daoInterface) {
		String[] classNameParts = daoInterface.getName().split("\\.");
		String className = classNameParts[classNameParts.length - 1];
		assert (className.endsWith("DAO")) : "Invalid DAO Interface Provided";
		return className.substring(0, className.length() - 3);
	}
 
	private final class SqlMapInvocationBridge implements InvocationHandler {
		private String namespace;
		private SqlMapClient sqlMap;
 
		public SqlMapInvocationBridge(SqlMapClient sqlMap, String namespace) {
			this.sqlMap = sqlMap;
			this.namespace = namespace;
		}
 
		public Object invoke(final Object proxy, final Method method, final Object[] args) 
                  throws Throwable {
			if (method.getReturnType().isAssignableFrom(List.class)) {
				return sqlMap.queryForList(namespace + "." + method.getName(), args[0]);
			} else if (method.getReturnType().isAssignableFrom(Map.class)) {
				return sqlMap.queryForList(namespace + "." + method.getName(), args[0]);
			} else {
				return sqlMap.queryForObject(namespace + "." + method.getName(), args[0]);
			}
		}
	}
}

Since, at this point it’s only implemented as a thought experiment, it only supports SELECT, but with very little work, it could also allow calls to UPDATE, DELETE, and INSERT.

Suggestions/criticisms are welcome.

General, Java , , ,

The Problem with Mind Mapping Software

March 2nd, 2009

If you give a student a paper and explain the rules of Mind Mapping and let them at it, they run out of room, they create horrible looking diagrams, and they all draw different maps for the same concepts.

One solution to this was to move the process into software. The benefits are “obvious”:

  • Cleaner Maps
  • Easier Undo
  • Auto-Layout

What’s wrong with those… everything!

When you use software to Mind Map you’re deliberately restricting your maps to whatever the developers have gotten around to coding.

Pencil and Paper are far better Mind Mapping tools than all current Mind Mapping Software. Period.

Because…

  • There’s no learning curve, “How do I save again?”
  • You’re limited only by your imagination not the limitations of the software.
  • You can draw truly arbitraty relationships between thoughts in the diagram. You’d have a hard time drawing arrows that snaked themselves between all the branches of a MindMap in most software
  • Each diagram can be completely different than all of the others you’ve drawn

I’m not suggesting that its impossible or even detrimental to write software for Mind Mapping, only that current mind mapping software isn’t inline with the creativity mind mapping is supposed to engender.

I’ll write a follow up blog soon about what I think a Mind Mapping software should look like (Hopefully with an application to boot).

General

Java Observer Pattern Woes

March 2nd, 2009

I have no problem with the Observer Pattern, only its default implementations. Most language libraries provide implementations that are way too abstract and result in good programmers writing buggy code.

As an intro for those who don’t know the back story, the Observer Pattern is a software design pattern that can be used to detach an object from its uses. There are always two players, the thing being Observed (the Observable) and the thing doing the Observing (the Observer). The typical usage scenario goes like this.

  1.  Instance of Observable gets created
  2.  Instance of Observer is created
  3.  Observer registers itself to the Observable for change notifications
  4.  Observable changes
  5.  Notification messages are sent to all objects registered as observers.

Taking a look at the observer as defined in the Java API (see below), you can see that the Observer makes few assumptions about the object emitting the updates, the idea being that it can be reused with different kinds of Observable objects.

public interface Observer {
    void update(Observable o, Object arg);
}

Unfortunately, this comes at a high cost. To make use of the update notification, the Observer typically needs to cast the Observable to a more useful type and interpret the argument appropriately.  If you were planning on reusing it with many kinds of Observable objects, you’d end up with an update method resembling a switch statement for each kind of Observable thing.

As a concrete, though convoluted, example, say I have a Directory class and a DirectoryWatcher that needs to correctly display the number of files in that directory.  The code might look like this:

class Directory extends Observable {
  public File[] getFiles() { ... }
 
  public void createFile(File file) {
    ...
    notifyObservers();
  }
 
  public void deleteFile(File file) { 
    ...
    notifyObservers();
  } 
}
 
 
class DirectoryWatcher implements Observer {
  public void update(Observable o, Object arg) {
    if (o instanceof Directory) {
      System.out.println(((Directory)o).getFiles().length);
    }    
  }
}

“if (o instanceof Directory) {” Yuk!

One improvement is to require that all Observers implement a custom interface and then invoke appropriate methods on them.

For example:

class Directory {
  private List<DirectoryObserver> observers = new LinkedList<DirectoryObserver>();
 
  interface DirectoryObserver{
    void fileDeleted(Directory directory, File file);
    void fileCreated(Directory directory, File file);
  }
 
  public void addObserver(DirectoryObserver o) {
    observers.add(o);
  }
 
  public void removeObserver(DirectoryObserver o) {
    observers.remove(o);
  }
 
  public File[] getFiles() { ... }  
 
  public void createFile(File file) {
    ...
    for (Observer o : observers) {
       o.fileCreated(file);
    }
  }
 
  public void deleteFile(File file) { 
    ...
    for (Observer o : observers) {
       o.fileDeleted(file);
    }
  }
}
 
class DirectoryWatcher implements Directory. DirectoryObserver {
 
  public void fileCreated(Directory directory, File file) {
     System.out.println(directory.getFiles().length);  
  }
 
 
  public void fileDeleted(Directory directory, File file) {
     System.out.println(directory.getFiles().length);  
  }
}

Now, I know that the code above has some flaws in the way it dispatches notifications (Exceptions being one) and that it is significantly longer that the more abstract code above, but this doesn’t need to be the case. By using a helper class ObserverPool (which I don’t define here, but I will eventually) this could be brought down significantly to the code below:

class Directory {
  public final ObserverPool<DirectoryObserver> observers 
                    = new ObserverPool<DirectoryObserver>(this);
 
  interface DirectoryObserver{
    void fileDeleted(Directory directory, File file);
    void fileCreated(Directory directory, File file);
  }
 
  public File[] getFiles() { ... }  
 
  public void createFile(File file) {
    ...
    observers.broadcast("fileCreated", file);
  }
 
  public void deleteFile(File file) { 
    ...
    observers.broadcast("fileDeleted", file);
  }
}
 
class DirectoryWatcher implements Directory.Observer {
 
  public void fileCreated(Directory directory, File file) {
     System.out.println(directory.getFiles().length);  
  }
 
  public void fileDeleted(Directory directory, File file) {
     System.out.println(directory.getFiles().length);  
  }
}

The benefits of the code above are that the observer may make use of the observable object in a type-safe way and each notification is implicitly more useful since it each kind of change may have its own method.

Problems with the above approach are that the observable object needs to call broadcast with an argument of the method on the observers that needs to be invoked. This is a magnet for bugs since a typo breaks everything at runtime. I believe this can be overcome by using Java’s Dynamic Proxy feature to create a proxy object that stands in for the observers.

Using this proxy approach the code could be:

class Directory {
  public final ObserverPool<DirectoryObserver> observers 
                    = new ObserverPool<DirectoryObserver>(DirectoryObserver.class);
 
  interface DirectoryObserver{
    void fileDeleted(Directory directory, File file);
    void fileCreated(Directory directory, File file);
  }
 
  public File[] getFiles() { ... }  
 
  public void createFile(File file) {
    ...
    observers.getProxy().fileCreated(this, file);
  }
 
  public void deleteFile(File file) { 
    ...
    observers.getProxy().fileDeleted(this, file);
  }
}
 
class DirectoryWatcher implements Directory.DirectoryObserver {
 
  public void fileCreated(Directory directory, File file) {
     System.out.println(directory.getFiles().length);  
  }
 
  public void fileDeleted(Directory directory, File file) {
     System.out.println(directory.getFiles().length);  
  }
}

Much better, if I say so myself.

To recap, the typical implementation of the Observer Pattern trades reuse for type safety. Because of this, programmers need to write terrible code to put the checks back in. It’s my opinion that writing more specific code that doesn’t require the loss of type safety is always a better approach, and that by making use of generics and some Dynamic Proxies your end product will be more robust and be easier to understand.

Ideas, Programming , ,

Auto-Zooming ZUI Experiment

February 25th, 2009

I’m curious about the feel of a zoomable interface that navigated by hovering the mouse, so I’ve decided to code a spike using Piccolo2D. I got the idea from reading the JustGo article.

Test 1

The UI is based on the simple logic: Anytime the mouse enters a panel, animate the camera to its extent.

After using it a bit, it’s pretty clear that there’s a flaw in doing it this way since without further user interaction, the mouse can leave a panel when it becomes the focus, which causes it to focus on its parent. This causes it to transition back and forth between the two panels.

Test 2

Giving it some thought, I realized that I could disallow transitions while the system was animating and reduce the strangeness tremendously.

Although this behaves far more logically (it doesn’t jump chaotically without user interaction), it still has a strange behaviour of the mouse leaving the panel during the transition without the user’s interaction. This means that occasionally, the mouse is in “no man’s land” and must be brought back into the panel.

Have a look: http://www.machete.ca/zui1/

Conclusion

Since the mouse enter behaviour can have 2 results, nothing (on the “no man’s land” transition) and camera focus, the auto-zooming navigation above is a modal interface. The user has to pay attention to know the state of the system in order to know what will happen when they hover over the panel.

Until I can figure out how to solve the transition problem, I think requiring a left click is the most logical way of solving the problem.

Usability, User Interfaces , , ,