<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>GWT / GAE development blog</title>
	<atom:link href="http://borglin.net/gwt-project/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://borglin.net/gwt-project</link>
	<description>Articles about GWT/GAE and the development of TeamScape: A sports team portal</description>
	<lastBuildDate>Sat, 10 Sep 2011 02:50:55 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Part 10: Hello gwt-platform</title>
		<link>http://borglin.net/gwt-project/?page_id=817</link>
		<comments>http://borglin.net/gwt-project/?page_id=817#comments</comments>
		<pubDate>Sat, 15 May 2010 16:09:12 +0000</pubDate>
		<dc:creator>Andreas Borglin</dc:creator>
				<category><![CDATA[GWT/GAE Project]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[gwt-platform]]></category>
		<category><![CDATA[mvp]]></category>

		<guid isPermaLink="false">http://borglin.net/gwt-project/?page_id=817</guid>
		<description><![CDATA[So. Here we are again, yet another MVP post. I've seen this one coming for a while though. gwt-presenter came out quick and strong after Ray Ryan's talk. It was off to a great start, but there are some architectural issues and lack of features that has yet to be solved. There hasn't been much [...]]]></description>
			<content:encoded><![CDATA[<p>So. Here we are again, yet another MVP post. I've seen this one coming for a while though. gwt-presenter came out quick and strong after Ray Ryan's talk. It was off to a great start, but there are some architectural issues and lack of features that has yet to be solved. There hasn't been much development going on either since January. In the mean time, frameworks like mvp4g and gwt-platform has popped up and they are very compelling alternatives that has solved many of the problems with gwt-presenter.</p>
<p>Note that this post is not as comprehensive as my previous posts about gwt-presenter. This is mainly due to the fact that gwt-platform is still evolving at a rapid pace, which means that whatever I write here will likely be outdated soon. Once gwt-platform reaches a 1.0 state with a somewhat finalized API, I will likely write another post with more details on both the framework and how TeamScape uses it.</p>
<p>So what is <a href="http://code.google.com/p/gwt-platform/">gwt-platform</a>? It is a complete MVP + Command pattern framework forked off gwt-presenter/dispatch by Philippe Beaudoin for his project PuzzleBazar.</p>
<p>Why not <a href="http://code.google.com/p/mvp4g/">mvp4g</a>? One reason alone: gwt-platform is based on gwt-presenter and share many traits with it. I have spent a lot of time learning gwt-presenter and TeamScape is currently using gwt-presenter, so the transition for me to gwt-platform makes much more sense than moving to a completely unknown territory. I have however looked into mvp4g and it seems like a very nice alternative as well. If you are looking for a MVP framework for a new application, I would recommend you to spend some time evaluating the alternatives.</p>
<p>You might be wondering which problems I see with the current state of gwt-presenter?</p>
<ul>
<li><span style="text-decoration: underline;">Presenter relationships:</span> Child presenters are injected in  parent which leads to tight coupling between your presenters. This also  makes it harder to structure your application for certain scenarios.</li>
<li><span style="text-decoration: underline;">Lack of lazy loading:</span> It does not have built in  support for lazy loading of presenters/views, which means you have to to  implement this in your application layer.</li>
<li><span style="text-decoration: underline;">Only singleton presenters:</span> No support for non-singleton  presenters which decreases the level of flexibility in your application  design.</li>
<li><span style="text-decoration: underline;">Places implementation:</span> Too much code to handle places (one  class for each place, etc). Also, each request leads to quering each place  if it is a match which can be a bottleneck (described this in Part 7).</li>
<li><span style="text-decoration: underline;">Code splitting:</span> No support for code splitting.</li>
<li><span style="text-decoration: underline;">Development activity:</span> The last "real" checkin was in  beginning of January. Although the authors have been active in the  forum, it seems that development has grinded to a halt.</li>
</ul>
<p>I'm sure that gwt-presenter will evolve past many of these problems, but I have waited long enough. I need to get my foundation in place now so I can stop worrying about that.</p>
<p>I have now rewritten all TeamScape client code from scratch using  gwt-platform instead of gwt-presenter/dispatch. Was it worth it? Oh yes,  definitely. So what is so compelling with gwt-platform that I decided to throw out a well-established framework and spend a whole weekend getting back to where I was?</p>
<ul>
<li><span style="text-decoration: underline;">Loose coupling between presenters</span>. There are no direct dependencies between parents and children. All communication takes place over the event bus and the child simply fires an event that a parent presenter reacts to. Want to change parent for a child? You change the event type being fired in the child..that's it. You can also reveal the child in different parents with this based on the context, for example token parameters. Parents annotate defined events with @ContentSlot where child presenters are injected when they fire that event.</li>
<li><span style="text-decoration: underline;">Lazy loading</span>. gwt-platform introduces the concept of light-weight proxies. These proxies listen to events and instantiates your presenters on demand. Your presenter/view is therefore not created until the first request.</li>
<li><span style="text-decoration: underline;">Non-singleton presenters</span>. Singleton presenters does not always make sense. Sometimes you want to re-use presenters in different contexts, and this is where PresenterWidgets come in handy.</li>
<li><span style="text-decoration: underline;">Code splitting</span>. Code splitting could not possibly be easier. You simply annotate your proxy with @ProxyCodeSplit, and the initialization of the presenter is behind a code split point. Incredibly easy and powerful.</li>
<li><span style="text-decoration: underline;">Place management</span>. Easier than ever. With three lines of code and no new classes, you have mapped your presenter to a place. The gwt-presenter problem with quering every place if it's a match is avoided as well.</li>
<li><span style="text-decoration: underline;">Search engine crawling:</span> Integrated support for letting search engines crawl your GWT app (still in experimental phase).</li>
<li><span style="text-decoration: underline;">Integrated command pattern for RPC communication</span>.</li>
</ul>
<p>I struggled a bit on how to design my application to handle the "3 pages" problem with gwt-presenter. With the code splitting feature and presenter architecture of gwt-platform, I quickly found a solution that I like. I now have three different PagePresenters that each map to a PageView that holds a DockLayoutPanel. Each PagePresenter is behind a code split point, so the user only downloads the relevant page content. If the user goes from say the main page to a team page, the MainPageView is swapped out at the root level and in comes TeamPageView.</p>
<p>The non-singleton presenters also makes it much easier to define a single "shared" presenter/view pair that can be instantiated for each page. This will be very useful for TeamScape since we can avoid redundant code that basically does the same thing in different contexts.</p>
<p>I thought long and hard about how to represent the "static" content on each page. With this I mean the content that is in the north, south, west and east directions in my layout that doesn't change as the result of a place request. The content may be updated as the result of user interaction, but it is never related to place management. The only feasible solution that I came up with was to let the PagePresenter "own" these presenters (gwt-presenter style). They are injected in the PagePresenter constructor and then initialized on the first request. Note that the views are still happily unaware of the content they are presenting at this level. I did post a question about possible solutions in the gwtp forum <a href="http://groups.google.com/group/gwt-platform/browse_frm/thread/224893bbac5b6b07">here</a>. <a href="http://code.google.com/p/gwt-platform/issues/detail?id=78">Issue 78 </a>for gwt-platform could be an interesting alternative solution.</p>
<p>Let's have a look at some examples on how you use gwt-platform.</p>
<p>We have two types of presenters: Presenter (singletons with view/proxy/place) and PresenterWidget (non-singleton, view only). Which one you define depends entirely on what you want to accomplish. You will always use singleton presenters to handle place requests, code splitting and revealing in parents. So when do you want to use PresenterWidgets? Say you have an application where users can post comments in many different places (via different presenters). In this case, you might want to define a CommentPresenterWidget mapped to a CommentView to handle comments. Instead of duplicating code in different places, you inject a new instance of CommentPresenterWidget in each presenter where you need this logic. There are other scenarios as well, but you should be getting the idea by now.</p>
<p>The interesting part of gwt-platform is the presenter-proxy handling. Let's have a look at a typical singleton presenter that maps to a place and handles token parameters.</p>
<pre class="brush: java;">
public class ShowPlayerPresenter extends TeamBasePresenter&lt;ShowPlayerPresenter.MyView, ShowPlayerPresenter.MyProxy&gt; {

    private String mPlayerId;
    private String mLastId;

    public interface MyView extends View {
      // methods to feed view with player data
    }

    @ProxyCodeSplit
    @NameToken(TSNameTokens.teamShowPlayer)
    public interface MyProxy extends Proxy&lt;ShowPlayerPresenter&gt;, Place {
    }

    @Inject
    public ShowPlayerPresenter(EventBus eventBus, MyView view, MyProxy proxy,
            DispatchAsync dispatcher, TokenFormatter formatter, CurrentTeam curTeam) {
        super(eventBus, view, proxy, dispatcher, formatter, curTeam);
    }

    @Override
    public void onReset() { // Read the comments in the post regarding onReset() / onReveal()
        super.onReset();
        if (mPlayerId != null &amp;&amp; mPlayerId != mLastId) {

            Player player = mCurrentTeam.getPlayerById(mPlayerId);

            if (player == null) {

                mDispatcher.execute(new GetModel(mPlayerId, Player.class, Player.isNumericId()),
                        new DispatchCallback&lt;GetModelResult&gt;() {

                            @Override
                            public void callback(GetModelResult result) {
                                Player player = (Player) result.getModel();
                                displayPlayer(player);
                            }

                        });
            }
            else {
                displayPlayer(player);
            }

            mLastId = mPlayerId;

        }

    }

    private void displayPlayer(Player player) {
        // feed the view with data via MyView interface
    }

    @Override
    protected void revealInParent() {
        RevealContentEvent.fire(eventBus, TeamPagePresenter.TYPE_TeamCenterContent, this);
    }

    @Override
    public void prepareFromRequest(PlaceRequest request) {
        mPlayerId = request.getParameter(TSParamTokens.PLAYER_ID, null);
        super.prepareFromRequest(request);
    }

    @Override
    public PlaceRequest prepareRequest(PlaceRequest request) {
        if (mPlayerId != null) {
            request = request.with(TSParamTokens.PLAYER_ID, mPlayerId);
        }
        return super.prepareRequest(request);
    }

}
</pre>
<p>The presenter above is responsible for showing information about a player in TeamScape. Let's go over how this works.</p>
<p>It inherits from TeamBasePresenter (which in turn inherits from PresenterImpl). All my "center" team presenters inherit from TeamBasePresenter in order to extract team token parameters in one place and update team data accordingly. You can see that I've used @ProxyCodeSplit and @NameToken to annotate MyProxy. This tells gwt-plattform that this presenter should sit behind a code split point and also be activated on a place request with the token defined in TSNameTokens.teamShowPlayer. You can also use @ProxyStandard, which means that the code will be downloaded by default. If you don't want your presenter to be mapped to a place, you simply remove the @NameToken annotation and remove the Place extension to the MyProxy interface.</p>
<p>If you come from gwt-presenter, you might remember onRevealDisplay()?. With gwt-platform, we have both onReset() and onReveal() that can be overriden. Read the comment below by Philippe on this. Use onReset() if you are unsure. We override this to update the view with relevant data (perhaps based on token parameters). In this case,  I check if we already have fetched the player. If not, we dispatch a call to the server to fetch it from the datastore. Then I call displayPlayer() which updates the view with the new player data.</p>
<p>The method revealInParent() is a new addition in gwt-platform. The relationship between parent and child presenters are entirely different with gwt-platform, and so the logic for it is as well. With gwt-platform, you define a type parameter in your parent like this:</p>
<pre class="brush: java;">
@ContentSlot
    public static final Type&lt;RevealContentHandler&lt;?&gt;&gt; TYPE_TeamCenterContent = new Type&lt;RevealContentHandler&lt;?&gt;&gt;();
</pre>
<p>When the child presenter is activated via a place request, revealInParent() is called and it is up to the child presenter to fire the appropriate event to get revealed. In this case, we want the presenter to be revealed in the center of the team page, hence TYPE_TeamCenterContent.</p>
<p>You will also recognize the last two methods, prepareFromRequest() (preparePresenter() in gwt-presenter) and prepareRequest(). These were defined in the Place-class in gwt-presenter &gt; v1.1. This can easily lead to confusion for beginners. When a place request is triggered with token parameters, you must first extract the parameters in prepareFromRequest, and then add them again in prepareRequest. Read more about this <a href="http://groups.google.com/group/gwt-platform/browse_frm/thread/a8f5aa74c6cf6bc0">here</a>.</p>
<p>Now you have seen what a typical singleton presenter looks like. There are lots of other nifty featues in gwt-platform such as secure places, on leave confirmation, search engine crawling, etc. I might come back to all that later and write a post about the more advanced features of gwt-platform, but for now I'm going to focus my time and energy on TeamScape instead. Feel free to ask questions for clarifications or other code examples.</p>
<p>Unfortunately I do not have a part available for download yet and there is no code checked in. Once I'm done migrating away from JDO and implementing "Entities #2", there will be a download for Part 10 - 12.</p>
<p>If you want to get started with gwt-platform, you might want to check out <a href="http://groups.google.com/group/gwt-platform/browse_frm/thread/9135c996eaf640ca">this thread </a>on how to include it in your project.</p>
<p>Interesting reading: <a href="http://groups.google.com/group/gwt-platform/browse_frm/thread/b479694d19501ad9">Post about shared views</a>, <a href="http://kyle.baley.org/ArchitecturalChangesOrLdquoHowToDecideIfAndWhenToStartOverrdquo.aspx">Kyle Baley's post about gwt-platform</a>.</p>
<p>Do checkout the gwt-platform wiki and forum. There are lots of interesting stuff to read. Looking at the<a href="http://code.google.com/p/gwt-platform/issues/list"> issues list</a>, it seems there are lots of nice improvements and new features in the pipe as well.</p>
]]></content:encoded>
			<wfw:commentRss>http://borglin.net/gwt-project/?feed=rss2&amp;page_id=817</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Summary</title>
		<link>http://borglin.net/gwt-project/?page_id=691</link>
		<comments>http://borglin.net/gwt-project/?page_id=691#comments</comments>
		<pubDate>Sat, 27 Mar 2010 15:09:15 +0000</pubDate>
		<dc:creator>Andreas Borglin</dc:creator>
				<category><![CDATA[GWT/GAE Project]]></category>

		<guid isPermaLink="false">http://borglin.net/gwt-project/?page_id=691</guid>
		<description><![CDATA[Previous: Feature checklist
In this section the authors got the opportunity to write about anything they wanted to summarize what their framework is about to you as a reader.
Sum it up!
Jeff Schnitzer (objectify)
With its transparent mapping to native operations, thorough documentation, clean API, and well commented code, Objectify should be the easiest way to get started using the [...]]]></description>
			<content:encoded><![CDATA[<p>Previous: <a href="http://borglin.net/gwt-project/?page_id=690">Feature checklist</a></p>
<p>In this section the authors got the opportunity to write about anything they wanted to summarize what their framework is about to you as a reader.</p>
<p><strong>Sum it up!</strong></p>
<p><span style="text-decoration: underline;"><em>Jeff Schnitzer (objectify)</em></span></p>
<p style="padding-left: 30px;">With its transparent mapping to native operations, thorough documentation, clean API, and well commented code, Objectify should be the easiest way to get started using the GAE/Java datastore. Its low-level nature makes it easy to optimize your application for performance and cost without having to hunt through 20 volumes of documentation.</p>
<p style="padding-left: 30px;">The specific feature set has evolved with real-world experience by several developers working on several different applications.  The strongest points:</p>
<ul>
<li>Short learning curve.</li>
<li>Full and effective use of Java generics.</li>
<li>Easy second-level caching in GAE's memcache service.</li>
<li>Solid tools for performing zero-downtime schema migrations.</li>
<li>Fine control of indexing, including partial indexes.</li>
<li>GWT-safe entities.</li>
<li>Active developer community.</li>
</ul>
<p><span style="text-decoration: underline;"><em>John Patterson (Twig)</em></span></p>
<p style="padding-left: 30px;">High performance, easy development:</p>
<ul>
<li>Clean data models with no requirements or dependencies</li>
<li> Works out of the box with no configuration for most data models</li>
<li> Parallel commands!  Multi task your application</li>
<li> Many performance optimising features</li>
<li> Very readable code</li>
<li> Branched commands allow sorted merged OR queries</li>
<li> Flexible strategies allows sharing data with JDO, Objectify, SimpleDS</li>
</ul>
<p><span style="text-decoration: underline;"><em>Ignacio  Coloma (SimpleDS)</em></span></p>
<p style="padding-left: 30px;">This is  the solution I developed to solve my own problems while working with  GAE, after battling with Datanucleus for a couple of weeks.</p>
<p style="padding-left: 30px;">I have  been working with persistent relationships since JBoss 2.4 (2001), and  again with JPA. That being said, I do not think that relationships are  the way to go with GAE, as I prefer having ultimate control about what  is loaded and what not. I honestly believe that (with proper caching)  this performs better and makes me more productive in a system where you  don't have to ask which datasource the data came from.</p>
<p style="padding-left: 30px;">For me, a  persistence framework is more about the features that you _don't_ put  into it, which is the best way to let others extend it. This is what we  have done with SimpleDS.</p>
<h3>My summary</h3>
<p>If you, like me, are looking into these frameworks as a replacement for JDO, there are mainly six things to consider. Each point has very different weight depending on your development style and your application requirements.</p>
<ul>
<li><strong>Features</strong> - Which features do you REALLY need for YOUR project? Sit down and think about the data model and relationships, which queries you will be running, etc. Then write down framework features that you think would make your work easier, and possibly, more efficient.</li>
<li><strong>Simplicity</strong> - Datastore operations are essential for any web application. It should be trivial to perform the basic datastore operations. The API should speak for itself to the highest degree possible. It should be clear how the API relates to the AppEngine concepts.</li>
<li><strong>Level of control</strong> - What level of control do you want? Do you want the framework to automagically do most of the stuff for you or do you prefer to have ultimate control over the flow of events? This is more related to taste than application requirements.</li>
<li><strong>Extensibility</strong> - Do you want to be able to adapt/extend the solution to fit your needs?  If so, make sure to evaluate the design and architecture of the  framework. Was it designed to support this?</li>
<li><strong>Performance</strong> - If you have a data heavy application, datastore performance is obviously very important. One thing to look out for is that the framework does not add cost to basic datastore calls. Another thing to look out for is what the frameworks offers to work around the limitation/problems with the datastore that affect performance negatively.</li>
<li><strong>Documentation </strong>-  No matter how simple the API is, you still need good  documentation that explains different concepts and provides code  examples. JavaDoc is an advantage as well.</li>
</ul>
<p>What it really boils down to is a matter of taste and what requirements you have for your application. Sit down, read the documentation, check out the API and the code examples. Hopefully this and the next article helps you further to find the best fit for your needs.</p>
<p>In the next article I will code up some solutions with each framework and write about my experience with that. I will discuss things more actively from my point of view in that article, which I tried to avoid here to let you, the readers, make up your own mind based on the authors comments.</p>
<p>As always, I encourage feedback and comments. I hope this article is  helpful for anyone trying to make a choice in the framework jungle. And  once again, big thanks to Jeff, John and Ignacio for participating in this!</p>
]]></content:encoded>
			<wfw:commentRss>http://borglin.net/gwt-project/?feed=rss2&amp;page_id=691</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Feature checklist</title>
		<link>http://borglin.net/gwt-project/?page_id=690</link>
		<comments>http://borglin.net/gwt-project/?page_id=690#comments</comments>
		<pubDate>Sat, 27 Mar 2010 15:09:08 +0000</pubDate>
		<dc:creator>Andreas Borglin</dc:creator>
				<category><![CDATA[GWT/GAE Project]]></category>

		<guid isPermaLink="false">http://borglin.net/gwt-project/?page_id=690</guid>
		<description><![CDATA[Previous: The frameworks
This is a checklist of supported features in each framework and JDO (as implemented on GAE).
Do note that this table only is a convenience guide to which features  are supported. It does not tell the whole story. If you are considering  to switch to one of these frameworks, you should consider [...]]]></description>
			<content:encoded><![CDATA[<p>Previous: <a href="http://borglin.net/gwt-project/?page_id=689">The frameworks</a></p>
<p><span style="font-weight: normal;">This is a checklist of supported features in each framework and JDO (as implemented on GAE).</span></p>
<p>Do note that this table only is a convenience guide to which features  are supported. It does not tell the whole story. If you are considering  to switch to one of these frameworks, you should consider all the points mentioned in the summary.</p>
<p>This table will be continously updated as the frameworks evolve. The only legal answers are Yes, No and In progress. Hover the mouse over the dotted underlined features for a popup description.</p>
<p><span style="text-decoration: underline;">Latest update:</span> 2010-07-05 (Objectify 2.1, Twig 1.0, SimpleDS  1.0 RC1)</p>
<table style="width: 580px; height: 536px;" border="0">
<tbody>
<tr>
<td><strong>Feature</strong></td>
<td><strong>Objectify<br />
</strong></td>
<td><strong>Twig<br />
</strong></td>
<td><strong>SimpleDS<br />
</strong></td>
<td><strong>JDO</strong></td>
</tr>
<tr>
<td> <acronym title='A parent-child relationship where the parent has a direct reference to the child. Entities are placed in the same entity group, which also enables transactions.'>Managed owned relationships</acronym> </td>
<td>No</td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td> If Yes above, <acronym title='When there is a chain of direct relationships, you can configure the fetch depth (how many levels of entities to fetch when fetching the &quot;root&quot;).'>configurable lazy fetching</acronym> </td>
<td>N/A</td>
<td>Yes</td>
<td>N/A</td>
<td>Yes</td>
</tr>
<tr>
<td> <acronym title='A direct reference to another entity that is not a parent-child relationship.'>Managed unowned relationships</acronym> </td>
<td>No</td>
<td>Yes</td>
<td>No</td>
<td>No*</td>
</tr>
<tr>
<td> <acronym title='Support for base class references to subclass instances in entities, query result, etc.'>Polymorphic relationships</acronym> </td>
<td>Yes</td>
<td>Yes</td>
<td>No</td>
<td>No*</td>
</tr>
<tr>
<td> <acronym title='Entities can inherit from other classes / entities.'>Inheritance</acronym> </td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td> <acronym title='Classes can be embedded as fields in entities.'>Embedded classses</acronym> </td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td> <acronym title='Any serializable Java object graph can be saved to the datastore.'>Serialized object graphs</acronym> </td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td> One to many relationships </td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td> Many to many relationships </td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td> <acronym title='Property on field that never will be queried on, for saving space and cpu time.'>Unindexed fields</acronym> </td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td> <acronym title='&quot;Dirty detection&quot;. Keeps track of changes in entities.'>Automatic detection of modified entities</acronym> </td>
<td>No</td>
<td>In progress</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td> <acronym title='For pagination or time consuming requests. Saves a checkpoint of query state.'>Query cursors</acronym> </td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td> != and IN queries </td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td> <acronym title='GAE datastore does not support inequality filters on more than one property. Framework support for accepting multiple OR queries and merging the results before returning them.'>Merged OR queries</acronym> </td>
<td>No</td>
<td>Yes</td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td> <acronym title='GAE datastore does not support inequality filters on more than one property. Framework support for accepting multiple AND queries and merging the results before returning them.'>Merged AND queries</acronym> </td>
<td>No</td>
<td>In progress</td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td> <acronym title='Fire off a query and fetch the results later. Enables possibility to run multiple queries/other commands simultaneously.'>Asynchronous queries</acronym> </td>
<td>No</td>
<td>Yes</td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td> <acronym title='Save the entity and fetch the result later. Enables possibility to run multiple puts/other commands simultaneously.'>Asynchronous puts</acronym> </td>
<td>No</td>
<td>Yes</td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td> <acronym title='Save a collection of entities with one call.'>Batch puts</acronym> </td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td> <acronym title='Get a collection of entities with a collection of keys/ids with one call.'>Batch gets</acronym> </td>
<td>Yes</td>
<td>No**</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td> <acronym title='Delete a collection of entities directly or via key with one call.'>Batch deletes</acronym> </td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td> <acronym title='For use with for example GWT, where you pass the entity to client side, do something, and then send it back to be saved/updated.'>Detached entities</acronym> </td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td> <acronym title='Callbacks to overriden methods in entity before persist and before load.'>Lifecycle callbacks</acronym> </td>
<td>Yes</td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td> <acronym title='Filter results before instanitating them into entities. Useful for example when you want to sort on properties other than filtered on (which is illegal in the datastore).'>Low-level filtering</acronym> </td>
<td>No</td>
<td>Yes</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td> Transactions </td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td> <acronym title='Some form of support mechanism to handle schema migration (entity changes, etc)'>Schema migration support</acronym> </td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>No*</td>
</tr>
<tr>
<td> <acronym title='Support for caching data in GAE memcache. Should be handled internally in the framework.'>Caching</acronym> </td>
<td>Yes</td>
<td>In progress</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td> <acronym title='Support for integration with DI frameworks, like Guice.'>Dependency injection</acronym> </td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
</tbody>
</table>
<p>* = JDO/DataNucleus has support for it, but the AppEngine  implementation does not. About <a href="http://groups.google.com/group/google-appengine-java/browse_frm/thread/b6441378f1c26ce8">schema migration</a>.</p>
<p>** = Not directly supported, but supported via the exposed Datastore  interface.</p>
<p>Next: <a href="http://borglin.net/gwt-project/?page_id=691">Summary</a></p>
]]></content:encoded>
			<wfw:commentRss>http://borglin.net/gwt-project/?feed=rss2&amp;page_id=690</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>The frameworks</title>
		<link>http://borglin.net/gwt-project/?page_id=689</link>
		<comments>http://borglin.net/gwt-project/?page_id=689#comments</comments>
		<pubDate>Sat, 27 Mar 2010 15:09:00 +0000</pubDate>
		<dc:creator>Andreas Borglin</dc:creator>
				<category><![CDATA[GWT/GAE Project]]></category>

		<guid isPermaLink="false">http://borglin.net/gwt-project/?page_id=689</guid>
		<description><![CDATA[Previous: AppEngine datastore
These questions are meant to give a high-level introduction to each  framework.
Objectify, Twig and SimpleDS are all frameworks wrapped around the datastore low-level API. When reading this, you might want to complement this text by reading:

Objectify docs and JavaDoc
Twig docs
SimpleDS docs

Describe  your framework with just one sentence so that a  [...]]]></description>
			<content:encoded><![CDATA[<p>Previous: <a href="http://borglin.net/gwt-project/?page_id=688">AppEngine datastore</a></p>
<p><span style="font-weight: normal;">These questions are meant to give a high-level introduction to each  framework.</span></p>
<p><span style="font-weight: normal;">Objectify, Twig and SimpleDS are all frameworks wrapped around the datastore low-level API. When reading this, you might want to complement this text by reading:</span></p>
<ul>
<li>Objectify <a href="http://code.google.com/p/objectify-appengine/wiki/Concepts?tm=6">docs</a> and <a href="http://objectify-appengine.googlecode.com/svn/trunk/javadoc/index.html">JavaDoc</a></li>
<li>Twig <a href="http://code.google.com/p/twig-persist/wiki/Contents?tm=6">docs</a></li>
<li>SimpleDS <a href="http://code.google.com/p/simpleds/w/list">docs</a></li>
</ul>
<p><strong>Describe  your framework with just one sentence so that a  AppEngine/datastore  beginner would understand it.</strong><span style="text-decoration: underline;"><br />
</span></p>
<p><span style="text-decoration: underline;"><em>Jeff Schnitzer (objectify)</em></span></p>
<p style="padding-left: 30px;">Objectify is an easy-to-use framework that represents the GAE datastore close to its true nature:  A persistent HashMap which allows you to put(), get(), delete(), and query() for your Java objects.</p>
<p><span style="text-decoration: underline;"><em>John Patterson (Twig)</em></span></p>
<p style="padding-left: 30px;">A simple interface that makes difficult problems easy, faster and more  readable while keeping your data models pure POJOS with no dependencies  on the low-level datastore.</p>
<p><span style="text-decoration: underline;"><em>Ignacio Coloma (SimpleDS)</em></span></p>
<p style="padding-left: 30px;">SimpleDS  is a framework that uses the Datastore to persist your own Java classes  instead of Entity instances.</p>
<p><strong>What  was the number one design goal for your solution?</strong><span style="text-decoration: underline;"><br />
</span></p>
<p><span style="text-decoration: underline;"><em>Jeff Schnitzer (objectify)</em></span></p>
<p style="padding-left: 30px;">Exposing all native datastore features in an easy-to-use, easy-to-understand fashion.</p>
<p><span style="text-decoration: underline;"><em>John Patterson (Twig)</em></span></p>
<p style="padding-left: 30px;">Being “feature rich” while maintaining a simple, easy-to-explore API.   Working out of the box with no configuration while allowing  optimisations later to be as fast as is possible with the low-level  interface.  Actually, by hacking into async queries it is now _faster_  than possible with the low-level API!</p>
<p><span style="text-decoration: underline;"><em>Ignacio Coloma (SimpleDS)</em></span></p>
<p style="padding-left: 30px;">Simplicity.  You are as close to the Datastore API as possible.</p>
<p><strong>Did  you have to make any tradeoffs to support that goal?</strong></p>
<p><span style="text-decoration: underline;"><em>Jeff Schnitzer (objectify)</em></span></p>
<p style="padding-left: 30px;">There are features which have been deliberately avoided (managed relationships in particular) because they introduce a significant amount of configuration complexity.  We pride ourselves that the Objectify documentation is both thorough and short.  Features that change either characteristic get a lot of resistance.</p>
<p><span style="text-decoration: underline;"><em>John Patterson (Twig)</em></span></p>
<p style="padding-left: 30px;">I specifically chose not to follow the low-level API design in any way  which means that developers who are already familiar with it might not  feel quite as at home.  The other frameworks follow the low-level API  more closely which has the benefit of reusing their experience if they  have already worked with the low-level API.</p>
<p style="padding-left: 30px;">There are two main reasons behind the decision not to follow the  low-level API.  Firstly, the fact that software maintenance costs are  typically twice the cost of the initial development and normally not  performed by you, the initial developer.  You might have needed to learn  the low-level API but don't expect that of the maintenance developer  who tries to quickly add a new feature in 5 years time.  I believe that  the benefit of that familiarity are very low over all.</p>
<p style="padding-left: 30px;">Secondly, the low-level API is not a good example to follow for an  Object Oriented persistence interface.</p>
<p style="padding-left: 30px;">An example of this is the low-level put() method which has direct  counter-parts in Objectify and SimpleDS.  Twig has two separate methods,  store() and update() for what the others combine into a single method.   The reason for this separation is that the intent of the two operations  is completely different and you are making your intent clear by using  one of the other.  If you make a mistake and try to update an instance  that is not already persistent an exception will be thrown which helps  catch such logic errors early.  If you try and store an existing  instance it will not be silently clobbered.</p>
<p style="padding-left: 30px;">This same pattern is tried and tested in SQL with INSERT and UPDATE and  Hibernate with save() and update().</p>
<p style="padding-left: 30px;">Admittedly, because the other frameworks do not manage instance identity  it is not possible for them to know if an instance is already  persistent without querying the datastore.  Twig works like Hibernate in  this respect - it keeps an internal cache of Key-&gt;Instance to ensure  that every instance is represented in memory by only one instance.  So  every persistent instance in memory must also have been loaded and  therefore will be in the cache.  When you call update(), Twig just needs  to check that the instance and its Key are already in the Cache.</p>
<p style="padding-left: 30px;">Both Objectify and SimpleDS do not manage instance identity which means  that you can load the same entity into memory multiple times and the  framework could never know.</p>
<p><span style="text-decoration: underline;"><em>Ignacio Coloma (SimpleDS)</em></span></p>
<p style="padding-left: 30px;">I had to  add features for common tasks that are not included in GAE: paged  queries and @MultivaluedIndex, for example.</p>
<p><strong><span style="text-decoration: underline;">How does your framework help an application perform better in terms of latency and cost?</span></strong><span style="text-decoration: underline;"><br />
</span></p>
<p><span style="text-decoration: underline;"><em>Jeff Schnitzer (objectify)</em></span></p>
<p style="padding-left: 30px;">Objectify performs some fairly clever static analysis of your entity classes so that loading and saving data into the low-level API should be roughly as fast as equivalent handwritten code.</p>
<p style="padding-left: 30px;">In terms of latency and cost,</p>
<ul>
<li>Batch get(), put(), and delete() operations are essential parts of Objectify's API.  It is both faster and cheaper to batch a number of operations together than to issue separate requests.</li>
<li>Objectify enables a second-level memcache of your entites with a simple @Cached annotation.  This cache stores negative as well as positive results and works intelligently with batch operations.  It gracefully handles heterogeneous expiration periods.</li>
<li>Objectify provides easy fine-grained control over indexing, including partial indexing.  Indexes are what make writes expensive. The api_cpu_ms cost to write an entity without indexes is 48ms. Every index adds 17ms to that figure.  This won’t affect latency (indexes are updated in parallel), but it will affect your bill at the end of the week.  If your application is write-heavy, you *must* choose your indexes carefully.</li>
<li>Objectify has very little "magic" in its API; almost all operations map clearly and transparently to underlying native operations.  You will not inadvertently write code that looks simple but in fact masks several expensive queries.  Code that looks fast will be fast.</li>
</ul>
<p><span style="text-decoration: underline;"><em>John Patterson (Twig)</em></span></p>
<p style="padding-left: 30px;">Parallel queries execute N queries in the time it takes for the slowest  to execute.  In other words if you run 10 queries in a request then Twig  could reduce the total query time to 10% of what it otherwise would be.</p>
<p style="padding-left: 30px;">Low-level filters are incredibly useful and exclude unwanted entities  from being converted into instances at all.  In GAE this is sadly needed  very often because you can only query or sort on a single property.   For example, the query "find all Hotels under $100 sorted by rating"  required you to load every instance into memory and then discard the  ones over $100.  Converting all those unneeded entities into instances  can be very wasteful of CPU resource.</p>
<p style="padding-left: 30px;">Using Java code and implementing StorageStrategy (or extending the  default) gives you precise control over what is indexed and stored.   These flexible configuration options mean it is possible to code your  own "partial indexes" solution.</p>
<p style="padding-left: 30px;">Precise control over the kind name significantly reduces the size of  Keys which can save storage costs.</p>
<p style="padding-left: 30px;">Embedded Collections give a huge performance gain.  They cut out the  need to perform many in memory joins that can kill an applications  performance.</p>
<p><span style="text-decoration: underline;"><em>Ignacio Coloma (SimpleDS)</em></span></p>
<p style="padding-left: 30px;">You can  retrieve and store multiple entities using a single API call (same way  as you would using the raw Datastore). In that case, unassigned entity  keys will be generated using a single API call per entity kind.<br />
We are also adding cache support to SimpleDS, but that's a work in  progress.</p>
<p><strong>Is your framework targeted solely for AppEngine, or did you have portability in mind when designing it?</strong><span style="text-decoration: underline;"><br />
</span></p>
<p><span style="text-decoration: underline;">Jeff Schnitzer (objectify)</span></p>
<p style="padding-left: 30px;">Just AppEngine.  However, the core mechanism of being able to "objectify" key/value stores is something that could just as well apply to Cassandra, MongoDB, HBase, etc.  One of the Objectify developers, Scott, is actively contributing to MongoDB's Java API now.</p>
<p style="padding-left: 30px;">While we don't wish to create a single project spanning multiple platforms, we are interested in creating Objectify-ish interfaces for other platforms which would make your porting your application easier - not necessarily automatic.</p>
<p><span style="text-decoration: underline;">John Patterson (Twig)</span></p>
<p style="padding-left: 30px;">Solely for GAE.  I had portability of the data models in mind – hence  pure POJOs – which leads to more portable code which uses that data.   But for querying and manipulating data I want to be as specific as  possible to get the most from the platform. An example of this is the method ensureUniqueKey() which is used like  this:</p>
<div>
<p style="padding-left: 30px;">datastore.store().instance(band).ensureUniqueKey().returnKeyNow();</p>
<p style="padding-left: 30px;">Other platforms probably have other ways to ensure unique constraints –  but on GAE it is a little tricky so I encapsulate that “pattern” in a  method to save developers re-inventing the wheel every time.</p>
</div>
<p><span style="text-decoration: underline;">Ignacio Coloma (SimpleDS)</span></p>
<p style="padding-left: 30px;">It's just for AppEngine.</p>
<p style="padding-left: 30px;">
<p><strong>How easily can a developer extend/override framework logic/features in their own code base? Was this considered when designing it?</strong></p>
<p><strong> </strong><span style="text-decoration: underline;"> </span> <span style="text-decoration: underline;">Jeff Schnitzer (objectify)</span></p>
<p style="padding-left: 30px;"><span style="text-decoration: underline;"> </span> As always, it depends on what you're trying to do.  We don't have a vast API of extension hooks.  We do however, have 1) code that is extraordinarily well commented by the standards of most opensource projects, 2) many classes that are easily extended, and 3) a framework which is actually pretty simple and easy to understand.</p>
<p><span style="text-decoration: underline;">John Patterson (Twig)</span></p>
<p style="padding-left: 30px;">In my opinion Twig is the most configurable interface because it was  designed from the start to be configured in Java code. –  Annotations  were added as a convenient implementation that hooks into those  extension points.  A developer can add their own TypeConverters,  PropertyTranslators (which give exact control over writing/reading  objects to low-level properties) and all significant behaviour can be  overridden by writing your own Strategy.</p>
<p style="padding-left: 30px;">A practical example of  this is using an implementation of FieldStrategy which allows you to  read and write data shared by JDO just by implementing this simple  "strategy"  interface to use the same kind and property names:</p>
<div style="padding-left: 30px;"><a href="http://code.google.com/p/twig-persist/source/browse/src/main/java/com/vercer/engine/persist/strategy/FieldStrategy.java" target="_blank">http://code.google.com/p/twig-persist/source/browse/src/main/java/com/vercer/engine/persist/strategy/FieldStrategy.java</a></div>
<p style="padding-left: 30px;">Voila!   Twig now reads your existing JDO, Objectify, SimpleDS or raw low-level  data.</p>
<p><span style="text-decoration: underline;">Ignacio Coloma (SimpleDS)</span></p>
<p style="padding-left: 30px;"><span style="text-decoration: underline;"> </span> It is trivial to add Converters for your own data types (e.g. Joda classes). SimpleDS is also strongly based on interfaces for their API classes, so a user should be able to replace implementation classes with his own.</p>
<p><strong>Does your framework have any external dependencies? If so, which and why?</strong></p>
<p><span style="text-decoration: underline;">Jeff Schnitzer (objectify)</span></p>
<p style="padding-left: 30px;">None.  Just add objectify.jar to your project.</p>
<p><span style="text-decoration: underline;">John Patterson (Twig)</span></p>
<p style="padding-left: 30px;">Only Google Collections which is just so  incredibly handy.</p>
<p><span style="text-decoration: underline;">Ignacio Coloma (SimpleDS)</span></p>
<p style="padding-left: 30px;">We are using the following dependencies:</p>
<ul>
<li>spring-core to find persistent classes. We are using Spring as any other library, not as a dependency injection framework. You may use your own for that purpose, or not use class scanning at all and just add your mappings by hand.</li>
<li>google collections, because life is too short to use raw Java collections. We also use Functions to implement the PagedQuery.transform() feature.</li>
<li>aspectjrt and aspectjweaver for @Transactional support using aspects.</li>
<li>commons-logging to, well, log.</li>
</ul>
<p><strong>Were you inspired by any existing framework/solution (not necessarily related to GAE)?</strong></p>
<p><strong> </strong> <span style="text-decoration: underline;">Jeff Schnitzer (objectify)</span></p>
<p style="padding-left: 30px;">We think Google did a great job with the Python API, so we mimicked GAE/Python where we could.</p>
<p><span style="text-decoration: underline;">John Patterson (Twig)</span></p>
<p style="padding-left: 30px;">Db4o inspired the Activation concept as a way to limit object graph retrieval without needing proxies etc. Martin Fowlers writings on fluent interfaces influenced the design of the command objects.  <a href="http://www.martinfowler.com/bliki/FluentInterface.html" target="_blank">http://www.martinfowler.com/bliki/FluentInterface.html</a></p>
<p><a href="http://www.martinfowler.com/bliki/FluentInterface.html" target="_blank"></a> <span style="text-decoration: underline;">Ignacio Coloma (SimpleDS)</span></p>
<p style="padding-left: 30px;">We have borrowed the generics approach from Google Collections, some architecture ideas from "Practical API Design" from Apress, and struggled to combine together a singleton-based and dependency injection approach. But mostly, we tried to keep the API as similar to the Datastore as possible, making it easier to use at some points.</p>
<p style="padding-left: 30px;">
<p><strong>Even though your solutions are different, many fundamental parts are solved in similar ways. Do you see any possiblity for a shared code base with the other frameworks? Or even a merge of the solutions? On the other hand, competition is healthy. What is your view on this?</strong></p>
<p><strong> </strong> <span style="text-decoration: underline;">Jeff Schnitzer (objectify)</span></p>
<p style="padding-left: 30px;">We're happy to share code and cooperate with other developers. Ultimately, all of these projects were created to meet the everyday development needs of the authors, and as such represent "lost time". The more we can share, the better.</p>
<p style="padding-left: 30px;">That said, the Objectify developers have a strong desire to keep the API small and learning curve short.  We are probably more cautious about introducing features than other projects are.  This philosophy would make it difficult to merge with more "kitchen sink"-oriented projects.</p>
<p><span style="text-decoration: underline;">John Patterson (Twig)</span></p>
<p style="padding-left: 30px;">Certainly collaboration on low level features such as data migration, profiling, logging this makes a lot of sense.  Scott (Objectify) suggested we try to keep annotations named the same which I agree with.</p>
<p style="padding-left: 30px;">There is already some borrowing of high level features.  Objectify integrated Embedded collections from Twig and I was influenced in Transaction handling by Objectify.</p>
<p style="padding-left: 30px;">A merge would not be practical with any of the other frameworks because all operate at a lower-level i.e. put, get, query, delete.</p>
<p><span style="text-decoration: underline;">Ignacio Coloma (SimpleDS)</span></p>
<p style="padding-left: 30px;">Twig and Objectify are putting more features on the table than SimpleDS, and that's on purpose. I see obvious value in trying to put together a solution for Indexes and Schema migration, but I don't know how far we can get until differences of criteria makes it complicated. Even the feature sets that we support using annotations are different.</p>
<p style="padding-left: 30px;">
<h3>My 2 cents</h3>
<p>Complementary reading that I recommend:</p>
<ul>
<li>Objectify announcement with some Objectify/SimpleDS discussion: <a href="http://groups.google.com/group/google-appengine-java/tree/browse_frm/thread/4467986eaf01788b/c6d007863a616a1b">Here</a></li>
<li>Objectify/Twig discussion: <a href="http://groups.google.com/group/google-appengine-java/browse_thread/thread/f20d922ffecb310c">Here</a></li>
<li>Debate thread: <a href="http://groups.google.com/group/google-appengine-java/browse_thread/thread/79078132130a3dfe">Here</a></li>
</ul>
<p>Next: <a href="http://borglin.net/gwt-project/?page_id=690">Feature checklist</a></p>
]]></content:encoded>
			<wfw:commentRss>http://borglin.net/gwt-project/?feed=rss2&amp;page_id=689</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>AppEngine datastore</title>
		<link>http://borglin.net/gwt-project/?page_id=688</link>
		<comments>http://borglin.net/gwt-project/?page_id=688#comments</comments>
		<pubDate>Sat, 27 Mar 2010 15:07:54 +0000</pubDate>
		<dc:creator>Andreas Borglin</dc:creator>
				<category><![CDATA[GWT/GAE Project]]></category>

		<guid isPermaLink="false">http://borglin.net/gwt-project/?page_id=688</guid>
		<description><![CDATA[Previous: Introduction
This first section of interview questions focuses on the AppEngine datastore and its offering. The idea with this section is that developers that are considering AppEngine gets a chance to hear what some experienced developers has to say about the datastore.
What are the  biggest strengths of the AppEngine datastore?
Jeff Schnitzer (objectify)

That someone else [...]]]></description>
			<content:encoded><![CDATA[<p>Previous: <a href="http://borglin.net/gwt-project/?page_id=604">Introduction</a></p>
<p>This first section of interview questions focuses on the AppEngine datastore and its offering. The idea with this section is that developers that are considering AppEngine gets a chance to hear what some experienced developers has to say about the datastore.</p>
<p><strong>What are the  biggest strengths of the AppEngine datastore?</strong></p>
<p><span style="text-decoration: underline;"><em>Jeff Schnitzer (objectify)</em></span></p>
<ul>
<li>That someone else manages it for you.  Server maintenance, backups, capacity, hardware failures, etc are all someone else's problem.</li>
<li>That it's schemaless.  It's actually pretty easy to make structural changes to your data on-the-fly with no downtime. Despite some significant schema changes, I've only taken Mobcast (my "day job") offline once, and that had nothing to do with the datastore.</li>
<li>That scaling the datastore is not an issue.  I feel pretty secure knowing that even if 10 million users all switch on my application tomorrow, they will all get about the same experience that users get today.  It means that I can spend every day writing new features instead of making sure the old ones continue to work.</li>
</ul>
<p><span style="text-decoration: underline;"><em>John Patterson (Twig)</em></span></p>
<ul>
<li>No need to administer you own servers - Hard problems like clustering,  security and hardware maintenance are taken off your hands.</li>
<li>Scalability - Confidence that as your app grows in popularity you will  have very few problems keeping pace. The limitations actually prohibit  architectural practices that do not scale.</li>
<li>Price - –Free to get started and investigate whether the platform suits  your requirements. Very competitively priced as your resource demands  increase.</li>
</ul>
<p><span style="text-decoration: underline;"><em>Ignacio Coloma (SimpleDS)</em></span></p>
<p style="padding-left: 30px;">You can deploy today, test your application and then turn your cell phone off for the weekend, knowing that if it goes down there will be an entire team working hard to get it back online again. It also has a really simple, straight-to-the-point set of features.</p>
<p><strong>What  about biggest weaknesses?</strong></p>
<p><span style="text-decoration: underline;"><em>Jeff Schnitzer (objectify)</em></span></p>
<p style="padding-left: 30px;">My biggest complaint, by far, is the lack of ad-hoc queries. In an RDBMS world you get used to firing up a SQL prompt and asking certain kinds of arbitrary questions about your data. It may take an hour to table scan a billion records, but you eventually get your answer.</p>
<p style="padding-left: 30px;">The GAE datastore is great for operational systems, but it's not very convenient for analytics. You can iterate through your dataset 30s at a time using the task queue, but even simple questions require a fair amount of code.</p>
<p style="padding-left: 30px;">Perhaps the looming map/reduce feature will address this issue, but it's hard to imagine it being as convenient as a SQL prompt. A SQL engine that you can run on top of an existing dataset and perform complex queries, no matter how slowly, would be extraordinarily useful. Unfortunately the folks building Cloud2db don't seem to be thinking along these lines - their solution is much more of an "all or nothing" approach.</p>
<p style="padding-left: 30px;">My second biggest complaint is that the datastore is actually kinda slow. I read boasts that applications on Cassandra, Tokyo Tyrant, and MongoDB get more than 10k writes per second *per instance*. I'm lucky to get 100 writes per second in a GAE request.  Two orders of magnitude difference!</p>
<p style="padding-left: 30px;">Other popular complaints are the lack of usable transactions and the lack of (automatic) joins. Not every application needs these things, so I'm more inclined to call them "constraints" rather than "weaknesses".</p>
<p><span style="text-decoration: underline;"><em>John Patterson (Twig)</em></span></p>
<p style="padding-left: 30px;">The datastore requires a complete change in mindset and a new toolset.   Not having the ability to run complex queries means you need to  pre-calculate results that you would be used to querying on the fly.</p>
<p style="padding-left: 30px;">Frequent loading requests – traditional frameworks such as Wicket and  Spring assume they can do work upfront to reduce per request effort.<br />
Engine apps need to start fast and amortise initialisation work over  many request or users are left waiting during the frequent loading  requests.  This is probably the issue that hits more projects than any  other. Often developers get quite far through the development process  before being shocked to realise that their initial framework choice has  made their application unusable.</p>
<p style="padding-left: 30px;">Transactions are very limited and your data model must be structured to  use them in a particular way from the start.</p>
<p style="padding-left: 30px;">No https support for your domain and nothing a developer can do to  remedy this themselves – apart from going elsewhere for this  functionality.  The more general issue is that if you need something the  platform doesn't offer you cannot simply install it yourself.</p>
<p style="padding-left: 30px;">Many Java libraries are incompatible - there is no SOAP RPC  implementation that runs on the Engine.</p>
<p><span style="text-decoration: underline;"><em>Ignacio  Coloma (SimpleDS)</em></span></p>
<p style="padding-left: 30px;">It has a  really simple set of features, which quite often makes the "not allowed  to do" list rather long. This is where third-party libraries should  extend the capabilities of GAE.</p>
<p><strong>What are  the  problems with the JDO/JPA solutions?</strong></p>
<p><span style="text-decoration: underline;"><em>Jeff Schnitzer (objectify)</em></span></p>
<p style="padding-left: 30px;">The biggest problem is that they're clumsy and unwieldy.  JDO contains a bazillion annotations, configuration options, and query language structures to allow it to straddle every conceivable kind of datastore, from an RDBMS to a object databases.  JPA is tailored specifically to the feature set of an RDBMS.  The GAE datastore is something new... so JDO gets a whole new arsenal of special extensions and JPA just gets left out in the cold.</p>
<p style="padding-left: 30px;">In the context of GAE, 80% of JDO and JPA are meaningless cruft, and the GAE-specific features that you *do* need have tortured syntax.  Do you really want to type things like @Extension(vendorName = "datanucleus", key = "gae.unindexed", value="true") everywhere? The syntax for batch gets - one of the most important operations on the datastore - is atrocious:</p>
<pre class="brush: java;">
Query q = pm.newQuery(&quot;select from &quot; + Book.class.getName() + &quot; where :keys.contains(key));
</pre>
<p style="padding-left: 30px;">Using JDO/JPA on GAE effectively requires climbing not only the learning curve for JDO/JPA (and figuring out which 20% works), but also learning how the datastore works and how to bend JDO/JPA around it.  It's just not worth it - and I say this as someone who has been working extensively with Hibernate and JPA since the days of Hibernate 1.0.</p>
<p style="padding-left: 30px;">Aside from the general complexity issue, there are some specific problems with JDO/JPA on GAE.  GAE has some interesting nuances (parent keys &amp; entity groups, partial indexes, collection properties) that don't have direct mappings in either JDO or JPA.  JPA is particularly troublesome; DataNucleus uses the bytecode enhancer, but JPA doesn't have a detach() method - so you can't serialize your entities, ever!</p>
<p><span style="text-decoration: underline;"><em>John Patterson (Twig)</em></span></p>
<p style="padding-left: 30px;">JDO is a one-size-fits-all interface that really doesn't fit the Engine  so well at all.  Doing simple things that are specific to the datastore  becomes incredibly complex and not at all intuitive.  You will spend a  large portion of your development time hunting for the right annotations  to use or figuring out if a feature is implemented.  Often you will be  disappointed - no support for polymorphism?  Come on, this is Java!</p>
<p style="padding-left: 30px;">More generally adhering to a spec limits how the implementation can  utilize the underlying features of the datastore.  In some cases this  needs to unnecessarily terrible performance.  Storing Lists of instances  must update every member Entity if the order is changed so that  behaviour adheres to the spec.</p>
<p style="padding-left: 30px;">Startup time is terrible.</p>
<p><span style="text-decoration: underline;"><em>Ignacio Coloma (SimpleDS)</em></span></p>
<p style="padding-left: 30px;">With JDO  you are going through an extensive API thought for the features present  in a relational database, or worse, any kind of datastore. GAE has a  limited nature that basically chops off all those features behind the  curtains. To me, it would be more natural to learn the things that are allowed in GAE instead of all the things that are forbidden (which  again, is a long list).</p>
<p style="padding-left: 30px;">The  Datanucleus JPA implementation has JDO underneath it, so you get Yet  Another Layer to understand and debug.</p>
<p><strong>Are  there any situations where you would recommend a developer to   use JDO/JPA rather than a third party framework?</strong></p>
<p><span style="text-decoration: underline;"><em>Jeff Schnitzer (objectify)</em></span></p>
<p style="padding-left: 30px;">I'm tempted to say:  "If you expect to port your system to another platform, you should probably use JDO or JPA." However, the first retort that pops into my mind is "If you expect to port your system to another platform, you should stop using GAE right now." There are quite a lot of issues involved in migrating a GAE app to another environment and the datastore is just one of them. If you aren't sure that GAE will work for you, keep reading the documentation until you *are* sure one way or another. You will save yourself a lot of pain later on.</p>
<p style="padding-left: 30px;">It's not that JDO/JPA doesn't have some nice features (change detection and cascading deletes, for example), it's just that I don't think these features are worth the trouble.  On the other hand, your apps may have entirely different demands than my apps, and maybe to you those features are golden.</p>
<p style="padding-left: 30px;">If you're new to Appengine, I would recommend developing a spike solution with Objectify, even for JDO/JPA experts that intend to develop with JDO/JPA fulltime.  Objectify will teach you how the datastore really works, knowledge that will arm you well for your future struggles.</p>
<p><span style="text-decoration: underline;"><em>John Patterson (Twig)</em></span></p>
<p style="padding-left: 30px;">If you have more time and money than you know what to do with I suggest  wasting both by using JDO/JPA.</p>
<p style="padding-left: 30px;">If you have an existing app that already uses JDO or JPA you may get  some reuse of your investment by sticking with them.  But in reality  your data model will need to change significantly, many if not all of  your queries will need to be restructured, transactions will not work in  the same way ... basically you will need to rewrite in any case.</p>
<p style="padding-left: 30px;">If you want to keep your options open to move your app to another  platform I still would not recommend it.  You will not be able to reuse  your data models because of all the Engine specific hacks and  dependencies you are forced to depend on.</p>
<p style="padding-left: 30px;">Twig data models are more portable than JDO models because they do are  pure Pojos with no dependencies on the low-level datastore or JDO.   Think of them as the DTOs that developers often need to write to hide  implementation details.  Its just that you persist these pure DTOs  directly.</p>
<p style="padding-left: 30px;">Some apps are just not possible to build with JDO-GAE due to its lack of  performance optimisations.  My experiments with JDO showed it was not  possible to get the performance I needed for my app to be practical.   The same logical query that could not complete within the 30 second  deadline using JDO now runs in 250ms thanks to Twigs embedded  collections and parallel queries.  Other users have found that queries  they had to run as background tasks previously now run in real time.</p>
<p><span style="text-decoration: underline;"><em>Ignacio Coloma (SimpleDS)</em></span></p>
<p style="padding-left: 30px;">People  aiming to make applications independent from the datastore will find  some value in JDO/JPA. This is a case that I have problems to imagine,  since your application will end tied to AppEngine one way or the other,  but the biggest amount of independence is going through JPA/JDO.</p>
<p><strong>Which  problems do you see with using the low-level API directly?</strong></p>
<p><span style="text-decoration: underline;"><em>Jeff Schnitzer (objectify)</em></span></p>
<ul>
<li>Untyped data structures.</li>
<li>Clunky query API.</li>
<li>Your data gets unceremoniously munged in odd ways (ie, all Integers go to Long, all collections to ArrayList).</li>
<li>Poor documentation.</li>
<li>It's simply not fun.</li>
</ul>
<p><span style="text-decoration: underline;"><em>John Patterson (Twig)</em></span></p>
<p style="padding-left: 30px;">You basically have to deal with bags of untyped values.  There is a  reason we program in languages like Java with class constructs and not  just Maps of Objects.</p>
<p style="padding-left: 30px;">Transactions are handled inconsistently.  Due to historical reasons, all  queries ignore the current transaction even if they include an ancestor  filter.  This could not be changed without breaking existing low-level  code.  Without that restriction Twig is free to always use the current  transaction in every operation including queries.</p>
<p style="padding-left: 30px;">If you have your own dynamic data models then they can map very well to  low-level Entities.  But Twig can also be configured to store any type  as Entities and Properties exactly as you want using its flexible  PropertyTranslator chains.</p>
<p><span style="text-decoration: underline;"><em>Ignacio Coloma (SimpleDS)</em></span></p>
<p style="padding-left: 30px;">There are  no checks at all. You may query for a field that is not there anymore,  or use a Key referencing the wrong kind. Of course, the biggest problem  is using HashMaps to handle Entity data instead of Java classes.</p>
<p><strong>There are a number of other frameworks currently  available   (objectify, Twig, SimpleDS, Slim3, Siena, cloud2db). If these existed  when you  decided to create your own framework, did you know of them? If  so, why  did these not live up to your requirements?</strong></p>
<p><span style="text-decoration: underline;"><em>Jeff Schnitzer (objectify)</em></span></p>
<p style="padding-left: 30px;">Yes, I reviewed all of these in fairly fine detail.  I would much rather build applications than tools.  I actually started working on patches to Siena in hopes of making it meet my needs, but Siena's cross-platform nature ran at odds with my need to squeeze every last ounce of performance out of the GAE datastore.</p>
<p style="padding-left: 30px;">The biggest problem I had with the others is key management.  My entities have simple ids; many have natural integer keys (facebook ids, place ids).  I want to use simple POJO classes like this:</p>
<pre class="brush: java;">
class Foo {
@Id long id;
String someData;
// ...etc
}
</pre>
<p style="padding-left: 30px;">Placing the datastore Key class (or even a stringified version of the Key) in the entity carries redundant information and complicates working with the data.  JPA entities have simple ids, why can't mine? SimpleDS and Slim3 force the Key into the entity. Siena gets it right but can't handle entity groups.</p>
<p style="padding-left: 30px;">Another issue was lack of deep support for generics.  It was tricky to weave a generic Key&lt;?&gt; class throughout Objectify's API, but the payoff is vastly more readable application code.</p>
<p style="padding-left: 30px;">And then there are aesthetics.  Other than Siena, I just couldn't bring myself to love the other APIs.  Yes, it's subjective... but here are the money shots, you can judge for yourself:</p>
<p style="padding-left: 30px;"><a href="http://objectify-appengine.googlecode.com/svn/trunk/javadoc/com/googlecode/objectify/Objectify.html" target="_blank">http://objectify-appengine.googlecode.com/svn/trunk/javadoc/com/googlecode/objectify/Objectify.html</a><br />
<a href="http://slim3.googlecode.com/svn/trunk/slim3/javadoc/org/slim3/datastore/Datastore.html" target="_blank">http://slim3.googlecode.com/svn/trunk/slim3/javadoc/org/slim3/datastore/Datastore.html</a><br />
<a href="http://loom.sourceforge.net/docs/simpleds/javadoc/org/simpleds/EntityManager.html" target="_blank">http://loom.sourceforge.net/docs/simpleds/javadoc/org/simpleds/EntityManager.html</a><br />
<a href="http://code.google.com/p/twig-persist/source/browse/src/main/java/com/vercer/engine/persist/ObjectDatastore.java" target="_blank">http://code.google.com/p/twig-persist/source/browse/src/main/java/com/vercer/engine/persist/ObjectDatastore.java</a> (no javadocs)</p>
<p><span style="text-decoration: underline;"><em>John Patterson (Twig)</em></span></p>
<p style="padding-left: 30px;">Although Twig is the most recently released of the three interfaces  discussed here, pre-release versions were made public that focused on  getting the core functionality working well and fast.  Only in the  recent final release were the user friendly fluent commands introduced  with the benefit of seeing the strengths and weaknesses of the other  API's as a base.</p>
<div class="im">
<p style="padding-left: 30px;">One key difference in the API's  is the use of fluent Commands over a flat Query interface.  The  difference is analogous to storing all your files in a single flat  directory or organising them into folders.  This allows Twig to add lots  of functionality that does not clutter the API and also leaves room for  new functionality to be added over time. Designing  these commands, the main thought process was “"is this obvious for  someone who does not already know the low-level API"?”.  To this end,  method invocations read like sentences:</p>
</div>
<pre class="brush: java;">
datastore.find().type(Hotel.class)
.withAncestor(chain)
.fetchResultsBy(50)
.continueFrom(myCursor)
.start From(100)
.addFilter(...)
.returnResultsNow(); //   returnKeysLater() performs a parallel query.
</pre>
<div class="im">
<p style="padding-left: 30px;">Some  other frameworks seem to value having short names to reduce key strokes  as more important.</p>
<p style="padding-left: 30px;">All the other frameworks make  you write data models specifically designed for and dependant on the  datastore.  Working with low-level Keys makes code messy and less  maintainable so right from the start Twig was designed to handle Keys  completely transparently.  This leaves your data models free of any  dependencies on the low-level interface.</p>
</div>
<p><span style="text-decoration: underline;"><em>Ignacio Coloma (SimpleDS)</em></span></p>
<p style="padding-left: 30px;">I  searched for alternatives before starting up SimpleDS and couldn't find  any. Anyway, I was looking for the simplest possible solution for GAE  storage, not for a full JDO replacement.</p>
<p style="padding-left: 30px;">
<h3>My 2 cents</h3>
<p>I had only worked with relational databases before I decided to try out AppEngine. I agree with all of the authors opinions here, but especially with John Patterson's comment about mindset. Not only did I go from standard relational SQL databases to BigTable, but also from standard PHP/HTML approach to Google Web Toolkit. Sometimes it feels like I would need behavioral therapy to;</p>
<ol>
<li>Stop thinking about my model relationships in relational/SQL terms.</li>
<li>Stop thinking in terms of pages and page navigation when using GWT. There are no pages (well, one perhaps)! Embrace the dynamic world with GWT history!</li>
</ol>
<p>I still love GWT + GAE though (well, besides the cold start time that is driving me a bit crazy). It's a great way for startups or hobby projects to get started without investing money in webservers, etc.</p>
<p>Next: <a href="http://borglin.net/gwt-project/?page_id=689">The frameworks</a></p>
]]></content:encoded>
			<wfw:commentRss>http://borglin.net/gwt-project/?feed=rss2&amp;page_id=688</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Datastore frameworks: The interview</title>
		<link>http://borglin.net/gwt-project/?page_id=604</link>
		<comments>http://borglin.net/gwt-project/?page_id=604#comments</comments>
		<pubDate>Sat, 27 Mar 2010 15:07:36 +0000</pubDate>
		<dc:creator>Andreas Borglin</dc:creator>
				<category><![CDATA[GWT/GAE Project]]></category>
		<category><![CDATA[datastore]]></category>
		<category><![CDATA[gae]]></category>
		<category><![CDATA[jdo]]></category>
		<category><![CDATA[objectify]]></category>
		<category><![CDATA[simpleds]]></category>
		<category><![CDATA[twig]]></category>

		<guid isPermaLink="false">http://borglin.net/gwt-project/?page_id=604</guid>
		<description><![CDATA[In this article we will have a look at three of the low-level wrapper frameworks for the AppEngine datastore. It's an interview-style post where the authors of each framework answers a number of questions related to the AppEngine datastore and their frameworks. There will also be a follow-up article where I solve some typical datastore [...]]]></description>
			<content:encoded><![CDATA[<p>In this article we will have a look at three of the low-level wrapper frameworks for the AppEngine datastore. It's an interview-style post where the authors of each framework answers a number of questions related to the AppEngine datastore and their frameworks. There will also be a follow-up article where I solve some typical datastore scenarios with each of the frameworks and write about my experience with that.</p>
<h2>Background</h2>
<p>Anyone who has tried to use JDO/JPA on AppEngine will probably agree that it is too complex and has a steep learning curve. Offering a JDO/JPA solution is kind of like saying "Hey. We have a standardized API so you don't have to worry about the implementation details of the underlying datastore.". The problem is that in the case of AppEngine, there is also a fine print saying "But you should also be aware of these limitations, these GAE extensions and...etc...etc...".</p>
<p>This means that you MUST worry about the implementation details anyway, since the datastore &lt;-&gt; JDO/JPA mapping is far from optimal. If you don't know about the datastore limitations and think you can use JDO/JPA like you would on a relational datastore, you are in for a bumpy ride. And just to make this clear, once again, the root cause of this problem is not related to JDO/JPA or the DataNucleus implementation in general.</p>
<p>The low-level API is on the other end of the scale. It has an extremply simple API, but it's not type safe and only works with native entities, which requires lots of tedious work from the developer. What should a developer do?</p>
<h5>The low-level wrapper frameworks to the rescue</h5>
<p>I'm not the only one who thinks that the JDO/JPA solution is too complex and makes development harder than it has to be. There are, to my knowledge, 6 different attempts at offering an alternative, which is not a coincidence. These 6 are <a href="http://code.google.com/p/objectify-appengine/">Objectify</a>, <a href="http://code.google.com/p/twig-persist/">Twig</a>, <a href="http://code.google.com/p/simpleds/">SimpleDS</a>, <a href="http://code.google.com/p/siena/">Siena</a>, <a href="http://code.google.com/p/slim3/">Slim3</a> and <a href="http://cloud2db.appspot.com/website/index.html">cloud2b</a>. Update: A 7th framework called <a href="http://www.jiql.org/xwiki/bin/view/Main/">jiql</a> which is a SQL/JDBC interface on top of AppEngine.</p>
<p>I have chosen to look at three of these; Objectify, Twig and SimpleDS. There is a good reason to why I chose those three. They are designed specifically for the AppEngine datastore with its features and limitations in mind. The other three frameworks are designed with other goals in mind.</p>
<p>Siena and cloud2b has multi-platform support and, like JDO/JPA, has a generic API to support this. Slim3 is a full-stack MVC framework that goes outside the scope of a thin low-level datastore wrapper. <strong>Update:</strong> Apparently Slim3 can be used as a standalone datastore framework, which wasn't clear from the documentation at the time. The documentation has now been updated to describe this.</p>
<p>I'm sure that these frameworks are great and probably good choices for a multi-platform strategy. Or, in the case of Slim3, a complete server-side framework. But I'm not at all interested in that. I want to use a simple and efficient datastore framework that mainly acts as a convenience layer on top of the AppEngine low-level API. Objectify, Twig and SimpleDS fulfills this requirement. <strong>Read</strong> <a href="http://groups.google.com/group/google-appengine-java/browse_thread/thread/c235e0e528023e26/32c33092a5452b4a">this</a> thread for some debating on this matter and why I don't want to use SQL/JDBC interfaces for my project.</p>
<h2>The interview</h2>
<p>Ok. Let's get on with the juicy stuff. First, let me introduce the authors. (Lots of credit and thanks to the authors for this!)</p>
<p><em>Jeff Schnitzer</em>, lead developer Objectify.</p>
<p><em>John Patterson</em>, lead developer Twig.</p>
<p><em>Ignacio Coloma</em>, lead developer SimpleDS.</p>
<p>The original plan was to wrap this article up with a nice debate, but one of the GAE/J threads turned into a fantastic debate that covers many different aspects of datastore philosophies and designs. The authors would need to repeat themselves here if we were to keep the debate, so I decided to skip it and refer to the debate thread instead. In one of the interview sections there are links to various stuff you should have a look at.</p>
<p>The interview has been split into 4 subpages to make it more lucid.</p>
<h4>Table of content</h4>
<p><a href="http://borglin.net/gwt-project/?page_id=688">AppEngine datastore</a></p>
<p><a href="http://borglin.net/gwt-project/?page_id=689">The frameworks</a></p>
<p><a href="http://borglin.net/gwt-project/?page_id=690">Feature checklist</a></p>
<p><a href="http://borglin.net/gwt-project/?page_id=691">Summary</a></p>
<p>Next: <a href="http://borglin.net/gwt-project/?page_id=688">AppEngine datastore</a></p>
]]></content:encoded>
			<wfw:commentRss>http://borglin.net/gwt-project/?feed=rss2&amp;page_id=604</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>gwt-presenter vs mvp4g</title>
		<link>http://borglin.net/gwt-project/?page_id=755</link>
		<comments>http://borglin.net/gwt-project/?page_id=755#comments</comments>
		<pubDate>Thu, 25 Mar 2010 16:17:04 +0000</pubDate>
		<dc:creator>Andreas Borglin</dc:creator>
				<category><![CDATA[GWT/GAE Project]]></category>

		<guid isPermaLink="false">http://borglin.net/gwt-project/?page_id=755</guid>
		<description><![CDATA[I recently found out about mvp4g, which is another MVP implementation (like gwt-presenter).
If you read my Page handling post, you know that I've been thinking about how to split TeamScape into several conceptual modules (main page, team page, association page).
I don't see how this can be solved with the current state of gwt-presenter which basically [...]]]></description>
			<content:encoded><![CDATA[<p>I recently found out about <a href="http://code.google.com/p/mvp4g/">mvp4g</a>, which is another MVP implementation (like gwt-presenter).</p>
<p>If you read my Page handling post, you know that I've been thinking about how to split TeamScape into several conceptual modules (main page, team page, association page).</p>
<p>I don't see how this can be solved with the current state of gwt-presenter which basically is a 1-1-1 mapping of place request -&gt; place -&gt; presenter.</p>
<p>I currently see three different ways forward:</p>
<ol>
<li>Branch off gwt-presenter and adapt it</li>
<li>Try out the PuzzleBazar version of gwt-presenter</li>
<li>Try out mvp4g, which has integrated support for multiple modules (with code splitting!)</li>
</ol>
<p>Has anyone tried mvp4g? Or does anyone have other ideas?</p>
]]></content:encoded>
			<wfw:commentRss>http://borglin.net/gwt-project/?feed=rss2&amp;page_id=755</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Page handling</title>
		<link>http://borglin.net/gwt-project/?page_id=588</link>
		<comments>http://borglin.net/gwt-project/?page_id=588#comments</comments>
		<pubDate>Sat, 06 Mar 2010 18:03:41 +0000</pubDate>
		<dc:creator>Andreas Borglin</dc:creator>
				<category><![CDATA[GWT/GAE Project]]></category>
		<category><![CDATA[discussion]]></category>

		<guid isPermaLink="false">http://borglin.net/gwt-project/?page_id=588</guid>
		<description><![CDATA[This is the first post in the Discussions arena where I describe something that needs to be solved and turn to the readers for some input and feedback.
I have to make a decision related to how we should handle pages, so I was hoping you guys could help me out on this one.
There are two [...]]]></description>
			<content:encoded><![CDATA[<p>This is the first post in the Discussions arena where I describe something that needs to be solved and turn to the readers for some input and feedback.</p>
<p><span style="text-decoration: line-through;">I have to make a decision related to how we should handle pages, so I was hoping you guys could help me out on this one.</span></p>
<p>There are two things to discuss here:</p>
<ul>
<li>How we should handle URL mapping of pages</li>
<li>How pages should be represented in GWT with the MVP pattern</li>
</ul>
<p>Let's start by describing what we need to do. TeamScape will have three different pages;</p>
<ol>
<li>A main page which a visitor comes to by going to http://www.teamscape.se. This page presents the site and you can register a team, search for teams, etc.</li>
<li>A team page, which represents registered teams and its players, leagues, matches etc.</li>
<li>An association page, which represents registered assocations/clubs and their sport offerings.</li>
</ol>
<p>All these pages will have different layouts, This means that there will be unique presenters/views for each page, but we also have some that needs to be shared between the pages.</p>
<p>Initially I had some ideas that this could be solved with servlet url-mappings and multiple GWT modules, but this turned out to be very bad ideas. First, I missed one very important detail related to servlets, and that is that the html file (read the js script) will be reloaded for each request. Second, splitting the project into several modules, entry points and host files only make the structure unnecassarily complex.</p>
<p>After some more research, it has become clear that GWT history + code splitting is the way to go.  I will probably postpone the implementation of this for a while, until I know more about how gwt-presenter will evolve with places and presenters. We have lots of work to do with the team page and entities before we have to bother with this anyway.</p>
]]></content:encoded>
			<wfw:commentRss>http://borglin.net/gwt-project/?feed=rss2&amp;page_id=588</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Discussions</title>
		<link>http://borglin.net/gwt-project/?page_id=588</link>
		<comments>http://borglin.net/gwt-project/?page_id=588#comments</comments>
		<pubDate>Sat, 06 Mar 2010 13:18:44 +0000</pubDate>
		<dc:creator>Andreas Borglin</dc:creator>
				<category><![CDATA[GWT/GAE Project]]></category>

		<guid isPermaLink="false">http://borglin.net/gwt-project/?page_id=587</guid>
		<description><![CDATA[]]></description>
			<content:encoded><![CDATA[]]></content:encoded>
			<wfw:commentRss>http://borglin.net/gwt-project/?feed=rss2&amp;page_id=587</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>What to expect</title>
		<link>http://borglin.net/gwt-project/?page_id=574</link>
		<comments>http://borglin.net/gwt-project/?page_id=574#comments</comments>
		<pubDate>Fri, 05 Mar 2010 08:27:35 +0000</pubDate>
		<dc:creator>Andreas Borglin</dc:creator>
				<category><![CDATA[GWT/GAE Project]]></category>

		<guid isPermaLink="false">http://borglin.net/gwt-project/?page_id=574</guid>
		<description><![CDATA[In unknown order, here are some of the things we'll be looking into.

MVP pattern with gwt-presenter
EventBus
GWT History mechanism
GWT Localisation/I18N mechanism
Dependency injection with GIN and Guice
RPC with gwt-dispatch
Standards mode compliance with GWT 2.0
Layout with UiBinder and MVP
Advanced layout with CSS
Using client bundles to handle css and image resources
Browser auto-complete login form
GWT/GAE testing methodologies
GAE Datastore (BigTable) offering [...]]]></description>
			<content:encoded><![CDATA[<p>In unknown order, here are <span style="text-decoration: underline;">some </span>of the things we'll be looking into.</p>
<ul>
<li>MVP pattern with gwt-presenter</li>
<li>EventBus</li>
<li>GWT History mechanism</li>
<li>GWT Localisation/I18N mechanism</li>
<li>Dependency injection with GIN and Guice</li>
<li>RPC with gwt-dispatch</li>
<li>Standards mode compliance with GWT 2.0</li>
<li>Layout with UiBinder and MVP</li>
<li>Advanced layout with CSS</li>
<li>Using client bundles to handle css and image resources</li>
<li>Browser auto-complete login form</li>
<li>GWT/GAE testing methodologies</li>
<li>GAE Datastore (BigTable) offering and limitations</li>
<li>JDO</li>
<li>Objectify (framework that wraps the datastore low-level API)</li>
<li>Security. Especially for client/server communication.</li>
<li>Performance and optimizations client and server side</li>
<li>GAE User service for Google accounts</li>
<li>GAE Memcache service</li>
<li>GAE Mail service</li>
<li>GAE Image service</li>
<li>And..more...</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://borglin.net/gwt-project/?feed=rss2&amp;page_id=574</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

