Archive

Archive for the ‘Programming’ Category

JavaScript Mock Objects

December 23rd, 2009

While testing a library I’m writing I found that I needed to pass in a simple mock object with a small set of methods and track how many times and with what values each of the methods gets called.

The following snippet of code is what I came up with.

function mock() {
    var mockMethods = arguments;
 
    var dummy = {}
    dummy.calls = [];
 
    for (var i=0; i< mockMethods.length; i++) {
        var methodName = mockMethods[i];
        dummy.calls[methodName] = [];
        dummy[methodName] = (function(methodName) {
            return function() {
                //Convert function arguments into an array
                var args = [];
                for (var i=0; i<arguments.length; i++) 
                    args[i] = arguments[i];
 
                this.calls[methodName].push(args);               
            }
        })(methodName);
    }
 
     return dummy;
}

And in an qunit test I’d use it like this:

test("fills rect when bounds and fillStyle are good", function() {
    var n = new PNode({
        bounds: new PBounds(0, 0, 20, 20),
        fillStyle: "rgb(255,0,0)"
    });
 
    var mockCtx = mock("fillRect");
    n.paint(mockCtx);
 
    same(mockCtx.calls.fillRect[0], [0,0,20,20]);
})

I hope someone finds this useful.

Agile Development, JavaScript , , ,

Google Analytics Trick

December 22nd, 2009

It’s not much, but the following jQuery trick allows me to track all outbound links on the site without modifying each and everyone of them.

try {
  var pageTracker = _gat._getTracker(TRACKER_CODE_HERE);
  pageTracker._trackPageview();
 
  $(function() {
    $("a").click(function() {
      var href = this.href;
      if (href.toString().indexOf("SITE_DOMAIN_HERE") == -1) {
        pageTracker._trackPageview('/outgoing/'+href.substring(7));
      }      
    });
  })
} catch(err) {
}

JavaScript , ,

Easy, Simple, Wrong

December 17th, 2009

<rant>
Hey everyone, you can’t simplify indefinitely so stop trying so square the circle!

I’m not saying stop trying to simplify things, just stop once there’s a minimal and acceptable level of complexity. If you dumb it down too much, it’s plain wrong.

Once you’ve reached that point, either you leave well enough alone, or add to it by organizing things. More often than not organizing will actually degrade runtime performance but will decrease development time. If you’re not happy with that, maybe development isn’t for you. You’re likely going to prefer messes and will spend too much time shifting crap around instead than dealing with it.
</rant>

Sorry about that. :)

General, Ideas, Programming, Rants ,

Client-Side JavaScript DSLs

December 14th, 2009

This blog post is about solving one of my JavaScript paint points; specifically its verbosity when defining inline functions. The way in which I solve it is interesting to me and hopefully to someone else too.

Here goes…

Why not do DSLs on the client side by compiling to JavaScript in a compiler written in JavaScript?

I realize that doing a “true compiler” is computationally expensive, but the leaps in JavaScript performance we’ve seen lately make it tractable.

To do the job with the respect it deserves, you need to build a full parse tree, but for my particular DSL, a replacement scheme that relies on regular expressions should do fine except in the pathological cases. Except for obfuscated code, I have yet to find a piece of code that uses commas to separate expressions for example.

So, what do I have in mind?

I love the JavaScript language, but its format for defining lambda expressions is nasty. You’re forced to insert the function keyword where (except for pathological cases) it could be inferred from its context. This wouldn’t bother me at all if I wasn’t required to define them so often while working with jQuery.

For those who are visual, this is the code I’d like to write:

<script type="text/x-javascript">
$({ 
  alert("Hello"); 
 
  $("a").click((e) { 
    alert("clicked"); 
  });
 
  $.post("testing.php", {a: 100, b:100}, (result) { 
    alert("Result is: " + result);
  });
});
</script>

And this is the code I have to write right now:

<script type="text/javascript">
$(function() { 
  alert("Hello"); 
 
  $("a").click(function (e) { 
    alert("clicked"); 
  });
 
  $.post("testing.php", {a: 100, b:100}, function(result) { 
    alert("Result is: " + result);
  });
});
</script>

Now, it’s not a big change, but it’s definitely worth it as your jQuery lambda heavy code starts to balloon.

This is how you could make it happen:

  1. Define a script section that uses an “invalid” mime type and place your code there. This will be ignored by the browser, so you won’t get any syntax errors.
  2. Include an external script that searches for scripts of a certain type, converts them, then evaluates.

If you want to see this idea in action take a look here: http://www.machete.ca/x-javascript.html

I can’t be the first person to have thought of this, but I thought I’d tell it on the mountain just incase.

Thoughts?

Ideas, JavaScript, Programming , , ,

Documentation Metrics

December 8th, 2009

I recently had a telephone conversation regarding documentation practices that planted a seed. I’m pretty sure this isn’t a new idea, how could it be, but it’s something that I’ve never seen explicitly stated.

I’m a big fan of static analysis and code metrics in general. The reason I’m a fan is that there’s something in my constitution that likes to see improvement over time. If I think a number correlates strongly enough with software quality, I’ll enjoy seeing that number improve. It’s soothing to me.

What I haven’t seen around is a metric that can be used to measure the quality of a software library’s documentation. Without such a metric, any investment in time towards improving its documentation will never be a sexy thing for me to work on, and I’m probably not alone in these feelings, since most projects have terrible documentation.

I think the # 1 most important thing to measure about a library’s documentation is its web analytics.

Here’s my train of thought: Ultimately documentation is about connecting users to answers. If your page is a promising candidate for solving their problem, then it should receive more quality visits. Anything you do that increases the number and/or quality of those visits is a step in the right direction. If you attempt to game the search engines, it would negatively affect the quantity of hits you’re documentation gets since search engines already take these kinds of things into account.

I’m not exactly sure how the metric will be computed but I’m absolutely sure it’d involve hits, duration of visits and bounce back rate.

I’m imagining a 3rd party documentation analytics embed code that can be used freely on open source projects and that can display on each documentation page a measurement of its “quality” and how its trended over time. It’d allow you to compare two equivalent projects’ documentation, and more importantly tell how much effort is being spent on a projects documentation.

Wouldn’t that be nice? So many open questions. What do you think?

Programming , ,

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 , , ,

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 , , ,

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 , ,

PHP Encapsulation Done Better

February 23rd, 2009

Encapsulation is great; it hides complexity and makes systems easier to maintain. With that in mind most developers thumb their noses at the idea of exposing internal state via public access modifiers.

What I’m proposing is that a PHP OO design is different than a full hog Java one, and that by using magic methods wisely, you can start off with a very simple public property based design, and then as requirements become more complex, refactor in the encapsulation using magic methods when required.

To illustrate the ideas take a look at the code below:

class Person {
  public $firstName;
  public $lastName;
 
  public function __construct($firstName, $lastName) {
    $this->firstName = $firstName;
    $this->lastName = $lastName;
  }
}
// Usage
$person1 = new Person('Allain', 'Lalonde');
echo $person1->firstName . ' ' . $person2->lastName;

Most developers consider the code above so bad that they’d willingly inflict the following torture on themselves:

class Person {
  private $_firstName;
  private $_lastName;
 
  public function __construct($firstName, $lastName) {
    $this->_firstName = $firstName;
    $this->_lastName = $lastName;
  }
 
  public function getFirstName() {
    return $this->_firstName;
  }
 
  public function getLastName() {
    return $this->_lastName;
  }
 
  public function setFirstName($firstName) {
    $this->_firstName = $firstName;
  }
 
  public function setLastName($lastName) {
    $this->_lastName = $lastName;
  }
}
 
// Usage
$person = new Person('Allain', 'Lalonde');
echo $person->getFirstName() . ' ' . $person->getLastName();

If you’re from a Java background, you might prefer the second version. It “feels” safer. You can change the implementation without breaking the code that uses the class.

Thing is though, using magic methods, you can encapsulate public fields.

As an exampke, say that you want to change the first piece of code so that the Person class is immutable (once an instance is created, it cannot change). You could refactor it as follows:

class Person {
  private $_firstName;
  private $_lastName;
 
  public function __construct($firstName, $lastName) {
    $this->_firstName = $firstName;
    $this->_lastName = $lastName;
  }
 
  public function __get($fieldName) {
    switch ($fieldName) {
      case "firstName":
        return $this->;_firstName;
      case "lastName":
        return $this->_lastName;
      default:
        throw new Exception("Attempted to access invalid property: ".$fieldName);
    }
  }
}
 
// Usage
$person1 = new Person('Allain', 'Lalonde');
echo $person1->firstName . ' ' . $person2->lastName;

The counter argument is that magic methods are considered slow, but I’ll argue that in most designs the use of this pattern would be minimal, and accessing a public property is faster than invoking a method. So it’ll probably be faster on average than invoking getters and setters for every property.

Now, I hope you followed my logic to now. And I’d love to hear your thoughts.

My 2 cents

PHP, Programming , , ,