<?xml version="1.0" encoding="UTF-8"?>
<!--Generated by Squarespace Site Server v5.11.81 (http://www.squarespace.com/) on Thu, 31 May 2012 01:32:20 GMT--><feed xmlns="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/"><title>Kevin Webber's Blog</title><subtitle>Blog</subtitle><id>http://kevinwebber.ca/blog/</id><link rel="alternate" type="application/xhtml+xml" href="http://kevinwebber.ca/blog/"/><link rel="self" type="application/atom+xml" href="http://kevinwebber.ca/blog/atom.xml"/><updated>2011-11-03T02:16:01Z</updated><generator uri="http://www.squarespace.com/" version="Squarespace Site Server v5.11.81 (http://www.squarespace.com/)">Squarespace</generator><entry><title>Multiplayer tic-tac-toe in Java using the WebSocket API, Netty (NIO), and jQuery</title><id>http://kevinwebber.ca/blog/2011/11/2/multiplayer-tic-tac-toe-in-java-using-the-websocket-api-nett.html</id><link rel="alternate" type="text/html" href="http://kevinwebber.ca/blog/2011/11/2/multiplayer-tic-tac-toe-in-java-using-the-websocket-api-nett.html"/><author><name>Kevin Webber</name></author><published>2011-11-02T21:31:28Z</published><updated>2011-11-02T21:31:28Z</updated><content type="html" xml:lang="en-US"><![CDATA[<p>What does this game of tic-tac-toe and Twitter have in common? Both have been implemented using relatively the same technologies: Java and Netty. It was big news in 2010 when Twitter <a href="http://engineering.twitter.com/2011/04/twitter-search-is-now-3x-faster_1656.html">migrated their search from Ruby on Rails to Java-based Netty</a>. Not only was it big in the news department, but it was also big in the results department: Twitter reported their search performance increased by 3x.&nbsp;</p>
<h2>What is Netty?</h2>
<p><a href="http://www.jboss.org/netty">Netty</a> is a client server framework by JBoss that simplifies network programming. Netty is built on top of <a href="http://en.wikipedia.org/wiki/New_I/O">Java NIO</a> but provides a much more simple API to work with. Netty can be used to build a custom server for network communications; it can be used to build anything including a lightweight HTTP server, a TCP / UDP server, a WebSocket server, or any other network server you can dream of. Because Netty is built on Java NIO, Netty's programming model is asynchronous. This means Netty is very well suited for any number of bi-directional communication projects such as real-time group chat or anything else requiring the server to <a href="http://en.wikipedia.org/wiki/Push_technology">push information to a client</a> rather than other methods of network communication such as <a href="http://en.wikipedia.org/wiki/Comet_(programming)">long-polling</a>.</p>
<h2>What is the WebSocket protocol?</h2>
<p>WebSocket is a protocol used for bi-directional asynchronous communications between a client (usually a web browser) and a server that supports the WebSocket protocol.</p>
<p>A WebSocket client connects to a server via standard HTTP and performs a handshake, which creates a persistent tunnel between the client and server. After the handshake is performed the client and the server communicate freely using a message/event-driven programming model (binding actions/methods to events). The beautiful thing about the WebSocket protocol is the number of persistent connections that WebSocket servers can handle, easily numbering in the ten-of-thousands, and the volume of messages that can be processed (depending on the way the server is implemented).</p>
<h2>Netty in action - A game of tic-tac-toe</h2>
<p>Rather than build the same-old group chat application everyone else does to show off the flexibility of Netty and the WebSocket protocol, I decided to build a simple game of tic-tac-toe instead. It seems like an odd decision considering tic-tac-toe is a turn-based game rather than a real-time game, but most tic-tac-toe game demos on the net are single-player. Rather than build another single player game of tic-tac-toe, let's build a multiplayer game!</p>
<p>The core concepts behind the game are:</p>
<ol>
<li>The tic-tac-toe client and server can support a (theoretically) infinite number of simultaneous games, and each game supports 2 players.</li>
<li>The player loads the client (a web page) and waits for an opponent.</li>
<li>An opponent loads the client.&nbsp;</li>
<li>Both players are matched together automatically.</li>
<li>The server responds to both players to let them know their game has started. The server notifies the client which player should go first and each player's assigned letter.</li>
<li>The client only allows one player to select a cell at once.</li>
<li>After each turn, the other player is notified of the other player's selection and their screen is updated automatically.</li>
<li>After each turn the server determines if someone has won or if the game is a draw.</li>
</ol>
<p>If you'd like to review the full code for the working Netty tic-tac-toe client and server before reading ahead, feel free to check it out:</p>
<p><a href="https://github.com/rocketpages/Netty-TicTacToe-Server">https://github.com/rocketpages/Netty-TicTacToe-Server</a></p>
<p><a href="https://github.com/rocketpages/TicTacToe-Client">https://github.com/rocketpages/TicTacToe-Client</a></p>
<h3>Building the Netty server</h3>
<p>The first step to creating our tic-tac-toe server is to build the server itself. Creating a new server in Netty is dead simple. We simply need to instruct Netty which port to bind to and which pipeline factory to use.</p>
<p>Netty works based on inbound and outbound "handlers"; upstream handlers and downstream handlers. As a message is either received by the server or sent by the server, it is acted upon by the handlers that you specify in the pipeline factory. This is a flexible architecture and lets us work in a very modular fashion on any given message. Anyone who has done MDB, MQ, or SOAP programming (SOAP handler chain) should be familiar with the concept already.</p>
<pre class="prettyPrint">public class TicTacToeServer {
    public static void main(String[] args) throws Exception {
        ChannelFactory factory =
            new NioServerSocketChannelFactory(
                    Executors.newCachedThreadPool(),
                    Executors.newCachedThreadPool());

        ServerBootstrap bootstrap = new ServerBootstrap(factory);

        bootstrap.setPipelineFactory(new WebSocketServerPipelineFactory());

        bootstrap.setOption("child.tcpNoDelay", true);
        bootstrap.setOption("child.keepAlive", true);

        bootstrap.bind(new InetSocketAddress(9000));
        
        System.out.println("TicTacToe Server: Listening on port 9000");
    }
}<span style="color: #181818; white-space: normal;">&nbsp;</span></pre>
<p>The next step is creating the pipeline factory. In this case we're using a custom pipeline factory called WebSocketServerPipelineFactory. We could also have built this as an anonymous class as our implementation is fairly simple, but I decided to break it out into it's own high-level class.</p>
<pre class="prettyPrint">public class WebSocketServerPipelineFactory implements ChannelPipelineFactory {
	public ChannelPipeline getPipeline() throws Exception {
		// Create a default pipeline implementation.
		ChannelPipeline pipeline = pipeline();
		pipeline.addLast("decoder", new HttpRequestDecoder());
		pipeline.addLast("aggregator", new HttpChunkAggregator(65536));
		pipeline.addLast("encoder", new HttpResponseEncoder());
		pipeline.addLast("handler", new TicTacToeServerHandler());
		return pipeline;
	}
}
</pre>
<p>Take a second to look at the above code. I'll break out some of the key terms and concepts to understand:</p>
<ul>
<li><strong>Channel:</strong> A channel is a persistent connection (tunnel) from a specific client to the server.</li>
<li><strong>ChannelPipeline:</strong> Each channel can be customized with it's own pipeline. When you take a second to think about it, it becomes obvious how powerful this concept is. Encoders, decoders, aggregator, and handlers are grouped together to form a <em>pipeline</em>. A pipeline instructs Netty how to act on each channel.</li>
<li><strong>Encoders, decoders, and aggregators:</strong> Netty is a low-level framework built on Java NIO. When a client first connects with the server, we need to perform a WebSocket handshake. NIO doesn't care about HTTP however, it cares about packets. In order to process the HTTP request and response, we need to instruct Netty how to deal with the packets we're receiving and sending. Netty makes this easy and provides multiple encoders, decoders, aggregator, and handlers. We'll typically extend Netty to create our own custom handlers, but if we're so inclined, we can also get really low-level and create our own encoders, etc. Also keep in mind that these can be swapped-out <em>at runtime. </em>After the initial HTTP handshake is performed, we're only going to be responding to WebSocket requests <em>for this channel</em>. You'll see later how we change from an HTTP-based pipeline to a WebSocket-based pipeline for a specific channel (aka client, aka player).</li>
<li><strong>TicTacToeServerHandler:</strong>&nbsp;This is the heart of the application, responsible for consuming and pushing all messages to and from clients. An instance of this handler is specific to a channel, but we can also declare static variables to keep track of all the games of tic-tac-toe in progress at any given time.</li>
</ul>
<p>Let's check out the TicTacToeServerHandler. <a href="https://github.com/rocketpages/Netty-TicTacToe-Server/blob/master/src/main/java/com/tictactoe/server/TicTacToeServerHandler.java">The complete code can be viewed here</a>. I'll discuss some of the core concepts below.&nbsp;</p>
<pre class="prettyPrint">	@Override
	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
			throws Exception {
		Object msg = e.getMessage();
		if (msg instanceof HttpRequest) {
			handleHttpRequest(ctx, (HttpRequest) msg);
		} else if (msg instanceof WebSocketFrame) {
			handleWebSocketFrame(ctx, (WebSocketFrame) msg);
		}
	}
</pre>
<p>The <em>messageReceived(...)</em> method is the main callback method provided by Netty to process incoming messages from clients. In our case, we'll only be processing two types of messages: HttpRequest (for the initial handshake from a client) and WebSocketFrame (for all incoming communications after the tunnel has been established).&nbsp;</p>
<pre class="prettyPrint">private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req)
		throws Exception {

	// Allow only GET methods.
	if (req.getMethod() != HttpMethod.GET) {
		sendHttpResponse(ctx, req, new DefaultHttpResponse(
				HttpVersion.HTTP_1_1, HttpResponseStatus.FORBIDDEN));
		return;
	}

	// Serve the WebSocket handshake request.
	if (req.getUri().equals(WEBSOCKET_PATH)
			&amp;&amp; Values.UPGRADE.equalsIgnoreCase(req.getHeader(CONNECTION))
			&amp;&amp; WEBSOCKET.equalsIgnoreCase(req.getHeader(Names.UPGRADE))) {

		// Create the WebSocket handshake response.
		HttpResponse res = new DefaultHttpResponse(
				HTTP_1_1,
				new HttpResponseStatus(101, "Web Socket Protocol Handshake"));
		res.addHeader(Names.UPGRADE, WEBSOCKET);
		res.addHeader(CONNECTION, Values.UPGRADE);

		// Fill in the headers and contents depending on handshake method.
		// New handshake specification has a challenge.
		if (req.containsHeader(SEC_WEBSOCKET_KEY1)
				&amp;&amp; req.containsHeader(SEC_WEBSOCKET_KEY2)) {
			
			// New handshake method with challenge
			res.addHeader(SEC_WEBSOCKET_ORIGIN, req.getHeader(ORIGIN));
			res.addHeader(SEC_WEBSOCKET_LOCATION, getWebSocketLocation(req));
			String protocol = req.getHeader(SEC_WEBSOCKET_PROTOCOL);
			if (protocol != null) {
				res.addHeader(SEC_WEBSOCKET_PROTOCOL, protocol);
			}

			// Calculate the answer of the challenge.
			String key1 = req.getHeader(SEC_WEBSOCKET_KEY1);
			String key2 = req.getHeader(SEC_WEBSOCKET_KEY2);
			int a = (int) (Long.parseLong(key1.replaceAll("[^0-9]", "")) / key1
					.replaceAll("[^ ]", "").length());
			int b = (int) (Long.parseLong(key2.replaceAll("[^0-9]", "")) / key2
					.replaceAll("[^ ]", "").length());
			long c = req.getContent().readLong();
			ChannelBuffer input = ChannelBuffers.buffer(16);
			input.writeInt(a);
			input.writeInt(b);
			input.writeLong(c);
			ChannelBuffer output = ChannelBuffers
					.wrappedBuffer(MessageDigest.getInstance("MD5").digest(
							input.array()));
			res.setContent(output);
		} else {
			// Old handshake method with no challenge:
			res.addHeader(WEBSOCKET_ORIGIN, req.getHeader(ORIGIN));
			res.addHeader(WEBSOCKET_LOCATION, getWebSocketLocation(req));
			String protocol = req.getHeader(WEBSOCKET_PROTOCOL);
			if (protocol != null) {
				res.addHeader(WEBSOCKET_PROTOCOL, protocol);
			}
		}

		// Upgrade the connection and send the handshake response.
		ChannelPipeline p = ctx.getChannel().getPipeline();
		p.remove("aggregator");
		p.replace("decoder", "wsdecoder", new WebSocketFrameDecoder());

		// Write handshake response to the channel
		ctx.getChannel().write(res);
		
		// Upgrade encoder to WebSocketFrameEncoder
		p.replace("encoder", "wsencoder", new WebSocketFrameEncoder());
		
		// Initialize the game. Assign players to a game and assign them a letter (X or O)
		initGame(ctx);

		return;
	}

	// Send an error page otherwise.
	sendHttpResponse(ctx, req, new DefaultHttpResponse(
			HttpVersion.HTTP_1_1, HttpResponseStatus.FORBIDDEN));
}
</pre>
<p>The code above is performed when the client initially connects to the tic-tac-toe server. The WebSocket specification defines how a <em>handshake </em>needs to be performed. There are two versions of the handshake implemented above: one based on the old WebSocket specification (75), and the other based on the new version of the WebSocket specification (76). The biggest difference between the two handshake methods is the old version does not require a challenge while the new version does. To slightly complicate matters, different browsers implement different versions of the WebSocket specification. Another twist is that neither 75 or 76 is the latest version of the WebSocket specification, but these are the most commonly implemented by modern browsers. A deep dive into the WebSocket specification is beyond the scope of this article, but <a href="http://www.whatwg.org/specs/web-socket-protocol/">you can find the latest draft specification here</a>.</p>
<p>This brings up an important point; the WebSocket specification is constantly evolving. Fast. I would strongly recommend exploring the option of using a higher-level framework for business programming rather than rolling your own server, because as you see above, you'll need to keep up-to-date with the latest changes in&nbsp;the spec and which versions are supported by which browsers. It's generally a good idea to leave this up to framework developers. That being said, even if you're planning to use a high-level framework, getting an in-depth knowledge of Netty is a very good thing. Down the road if you need the kind of flexibility and power that Twitter does you'll already know how to implement it.</p>
<p>Also note that we're programmatically changing the aggregator, encoder, and decoder for <em>this channel only</em>. As soon as the handshake is successful we will be communicating with the client exclusively using the WebSocket protocol rather than HTTP. If we were to leave the original HTTP encoder, decoder, and aggregator alone, our server would not understand how to deal with a WebSocket packet; it would still be trying to piece together usable HTTP requests and responses.</p>
<p>Now let's take a look at some tic-tac-toe specific logic. First we'll need to create a game and assign players to it. As players connect to our server they're paired off and assigned to a game. Our server will be able to support an infinite number of games simultaneously, although I doubt tic-tac-toe will ever become as popular as Twitter.</p>
<pre class="prettyPrint">private void initGame(ChannelHandlerContext ctx) {
	// Try to find a game waiting for a player. If one doesn't exist, create a new one.
	Game game = findGame();
	
	// Create a new instance of player and assign their channel for WebSocket communications.
	Player player = new Player(ctx.getChannel());
	
	// Add the player to the game.
	Game.PlayerLetter letter = game.addPlayer(player);
	
	// Add the game to the collection of games.
	games.put(game.getId(), game);
	
	// Send confirmation message to player with game ID and their assigned letter (X or O) 
	ctx.getChannel().write(new DefaultWebSocketFrame(new HandshakeMessageBean(game.getId(), letter.toString()).toJson()));
	
	// If the game has begun we need to inform the players. Send them a "turn" message (either "waiting" or "your_turn")
	if (game.getStatus() == Game.Status.IN_PROGRESS) {			
		game.getPlayer(PlayerLetter.X).getChannel().write(new DefaultWebSocketFrame(new TurnMessageBean(YOUR_TURN).toJson()));
		game.getPlayer(PlayerLetter.O).getChannel().write(new DefaultWebSocketFrame(new TurnMessageBean(WAITING).toJson()));
	}
}

private Game findGame() {		
	// Find an existing game and return it
	for (Game g : games.values()) {
		if (g.getStatus().equals(Game.Status.WAITING)) {
			return g;
		}
	}
	
	// Or return a new game
	return new Game();
}
</pre>
<p>The code above is mainly responsible for creating and maintaining games, which are stored in the TicTacToeServerHandler as a static collection (shared across all instances of our handler). As players connect to our server we assign them to a game and let them know that they are either waiting for an opponent or that an opponent has connected and their game has begun. Exciting!</p>
<p>Finally, we need to accept incoming WebSocket messages. Each message represents a player's turn (which cell they selected). After we process the turn information we need to push data out to their opponent to let them know how badly they're getting <em>pwned</em>. We also need to check the status of the ongoing game; it's fairly important to be able to tell if a game has been won or tied after the last move!</p>
<pre class="prettyPrint">private void handleWebSocketFrame(ChannelHandlerContext ctx,
		WebSocketFrame frame) {
	
	Gson gson = new Gson();
	IncomingMessageBean message = gson.fromJson(frame.getTextData(), IncomingMessageBean.class);
	
	Game game = games.get(message.getGameId());
	Player opponent = game.getOpponent(message.getPlayer());
	Player player = game.getPlayer(PlayerLetter.valueOf(message.getPlayer()));
	
	// Mark the cell the player selected.
	game.markCell(message.getGridIdAsInt(), player.getLetter());
	
	// Get the status for the current game.
	boolean winner = game.isPlayerWinner(player.getLetter());
	boolean tied = game.isTied();
	
	// Respond to the opponent in order to update their screen.
	String responseToOpponent = new OutgoingMessageBean(player.getLetter().toString(), message.getGridId(), winner, tied).toJson();		
	opponent.getChannel().write(new DefaultWebSocketFrame(responseToOpponent));
	
	// Respond to the player to let them know they won.
	if (winner) {
		player.getChannel().write(new DefaultWebSocketFrame(new GameOverMessageBean(YOU_WIN).toJson()));
	} else if (tied) {
		player.getChannel().write(new DefaultWebSocketFrame(new GameOverMessageBean(TIED).toJson()));
	}
}
</pre>
<p>Remember earlier that handleWebSocketFrame is one of our own methods, not a callback method provided by Netty. This method is invoked when we inspect the incoming message and determine it's a WebSocketFrame rather than an HttpRequest. The core of the logic above deals with updating the <em>game board </em>and marking the current player's last move. We also need to check for victory or draw conditions and update the player and opponent with the latest game status.</p>
<p>That's it! We've coded an entire tic-tac-toe server from scratch and it was very painless. Netty <strong>rocks</strong>. The only classes we didn't review are the specific POJOs for tic-tac-toe related logic. You can check out the source below:</p>
<ul>
<li><a href="https://github.com/rocketpages/Netty-TicTacToe-Server/blob/master/src/main/java/com/tictactoe/game/Board.java">Board.java</a></li>
<li><a href="https://github.com/rocketpages/Netty-TicTacToe-Server/blob/master/src/main/java/com/tictactoe/game/Game.java">Game.java</a></li>
<li><a href="https://github.com/rocketpages/Netty-TicTacToe-Server/blob/master/src/main/java/com/tictactoe/game/Player.java">Player.java</a></li>
</ul>
<h3>Creating the tic-tac-toe client using jQuery</h3>
<p>Building our tic-tac-toe server was fairly simple. Building our tic-tac-toe client is even easier thanks to the power of jQuery! If you'd like to skip straight to the source code, it can be viewed below:</p>
<p><a href="https://github.com/rocketpages/TicTacToe-Client">https://github.com/rocketpages/TicTacToe-Client</a></p>
<p>The bulk of the logic is contained in our JavaScript file. After the initial handshake is performed, all communication with the server will be done asynchronously via the WebSocket API. Please note that not all browsers support the WebSocket protocol. <a href="http://en.wikipedia.org/wiki/Comparison_of_layout_engines_%28HTML_5%29#Related_specifications">This is an up-to-date list of which layout engines support which HTML5 features</a>.</p>
<p>Below is a copy of the JavaScript for the tic-tac-toe client.</p>
<pre class="prettyPrint">// Constants - Status Updates
var STRATEGIZING_STATUS = "Your opponent is strategizing.";
var WAITING_STATUS = "Waiting for an opponent.";
var YOUR_TURN_STATUS = "It's your turn!";
var YOU_WIN_STATUS = "You win!";
var TIED_STATUS = "The game is tied.";
var WEBSOCKET_CLOSED_STATUS = "The WebSocket Connection Has Been Closed.";

// Constants - Game
var PLAYER_O = "O";
var PLAYER_X = "X";

// Constants - Incoming message types
var MESSAGE_HANDSHAKE = "handshake";
var MESSAGE_OPPONENT_UPDATE = "response";
var MESSAGE_TURN_INDICATOR = "turn";
var MESSAGE_GAME_OVER = "game_over";

// Constants - Message turn indicator types
var MESSAGE_TURN_INDICATOR_YOUR_TURN = "YOUR_TURN";
var MESSAGE_TURN_INDICATOR_WAITING = "WAITING";

// Constants - Game over message types
var MESSAGE_GAME_OVER_YOU_WIN = "YOU_WIN";
var MESSAGE_GAME_OVER_TIED = "TIED";

// Constants - WebSocket URL
var WEBSOCKET_URL = "ws://localhost:9000/websocket";


// Variables
var player;
var opponent;
var gameId;
var yourTurn = false;

// WebSocket connection
var ws;

$(document).ready(function() {
	
	/* Bind to the click of all divs (tic tac toe cells) on the page
	   We would want to qualify this if we styled the game fancier! */
	$("div").click(function () {
		// Only process clicks if it's your turn.
		if (yourTurn == true) { 
	      // Stop processing clicks and invoke sendMessage(). 
		  yourTurn = false;
    	  sendMessage(this.id);
    	  // Add the X or O to the game board and update status.
	      $("#" + this.id).addClass(player);
	      $("#" + this.id).html(player);	    	  
	      $('#status').text(STRATEGIZING_STATUS);    	 					      
    	}
    });	

    // On the intial page load we perform the handshake with the server.
    ws = new WebSocket(WEBSOCKET_URL);
    
    ws.onopen = function(event) { 
    	$('#status').text(WAITING_STATUS); 
    }
    
    // Process turn message ("push") from the server.
	ws.onmessage = function(event) {
 		var message = jQuery.parseJSON(event.data);
 		
 		// Process the handshake response when the page is opened
 		if (message.type === MESSAGE_HANDSHAKE) {
   	 		gameId = message.gameId;
   	 		player = message.player;

   	 	 	if (player === PLAYER_X) {
   	 	 		opponent = PLAYER_O; 
   	 	 	} else {
   	 	 		opponent = PLAYER_X;   	 	 	
   	 	 	}
 		}
 		
 		// Process your opponent's turn data.
 		if (message.type === MESSAGE_OPPONENT_UPDATE) {
 			// Show their turn info on the game board.
 			$("#" + message.gridId).addClass(message.opponent);
 			$("#" + message.gridId).html(message.opponent);
 			
 			// Switch to your turn.
 			if (message.winner == true) {
 				$('#status').text(message.opponent + " is the winner!"); 
 			} else if (message.tied == true) {
 				$('#status').text(TIED_STATUS);   	   	 			
 			} else {
 				yourTurn = true;
    			$('#status').text(YOUR_TURN_STATUS);    	   	 			
    		}
 		}   	 	
 		
 		/* The initial turn indicator from the server. Determines who starts
 		   the game first. Both players wait until the server gives the OK
 		   to start a game. */
 		if (message.type === MESSAGE_TURN_INDICATOR) {
 			if (message.turn === MESSAGE_TURN_INDICATOR_YOUR_TURN) {
 				yourTurn = true;
	    		$('#status').text(YOUR_TURN_STATUS);    	 			
    		} else if (message.turn === MESSAGE_TURN_INDICATOR_WAITING) {
				$('#status').text(STRATEGIZING_STATUS);    	 					    	
    		}
 		}
 		
 		/* The server has determined you are the winner and sent you this message. */
 		if (message.type === MESSAGE_GAME_OVER) {
	 		if (message.result === MESSAGE_GAME_OVER_YOU_WIN) {
				$('#status').text(YOU_WIN_STATUS);
			} 
			else if (message.result === MESSAGE_GAME_OVER_TIED) {
				$('#status').text(TIED_STATUS);
			}
 		}	
 	} 
 	
 	ws.onclose = function(event) { 
 		$('#status').text(WEBSOCKET_CLOSED_STATUS); 
 	} 
		
});

// Send your turn information to the server.
function sendMessage(id) {
	var message = {gameId: gameId, player: player, gridId:id};
	var encoded = $.toJSON(message);
	ws.send(encoded);
}
</pre>
<p>The bulk of the logic above deals with two distinct activities; maintaining state and processing messages. You'll notice that when the page first loads we'll use the documentReady function to initiate the WS handshake.&nbsp;You'll also notice that we use jQuery to bind different WebSocket events to code blocks.</p>
<p>jQuery makes it fairly trivial to communicate with a WS server. Rather than polling the server, the WebSocket API allows us to bind logic to the onmessage event and perform the appropriate logic. This is awesome! Our tic-tac-toe game is a simple webpage that never needs refreshing. We also don't need to waist IO constantly polling the server. As soon as our opponent makes his or her move, our screen is immediately updated and we get to take our turn.</p>
<h2>Just the beginning</h2>
<p>That's a very high level look at the power of Java, Netty, the WebSocket API, and jQuery. We can make a number of improvements to this game, such as tracking and displaying ongoing stats (win, loss, draw) and even allowing the same player to compete in <em>multiple games of tic-tac-toe at once!</em> Using these technologies we may actually be able to make tic-tac-toe a challenge. Stay tuned!</p>]]></content></entry><entry><title>Fixing Fancybox with AJAX (and Wicket)</title><id>http://kevinwebber.ca/blog/2010/12/28/fixing-fancybox-with-ajax-and-wicket.html</id><link rel="alternate" type="text/html" href="http://kevinwebber.ca/blog/2010/12/28/fixing-fancybox-with-ajax-and-wicket.html"/><author><name>Kevin Webber</name></author><published>2010-12-28T23:22:13Z</published><updated>2010-12-28T23:22:13Z</updated><content type="html" xml:lang="en-US"><![CDATA[<p>A personal project I'm working on uses the jQuery <a class="offsite-link-inline" href="http://fancybox.net" target="_blank">Fancybox</a> library to display images. It's a great lightbox, except for one small problem: AJAX refreshes break it.</p>
<p>A page I'm working on accepts multiple image uploads. Once the images are successfully processed asynchronously on the server, an image panel on the same page is automatically refreshed. The AJAX callback works fine and updates the panel view with the newly uploaded photos, but the net result is that Fancybox stops working completely.</p>
<p>The solution is pretty simple: Fancybox needs to be re-initialized after the view is refreshed. This involves invoking a JavaScript function <em>after</em> the AJAX callback completes. Fortunately, I'm using Wicket, which makes invoking JavaScript after the callback a breeze.</p>
<p>Here's the (condensed version of) code for my behavior class that handles the repainting, callback, and post-callback JS invocation:</p>
<pre class="prettyprint">        final IBehavior repaintBehavior = new AbstractDefaultAjaxBehavior() {<br />	    @Override<br />	    protected void respond(AjaxRequestTarget target)<br />	    {<br />		ThingModel thingModel = new ThingModel(thingId);<br />		UnprocessedPhotosModel photosModel = new UnprocessedPhotosModel(getCurrentUser().getId(), tokenId);<br />		List photos = photosModel.getObject();<br /><br />		for (Photo photo : photos)<br />		{<br />		    photo.setThing(thingModel.getObject());<br />		    ServiceFactory.getPhotoService().savePhoto(photo);<br />		}<br /><br />		target.addComponent(photosPanel);<br />		target.appendJavascript("$.fancyboxResetBusy(); reinitFancybox();");<br />	    }<br /><br />	    @Override<br />	    public void renderHead(IHeaderResponse response)<br />	    {<br />		super.renderHead(response);<br />		CharSequence callback = getCallbackScript();<br />		response.renderJavascript("function uploadCompleted() { " + callback + "}", "customUploadCompleted");<br />	    }<br />	};<br /></pre>
<p>For those who aren't familiar with Wicket, the <strong>renderHead</strong> method is rendering a custom JavaScript function in the view. The multiple upload Flash component I use invokes the rendered JS function after it finishes processing the images. When the Flash uploader invokes <strong>uploadCompleted</strong>, Wicket handles all the AJAX plumbing and executes the Java code in the <strong>respond</strong> method above.</p>
<p>The two most important lines of code are the calls to <em><strong>target</strong></em>. <em>target.addComponent</em> instructs Wicket to refresh the photo panel, and <em>target.appendJavascript</em> instructs Wicket to invoke the functions in the String parameter after the panel is refreshed.</p>
<p>Let's take a look at the <strong>reinitFancybox</strong> JS function which gets invoked after the panel is refreshed.</p>
<pre class="fancybox">function reinitFancybox() {	<br />	// CSS<br />	$(".gallery img, portfolio.list img, .portfolio.grid-2 div img, a.fancy, ul.screens img").css("opacity", "1");<br /><br />	// ON MOUSE OVER<br />	$(".gallery img, .portfolio-list img, .portfolio.grid-2 div img, a.fancy, ul.screens img").hover(function () {<br /><br />		// SET OPACITY TO 100%<br />		$(this).stop().animate({<br />		opacity: 0.5<br />		}, "fast");<br />	},<br /><br />	// ON MOUSE OUT<br />	function () {<br /><br />		// SET OPACITY BACK TO 100%<br />		$(this).stop().animate({<br />		opacity: 1<br />		}, "fast");<br />	});<br />	<br />	// INIT FANCYBOX<br />	$("li.image a, a.fancy, .portfolio.grid li a.folio-zoom, .portfolio-list.image a").fancybox({<br />		'titlePosition'		: 'over'<br />	});<br />}<br /></pre>
<p>Most of the code above re-initializes the CSS hover effects I use to pretty up my image panel. The last piece is responsible for re-initializing Fancybox itself. <em>At this point, we should be done, Fancybox should work perfectly again.</em> But there's a small catch, the Fancybox script includes a global variable named <strong>busy</strong> which is set to <em>true </em>at the beginning of almost every single function. If for any reason the script is interrupted before busy is set back to <em>false, </em>re-initialization will always abort. Here's a snippet of the Fancybox code below:</p>
<pre class="prettyprint">$.fancybox = function(obj) {<br />	if (busy) {<br />		return;<br />	}<br /><br />	busy = true;<br /><br />        ...<br /></pre>
<p>It's pretty obvious that if busy is <em>true</em> Fancybox won't initialize. We need to make sure busy is set to false before attempting to re-initialize. Unfortunately, this requires a small <span style="text-decoration: line-through;">kludge</span> addition to the Fancybox script itself. I've added the following public function:</p>
<pre class="prettyprint">$.fancyboxResetBusy = function() {<br />	busy = false;<br />}<br /></pre>
<p>Invoking this before the initialize function ensures the initialization doesn't return prematurely.</p>
<p>This fix worked for me, let me know if you get any mileage out of it (or if a better solution exists).</p>]]></content></entry><entry><title>Connection pooling with Hibernate 3.3.x and C3P0</title><id>http://kevinwebber.ca/blog/2010/12/26/connection-pooling-with-hibernate-33x-and-c3p0.html</id><link rel="alternate" type="text/html" href="http://kevinwebber.ca/blog/2010/12/26/connection-pooling-with-hibernate-33x-and-c3p0.html"/><author><name>Kevin Webber</name></author><published>2010-12-26T16:50:06Z</published><updated>2010-12-26T16:50:06Z</updated><content type="html" xml:lang="en-US"><![CDATA[<h3>What is C3P0?</h3>
<p>Hibernate uses it's own built-in connection pool out of the box. There are some pretty heavy duty sites running with the default connection pool enabled in production despite the obvious warning against doing this:</p>
<pre class="prettyprint">INFO DriverManagerConnectionProvider:64 - Using Hibernate built-in connection pool (not for production use!)
INFO DriverManagerConnectionProvider:65 - Hibernate connection pool size: 1
</pre>
<p>A few minor problems creep up with this default configuration left alone, such as the inability for Hibernate to reconnect closed connections. MySQL closes unused connections after 8 hours by default, which causes problems for low-volume applications that may not experience any database usage overnight.&nbsp;</p>
<p>One solution is to use <a class="offsite-link-inline" href="http://www.mchange.com/projects/c3p0/index.html" target="_blank">C3P0</a>, an incredibly simple library that augments the standard JDBC drivers essentially making them "enterprise-ready". One of the main features of C3P0 is:</p>
<blockquote>
<p>Transparent pooling of Connection and PreparedStatements behind DataSources which can "wrap" around traditional drivers or arbitrary unpooled DataSources.</p>
</blockquote>
<p>In other words, you don't have to change any of your code to use C3P0 connection pools if you're using Hibernate. C3P0 takes care of maintaining the pool and testing connections, so your code stays in tact.</p>
<h3>Configuring C3P0</h3>
<p>1. Add the C3P0 jar to your classpath. If you're using Maven, simply add the following to your pom.xml file:</p>
<pre class="prettyprint">&lt;dependency&gt;
	&lt;groupId&gt;org.hibernate&lt;/groupId&gt;
	&lt;artifactId&gt;hibernate-c3p0&lt;/artifactId&gt;
	&lt;version&gt;3.3.2.GA&lt;/version&gt;
&lt;/dependency&gt;
</pre>
<p>2. Make the following changes to your hibernate.cfg.xml file:</p>
<pre class="prettyprint">&lt;property name="connection.url"&gt;jdbc:mysql://127.0.0.1/your_db&lt;/property&gt;
&lt;property name="connection.username"&gt;your_username&lt;/property&gt;
&lt;property name="connection.driver_class"&gt;com.mysql.jdbc.Driver&lt;/property&gt;
&lt;property name="dialect"&gt;org.hibernate.dialect.MySQLDialect&lt;/property&gt;
&lt;property name="hibernate.connection.provider_class"&gt;org.hibernate.connection.C3P0ConnectionProvider&lt;/property&gt;

&lt;!-- JDBC connection pool (C3P0) --&gt;
&lt;property name="c3p0.min_size"&gt;5&lt;/property&gt;
&lt;property name="c3p0.max_size"&gt;20&lt;/property&gt;
&lt;property name="c3p0.timeout"&gt;1800&lt;/property&gt;
&lt;property name="c3p0.max_statements"&gt;50&lt;/property&gt;
</pre>
<p>Pay special attention to the <strong>provider_class</strong> property. Previous versions did not require this property, so most of the tutorials on the net are missing this key piece of info.</p>
<p>3. Create a c3p0.properties file</p>
<p>In order to configure C3P0 for your specific needs, you'll need a <strong>c3p0.properties</strong> file on the classpath. Take a look <a class="offsite-link-inline" href="http://www.mchange.com/projects/c3p0/index.html#configuration_files" target="_blank">here</a> for all the available settings you can tweak. Here's an example that ensures any closed connection is tested and re-opened rather than MySQL throwing an exception:</p>
<pre class="prettyprint">c3p0.testConnectionOnCheckout=true
</pre>
<h3>Verifying it worked</h3>
<p>Configuring C3P0 is pretty simple! If everything works correctly, you'll see the following in your logs:</p>
<pre class="prettyprint">INFO ConnectionProviderFactory:95 - Initializing connection provider: org.hibernate.connection.C3P0ConnectionProvider
INFO C3P0ConnectionProvider:103 - C3P0 using driver: com.mysql.jdbc.Driver at URL: jdbc:mysql://127.0.0.1/your_db
INFO C3P0ConnectionProvider:104 - Connection properties: {user=****, password=****}
</pre>]]></content></entry><entry><title>Beyond Java</title><id>http://kevinwebber.ca/blog/2010/12/22/beyond-java.html</id><link rel="alternate" type="text/html" href="http://kevinwebber.ca/blog/2010/12/22/beyond-java.html"/><author><name>Kevin Webber</name></author><published>2010-12-23T04:28:31Z</published><updated>2010-12-23T04:28:31Z</updated><content type="html" xml:lang="en-US"><![CDATA[<p><span class="full-image-float-left ssNonEditable"><span><img style="width: 300px;" src="http://kevinwebber.ca/storage/1262636330Z8l4WUa.jpg?__SQUARESPACE_CACHEVERSION=1293076296756" alt="" /></span></span>A recent post&nbsp;by Mike Gualtieri of Forrester caught my attention. Mike strongly asserts that <a class="offsite-link-inline" href="http://blogs.forrester.com/mike_gualtieri/10-11-23-java_is_a_dead_end_for_enterprise_app_development" target="_blank">Java is a dead end for enterprises</a> and business software should be built with <em>something else</em>. Mike mentions a few different options, but mainly promotes 4GL tools such as Powerbuilder and "all in one" business infrastructure software such as SoftwareAG webMethods. He also touches on BPM and event processing, and by event processing I'm pretty sure he means CEP tools such as Esper.</p>
<p>I've worked with Java for 10 years. (I admit, sometimes it feels like 20. Life isn't pain free.) I've also worked briefly with FoxPro, just spent a few months at a client site digging through SAS code (another 4GL) that's being migrated to Java, and at my previous job I spent almost a month on a&nbsp; SoftwareAG training course to learn the "webMethods way" of doing things. Is Mike really advocating the use of proprietary, niche languages such as&nbsp;<a class="offsite-link-inline" href="http://en.wikipedia.org/wiki/WebMethods_Flow" target="_blank">webMethods Flow</a>&nbsp;over Java? Really? I'm not an analyst at Forrester, but I've been turning Powerpoint slides into functioning software for long enough that I feel (just about) qualified enough to chime in on the subject.</p>
<p>I agree with the spirit of Mike's post that Java can be a real pain in the ass to build typical business software with. But the problem isn't Java itself, the problem is that businesses use it for <em>everything</em>. "Want yet another custom time tracking intranet site? Let's build it with JEE! How about a utility that counts the number of ponies in our database? Hell yeah... it's Java time, baby! What about that UI heavy site with super-complex workflow? I've got a fever, and the only prescription is JSF, SPRING, and HIBERNATE!"</p>
<p>People have tried for decades to move away from third-generation languages like Java and towards the nirvana of business folks creating their own apps with some kind of flow-charting tool. One of the first guys I worked with -- he had punch cards in his drawer that *he* punched -- told me all about it. It's the longest running punch line in IT. Mike's post might have been titled "Java is a dead end", but it really should have been titled "third-generation languages are a dead end". And the date of the article could easily have been 1980 or 1990. The dead end is not third-generation languages; languages are merely a tool.</p>
<p><strong>The dead end is producing crap software and expecting to keep up with the rest of the world. </strong>The dead end is promoting a stock trader or pony salesman or MBA-type to head up your IT department just because he or she really knows their way around office politics. The dead end is misusing a language or technology for years and <em>blaming the technology and blaming your developers</em>&nbsp;rather than <em>hiring the right people to come up with your strategy and empowering your developers</em>.&nbsp;</p>
<p>The only reason these strategies worked in the past is because <strong>everyone</strong>&nbsp;was fucking up equally. But nothing lasts forever.</p>
<p>Here's a hands-on developer's opinion on the whole "Java is dead" debate, summed up with bullets 'n everything:</p>
<ul>
<li>Java is no more of a dead end than C, C++, or MATLAB. They all have their uses, but using Java for everything is just as dumb as trying to use MATLAB for everything. Stop drinking the Kool Aid.</li>
<li>If you want to build great software, you need to hire great software developers. There's no magic tool that will allow your business folks to put together fantastic software all by themselves. These ideas look fantastic in a Powerpoint slide or Forrester report, but fall flat in the real world.&nbsp;</li>
<li>How do you hire great software developers? <strong>Be a great team to work for.</strong>&nbsp;Understand what's important to top-tier developers. Here's a <a class="offsite-link-inline" href="http://www.joelonsoftware.com/articles/fog0000000043.html" target="_blank">good place to start</a> (this was written 10 years ago and most companies <em>still</em> aren't close).</li>
<li>Treat software development as a first-class citizen of your business if you're going to bother <strong>building</strong> software. Otherwise, STOP BUILDING and START BUYING; find a trusted partner to build for you, or go back to pen and paper. </li>
<li>If you've got a department writing software that operates like anything other than a <em><span style="text-decoration: underline;">software</span> business</em>, you've got a bunch of problems that no tool in the world will ever fix. There's nothing worse in the world than software decisions made by companies who treat software as a necessary evil.</li>
<li>Stop putting stock traders and accountants and lawyers in charge of your IT department. They may be smart folks, and that kind of strategy may work in politics, but it's painful to watch the decisions these people make day in and day out. Decisions like outsourcing a project to India with almost no oversight and wondering why it looks like a box of pudding when it finally gets delivered. Or having a budget of $100mil and not bothering to hire UX and UI ninjas. (Nothing like saving a few bucks and having colour-blind programmers design your user interfaces, eh. Can we get that icon in cornflower blue?)</li>
<li>Developers need to speak up! I've seen projects go completely off the rails because developers allow corporate inertia to dictate decisions rather than technical merits. I've also seen money saved because someone asks the question, "Why are we building a custom app when we can buy it off the shelf instead?"</li>
</ul>
<p>Just remember that most companies currently shooting off their toes with Java wouldn't fare any better with Ruby on Rails or Python on the Subway. (Actually, pythons on the subway are usually a bad omen. Just sayin'. And don't get me wrong, I think both Ruby and Python are fantastic for certain things, just like Java is fantastic for other things.) Java is long in the tooth, absolutely, but there's still so much goodness in the Java world: GWT, Wicket, Guice, and on and on. Talented programmers can create beautiful things with these tools. Or if you think I'm dead wrong, you can always develop your next app using SAS, FoxPro, and webMethods...</p>]]></content></entry><entry><title>The future of Java in the enterprise</title><id>http://kevinwebber.ca/blog/2010/11/15/the-future-of-java-in-the-enterprise.html</id><link rel="alternate" type="text/html" href="http://kevinwebber.ca/blog/2010/11/15/the-future-of-java-in-the-enterprise.html"/><author><name>Kevin Webber</name></author><published>2010-11-15T18:47:53Z</published><updated>2010-11-15T18:47:53Z</updated><content type="html" xml:lang="en-US"><![CDATA[<p>It&rsquo;s been a busy few years in the Java world. Oracle&rsquo;s acquisition of Sun is&nbsp;obviously the&nbsp;largest piece of news and has a significant impact on the future of Java. Oracle&rsquo;s new position as owner and commander-in-chief now places Java squarely in the enterprise realm alongside Oracle&rsquo;s other products. Java has <strong>always&nbsp;</strong>been an enterprise technology, but <a class="offsite-link-inline" href="http://gee.cs.oswego.edu/dl/html/jcp22oct10.html" target="_blank">without the JCP promoting collaborative innovation</a>, who knows what kind of traction Java would have made in the world? Appealing to both academia and industry helped push Java forward and attract a lot of new blood in the early years.</p>
<p>Fast forward to 2010. Java is&nbsp;a utilitarian, status-quo&nbsp;ecosystem for getting things done, albeit not very quickly. This is actually a good thing. Instead of worrying about sharp edges, developers get to work with a very stable, very slow moving target.&nbsp;This won't change as&nbsp;Oracle's only motivation&nbsp;is to&nbsp;sell support licenses and&nbsp;create other fee-based streams of revenue. Major improvements to Java&nbsp;are not on the agenda.&nbsp;Innovation from the <em>core </em>Java team will almost certainly slow down and Java will move deeper into a stabilization and maturity phase. Anything considered an <strong>official spec</strong> is almost certainly going to see a reduced adoption rate as only the largest of the large corporations stick with pure Java standards. As business goes on as usual, everyone is anxiously waiting for a true Java successor to emerge. Will it be Scala? Google Go? Neither are even on the radar of most corporate cubicle farms.</p>
<p>Contrary to the belief of Java-contrarians, Java will not die any time soon, nor should it. Java is well suited to organizations that span many silos with many integration points as Java integrates so well with other technologies. The language itself is also well suited to large development teams; not only does it have&nbsp;a massive library of utilities available to Java developers, but its statically typed nature makes refactoring relatively easy. A counter point is that dynamically&nbsp;typed languages result in less of a need to refactor, but that's another post entirely.</p>
<p>In my opinion Java will actually experience a period of growth as IT spending increases with the (slowly) rebounding economy. Even if the economy takes another nosedive, organizations realize that mass cost savings can be realized through superior technology, and Java's place as a mature and stable language position it as a reasonable choice for a risk-adverse economic climate. Maturity and stability, not innovation, is what the enterprise values most. (I would wager that there are <strong>many </strong>more lines of COBOL currently in production than lines of Ruby.) Even though Java is mature, most corporations haven&rsquo;t leveraged even a fraction of what Java is capable of. The problem in many shops isn&rsquo;t even the language itself;&nbsp;a powerful shiny new language won&rsquo;t fix the process&nbsp;problems that plague most corporate development shops, a powerful shiny new language would most likely just exacerbate them. Java on Android is also a&nbsp;big deal for Java developers considering that&nbsp;<a class="offsite-link-inline" href="http://news.techworld.com/mobile-wireless/3239798/google-android-overtakes-windows-mobile-market-share/?olo=rss" target="_blank">Android recently surpassed iOS</a> in terms of mobile OS market share. Unless Google declares war on Java, the trend is growth.</p>
<p>Over the next decade expect mainframe systems to slowly be retired and legacy Java applications be refactored into client-centric enterprise portals. The simple fact is that Java as an ecosystem (language + tools + frameworks + runtime environment + <em>etc</em>) is a fantastic choice for system integration projects and <em>some</em> new development in large organizations. Java is rock-solid and <strong>proven</strong>.</p>]]></content></entry><entry><title>Code for life</title><id>http://kevinwebber.ca/blog/2010/11/11/code-for-life.html</id><link rel="alternate" type="text/html" href="http://kevinwebber.ca/blog/2010/11/11/code-for-life.html"/><author><name>Kevin Webber</name></author><published>2010-11-12T01:10:13Z</published><updated>2010-11-12T01:10:13Z</updated><content type="html" xml:lang="en-US"><![CDATA[<p><span class="full-image-float-left ssNonEditable"><span><img src="http://kevinwebber.ca/storage/Alan_Turing_photo.jpg?__SQUARESPACE_CACHEVERSION=1289523265723" alt="" /></span></span>All programmers inevitably face <strong>the</strong><strong> decision</strong>; to either stay in their hands-on development role, or to switch into a hands-off role.</p>
<p>I'll cut to the chase. I think the reason a lot of corporate software <strong>sucks </strong>is because most corporations push their most talented technical people into hands-off roles. The advancement opportunities dry up for a hands-on developer around the time they hit the&nbsp;<em>really</em><span> senior developer role. The title may be different depending on the company, but it's the last rung on the ladder before you move to the high-walled corner cubicle (management) or ivory tower (architecture). But you'll almost never see a hands-on developer with <span>VP</span> at the end or their title unless your company name starts with </span><strong>Face</strong> and ends with <strong>book</strong>. So, what's the deal? Why don't banks, insurance companies, and so forth include hands-on developers in their upper ranks?</p>
<p>It's because your value to a company as a full-time employee has less to do with your technical chops than your <em>business domain expertise</em><span>. There's a big difference between working in a brand new business domain (internet search, social networking) and working within a well established one (banking, government, health care). It's the reason why developers are <span>outsourced</span> but (for the most part) business analysts are not.</span></p>
<p>Let's say you work at a bank. You write code. Unfortunately, banks don't consider themselves software <em>product</em> companies, even though most banks live and die based on the quality of their software. So in order to be viewed as a valuable member of the team and a candidate for that huge corner office, you need to know an <strong><span>awful</span></strong> lot about banking. And if you know that much about banking, chances are the powers that be don't want you writing Java, they want you working your mathematical magic and/or talking at a lot of meetings. There's nothing wrong with going to meetings all day if that's your thing, but there's nothing worse than watching someone get railroaded into that position. In corporate-ville, talented developers are believed to grow on trees; the Tata tree, for instance. Developers are viewed as pluggable, modular components. They fit in a hierarchy chart nicely, sometimes listed by their name, other times listed by their title: "Developer 1", "Developer 2", and so forth.</p>
<p>So, what's the hardcore lifelong hands-on code monkey to do?</p>
<ul>
<li>Learn your business domain inside and out. Think PMP, CMMI, CFA, etc. There's no reason why developers shouldn't <em>at least</em> know what the heck these things are, depending on the business domain obviously.</li>
<li>Quit your 9 to 5 and consult or contract. Work your ass off. Always  deliver more than what's expected. Guard your reputation like your life  depends on it. And have lots of fun in the process.</li>
<li>Understand your place on the corporate hierarchy and use it to your advantage. How many people get to switch from one interesting job to another, make great money, never have to feign loyalty to any single entity, and make new contacts each time? Not many!</li>
<li>Keep your technical skills razor sharp and always up to date. Teach other people what you know. Network <strong>constantly</strong>. </li>
</ul>
<p>There are a lot of options for code monkeys who keep an open mind about their career: technical team leadership, <strong>hands-on</strong> architecture, business systems analysis, and the list goes on. Sure, BSA work isn't exactly writing code, but working as a BSA for three or six months would give any developer a whole new set of tools for their toolbox.</p>
<p>Just don't let yourself get railroaded into a career path that doesn't work for you, because there's nothing worse than watching an amazing developer become a horrible manager. Take control of your career, otherwise other people will take control of it for you. And even if other people don't always acknowledge it, realize that by staying in the trenches you're helping to make corporate software suck a <strong>whole lot less</strong>.</p>]]></content></entry><entry><title>The future of self service banking</title><category term="Customer"/><category term="Usability"/><id>http://kevinwebber.ca/blog/2010/9/5/the-future-of-self-service-banking.html</id><link rel="alternate" type="text/html" href="http://kevinwebber.ca/blog/2010/9/5/the-future-of-self-service-banking.html"/><author><name>Kevin Webber</name></author><published>2010-09-06T02:56:58Z</published><updated>2010-09-06T02:56:58Z</updated><content type="html" xml:lang="en-US"><![CDATA[<p><span class="full-image-block ssNonEditable"><span><img src="http://kevinwebber.ca/storage/ideo.png?__SQUARESPACE_CACHEVERSION=1283742360150" alt="" /></span></span></p>
<p>Designing user up, rather than components down. That's the vision behind the <a class="offsite-link-inline" href="http://futureselfservicebanking.com/" target="_blank">new generation of automated teller machines</a> being installed throughout Spain. For decades ATMs have focused on a few very specific transactions, but ATMs being created by a company called IDEO are completely user focused and re-think the way the machines interact with people.</p>
<p>How long before Canada gets these?</p>]]></content></entry><entry><title>The future of software</title><category term="Software development"/><category term="Usability"/><category term="architecture"/><category term="desire path"/><category term="user experience"/><id>http://kevinwebber.ca/blog/2010/9/5/the-future-of-software.html</id><link rel="alternate" type="text/html" href="http://kevinwebber.ca/blog/2010/9/5/the-future-of-software.html"/><author><name>Kevin Webber</name></author><published>2010-09-05T04:40:07Z</published><updated>2010-09-05T04:40:07Z</updated><content type="html" xml:lang="en-US"><![CDATA[<p><span class="full-image-block ssNonEditable"><span><img src="http://kevinwebber.ca/storage/desire_path.jpg?__SQUARESPACE_CACHEVERSION=1283662050682" alt="" /></span></span></p>
<p>A <a class="offsite-link-inline" href="http://findsubstance.com/2010/07/06/desire-paths/" target="_blank">desire path</a> is what a person wants rather than what an architect builds. The term <em>desire path </em>originated from landscape architecture, but it's an increasingly important concept for software architects to grasp. If you understand desire paths, you understand the future of software development.</p>
<p>A desire path represents the evolutionary nature of how people interact with their environment. An engineer designs a concrete path, but people find it more convenient to create their own. Software isn't any different. Users bump up against the limitation of an application but find their own workaround through sheer necessity. The next generation of software won't dictate to users, it will listen to them, and let them guide design rather than the other way around. Anyone who keeps this in the back of  their mind is already ahead of the curve and ready for the changing  software landscape.</p>
<p>Large corporations are often slow to respond to change. In no space is this more evident than technology. If you're a developer and have used both ClearCase <strong>and</strong> Git(Hub) for version control, you know exactly what I'm talking about. The big business version of source control is <strong><em>painful </em></strong>to use compared to the next generation of light and nimble apps crafted by small or open source development shops. Git and GitHub are a true pleasure to work with, while ClearCase is known to cause nightmares, paranoia, insomnia, dry mouth, anxiety attacks, and lethargy. (They should put a warning label on the box, just sayin'.)</p>
<!--more-->
<p>This is a fairly accurate picture of the future of software; an increasingly polarized space where the next generation of software developers duke it out with their predecessors. A space where large corporations try to adapt to users as quickly as their smaller counterparts, but bump up against the severe technical limitations of their outdated infrastructure. A space where resting on your laurels may mean going out of business or watching your professional software development career come to an abrupt end. A space where developing crappy applications will get an organization or developer laughed out of the industry. A space where kids who grew up with a laptop in their baby crib become consumers (and even the heads of corporations) and have a completely different expectation of what software should do.</p>
<p>CIBC was the <a class="offsite-link-inline" href="http://thebankwatch.com/2010/02/02/cibc-release-first-canadian-bank-iphone-app/" target="_blank">first Canadian bank to release an iPhone app</a>. It reminds me of a scene from the movie Glengarry Glen Ross:</p>
<blockquote>
<p><em>We're adding a little something to this month's sales contest. As you  all know, first prize is a Cadillac Eldorado. Anybody want to see second  prize? [<em>Holds up prize</em>] Second prize is a set of steak knives. Third prize is you're fired.</em></p>
</blockquote>
<p><em></em>The last bank to release an iPhone app only has a chance of saving face if it's the greatest iPhone app ever invented. <em>(Coffee is for closers.)</em> Is an iPhone app really going to change the bottom line of a bank overnight? Absolutely not. But in a market like banking where switching to a competitor is incredibly difficult, the only way to ensure future success is to convince young people to get on board from the beginning. Once they choose their first bank, odds are they'll stick with them for a very long time. These seemingly small technical advantages may not appear to be a big deal today, but <a class="offsite-link-inline" href="http://www.theglobeandmail.com/globe-investor/cibc-rewarded-for-cautious-stance/article1684348/" target="_blank">CIBC just posted an impressive profit</a> by focusing on retail banking. The cornerstone of retail banking is customer engagement, and trust me, small things count.</p>
<p>Mobile computing will continue to have a profound impact on how users interact with apps. More users are turning to native applications: think Twitter, Facebook, etc. How many people use Twitter's web UI? Hardly any. Most people use a native application instead. Desktop and laptop computers are slowly being outnumbered by PDAs, cell phones, tablets, and a variety of other gadgets, especially outside of North America where cost is a much bigger issue. Web-based user interfaces are becoming less important while APIs are becoming more important. Don't get me wrong, web-based interfaces will be around for quite a long time, but users will depend on them less. <em>If software were fashion, APIs would be the new black.</em></p>
<p><strong>Integration</strong> and <strong>continuous improvement</strong> are becoming the two most important aspects of software development today, and will only increase in importance over the next decade. Simple, light, extensible, and integrated; big bang development may continue, but smart companies realize that there is no such thing as a finished application. Applications are no more finished than the people who build them! Think evolution rather than revolution. "Application oriented" development will replace "object oriented" development in terms of developer mindset.</p>
<p>Software spending is becoming an arms race. The gap between the <em>haves</em> and the <em>have nots</em> will grow significantly. Organizations that fail to adapt will fall quickly behind their more adaptable competition and bleed market share.  <span style="text-decoration: underline;">Flexibility is key.</span> Your architecture must be flexible enough to adapt to an evolving world in a moments notice. Flexibility has always been important, but five years from now, it could mean the difference between your organization being #1 or being out of business.</p>
<p>The opportunities over the next few years are immense for organizations that really <em>get it</em>. Frankly speaking, <strong>most software sucks</strong>. Building something better isn't all that challenging if you listen to customers. ING Direct Canada was able to steal market share from every other bank simply because they built software that was easy to use and <span style="text-decoration: underline;">didn't suck</span>. Sure, they competed on rates, but Canadians lined up to stuff their money in some Dutch guy's shorts rather than walk down the street and hand it over to a Canadian bank. Why? Canadian banks were slow to adapt to a market that increasingly craves convenience and simplicity rather than filling out forms in triplicate, haggling over 25 basis points, understanding complex fee schedules, and rushing to a branch in person before some guy takes his two-hour lunch break. Ten years ago, if Canadian banks had simplified their processes and software, ING Direct wouldn't have had a chance to get a foothold in the Canadian market. ING listened to the market and scored, while Canadian banks dictated to the market and lost. Yeah, Canadian banks are the apple of the world's eye right now, but they still dropped the ball. Otherwise the guy juggling oranges on TV wouldn't be so damn smug.</p>
<p>The good news is it's not too late for companies of all sizes to compete on technical prowess and simplified processes. To put it plainly, <strong>most software still sucks</strong>. But it won't forever.</p>]]></content></entry><entry><title>The greatest line of code ever</title><category term="Horror"/><id>http://kevinwebber.ca/blog/2010/8/22/the-greatest-line-of-code-ever.html</id><link rel="alternate" type="text/html" href="http://kevinwebber.ca/blog/2010/8/22/the-greatest-line-of-code-ever.html"/><author><name>Kevin Webber</name></author><published>2010-08-22T05:42:56Z</published><updated>2010-08-22T05:42:56Z</updated><content type="html" xml:lang="en-US"><![CDATA[<pre class="prettyprint">if (statusIsNotValid.compareTo( Boolean.FALSE ) != 0) skipValidation = false;</pre>
<p>I don't know what's more shocking, that someone who calls themselves a <em>professional </em>programmer wrote that piece of... whatever... or that it wasn't clubbed to death like a baby seal during a code review. If you ever find yourself working in a team that doesn't see the importance of code reviews, remind them that they could easily wind up with a few million lines of...&nbsp;<strong>that</strong>.<br /><br />(Taken from <a href="http://thedailywtf.com/Articles/Boolean-Illogic.aspx" target="_blank">The Daily WTF</a>.)</p>]]></content></entry><entry><title>Integrating Uploadify with Java using Apache Wicket</title><category term="Flash"/><category term="Software development"/><category term="Wicket"/><id>http://kevinwebber.ca/blog/2010/4/30/integrating-uploadify-with-java-using-apache-wicket.html</id><link rel="alternate" type="text/html" href="http://kevinwebber.ca/blog/2010/4/30/integrating-uploadify-with-java-using-apache-wicket.html"/><author><name>Kevin Webber</name></author><published>2010-04-30T06:12:32Z</published><updated>2010-04-30T06:12:32Z</updated><summary type="html" xml:lang="en-US"><![CDATA[<p>One of the most requested features on any site that accepts file submissions is the ability to handle multiple uploads elegantly. The current HTML standard only permits one file upload at a time, which makes transferring a large number of files quite tedious.</p>

<p>This tutorial will show how to painlessly integrate Uploadify and Java using Apache Wicket. You should have at least beginner-level knowledge of Wicket before moving forward, but feel free to dive right in even if you've never used Wicket before. (If you haven't used Wicket before, I can't suggest it strongly enough for developing stateful Java-based web applications.)</p>]]></summary></entry></feed>
