November 1, 2006

Dojo vs. GWT 1.2

There was some talk about Dojo during the GWT podcast with Bruce Johnson, Robert Hanson, and myself comparing it to GWT to build Ajax applications. Dojo has been around longer and may be more mature, GWT leverages java’s development tools, etc.

GWT really excels over the development lifecycle but the one area that I thought it fell behind, and did not think it had much of a chance of catching up, is with the fast tweak/test cycle that fits scripting so well. With GWT you would refresh your browser to see your changes but since GWT compiles java to javascript this would be much slower.

A release candidate for GWT 1.2 was released yesterday with an speed improvment for refreshes during debugging. Bruce Johnson suggests the most efficient develop method with GWT 1.2 in this issue report:

Now caching between runs. Startup is 20-30% faster, and refreshes are much, much faster. Since refreshes are very fast now, the most efficient way to develop is to leave a hosted browser open, make source changes, then click “Refresh”.

I tested this with gpokr and found that startup was 25% faster and refresh was about twice as fast - still not as fast as a refresh of a fully compiled gpokr running in a browser which is a remarkable 1 second. Compare this to the 7 seconds it takes to load the Dojo sample mail application in firefox, (this app seems to have far less functionality than gpokr so it should be faster, this illustrates the advantage of compiling code to javascript eliminating the need for nice looking, readable, debugable javascript that is a tradeoff with speed).

Filed under: ajax, gwt, google web toolkit, gpokr, dojo
October 31, 2006

Hanging HTTP Connections

Gpokr was running for about 3 months before I realized that IE’s 2 connection limit per hostname and a hanging HTTP connection is a risky situation.A hanging connection is when the Ajax application makes a request for data and the server waits with an open connection until data is avaialble. When data is available it is returned immediatly simulating an instant notification from the server.

This is why gpokr seems to always be moving. Cards are dealth, bets are placed, and chat happens seemingly instantly.

It seems like a hack but there are not many options to out there that give Ajax applications the ability to receive data asynchronously from the server. Yes asynchronous is part of the Ajax achronym but this is just asynchronously getting data from the server. For an event driven application like poker the client needs to get data only when it is available. Of course it could check the server every few seconds but this can be a massive overhead. A hanging connection lets the client idle until there is something to do.

The problem is that it takes up a connection. I’m ok with this on the server but the browser limits 2 connections per hostname. Thats one to hang for events, and another to send a chat message, but what if a picture needs to be downloaded at the same time. It needs to wait. Or, in the case with gpokr, what if one connection is hanging for events, the other is downloading a large image, and you only have three seconds left to make a call on pocket Aces or you’ll be folded by the server. The server folds you and you get very mad.

It doesn’t seem like this issue is talked about much within Ajax development circles. Although I ran into this article that measures the use of multiple hostnames to improve performance of a web page - essentially making more connections available to load the page in parallel.

Now, for gpokr, I use one hostname for hanging calls and another for HTTP objects so that the hanging call never slows down the sites action.

Filed under: ajax, gpokr
October 16, 2006

New Podcast About GWT

I had the opportunity to join in on a round table discussion podcast with Bruce Johnson, technical lead of the GWT project at Google, and Robert Hanson, keeper of the GWT widget library, hosted by Java Posse.

GWT Round Table

Filed under: ajax, java, gwt, google web toolkit, gpokr
September 10, 2006

Rule #4080: Differentiate your Software

Not a texas holdem server clone, or a party poker clone even, this man from Belgium wants his very own Gpokr Clone.

Filed under: ajax, marketing, pr, startup, google, poker, gwt, google web toolkit, gpokr
September 5, 2006

Dual Xeon

Lets recap.

June 16th:
gpokr opens for some alpha alpha testing running on a VMWare virtual PC running on my Windows development box

June 21st:
gpokr moves to a shared hosting account at godaddy costing $6.99 per month.

July 11th
gpokr officially opens for wider audience and gets blog posts on jayisgames and the GWT blog

July 21st
gpokr moves to a 2Ghz/512Mb dedicated server at 1and1 for $99/month.
July 31th
gpokr gets a write up on tech crunch.

Sept 5th
gpokr moves to a Dual Xeon /2GB server hosted by liviant.com

Filed under: godaddy, gpokr
August 3, 2006

Improving GWT RPC Serialization Performance by a Factor of 10

So aparently serialization was taking 100% of my application
cpu time. I’ve made some changes to the serialization and my apps cpu usage has gone from 100% with about 7 tables running, (approximately 60-80 clients constantaly serializing)
down to 10%. So with the same load on the server the cpu has 90% free
cycles now!

This is from making a few simple changes to
ServerSerializableTypeOracleImpl. Here’s what I did:

1)  Add a new static map to the class…

private static final Map CUSTOM_FIELD_SERIALIZERS = new HashMap();

2)  Add static initialization to the class…

static{
try{
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.boolean_Array”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.boolean_Array_CustomFieldSer­ializer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.Boolean”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.Boolean_CustomFieldSerialize­r”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.byte_Array”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.byte_Array_CustomFieldSerial­izer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.Byte”, Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.Byte_CustomFieldSerializer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.char_Array”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.char_Array_CustomFieldSerial­izer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.Character”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.Character_CustomFieldSeriali­zer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.double_Array”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.double_Array_CustomFieldSeri­alizer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.Double”, Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.Double_CustomFieldSerializer­”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.float_Array”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.float_Array_CustomFieldSeria­lizer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.Float”, Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.Float_CustomFieldSerializer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.int_Array”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.int_Array_CustomFieldSeriali­zer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.Integer”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.Integer_CustomFieldSerialize­r”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.long_Array”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.long_Array_CustomFieldSerial­izer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.Long”, Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.Long_CustomFieldSerializer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.Object_Array”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.Object_Array_CustomFieldSeri­alizer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.short_Array”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.short_Array_CustomFieldSeria­lizer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.Short”, Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.Short_CustomFieldSerializer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.lang.String”, Class.forName(
“com.google.gwt.user.client.rpc.core.java.lang.String_CustomFieldSerializer­”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.util.ArrayList”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.util.ArrayList_CustomFieldSeriali­zer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.util.Date”, Class.forName(
“com.google.gwt.user.client.rpc.core.java.util.Date_CustomFieldSerializer”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.util.HashMap”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.util.HashMap_CustomFieldSerialize­r”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.util.HashSet”,
Class.forName(
“com.google.gwt.user.client.rpc.core.java.util.HashSet_CustomFieldSerialize­r”
) );
        CUSTOM_FIELD_SERIALIZERS.put(”java.util.Vector”, Class.forName(
“com.google.gwt.user.client.rpc.core.java.util.Vector_CustomFieldSerializer­”
) );
        } catch (ClassNotFoundException e) {
      // purposely ignored
    }

}

 

3) Change hasCustomFieldSerializer to use this map….

 public Class hasCustomFieldSerializer(Class instanceType) {
    String qualifiedTypeName;
    if (instanceType.isArray()) {
      Class componentType = instanceType.getComponentType();
      if (componentType.isPrimitive()) {
        qualifiedTypeName = “java.lang.” + componentType.getName();
      } else {
        qualifiedTypeName = Object.class.getName();
      }
      qualifiedTypeName += “_Array”;
    } else {
      qualifiedTypeName = instanceType.getName();
    }
    return (Class)CUSTOM_FIELD_SERIALIZERS.get(qualifiedTypeName);

}

Thats it! Although this limits the custom field serializaers
extensibility it works very well for me since i don’t have any custom
serializers.

Filed under: google, java, gwt, google web toolkit, tomcat, gpokr
August 1, 2006

Why a Small Piece of HTML is Huge for User Exeperience

I read Buzz Marketing, The Tipping Point and the inferior Pyro Marketing earlier this year. My first experiment with these buzz building ideas in mind, the T.Q. Test, worked well. Unfortunately when people were done with the test the didn’t come back. It lacked stickiness.

Experiment #2, gpokr.com, really improves on a web apps stickiness. Its nothing new. You can play holdem poker for free everywhere on the net. There are actually several very small details that make it different and much more sticky, (although you can’t play for money so obviously its not right for gamblers).

My favorite detail that improves the user experience of the site the most for the amount of code involved is a simple little ranking next to the chip count at the table. After every hand this ranking is updated. I love seeing my progress on a hand to hand basis and have an interest to come back and check it out again. It has a pull to it. I could dream up dramatic development intensive features thinking bigger is better, and I think I usually do, but these little features are so much more valueable. One they are easy to implement and two they do not bloat the app giving it the ability to remain simple.

Filed under: marketing, pr, gpokr, user experience
July 31, 2006

Techcrunch and gpokr and Server Crashes

Techcrunch posted about gpokr today, the the server was shutdown by the host, they received angry phone calls, and the server is running.

Filed under: pr, gwt, gpokr
July 21, 2006

gpokr updates

  1. Up to 50 tables. Sure there are only ever 2 tables busy but maybe there will be a bit more traffic someday.
  2. An ideas page base on ideas.43things.com. There’s some great ideas posted here.
  3. Profile pages. Each player has a profile page which lists how they’ve interacted with the site.
  4. A whole lot of playing statistics along with a new top holdem players page with a few different top 10 lists.
Filed under: Uncategorized, ajax, poker, gwt, google web toolkit, texas holdem, gpokr
July 12, 2006

gpokr X 4

Last night the gpokr server was updated to support more than one table along with some other bug fixes including “Check Wars” and “Folded gets Pot” bugs.

Filed under: poker, gwt, google web toolkit, texas holdem, gpokr