<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;D0YMQHk6fSp7ImA9WxBTGE4.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225</id><updated>2009-12-14T18:59:41.715-05:00</updated><title>Sharing Technologies</title><subtitle type="html" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://domderrien.blogspot.com/" /><link rel="hub" href="http://pubsubhubbub.appspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>37</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/SharingTechnologies" /><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/2.5/" /><logo>http://creativecommons.org/images/public/somerights20.gif</logo><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry gd:etag="W/&quot;D0cBSXw_cCp7ImA9WxBTGE4.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-7433418658313596224</id><published>2009-11-20T18:49:00.010-05:00</published><updated>2009-12-14T18:57:38.248-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-14T18:57:38.248-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Technology" /><category scheme="http://www.blogger.com/atom/ns#" term="Community" /><title>Unit tests, Mock objects, and App Engine</title><content type="html">&lt;p&gt;
For my [still a secret] project which is running on Google App
Engine infrastructure [1], I want to make it as solid as possible from
the beginning by applying most of the best practices of the Agile
methodology [2].&lt;/p&gt;
&lt;div class="updateNotice"&gt;
&lt;u&gt;Update 2009/12/05:&lt;/u&gt;&lt;br/&gt;
With the release of the App Engine Java SDK 1.2.8 (read &lt;a href="http://code.google.com/p/googleappengine/wiki/SdkForJavaReleaseNotes"&gt;release notes&lt;/a&gt;, I had to update my code and this post on two points:&lt;ul&gt;
&lt;li&gt;Without the specification of the JDO inheritance type, the environment assumes it's &lt;code&gt;superclass-table&lt;/code&gt;. This type is not supported by App Engine. Only &lt;code&gt;subclass-table&lt;/code&gt; and &lt;code&gt;complete-table&lt;/code&gt; are supported. In the &lt;code&gt;Entity&lt;/code&gt; class described below, I had to add &lt;code&gt;@Inheritance(strategy = InheritanceStrategy.SUBCLASS_TABLE)&lt;/code&gt;. Read the documentation about &lt;a href="http://code.google.com/appengine/docs/java/datastore/dataclasses.html#Inheritance"&gt;Defining data classes&lt;/a&gt; for more information.&lt;/li&gt;
&lt;li&gt;With the automation of the task execution, the &lt;code&gt;MockAppEngineEnvironment&lt;/code&gt; class listed below had to be updated to serve an expected value when the &lt;code&gt;Queue&lt;/code&gt; runs in the live environment. Read the details on the thread announcing the &lt;a href="http://groups.google.com/group/google-appengine-java/browse_thread/thread/fe334c9e461026fa/8f5872b052144c8d?#8f5872b052144c8d"&gt;1.2.8. SDK prerelease&lt;/a&gt; on Google Groups.&lt;/li&gt;&lt;/ul&gt;
Now, all tests pass again ;)&lt;/div&gt;
&lt;p&gt;
As written on my &lt;a
 href="http://domderrien.blogspot.com/2009/09/progress-update.html"&gt;post
from September 18&lt;/a&gt;, I had to develop many mock classes to keep reaching
the mystical 100% of code coverage (by unit tests) [3]. A good
introduction of mock objects is given by Vincent Massol in his book
“JUnit in Action” [4]. To summarize, mock objects are especially useful
to inject behavior and force the code using them to exercise complex
control flows.&lt;/p&gt;
&lt;p&gt;
Developing applications for Google App Engine is not that complex
because the system has a good documentation and an Eclipse plug-in ease
the first steps.&lt;/p&gt;
&lt;p style="font-size: larger;"&gt;
Use case description&lt;/p&gt;
&lt;p&gt;
Let's consider a simple class organization implementing a common
J2EE pattern:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;span style="border-bottom: dotted 1px #666666;"
  title="Data Transfer Object"&gt;DTO&lt;/span&gt; class for a &lt;code&gt;Consumer&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;The &lt;span style="border-bottom: dotted 1px #666666;"
  title="Data Access Object"&gt;DAO&lt;/span&gt; class getting the &lt;code&gt;Consumer&lt;/code&gt;
from the persistence layer, and sending it back with updates; and&lt;/li&gt;
&lt;li&gt;A Controller class routing &lt;span
  style="border-bottom: dotted 1px #666666;"
  title="Representational State Transfer"&gt;REST&lt;/span&gt; requests. The
Controller is an element of the implemented &lt;span
  style="border-bottom: dotted 1px #666666;"
  title="Model-View-Controller pattern"&gt;MVC pattern&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;center&gt;
&lt;div class="codeSnippetTitle"&gt;
Use case illustration&lt;/div&gt;
&lt;object data="http://domderrien.github.com/diagrams/2009-11-20-illustration.svg" height="580"
 style="border: 2px solid transparent;" title="Use case illustration"
 type="image/svg+xml" width="670"&gt; &lt;img src="http://domderrien.github.com/diagrams/2009-11-20-illustration.png"
  title="Use case illustration" /&gt; &lt;/object&gt;&lt;/center&gt;
&lt;p&gt;
The code for the DTO class is instrumented with JDO annotations
[5]:&lt;/p&gt;
&lt;div class="codeSnippetTitle"&gt;
&lt;code&gt;Consumer&lt;/code&gt; DTO class
definition&lt;/div&gt;
&lt;pre class="prettyprint limitSnippetHeight"&gt;@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true")
@Inheritance(strategy = InheritanceStrategy.SUBCLASS_TABLE)
public class Consumer extends Entity {
    @Persistent
    private String address;
 
    @Persistent
    private String displayName;
 
    @Persistent
    private String email;
 
    @Persistent
    private String facebookId;
 
    @Persistent
    private String jabberId;
 
    @Persistent
    private Long locationKey;
 
    @Persistent
    private String twitterId;
 
    /** Default constructor */
    public Consumer() {
        super();
    }
 
    /**
     * Creates a consumer
     * @param in HTTP request parameters
     */
    public Consumer(JsonObject parameters) {
        this();
        fromJson(parameters);
    }
 
    public String getAddress() {
        return address;
    }
    
    public void setAddress(String address) {
        this.address = address;
    }
    
    //...
}&lt;/pre&gt;
&lt;p&gt;
My approach for the DAO class is modular:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When the calling code is doing just one call, like the &lt;code&gt;ConsumerOperations.delete(String)&lt;/code&gt;
method deleting the identified &lt;code&gt;Consumer&lt;/code&gt; instance, the call
can be done without the persistence layer knowledge.&lt;/li&gt;
&lt;li&gt;When many calls to the persistence layer are required, the DAO
API offers the caller to pass a &lt;code&gt;PersistenceManager&lt;/code&gt;
instance that can be re-used from call to call. With the combination of
the &lt;code&gt;detachable="true"&lt;/code&gt; parameter specified in the JDO
annotation for the &lt;code&gt;Consumer&lt;/code&gt; class, it saves many cycles.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="codeSnippetTitle"&gt;
Excerpt from the &lt;code&gt;ConsumerOperations&lt;/code&gt;
DAO class definition&lt;/div&gt;
&lt;pre class="prettyprint"&gt;/**
 * Persist the given (probably updated) resource
 * @param consumer Resource to update
 * @return Updated resource
 * @see ConsumerOperations#updateConsumer(PersistenceManager, Consumer)
 */
public Consumer updateConsumer(Consumer consumer) {
    PersistenceManager pm = getPersistenceManager();
    try {
        // Persist updated consumer
        return updateConsumer(pm, consumer);
    }
    finally {
        pm.close();
    }
}
 
/**
 * Persist the given (probably updated) resource while leaving the given persistence manager open for future updates
 * @param pm Persistence manager instance to use - let opened at the end to allow possible object updates later
 * @param consumer Resource to update
 * @return Updated resource
 */
public Consumer updateConsumer(PersistenceManager pm, Consumer consumer) {
    return pm.makePersistent(consumer);
}&lt;/pre&gt;
&lt;p&gt;
The following piece of the abstract class &lt;code&gt;BaseOperations&lt;/code&gt;
shows the accessor made availabe to any controller code to get one
handle of a valid &lt;code&gt;PersistenceManager&lt;/code&gt; instance.&lt;/p&gt;
&lt;div class="codeSnippetTitle"&gt;
Excerpt from the abstract &lt;code&gt;BaseOperations&lt;/code&gt;
DAO class definition&lt;/div&gt;
&lt;pre class="prettyprint limitSnippetHeight"&gt;/**
 * Accessor isolated to facilitate tests by IOP
 * @return Persistence manager instance
 */
public PersistenceManager getPersistenceManager() {
    PersistenceManager pm = getPersistenceManagerFactory().getPersistenceManager();
    pm.setDetachAllOnCommit(true);
    pm.setCopyOnAttach(false);
    return pm;
}&lt;/pre&gt;
&lt;p&gt;
To finish the use case setup, here is a part of the controller
code which deals with incoming HTTP requests and serves or operates
accordingly. This specific piece of code replies to a GET request like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Invocation: &lt;code&gt;http://&amp;lt;host:port&amp;gt;/API/Consumer/43544"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Response:
&lt;ul&gt;
&lt;li&gt;&lt;pre&gt;{key:43544, displayName:"John", address:"75, Queen, Montréal, Qc, Canada", 
locationKey:3245, location: {id:3245, postalCode:"H3C2N6", countryCode:"CA",
latitude:43.3, longitude:-73.4}, ...}&lt;/pre&gt;
&lt;/li&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;div class="codeSnippetTitle"&gt;
Excerpt from the &lt;code&gt;ConsumerRestlet&lt;/code&gt; Controller class definition&lt;/div&gt;
&lt;pre class="prettyprint"&gt;@Override
protected JsonObject getResource(JsonObject parameters, String resourceId, User loggedUser) throws DataSourceException {
    PersistenceManager pm = getBaseOperations().getPersistenceManager();
    try {
        // Get the consumer instance
        Consumer consumer = getConsumerOperations().getConsumer(pm, Long.valueOf(resourceId));
        JsonObject output = consumer.toJson();
        // Get the related information
        Long locationKey = consumer.getLocationKey();
        if (locationKey != null) {
            Location location = getLocationOperations().getLocation(pm, locationKey);
            output.put(Consumer.LOCATION, location.toJson());
        }
        // Return the complete set of information
        return output;
    }
    finally {
        pm.close();
    }
}&lt;/pre&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p style="font-size: larger;"&gt;
Simple mock&lt;/p&gt;
&lt;p&gt;
Now, it's time to test! To start slowly, let's deal with the Restlet &lt;code&gt;getResource()&lt;/code&gt; method to verify:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Just one and only one instance of &lt;code&gt;PersistenceManager&lt;/code&gt; is loaded by the function;&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;PersistenceManager&lt;/code&gt; instance is cleanly closed at the end of the process;&lt;/li&gt;
&lt;li&gt;There's a call issued to get the identified &lt;code&gt;Consumer&lt;/code&gt; instance;&lt;/li&gt;
&lt;li&gt;There's possibly a call issued to get the identified &lt;code&gt;Location&lt;/code&gt; instance;&lt;/li&gt;
&lt;li&gt;The output value has the expected information.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
In the corresponding unit test series, we don't want to interfere with the App Engine infrastructure (the following chapter will address that aspect). So we'll rely on a mock for the &lt;code&gt;PersistenceManager&lt;/code&gt; class that will be injected into the &lt;code&gt;ConsumerRestlet&lt;/code&gt; code. The full source of this class is available on my open source project &lt;a href="http://github.com/DomDerrien/two-tiers-utils"&gt;two-tiers-utils&lt;/a&gt;: &lt;code&gt;&lt;a href="http://github.com/DomDerrien/two-tiers-utils/blob/master/src/Java/javax/jdo/MockPersistenceManager.java"
&gt;javax.jdo.MockPersistenceManager&lt;/a&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;div class="codeSnippetTitle"&gt;
Custom part of the mock for the &lt;code&gt;PersistenceManager&lt;/code&gt; class&lt;/div&gt;
&lt;pre class="prettyprint"&gt;public class MockPersistenceManager implements PersistenceManager {
    private boolean closed = false; // To keep track of the "closed" state
    public void close() {
        closed = true;
    }
    public boolean isClosed() {
        return closed;
    }

    // ...
}&lt;/pre&gt;
&lt;p&gt;
Here are the unit tests verifying the different flow paths:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When an exception is thrown, because the back-end does not serve the data for example;&lt;/li&gt;
&lt;li&gt;When the &lt;code&gt;Consumer&lt;/code&gt; instance returns without location coordinates;&lt;/li&gt;
&lt;li&gt;When the &lt;code&gt;Consumer&lt;/code&gt; instance is fully documented.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="codeSnippetTitle"&gt;
Three tests validating the behavior of the &lt;code&gt;ConsumerRestlet.getResource()&lt;/code&gt; method&lt;/div&gt;
&lt;pre class="prettyprint limitSnippetHeight"&gt;@Test(expected=IllegalArgumentException.class)
public void testUnexpectedError() {
    // Test prepration
    final PersistenceManager pm = new MockPersistenceManager();
    final BaseOperations baseOps = new BaseOperations() {
        boolean askedOnce = false;
        @Override
        PersistenceManager getPersistenceManager() {
            if (askedOnce) {
                fail("Expects only one call");
            }
            askedOnce = true;
            return pm;
        }
    };
    final Long consumerId = 12345L;
    final ConsumerOperations consumerOps = new ConsumerOperations() {
        @Override
        Consumer getConsumer(PersistenceManager pm, Long id) {
            assertEquals(consumerId, id);
            throw new IllegalArgumentException("Done in purpose!");
        }
    };
    ConsumerRestlet restlet = new ConsumerRestlet() {
        @Override BaseOperation getBaseOperations() { return baseOps; }
        @Override ConsumerOperation getConsumerOperations() { return consumerOps; }
    }
    
    // Test itself
    JsonObject response = restlet.getResource(null, consumerId.toString, null);
}&lt;/pre&gt;
&lt;pre class="prettyprint limitSnippetHeight"&gt;@Test
public void testGettingOneConsumer() {
    // Test prepration
    final PersistenceManager pm = new MockPersistenceManager();
    final BaseOperations baseOps = new BaseOperations() {
        boolean askedOnce = false;
        @Override
        PersistenceManager getPersistenceManager() {
            if (askedOnce) {
                fail("Expects only one call");
            }
            askedOnce = true;
            return pm;
        }
    };
    final Long consumerId = 12345L;
    final ConsumerOperations consumerOps = new ConsumerOperations() {
        @Override
        Consumer getConsumer(PersistenceManager pm, Long id) {
            assertEquals(consumerId, id);
            Consumer consumer = new Consumer();
            consumer.setId(consumerId);
            return consumer;
        }
    };
    final Long locationId = 67890L;
    final LocationOperations locationOps = new LocationOperations() {
        @Override
        Location getLocation(PersistenceManager pm, Long id) {
            fail("Call not expected here!");
            return null;
        }
    };
    ConsumerRestlet restlet = new ConsumerRestlet() {
        @Override BaseOperation getBaseOperations() { return baseOps; }
        @Override ConsumerOperation getConsumerOperations() { return consumerOps; }
        @Override LocationOperation getLocationOperations() { return locationOps; }
    }
    
    // Test itself
    JsonObject response = restlet.getResource(null, consumerId.toString, null);
    
    // Post-test verifications
    assertTrue(pm.isClosed());
    assertNotSame(0, response.size());
    assertTrue(response.containsKey(Consumer.ID);
    assertEquals(consumerId, response.getLong(Consumer.ID));
}&lt;/pre&gt;
&lt;pre class="prettyprint limitSnippetHeight"&gt;@Test
public void testGettingConsumerWithLocation() {
    // Test prepration
    final PersistenceManager pm = new MockPersistenceManager();
    final BaseOperations baseOps = new BaseOperations() {
        boolean askedOnce = false;
        @Override
        PersistenceManager getPersistenceManager() {
            if (askedOnce) {
                fail("Expects only one call");
            }
            askedOnce = true;
            return pm;
        }
    };
    final Long consumerId = 12345L;
    final Long locationId = 67890L;
    final ConsumerOperations consumerOps = new ConsumerOperations() {
        @Override
        Consumer getConsumer(PersistenceManager pm, Long id) {
            assertEquals(consumerId, id);
            Consumer consumer = new Consumer();
            consumer.setId(consumerId);
            consumer.setLocationId(locationId);
            return consumer;
        }
    };
    final LocationOperations locationOps = new LocationOperations() {
        @Override
        Location getLocation(PersistenceManager pm, Long id) {
            assertEquals(locationId, id);
            Location location = new Location();
            location.setId(locationId);
            return location;
        }
    };
    ConsumerRestlet restlet = new ConsumerRestlet() {
        @Override BaseOperation getBaseOperations() { return baseOps; }
        @Override ConsumerOperation getConsumerOperations() { return consumerOps; }
        @Override LocationOperation getLocationOperations() { return locationOps; }
    }
    
    // Test itself
    JsonObject response = restlet.getResource(null, consumerId.toString, null);
    
    // Post-test verifications
    assertTrue(pm.isClosed());
    assertNotSame(0, response.size());
    assertTrue(response.containsKey(Consumer.ID);
    assertEquals(consumerId, response.getLong(Consumer.ID));
    assertTrue(response.containsKey(Consumer.LOCATION_ID);
    assertEquals(locationId, response.getLong(Consumer.LOCATION_ID));
    assertTrue(response.containsKey(Consumer.LOCATION);
    assertEquals(consumerId, response.getJsonObject(Consumer.LOCATION).getLong(Location.ID));
}
&lt;/pre&gt;
&lt;p&gt;
Note that I would have been able to override just the &lt;code&gt;PersistenceManager&lt;/code&gt; class to have the &lt;code&gt;Object getObjectById(Object arg0)&lt;/code&gt; method returning the expected exception, &lt;code&gt;Consumer&lt;/code&gt;, and &lt;code&gt;Location&lt;/code&gt; instances. But I would have pass over the strict limit of a unit test by then testing also the behavior of the &lt;code&gt;ConsumerOperations.getConsumer()&lt;/code&gt; and &lt;code&gt;LocationOperations.getLocation()&lt;/code&gt; methods.&lt;/p&gt;
&lt;p style="font-size: larger;"&gt;
App Engine environment mock&lt;/p&gt;
&lt;p&gt;
Now, testing the &lt;code&gt;ConsumerOperations&lt;/code&gt; class offers a better challenge.&lt;/p&gt;
&lt;p&gt;
As suggested above, I could override many pieces of the &lt;code&gt;PersistenceManager&lt;/code&gt; class to be sure to control the flow. But to do a nice simulation, I almost need to have the complete specification of the Google App Engine infrastructure to be sure I mock it correctly. This is especially crucial when processing &lt;code&gt;Query&lt;/code&gt; because Google data store has many limitations [6] that others traditional database, like MySQL, don't have...&lt;/p&gt;
&lt;p&gt;
Because this documentation is partially available and because Google continues to update its infrastructure, I looked for a way to use the standalone environment made available with the App Engine SDK [1]. This has not been easy because I wanted to have the test running independently from the development server itself. I found first some documentation on Google Code website: &lt;a href="http://code.google.com/appengine/docs/java/howto/unittesting.html"
&gt;Unit Testing With Local Service Implementations&lt;/a&gt;, but it was very low level and did not fit with my JDO instrumentation of the DTO classes. Hopefully, I found this article &lt;a href="http://blog.appenginefan.com/2009/05/jdo-and-unit-tests.html"
&gt;JDO and unit tests&lt;/a&gt; from &lt;a href="http://blog.appenginefan.com/"&gt;App Engine Fan&lt;/a&gt;, a great community contributor I mentioned many times in previous posts!&lt;/p&gt;
&lt;p&gt;
By cooking information gathered on Google Code website and on App Engine Post, I've produced a &lt;code&gt;&lt;a href="http://github.com/DomDerrien/two-tiers-utils/blob/master/src/Java/com/google/apphosting/api/MockAppEngineEnvironment.java"
&gt;com.google.apphosting.api.MockAppEngineEnvironment&lt;/a&gt;&lt;/code&gt; I can use for my JUnit4 tests.&lt;/p&gt;
&lt;div class="codeSnippetTitle"&gt;
Three tests validating the behavior of the &lt;code&gt;ConsumerRestlet.getResource()&lt;/code&gt; method&lt;/div&gt;
&lt;pre class="prettyprint limitSnippetHeight"&gt;package com.google.apphosting.api;
 
// import ...
 
/**
 * Mock for the App Engine Java environment used by the JDO wrapper.
 *
 * These class has been build with information gathered on:
 * - App Engine documentation: http://code.google.com/appengine/docs/java/howto/unittesting.html
 * - App Engine Fan blog: http://blog.appenginefan.com/2009/05/jdo-and-unit-tests.html
 *
 * @author Dom Derrien
 */
public class MockAppEngineEnvironment {
 
    private class ApiProxyEnvironment implements ApiProxy.Environment {
        public String getAppId() {
          return "test";
        }
 
        public String getVersionId() {
          return "1.0";
        }
 
        public String getEmail() {
          throw new UnsupportedOperationException();
        }
 
        public boolean isLoggedIn() {
          throw new UnsupportedOperationException();
        }
 
        public boolean isAdmin() {
          throw new UnsupportedOperationException();
        }
 
        public String getAuthDomain() {
          throw new UnsupportedOperationException();
        }
 
        public String getRequestNamespace() {
          return "";
        }
 
        public Map&lt;String, Object&gt; getAttributes() {
            Map&lt;String, Object&gt; out = new HashMap&lt;String, Object&gt;();

            // Only necessary for tasks that are added when there is no "live" request
            // See: http://groups.google.com/group/google-appengine-java/msg/8f5872b05214...
            out.put("com.google.appengine.server_url_key", "http://localhost:8080");

            return out;
        }
    };
 
    private final ApiProxy.Environment env;
    private PersistenceManagerFactory pmf;
 
    public MockAppEngineEnvironment() {
        env = new ApiProxyEnvironment();
    }
 
    /**
     * Setup the mock environment
     */
    public void setUp() throws Exception {
        // Setup the App Engine services
        ApiProxy.setEnvironmentForCurrentThread(env);
        ApiProxyLocalImpl proxy = new ApiProxyLocalImpl(new File(".")) {};
 
        // Setup the App Engine data store
        proxy.setProperty(LocalDatastoreService.NO_STORAGE_PROPERTY, Boolean.TRUE.toString());
        ApiProxy.setDelegate(proxy);
    }
 
    /**
     * Clean up the mock environment
     */
    public void tearDown() throws Exception {
        // Verify that there's no pending transaction (ie pm.close() has been called)
        Transaction transaction = DatastoreServiceFactory.getDatastoreService().getCurrentTransaction(null);
        boolean transactionPending = transaction != null;
        if (transactionPending) {
            transaction.rollback();
        }
 
        // Clean up the App Engine data store
        ApiProxyLocalImpl proxy = (ApiProxyLocalImpl) ApiProxy.getDelegate();
        if (proxy != null) {
            LocalDatastoreService datastoreService = (LocalDatastoreService) proxy.getService("datastore_v3");
            datastoreService.clearProfiles();
        }
 
        // Clean up the App Engine services
        ApiProxy.setDelegate(null);
        ApiProxy.clearEnvironmentForCurrentThread();
 
        // Report the issue with the transaction still open
        if (transactionPending) {
            throw new IllegalStateException("Found a transaction nor commited neither rolled-back." +
                    "Probably related to a missing PersistenceManager.close() call.");
        }
    }
 
    /**
     * Creates a PersistenceManagerFactory on the fly, with the exact same information
     * stored in the &lt;war-dir&gt;/WEB-INF/META-INF/jdoconfig.xml file.
     */
    public PersistenceManagerFactory getPersistenceManagerFactory() {
        if (pmf == null) {
            Properties newProperties = new Properties();
            newProperties.put("javax.jdo.PersistenceManagerFactoryClass",
                    "org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory");
            newProperties.put("javax.jdo.option.ConnectionURL", "appengine");
            newProperties.put("javax.jdo.option.NontransactionalRead", "true");
            newProperties.put("javax.jdo.option.NontransactionalWrite", "true");
            newProperties.put("javax.jdo.option.RetainValues", "true");
            newProperties.put("datanucleus.appengine.autoCreateDatastoreTxns", "true");
            newProperties.put("datanucleus.appengine.autoCreateDatastoreTxns", "true");
            pmf = JDOHelper.getPersistenceManagerFactory(newProperties);
        }
        return pmf;
    }
 
    /**
     * Gets an instance of the PersistenceManager class
     */
    public PersistenceManager getPersistenceManager() {
        return getPersistenceManagerFactory().getPersistenceManager();
    }
}
&lt;/pre&gt;
&lt;p&gt;
With such a class, the unit test part is easy and I can build complex test cases without worrying about the pertinence of my mock classes! That's really great. &lt;div class="codeSnippetTitle"&gt;
Excerpt of the &lt;code&gt;TestConsumerOperations&lt;/code&gt; class&lt;/div&gt;
&lt;pre class="prettyprint limitSnippetHeight"&gt;public class TestConsumerOperations {
 
    private MockAppEngineEnvironment mockAppEngineEnvironment;
 
    @Before
    public void setUp() throws Exception {
        mockAppEngineEnvironment = new MockAppEngineEnvironment();
        mockAppEngineEnvironment.setUp();
    }
 
    @After
    public void tearDown() throws Exception {
        mockAppEngineEnvironment.tearDown();
    }
 
    @Test
    public void testCreateVI() throws DataSourceException, UnsupportedEncodingException {
        final String email = "unit@test.net";
        final String name = "Mr Unit Test";
        Consumer newConsumer = new Consumer();
        newConsumer.setDisplayName(name);
        newConsumer.setEmail(email);
        assertNull(newConsumer.getId());
 
        // Verify there's no instance
        Query query = new Query(Consumer.class.getSimpleName());
        assertEquals(0, DatastoreServiceFactory.getDatastoreService().prepare(query).countEntities());
 
        // Create the user once
        ConsumerOperations ops = new ConsumerOperations();
        Consumer createdConsumer = ops.createConsumer(newConsumer);
 
        // Verify there's one instance
        query = new Query(Consumer.class.getSimpleName());
        assertEquals(1, DatastoreServiceFactory.getDatastoreService().prepare(query).countEntities());
 
        assertNotNull(createdConsumer.getId());
        assertEquals(email, createdConsumer.getEmail());
        assertEquals(name, createdConsumer.getName());
    }
    
    // ...
}&lt;/pre&gt;
&lt;p style="font-size: larger;"&gt;
Conclusion&lt;/p&gt;
&lt;p&gt;
As a big fan of &lt;span style="border-bottom: dotted 1px #666666;" title="Test Driven Development"&gt;TDD&lt;/span&gt;, I'm now all set to cover the code of my [still a secret] project efficiently. It does not mean everything is correct, more that everything I thought about is correctly covered. At the time of this writing, just for the server-side logic, the code I produced covers more than 10,000 lines and the unit tests bring  an additional set of 23,400 lines.&lt;/p&gt;
&lt;p&gt;
When it's time to refactor a bit or to add new features (plenty of them are aligned in my task list ;), I feel comfortable because I know I can detect most of regressions (if not all) after 3 minutes of running the test suite.&lt;/p&gt;
&lt;p&gt;
If you want to follow this example, feel free to get the various mock classes I have added to my &lt;a href="http://github.com/DomDerrien/two-tiers-utils"&gt;two-tiers-utils&lt;/a&gt; open-source project. In addition to mock classes for the App Engine environment,  you'll find:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Basic mock classes for the servlet (see &lt;code&gt;&lt;a href="http://github.com/DomDerrien/two-tiers-utils/tree/master/src/Java/javax/servlet/"
&gt;javax.servlet&lt;/a&gt;&lt;/code&gt;) and &lt;code&gt;&lt;a href="http://github.com/DomDerrien/two-tiers-utils/tree/master/src/Java/javamocks/io/"
&gt;javamocks.io&lt;/a&gt;&lt;/code&gt; packages -- I had to adopt the root &lt;code&gt;javamocks&lt;/code&gt; because the JVM class loader does not accept the creation
on the fly of classes in the &lt;code&gt;java&lt;/code&gt; root).&lt;/li&gt;
&lt;li&gt;A mock class for &lt;code&gt;&lt;a href="http://github.com/DomDerrien/two-tiers-utils/tree/master/src/Java/twitter4j"
&gt;twitter4j.TwitterUser&lt;/a&gt;&lt;/code&gt; -- I needed a class with public constructor and a easy way to create a default account.&lt;/li&gt;
&lt;li&gt;A series of mock class for &lt;a href="http://github.com/DomDerrien/two-tiers-utils/tree/b8ef96bd09a684651cd4164c1fe6abf6c64ef419/src/Java/com/dyuproject"
&gt;David Yu's Project&lt;/a&gt; which I use to allow users with OpenID credentials
to log in. Read the &lt;a href="http://code.google.com/p/dyuproject/issues/detail?id=16"&gt;discussion&lt;/a&gt;
I had with David on ways to test his code, in fact the code he produced and I customized for my own needs
and for other security reasons.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
For other details on my library, read my post &lt;a href="http://domderrien.blogspot.com/2009/10/internationalization-and-my-two-tiers.html"
&gt;Internationalization and my two-tiers-utils library&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;
I hope this helps.&lt;/p&gt;
&lt;p&gt;
A+, Dom&lt;br/&gt;--&lt;br/&gt;References:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Google App Engine: the &lt;a href="http://appengine.google.com/"&gt;homepage&lt;/a&gt;
and the &lt;a href="http://code.google.com/appengine/"&gt;SDK page&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;See my post on &lt;a
  href="http://domderrien.blogspot.com/2009/04/agile-scrum-is-hype-but-xp-is-more.html"&gt;Agile:
SCRUM is Hype, but XP is More Important...&lt;/a&gt; where I mentionned the
following techniques: Continuous Integration (CI), Unit testing and
code coverage (CQC), and Continuous refactoring.&lt;/li&gt;
&lt;li&gt;I know that keeping 100% as the target for code coverage
numbers is a bit extreme. I read this article &lt;a
  href="http://www.ibm.com/developerworks/java/library/j-cq01316/index.html?ca=drs"&gt;Don't
be fooled by the coverage report&lt;/a&gt; soon after I started using &lt;a
  href="http://cobertura.sourceforge.net/index.html"&gt;Cobertura&lt;/a&gt;. In
addition to reducing the exposition to bugs, the 100% coverage gives a
very high chance to detect regressions before pushing the updates to
the source control system!&lt;/li&gt;
&lt;li&gt;Vincent Massol; &lt;i&gt;JUnit in Action&lt;/i&gt;; Editions Manning; &lt;a
  href="http://www.manning.com/massol/"&gt;www.manning.com/massol&lt;/a&gt; and
Petar Tahchiev, Felipe Leme, Vincent Massol, and Gary Gregory; &lt;i&gt;JUnit
in Action, Second Edition&lt;/i&gt;; Editions Massol; &lt;a
  href="http://www.manning.com/tahchiev/"&gt;www.manning.com/tahchiev&lt;/a&gt;.
I was used to asking any new developer joigning my team to read at
least this &lt;a
  href="http://www.manning-source.com/books/massol/massol_ch07.pdf"&gt;chapter
7: Testing in isolation with mock objects&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;JDO stands for &lt;a href="http://java.sun.com/jdo/index.jsp"&gt;Java
Data Objects&lt;/a&gt; and is an attempt abstract the data storage manipulation.
The code is instrumented with Java annotations like &lt;code&gt;@Persistent&lt;/code&gt;,
it is instrumented at compile time, and dynamically connect to the data
source thanks few properties files. Look at the &lt;a
  href="http://code.google.com/appengine/docs/java/gettingstarted/usingdatastore.html"&gt;App
Engine - Using the Datastore with JDO&lt;/a&gt; documentation for more
information.&lt;/li&gt;
&lt;li&gt;For general limitations, check this page &lt;a href="http://groups.google.com/group/google-appengine-java/web/will-it-play-in-app-engine?pli=1"
 &gt;Will it play in App Engine&lt;/a&gt;. For JDO related limitations, check the bottom of the
page &lt;a href="http://code.google.com/appengine/docs/java/datastore/usingjdo.html"&gt;Usin JDO with App Engine&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-7433418658313596224?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=3gEJWggYGdQ:UdLMqU0CvC8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=3gEJWggYGdQ:UdLMqU0CvC8:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=3gEJWggYGdQ:UdLMqU0CvC8:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=3gEJWggYGdQ:UdLMqU0CvC8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=3gEJWggYGdQ:UdLMqU0CvC8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/3gEJWggYGdQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/7433418658313596224/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/11/unit-tests-mock-objects-and-app-engine.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/7433418658313596224?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/7433418658313596224?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/3gEJWggYGdQ/unit-tests-mock-objects-and-app-engine.html" title="Unit tests, Mock objects, and App Engine" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/11/unit-tests-mock-objects-and-app-engine.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cNQn0zeyp7ImA9WxBTGE4.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-623874656538219093</id><published>2009-10-16T19:58:00.000-04:00</published><updated>2009-12-14T18:58:13.383-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-14T18:58:13.383-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Technology" /><title>Canadian Wireless Management Forum - my review</title><content type="html">Last week, I attended the &lt;a href="http://www.forumgestionsansfils.ca/index_en.php"&gt;Canadian Wireless Management Forum&lt;/a&gt; in Montreal. Honestly, I've been a bit disappointed because none of the presenters were as great as &lt;a href="http://domderrien.blogspot.com/2008/10/canadian-wireless-management-forum.html"&gt;the ones I met last year&lt;/a&gt;. Over the day, I've still been able to gather bits of information I want to share here ;) Thanks to my company &lt;a href="http://www.compuware.com/"&gt;Compuware&lt;/a&gt; to have allowed sparing one day there.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;iPhone and other smart phones deployed in enterprises&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
The main focus of the conference is around managing wireless (read mobile phone) communications in enterprises. Some presenters talked about how to control expenses, from sharing guidelines up to using monitoring tools suggesting policies from the statistical analysis of the monthly bills. Testimonies showed that applying a strict control on the mobile phone usage and on the contracts allowed cutting costs from 10 to 30%!&lt;br /&gt;
&lt;br /&gt;
At one point, &lt;a href="http://www.forumgestionsansfils.ca/speaker.php?cid=3"&gt;Nicolas Arsenault&lt;/a&gt; made a strange point. Here is what I remind from his talk:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="margin: 0pt 30px;"&gt;&lt;div style="float: left; margin: 0pt 10px 10px 0pt; text-align: center;"&gt;&lt;img src="http://farm1.static.flickr.com/80/243093440_9e6c67c6cc_t.jpg" title="BlackBerry by RIM" /&gt;&lt;br /&gt;
&lt;span style="font-size: smaller;"&gt;Credits: &lt;a href="http://www.flickr.com/photos/smoothouse/"&gt;smoothouse&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="float: right; margin: 0pt 10px 10px 0pt; text-align: center;"&gt;&lt;img src="http://farm2.static.flickr.com/1144/1361954749_d35a3acd54_t.jpg" title="iPhone by Apple" /&gt;&lt;br /&gt;
&lt;span style="font-size: smaller;"&gt;Credits:&lt;a href="http://www.flickr.com/photos/joshb/"&gt;Josh Bancroft&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;Deploying an iPhone application for your employees, when compared to a BlackBerry application, has a much lower cost because the employee already owns the device or he's more likely to buy it. With the employee paying for the phone, probably paying to get new phones regularly (like to move from a iPhone 3G to the latest 3GS), employers can just assume the data plans and can spend more resources on the application development, that at one point can be offered to the company customers. Another benefit is related to the technical support: phone owners stop annoying enterprises' help desk for their phone, they contact the manufacturers or the software vendors directly (they are on their own)...&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
If this approach have evident economical benefits, I disagree with it because:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;In general, letting employees owning their work mobile phones cause problems when they leave the company. Most of employees have a non concurrence clause in their contract, usually valid 6 months after the employment contract termination. During that period, they cannot compete with their previous employer. Imagine a salesperson, an account manager, or a consultant who owns his phone number, who is referenced in the phone directories all his previous contacts. When these contacts want to deal with the company, who do you think they'll call: the mobile phone or the company front line? Now that these employees are out, they don't have to submit their phone bills anymore (as they did with their expenses reports). No one can detect the issues anymore… And this is without mentioning that the employee replacement or his colleagues have no way to get the mobile phone contact list to continue the business as usual!&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;In the company I worked, none let me use my own computer on their network! For the IT departments, this practice would raise too much security concerns. I even know cases that just installing a VPN software on your own machine install silently a bunch of monitoring tools that can mess up your systems (thanks to VirtualBox, it easy to limit these nasty side effects ;). In the old days, when phones were just stupid, just able to handle voice call and exchange text messages (SMS), the risk of phone infection by viruses were pretty negligible. The widely used phone operating system is Symbian, used on Nokia and Sony Ericsson phones, and J2ME is a common application framework, even on phones running Windows Mobile. If the identified viruses are not a lot, and if they are not some damageable (send on your behalf SMS to expensive services, for example), the newest smart platforms provide much more threats because the corresponding phones can host tons of applications. In such an environment, how can a company force software upgrades on systems it does not own? How can it force an employee to upgrade to a new hardware because the current one is compromised?&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;My last point is more ethical: how far companies should go with putting the burden on their employees? An iPhone costs around 800$. It's often offered around 200$ with a 3-year contract, which costs basically around 60$/month with a simple data plan. If the telecom operators (telco) subsidize so aggressively such a phone, they surely expect higher average revenue per user (ARPU). In addition to be linked to the telco for a long period of time (compare 3 years with the 3 to 6 months between technological evolution: 6 to 12 times longer!), employees have to support costs the company should assume. Usually, companies try to provide a comfortable work environment to get most of their employees, and that's fair to me: if the company gives more than the salary, employees are more likely to deliver better work. With the incitation of employees assuming the cost of the new mobile phones, I see a regression: companies give less while expecting more (reachable—possibly traceable—outside the office hours, for example). IMO, it's yet another example of a technological progress that might worsen fragile people condition...&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Mobile payment and Near-field-communication (NFC)&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Shortly on this topic, I want to mention presentation made by &lt;a href="http://www.forumgestionsansfils.ca/speaker.php?cid=2"&gt;Daniel Martin&lt;/a&gt; for Atlas Telecom Mobile, &lt;a href="http://www.forumgestionsansfils.ca/speaker.php?cid=5"&gt;David Robinson&lt;/a&gt; for Rogers Wireless, and &lt;a href="http://www.forumgestionsansfils.ca/speaker.php?cid=31"&gt;Prakash Hariramani&lt;/a&gt; for Visa. They talked about an experiment conducted downtown Toronto where they were able, thanks to Motorola phones equipped with a NFC emitter and a good number of retailers there, to allow mobile payment over the mobile phone network. Visa's solution, called PayWave™ (MasterCard's one is called PayPass™), was inserted into the Motorola phone extension and allow consumers to pay for their purchase quite easily.&lt;br /&gt;
&lt;br /&gt;
During the discussion, Mr. Robinson talked about Rogers Wireless approach being strictly based on standards. He mentioned the recent u-turn of telco who continued to invest in closed and proprietary solutions (like CDMA) and now move to standardized ones (like HSPA which is an upgrade of GSM, on the road to LTE—see example of &lt;a href="http://www.broadbandreports.com/shownews/Bell-Canada-Telus-To-Deploy-HSPA-98332"&gt;Bell and Telus&lt;/a&gt; in Canada). Rogers Wireless' approach is then to work with the rest of the major industry players (Orange, Vodafone, etc.) to define a solution for anyone anywhere. Mr. Robinson talked about the possibility to define an extended SIM card (for Subscriber Identity Module; the card contains a micro-SIMCARD processor which manage very securely information). This new SIM card will have NFC capabilities and will be able to interact with contactless payment terminals. It's possible that these SIM cards will contain additional information like driver license identifier that police officers will be able to read, insurance number for the government agencies, etc. The phone will provide the interface to enable the data access, and smart phones with touch screens open the door to various and robust verification techniques.&lt;br /&gt;
&lt;br /&gt;
Because more and more people are more attached to their phone than to their wallet, this approach will possibly be more convenient, more secure, and smaller (no more cash, business cards, credits cards, etc. ;) Who said that implanting the SIM under anyone's skin, a SIM that can unlock your phones, cars, houses, computers, etc, is just science fiction?&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Telco business model in danger!&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: grey; border: 1px solid black; float: right; margin: 10px 0pt 10px 10px; padding: 10px; width: 20%;"&gt;iBwave offers solutions improving in-building wireless coverage. Knowing the fact that 60%-80% of mobile usages are indoor, that telco have difficulties to boost the power or to multiply outdoor antennas near high density areas, these places stay mostly uncovered. Mr. Bouchard illustrated his point with the simulation of the poor performance of the traditional networks on the McGill campus—really amazing! In conclusion, iBwave sits in a very nice and promising niche ;)&lt;br /&gt;
&lt;/div&gt;The last point of interest to me came from &lt;a href="http://www.forumgestionsansfils.ca/speaker.php?cid=25"&gt;Mario Bouchard&lt;/a&gt;, from iBwave.&lt;br /&gt;
&lt;br /&gt;
To introduce his company activities, Mr. Bouchard shows two diagrams which made me think for a while. Let me try to reproduce them.&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;a href="http://1.bp.blogspot.com/_VZZAFHl2_Og/StkC-VWE6GI/AAAAAAAACxc/tRCdJJPqVxk/s1600/chain-15yearsago.png" rel="lightbox"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_VZZAFHl2_Og/StkC-VWE6GI/AAAAAAAACxc/tRCdJJPqVxk/s400/chain-15yearsago.png" /&gt;&lt;/a&gt;&lt;/center&gt;&lt;br /&gt;
Mr. Bouchard states that 15 years ago, the innovation came from the network manufacturers: they invented the technology, others created cell phones to connect to the new network, some operators offered (very expensive) plans, and consumers (locked with long term contracts) tried to communicate.&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;a href="http://4.bp.blogspot.com/_VZZAFHl2_Og/StkDUiE6HGI/AAAAAAAACxk/4SfK_foyZi4/s1600/chain-today.png" rel="lightbox"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_VZZAFHl2_Og/StkDUiE6HGI/AAAAAAAACxk/4SfK_foyZi4/s400/chain-today.png" /&gt;&lt;/a&gt;&lt;/center&gt;&lt;br /&gt;
&lt;div style="float: right; margin: 0pt 0pt 10px 10px; text-align: center;"&gt;&lt;img src="http://farm4.static.flickr.com/3406/3565116428_90840c4240_t.jpg" title="First generation cellphone" /&gt;&lt;br /&gt;
&lt;span style="font-size: smaller;"&gt;Credits: &lt;a href="http://www.flickr.com/photos/digitalalan/"&gt;DigitalAlan&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/div&gt;Today, the order has been scrambled:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Thanks to the rapid technology evolution, designers of mobile devices can embed many types of sensors into communicant machines, and with the increasing miniaturization, such machines are pervasiveness!&lt;/li&gt;
&lt;li&gt;Because of the reduced delay between big technology evolutions (think about the iPhone which is just 2 years old), consumers choose their devices carefully, and bargain more to get the best quality-price ratio.&lt;/li&gt;
&lt;li&gt;Network manufacturers now to their best to provide networks than can deliver at the rhythm the devices can consume. When the European community created the Groupe Spécial Mobile (initial meaning of the GSM acronym, known now for Global System for Mobile communications) in 1982, we had to wait up to 1991 to experiment the first GSM network. GSM is also known the 2G technology. The EDGE (Enhanced Data rates for GSM Evolution, or 2.5G) has been introduced in 1999, the first 3G technology (HSPA/UMTS, and EV-DO/CDMA) has been delivered late 2001, and the coming 4G ones (LTE for Long Term Evolution or WiMax) are on the bench.&lt;/li&gt;
&lt;li&gt;At the end of the line, now there are the telcos:&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Investments are phenomenal&lt;/li&gt;
&lt;li&gt;The competition is rude (not rude enough in Canada, IMO)&lt;/li&gt;
&lt;li&gt;Customers are volatile and they always want the latest phone&lt;/li&gt;
&lt;li&gt;They have to subsidize the phones to lower the barriers to entry&lt;/li&gt;
&lt;li&gt;They have to provide the best coverage everywhere&lt;/li&gt;
&lt;li&gt;Customers are quick to leverage social tools to complain about them&lt;/li&gt;
&lt;li&gt;Customers don't respect the old rules (read: jailbreak their phone)&lt;/li&gt;
&lt;li&gt;Customers are not the cash cows they used to be...&lt;/li&gt;
&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;
I don't think the telco future looks very nice. As traditional telecommunication service providers, they are &lt;a href="http://domderrien.blogspot.com/2009/03/telcos-vs-internet-providers.html"&gt;more and more just Internet providers&lt;/a&gt;. Personally, I'm fine with communication on Internet (VOIP/SIP), with the possibility to stream on Internet (Qik.com, Layar.com), to receive instant messages (IM) instead of text messages (SMS). And look, when I've a chance to connect &lt;a href="http://domderrien.blogspot.com/2009/06/android-dev-phone-1-setup.html"&gt;my phone&lt;/a&gt; to a wifi network, I'm happy to get a better connectivity while saving few bucks.&lt;br /&gt;
&lt;br /&gt;
Interesting developments to follow, aren't they?&lt;br /&gt;
&lt;br /&gt;
A+, Dom&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-623874656538219093?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=Rc5_hl-aE1M:Xmx-pj9rufc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=Rc5_hl-aE1M:Xmx-pj9rufc:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=Rc5_hl-aE1M:Xmx-pj9rufc:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=Rc5_hl-aE1M:Xmx-pj9rufc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=Rc5_hl-aE1M:Xmx-pj9rufc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/Rc5_hl-aE1M" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/623874656538219093/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/10/canadian-wireless-management-forum-my.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/623874656538219093?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/623874656538219093?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/Rc5_hl-aE1M/canadian-wireless-management-forum-my.html" title="Canadian Wireless Management Forum - my review" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_VZZAFHl2_Og/StkC-VWE6GI/AAAAAAAACxc/tRCdJJPqVxk/s72-c/chain-15yearsago.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/10/canadian-wireless-management-forum-my.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0YER3czeyp7ImA9WxBTGE4.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-7194928105258424846</id><published>2009-10-05T21:31:00.006-04:00</published><updated>2009-12-14T18:58:26.983-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-14T18:58:26.983-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Technology" /><category scheme="http://www.blogger.com/atom/ns#" term="Community" /><title>Internationalization and my two-tiers-utils library</title><content type="html">This is a follow-up article of &lt;a href="/2009/06/internationalization-of-gae.html"&gt;Internationalization of GAE applications&lt;/a&gt;, which itself is part of the series &lt;a href="/2009/01/web-application-on-resources-in-cloud.html"&gt;Web Application on Resources in the Cloud&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
In my initial article, I explained some hurdles of globalizing applications, especially the ones being implemented with many programming languages. In this article, I'm going to describe few use-cases and how my open-source library &lt;a href="http://github.com/DomDerrien/two-tiers-utils"&gt;two-tiers-utils&lt;/a&gt; can ease the implementation. Here are the covered topics:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;&lt;a href="#get"&gt;Get the user's preferred locale&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#diffLocales"&gt;Display messages in different locales&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#diffLanguages"&gt;Handle localized messages with different programming languages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#generate"&gt;Generate the localized bundles per programming language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="bonus"&gt;Bonus&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;br /&gt;
&lt;div style="font-size: large;"&gt;&lt;a name="get"&gt;&lt;/a&gt;Get the user's preferred locale&lt;/div&gt;&lt;br /&gt;
For this use-case, let's only consider the Java programming language. Another assumption is the availability of the localized resources in the corresponding Java format (&lt;span style="font-style: italic;"&gt;i.e.&lt;/span&gt; accessible &lt;span style="font-style: italic;"&gt;via&lt;/span&gt; a &lt;a href="http://java.sun.com/javase/6/docs/api/java/util/PropertyResourceBundle.html"&gt;PropertyResourceBundle&lt;/a&gt; instance).&lt;br /&gt;
&lt;br /&gt;
In a Web application, the user's preferred locale can be retrieved from:&lt;ul&gt;&lt;li&gt;The HTTP headers:&lt;br /&gt;
&lt;pre class="prettyprint limitSnippetHeight"&gt;locale = ((HttpServletRequest) request).getLocale();&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;The HTTP session (if saved there previously):&lt;br /&gt;
&lt;pre class="prettyprint limitSnippetHeight"&gt;HttpSession session = ((HttpServletRequest) request).getSession(false);
if (session != null) {
  locale = new Locale((String) session.getAttribute(SESSION_USER_LOCALE_ID));
}&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;The record containing the user's information:&lt;br /&gt;
&lt;pre class="prettyprint limitSnippetHeight"&gt;locale = ((UserDTO) user).getPreferredLocale();&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;To ease this information retrieval, the two-tiers-utils library provides the &lt;code&gt;domderrien.i18n.LocaleController&lt;/code&gt; class&lt;br /&gt;
&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;Excerpt of public methods offered within &lt;code&gt;domderrien.i18n.LocaleController&lt;/code&gt;&lt;/div&gt;&lt;img src="http://lh4.ggpht.com/_VZZAFHl2_Og/SsI4xfyUObI/AAAAAAAACwM/P6gp3nuw2BQ/s800/2tu-javadoc-detectLocale.png" style="margin: 0pt auto 10px; display: block; text-align: center;" title="Methods from domderrien.i18n.LocaleController" alt="" /&gt;&lt;br /&gt;
This class can be used in two situations:&lt;ol&gt;&lt;li&gt;In a login form, for example, when we can just guess the desired locale from the browser preferred language list or from an argument in the URL.&lt;/li&gt;
&lt;li&gt;In pages accessible to identified users thanks to the HTTP session.&lt;/li&gt;
&lt;/ol&gt;&lt;div class="codeSnippetTitle"&gt;Usage example of the &lt;code&gt;domderrien.i18n.LocaleController.detectLocale()&lt;/code&gt;&lt;/div&gt;&lt;pre class="prettyprint limitSnippetHeight"&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"&amp;gt;
&amp;lt;%@page
    language="java"
    contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"
    import="org.domderrien.i18n.LabelExtractor"
    import="org.domderrien.i18n.LocaleController"
%&amp;gt;&amp;lt;%
    // Locale detection
    Locale locale = LocaleController.detectLocale(request);
%&amp;gt;&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;&amp;lt;%= LabelExtractor.get("dd2tu_applicationName", locale) %&amp;gt;&amp;lt;/title&amp;gt;
    ...
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    ...
    &amp;lt;img
        class="anchorLogo"
        src="images/iconHelp.png"
        width="16"
        height="16"
        title="&amp;lt;%= LabelExtractor.get("dd2tu_topCommandBox_helpIconLabel", locale) %&amp;gt;"
    /&amp;gt;
    ...
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;br /&gt;
&lt;div style="font-size: large;"&gt;&lt;a name="diffLocales"&gt;&lt;/a&gt;The same message in different locales&lt;/div&gt;&lt;br /&gt;
The previous example introduces also a second class: &lt;code&gt;domderrien.i18n.LabelExtractor&lt;/code&gt;. Being given an identifier, an optional array of Object references, and a locale, the &lt;code&gt;get&lt;/code&gt; static method loads the corresponding string from the localized resource bundle.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;Excerpt of public methods offered within domderrien.i18n.LabelExtractor&lt;/div&gt;&lt;img src="http://lh5.ggpht.com/_VZZAFHl2_Og/SsJFlYbJw8I/AAAAAAAACwQ/AtEke9cg8NU/s800/2tu-javadoc-get.png" style="margin: 0pt auto 10px; display: block; text-align: center;" title="Methods from domderrien.i18n.LabelExtractor alt=" /&gt;A series of localized entries like &lt;code&gt;en:“Welcome {0} {1}”&lt;/code&gt;, &lt;code&gt;fr:“Bonjour {2} {1}”&lt;/code&gt;, and &lt;code&gt;ja:“お早う {0}{1}”&lt;/code&gt; can be easily invoked with a simple command like: &lt;code&gt;LabelExtractor.get("welcome_message", new Object[] { user.getFirstName(), user.getLastName() }, user.getLocale());&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="font-size: large;"&gt;&lt;a name="diffLanguages"&gt;&lt;/a&gt;The same message used from different programming languages&lt;/div&gt;&lt;br /&gt;
Java is a pretty neat language with a large set of editors and code inspectors. But Java is not the only languages used for Web applications. If the two-tiers-utils library provides nice Java features, the delivery of the same library interfaces for the programming languages JavaScript and Python libraries makes it way more valuable!&lt;br /&gt;
&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;Code of the &lt;code&gt;domderrien.i18n.LabelExtractor.get()&lt;/code&gt; method for the JavaScript language.&lt;/div&gt;&lt;pre class="prettyprint limitSnippetHeight"&gt;(function() { // To limit the scope of the private variables

    /**
     * @author dom.derrien
     * @maintainer dom.derrien
     */
    var module = dojo.provide("domderrien.i18n.LabelExtractor");

    var _dictionnary = null;

    module.init = function(/*String*/ namespace, /*String*/ filename, /*String*/ locale) {
        // Dojo uses dash-separated (e.g en-US not en_US) and uses lower case names (e.g en-us not en_US)
        locale = (locale || dojo.locale).replace('_','-').toLowerCase();

        // Load the bundle
        try {
            // Notes:
            // - Cannot use the notation "dojo.requirelocalization" because dojo parser
            //   will try to load the bundle when this file is interpreted, instead of
            //   waiting for a call with meaningful "namespace" and "filename" values
            dojo["requireLocalization"](namespace, filename, locale); // Blocking call getting the file per XHR or &amp;lt;iframe/&amp;gt;

            _dictionary = dojo.i18n.getLocalization(namespace, filename, locale);
        }
        catch(ex) {
            alert("Deployment issue:" +
                    "\nCannot get localized bundle " + namespace + "." + filename + " for the locale " + locale +
                    "\nMessage: " + ex
                );
        }

        return module;
    };

    module.get = function(/*String*/key, /*Array*/args) {
        if (_dictionary == null) {
            return key;
        }
        var message = _dictionary[key] || key;
        if (args != null) {
            dojo.string.substituteParams(message, args);
        }
        return message;
    };

})(); // End of the function limiting the scope of the private variables&lt;/pre&gt;&lt;br /&gt;
The following piece of code illustrates how the JavaScript &lt;code&gt;domderrien.i18n.LabelExtractor&lt;/code&gt; class instance should be initialized (the value of the &lt;code&gt;locale&lt;/code&gt; variable can come from &lt;code&gt;dojo.locale&lt;/code&gt; or a value injected server-side into a JSP page) and how it can be invoked to get a localized label.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;Usage example of the &lt;code&gt;domderrien.i18n.LocaleController.get()&lt;/code&gt;&lt;/div&gt;&lt;pre class="prettyprint limitSnippetHeight"&gt;(function() { // To limit the scope of the private variables

    var module = dojo.provide("domderrien.blog.Test");

    dojo.require("domderrien.i18n.LabelExtractor");

    var _labelExtractor;

    module.init = function(/*String*/ locale) {
        // Get the localized resource bundle
        _labelExtractor = domderrien.i18n.LabelExtractor.init(
                "domderrien.blog",
                "TestBundle",
                locale // The library is going to fallback on dojo.locale if this parameter is null
            );

        ...
    };

    module._postData = function(/*String*/ url, /*Object*/ jsonParams) {
        var transaction = dojo.xhrPost({
            content : jsonParams,
            handleAs : "json",
            load : function(/*object*/ response, /*Object*/ioargs) {
                if (response == null) {
                    // Message prepared client-side
                    _reportError(_labelExtractor.get("dd2tu_xhr_unexpectedError"), [ioargs.xhr.status]);
                }
                if (!response.success) {
                    // Message prepared server-side
                    _reportError(_labelExtractor.get(response.messageKey), response.msgParams);
                }
                ...
            },
            error : function(/*Error*/ error, /*Object*/ ioargs) {
                    // Message prepared client-side
                _reportError(error.message, [ioargs.xhr.status]);
            },
            url : url
        });
    };

    var _reportError = function(/*String*/ message, /*Number ?*/xhrStatus) {
        var console = dijit.byId("errorConsole");
        ...
    };

    ...

})(); // End of the function limiting the scope of the private variables&lt;/pre&gt;&lt;br /&gt;
The following series of code excerpts show the pieces involved in getting the localized resources with the Python programming language.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;LabelExtractor methods definitions from &lt;code&gt;domderrien/i18n/LabelExtractor.py&lt;/code&gt;&lt;/div&gt;&lt;pre class="prettyprint limitSnippetHeight"&gt;# -*- coding: utf-8 -*-

import en
import fr
 
def init(locale):
    """Initialize the global dictionary for the specified locale"""
    global dict
    if locale == "fr":
        dict = fr._getDictionary()
    else: # "en" is the default language
        dict = en._getDictionary()
    return dict&lt;/pre&gt;&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;Sample of a localized dictionary from &lt;code&gt;domderrien/i18n/en.py&lt;/code&gt;&lt;/div&gt;&lt;pre class="prettyprint limitSnippetHeight"&gt;# -*- coding: utf-8 -*-
 
dict_en = {}
 
def _getDictionary():
    global dict_en
    if (len(dict_en) == 0):
        _fetchDictionary(dict_en)
    return dict_en
 
def _fetchDictionary(dict):
    dict["_language"] = "English"
    dict["dd2tu_applicationName"] = "Test Application"
    dict["dd2tu_welcomeMsg"] = "Welcome {0}."
    ...&lt;/pre&gt;&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;Definitions of filters used by the Django templates, from &lt;code&gt;domderrien/i18n/filters.py&lt;/code&gt;&lt;/div&gt;&lt;pre class="prettyprint limitSnippetHeight"&gt;from google.appengine.ext import webapp
 
def get(dict, key):
    return dict[key]
 
def replace0(pattern, value0):
    return pattern.replace("{0}", str(value0))
 
def replace1(pattern, value1):
    return pattern.replace("{1}", str(value1))
 
...
 
# http://javawonders.blogspot.com/2009/01/google-app-engine-templates-and-custom.html
# http://daily.profeth.de/2008/04/using-custom-django-template-helpers.html
 
register = webapp.template.create_template_register()
register.filter(get)
register.filter(replace0)
register.filter(replace1)
...&lt;/pre&gt;&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;Django template from &lt;code&gt;domderrien/blog/Test.html&lt;/code&gt;&lt;/div&gt;&lt;pre class="prettyprint limitSnippetHeight"&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;
&amp;lt;html xmlns="http://www.w3.org/1999/xhtml"&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;{{ dictionary|get:dd2tu_applicationName }}&amp;lt;/title&amp;gt;
    ....
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    ...
    &amp;lt;div class="..."&amp;gt;{{ dictionary|get:dd2tu_welcomeMsg|replace0:parameters.loggedUser }}&amp;lt;/div&amp;gt;
    ...
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;Test handler from &lt;code&gt;domderrien/blog/Test.py&lt;/code&gt;&lt;/div&gt;&lt;pre class="prettyprint limitSnippetHeight"&gt;from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template

def prepareDictionary(Request):
    locale = request.get('lang', 'en')
    return LabelExtractor.init(locale)

class MainPage(webapp.RequestHandler):
    def get(self):
        parameters = {}
        parameters ['dictionary'] = domderrien.i18n.LabelExtractor.init(self.request)
        parameters ['loggedUser'] = users.get_current_user()
        path = os.path.join(os.path.dirname(__file__), 'domderrien/blog/Test.html')
        self.response.out.write(template.render(path, parameters))

application = webapp.WSGIApplication(
    [('/', MainPage)],
    debug=True
)
 
def main():
    webapp.template.register_template_library('domderrien.i18n.filters')
    run_wsgi_app(application)
 
if __name__ == "__main__":
    main()&lt;/pre&gt;&lt;br /&gt;
&lt;div style="font-size: large;"&gt;&lt;a name="generate"&gt;&lt;/a&gt;Generate the localized bundles per programming language&lt;/div&gt;&lt;br /&gt;
In my previous post &lt;a href="/2009/06/internationalization-of-gae.html"&gt;Internationalization of GAE applications&lt;/a&gt;, I suggest to use a dictionary format that would be programming lnaguage agnostic while being known by translator: TMX, for Tanslation Memory eXchange.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;Snippet of a translation unit definition for a TMX formatted file&lt;/div&gt;&lt;pre class="prettyprint limitSnippetHeight"&gt;&amp;lt;tu tuid="&lt;span style="color: red;"&gt;dd2tu_welcomeMessage&lt;/span&gt;" datatype="Text"&amp;gt;
 &amp;lt;tuv xml:lang="en"&amp;gt;
  &amp;lt;seg&amp;gt;Welcome {0}&amp;lt;/seg&amp;gt;
 &amp;lt;/tuv&amp;gt;
 &amp;lt;note&amp;gt;{0} is going to be replaced by the logged user's display name&amp;lt;/note&amp;gt;
 &amp;lt;prop type="x-tier"&amp;gt;dojotk&amp;lt;/prop&amp;gt;
 &amp;lt;prop type="x-tier"&amp;gt;javarb&amp;lt;/prop&amp;gt;
 &amp;lt;prop type="x-tier"&amp;gt;python&amp;lt;/prop&amp;gt;
&amp;lt;/tu&amp;gt;&lt;/pre&gt;&lt;br /&gt;
The two-tiers-utils library provides a Java runtime &lt;code&gt;domderrien.build.TMXConverter&lt;/code&gt; that generates the  resource bundles for Java/JavaScript/Python. If a simple series of XSL-Transform runs can do the job, the &lt;code&gt;TMXConverter&lt;/code&gt; does a bit more by:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Comparing the modification dates of the generated files with the TMX one to generate them only if needed&lt;/li&gt;
&lt;li&gt;Check the uniqueness of the label keys&lt;/li&gt;
&lt;li&gt;Generate the list of supported languages&lt;/li&gt;
&lt;/ul&gt;Invoking the &lt;code&gt;TMXConverter&lt;/code&gt; runtime from an &lt;code&gt;ant&lt;/code&gt; build file is very simple, while a bit verbose:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;&lt;code&gt;Ant&lt;/code&gt; target definition invoking the &lt;code&gt;TMXConverter&lt;/code&gt;&lt;/div&gt;&lt;pre class="prettyprint limitSnippetHeight"&gt;&amp;lt;target name="step-tmx-convert"&amp;gt;
    &amp;lt;mkdir dir="${temp.dir}/resources" /&amp;gt;
    &amp;lt;mkdir dir="src/WebContent/js/domderrien/i18n/nls" /&amp;gt;
    &amp;lt;java classname="domderrien.build.TMXConverter" fork="true" failonerror="true"&amp;gt;
        &amp;lt;classpath refid="tmxconverter.classpath" /&amp;gt;
        &amp;lt;classpath location="${temp.dir}/resources" /&amp;gt;
        &amp;lt;jvmarg value="-Dfile.encoding=UTF-8" /&amp;gt;
        &amp;lt;arg value="-tmxFilenameBase" /&amp;gt;
        &amp;lt;arg value="${dd2tu.localizedLabelBaseFilename}" /&amp;gt;
        &amp;lt;arg value="-sourcePath" /&amp;gt;
        &amp;lt;arg value="${basedir}\src\resources" /&amp;gt;
        &amp;lt;arg value="-jsDestPath" /&amp;gt;
        &amp;lt;arg value="${basedir}\src\WebContent\js\domderrien\i18n\nls" /&amp;gt;
        &amp;lt;arg value="-javaDestPath" /&amp;gt;
        &amp;lt;arg value="${temp.dir}/resources" /&amp;gt;
        &amp;lt;arg value="-languageFilenameBase" /&amp;gt;
        &amp;lt;arg value="${dd2tu.languageListFilename}" /&amp;gt;
        &amp;lt;arg value="-buildStamp" /&amp;gt;
        &amp;lt;arg value="${dd2tu.stageId}" /&amp;gt;
    &amp;lt;/java&amp;gt;
    &amp;lt;native2ascii
        src="${temp.dir}/resources"
        dest="${temp.dir}/resources"
        encoding="UTF8"
        includes="*.properties-utf8"
        ext=".properties"
    /&amp;gt;
    &amp;lt;copy
        file="${temp.dir}/resources/${dd2tu.localizedLabelBaseFilename}.properties"
        tofile="${temp.dir}/resources/${dd2tu.localizedLabelBaseFilename}_en.properties"
    /&amp;gt;
    &amp;lt;mkdir dir="src/WebContent/js/domderrien/i18n/nls/en" /&amp;gt;
    &amp;lt;copy
        file="src/WebContent/js/domderrien/i18n/nls/{dd2tu.localizedLabelBaseFilename}.js"
        todir="src/WebContent/js/domderrien/i18n/nls/en"
    /&amp;gt;
&amp;lt;/target&amp;gt;&lt;/pre&gt;&lt;br /&gt;
With the TMX file as the source of thruth for the label definitions, it is just a matter of altering the value a &lt;code&gt;&amp;lt;prop/&amp;gt;&lt;/code&gt; tag and running the build once again to move one label definition from one programming language to another. No more error prone copy-and-paste of text between different file formats!&lt;br /&gt;
&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;Excerpt of the generated Java resource bundle&lt;/div&gt;&lt;pre class="prettyprint limitSnippetHeight"&gt;bundle_language=English
unit_test_sample=N/A
dd2tu_applicationName="Test Application"
dd2tu_welcomeMessage=Welcome {0}
...
x_timeStamp=20091001.1001&lt;/pre&gt;&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;Excerpt of the generated JavaScript resource bundle&lt;/div&gt;&lt;pre class="prettyprint limitSnippetHeight"&gt;({bundle_language:"English",
unit_test_sample:"N/A",
dd2tu_applicationName:"Test Application",
dd2tu_welcomeMessage:"Welcome ${0}",
...
x_timeStamp:"20091001.1001"})&lt;/pre&gt;&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;Excerpt of the generated Python class definition&lt;/div&gt;&lt;pre class="prettyprint limitSnippetHeight"&gt;# -*- coding: utf-8 -*-
 
dict_en = {}
 
def _getDictionary():
    global dict_en
    if (len(dict_en) == 0):
        _fetchDictionary(dict_en)
    return dict_en
 
def _fetchDictionary(dict):
    dict["_language"] = "English"
    dict["dd2tu_applicationName"] = "Test Application"
    dict["dd2tu_welcomeMsg"] = "Welcome {0}."
    ...
    dict["x_timestamp"] = "20091001.1001"&lt;/pre&gt;&lt;br /&gt;
&lt;div style="font-size: large;"&gt;&lt;a name="bonus"&gt;&lt;/a&gt;Bonus&lt;/div&gt;&lt;br /&gt;
The &lt;code&gt;TMXConverter&lt;/code&gt; being part of the build process and going over all localized TMX files, it generates the list of supported languages.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;JSP code fetching a HTML &amp;amp;ltselect/&amp;gt; box with the list of supported languages&lt;/div&gt;&lt;pre class="prettyprint limitSnippetHeight"&gt;&amp;lt;span class="topCommand topCommandLabel"&amp;gt;&amp;lt;%= LabelExtractor.get("rwa_loginLanguageSelectBoxLabel", locale) %&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;select
    class="topCommand"
    dojotType="dijit.form.FilteringSelect"
    id="languageSelector"
    onchange="switchLanguage();"
    title="&amp;lt;%= LabelExtractor.get("rwa_loginLanguageSelectBoxLabel", locale) %&amp;gt;"
&amp;gt;&amp;lt;%
    ResourceBundle languageList = LocaleController.getLanguageListRB();
    Enumeration&amp;lt;String&amp;gt; keys = languageList.getKeys();
    while(keys.hasMoreElements()) {
        String key = keys.nextElement();%&amp;gt;
        &amp;lt;option&amp;lt;% if (key.equals(localeId)) { %&amp;gt; selected&amp;lt;% } %&amp;gt; value="&amp;lt;%= key %&amp;gt;"&amp;gt;&amp;lt;%= languageList.getString(key) %&amp;gt;&amp;lt;/option&amp;gt;&amp;lt;%
    } %&amp;gt;
&amp;lt;/select&amp;gt;&lt;/pre&gt;&lt;br /&gt;
The following figures illustrates the corresponding code in action.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;Part of a login screen as defined with the default (English) TMX file.&lt;/div&gt;&lt;img src="http://lh3.ggpht.com/_VZZAFHl2_Og/SspLfUP_bSI/AAAAAAAACxE/-JYmKG2paVA/s800/2009-10-05_1537.png" title="UI defined with the default TMX file" style="text-align:center; display:block;margin:auto;" /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;Part of a login screen as defined with the French TMX file.&lt;/div&gt;&lt;img src="http://lh6.ggpht.com/_VZZAFHl2_Og/SspLfW9y7VI/AAAAAAAACxI/GscDMHylSzg/s800/2009-10-05_1538.png" title="UI defined with the French TMX file" style="text-align:center; display:block;margin:auto;" /&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style="font-size: large;"&gt;&lt;a name="bonus"&gt;&lt;/a&gt;Conclusion&lt;/div&gt;&lt;br /&gt;
The &lt;a href="http://github.com/DomDerrien/two-tiers-utils"&gt;two-tiers-utils&lt;/a&gt; library is offered with the &lt;a href="http://github.com/DomDerrien/two-tiers-utils/blob/master/src/Java/domderrien/LICENSE"&gt;BSD-like license&lt;/a&gt;. Anyone is free to use it for his own purposes. but I'll appreciate any feedback, contribution, and feature requirement.&lt;br /&gt;
&lt;br /&gt;
See you on github.com ;)&lt;br /&gt;
“May the &lt;i&gt;fork&lt;/i&gt; be with you.”&lt;br /&gt;
&lt;br /&gt;
A+, Dom&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-7194928105258424846?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=e5D4AGClnyU:s68xHs0aHSk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=e5D4AGClnyU:s68xHs0aHSk:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=e5D4AGClnyU:s68xHs0aHSk:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=e5D4AGClnyU:s68xHs0aHSk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=e5D4AGClnyU:s68xHs0aHSk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/e5D4AGClnyU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/7194928105258424846/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/10/internationalization-and-my-two-tiers.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/7194928105258424846?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/7194928105258424846?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/e5D4AGClnyU/internationalization-and-my-two-tiers.html" title="Internationalization and my two-tiers-utils library" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/_VZZAFHl2_Og/SsI4xfyUObI/AAAAAAAACwM/P6gp3nuw2BQ/s72-c/2tu-javadoc-detectLocale.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/10/internationalization-and-my-two-tiers.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cGR38-eCp7ImA9WxBTGE4.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-3558122177910541593</id><published>2009-09-18T23:39:00.001-04:00</published><updated>2009-12-14T18:57:06.150-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-14T18:57:06.150-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Experience" /><title>Progress update</title><content type="html">Almost three months without publishing anything! I am definitively not proud of this score...&lt;br /&gt;
&lt;br /&gt;
I have been busy on three fronts:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;At work,  I continue working on mobile related development. The easiest platform to play with is the Android one (see my post on &lt;a href="http://domderrien.blogspot.com/2009/06/android-dev-phone-1-setup.html"&gt;Android Dev Phone 1&lt;/a&gt;) and I thrilled to see new handsets being made available, like the HTC Dream and Motorola Cliq, with their respective HTC Sense and Moto BLUR custom UIs (see &lt;a href="#ProgressUpdate-Videos"&gt;videos below&lt;/a&gt;). Even if its SDK is not as rich as Android's one, even if the gadgets are not as polished as Android's ones, I also like developing for BlackBerry phones, like the BlackBerry Storm.&lt;/li&gt;
&lt;/ol&gt;&lt;ol start="2"&gt;&lt;li&gt;For my side project, running on Google App Engine infrastructure, it is progressing very well. Today, I reached a milestone: the first part of [still a secret] runs live. In terms of coding, it represents ~6,000 lines for the source files and ~12,000 lines for the test. I have always considered source &lt;i&gt;vs&lt;/i&gt; test as being 50-50; it seems I should re-evaluate the balance to 1/3-2/3 ;)&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_VZZAFHl2_Og/SrRHN7_L6zI/AAAAAAAACvs/NSQROYxK_ZE/s1600/line-numbers.png" /&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
Thanks to different contributors, I have developed a series of &lt;i&gt;mock&lt;/i&gt; classes allowing to test transactions with BigTable, the database used by App Engine. A really neat piece of code I am going to describe here later. &lt;/li&gt;
&lt;/ol&gt;&lt;ol start="3"&gt;&lt;li&gt;On the social side, I am working with the board of &lt;a href="http://www.diku-dilenga.org/"&gt;Diku Dilenga&lt;/a&gt; Canada (board I am member of) to move as its Executive Director (still as a volunteer). The move has been inspired by Jean-Pierre Tchang, founder of &lt;a href="http://irismundial.ca/"&gt;IRIS Mundial&lt;/a&gt;. I hope this update will make Diku Dilenga (Canada) as successful as IRIS Mundial.&lt;br /&gt;
&lt;br /&gt;
I had a lot of activities on this front recently: a fundraiser thanks to &lt;a href="http://diku-dilenga.org/lang-en/partenaires/dd-canada/94-le-parcours-en-direct-de-louis-lamontagne-sur-le-chemin-de-compostelle"&gt;Louis Lamontagne walking between Saint Jean Pied de Port (France) and Santiago de Compostela (Spain)&lt;/a&gt;, a trip of 780km, a first series of computers to be shipped to Kananga, Democratic Republic of the Congo, etc.&lt;br /&gt;
&lt;br /&gt;
The plan to link the [still a secret] project with Diku Dilenga activities have been formally approved by the board during the summer. This side, there is a possibility I will do a presentation to the &lt;a href="http://www.microcreditsummit.org/partner_with_us/"&gt;2010 Africa/Middle East Regional Microcredit Summit (AMERMS)&lt;/a&gt; to be held in Nairobi, Kenya April 7-10, 2010. It would be nice to participate, isn't it?&lt;/li&gt;
&lt;/ol&gt;&lt;br /&gt;
Stay tuned, I should be back in few days with technical information about unit testing transactional code on Google App Engine ;)&lt;br /&gt;
&lt;br /&gt;
A+, Dom&lt;br /&gt;
--&lt;br /&gt;
Videos:&lt;br /&gt;
&lt;br /&gt;
&lt;a name="ProgressUpdate-Videos"&gt;&lt;/a&gt;&lt;center&gt;&lt;object height="340" width="560"&gt;&lt;param name="movie" value="http://www.youtube.com/v/of-5IFSREVk&amp;hl=en&amp;fs=1&amp;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/of-5IFSREVk&amp;hl=en&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="560" height="340"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;
HTC Hero, the first phone with the HTC Sense, a customized UI scheme on the top of Android.&lt;/center&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;object height="340" width="560"&gt;&lt;param name="movie" value="http://www.youtube.com/v/8LtKAnJf1Ss&amp;hl=en&amp;fs=1&amp;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/8LtKAnJf1Ss&amp;hl=en&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="560" height="340"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;
Motorola Cliq, the first phone with Moto BLUR, a customized UI scheme on the top of Android.&lt;/center&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;object height="344" width="425"&gt;&lt;param name="movie" value="http://www.youtube.com/v/6IRVs4hXDIU&amp;hl=en&amp;fs=1&amp;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/6IRVs4hXDIU&amp;hl=en&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;
BlackBerry Storm, first BlackBerry phone with a touch screen&lt;/center&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-3558122177910541593?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=UUiFvogykSc:44ojE5G_vY4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=UUiFvogykSc:44ojE5G_vY4:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=UUiFvogykSc:44ojE5G_vY4:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=UUiFvogykSc:44ojE5G_vY4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=UUiFvogykSc:44ojE5G_vY4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/UUiFvogykSc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/3558122177910541593/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/09/progress-update.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/3558122177910541593?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/3558122177910541593?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/UUiFvogykSc/progress-update.html" title="Progress update" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_VZZAFHl2_Og/SrRHN7_L6zI/AAAAAAAACvs/NSQROYxK_ZE/s72-c/line-numbers.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/09/progress-update.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0YHRXk9eCp7ImA9WxBTGE4.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-7579446453191855570</id><published>2009-06-12T14:55:00.003-04:00</published><updated>2009-12-14T18:58:54.760-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-14T18:58:54.760-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Technology" /><category scheme="http://www.blogger.com/atom/ns#" term="Community" /><title>JavaOne Conference</title><content type="html">&lt;div class="separator" style="float: right; font-size: smaller; margin: 0pt 0pt 5px 5px; text-align: center;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_VZZAFHl2_Og/SjAPUre00fI/AAAAAAAACto/DcNkqJVwssc/s320/dom-at-javaone-with-duke-2.png" /&gt;&lt;br /&gt;
Duke and myself ;)&lt;/div&gt;It has been a long week in San Francisco while I was attending the JavaOne conference. Sessions started at 8:30 AM and finished after 9:30 PM!&lt;br /&gt;
&lt;br /&gt;
Among all reviews that have been published, read this ones: &lt;a href="http://ctpjava.blogspot.com/2009/06/java-one-2009-summary-monday.html"&gt;Community day&lt;/a&gt; on Monday, &lt;a href="http://ctpjava.blogspot.com/2009/06/java-one-2009-summary-tuesday-day-1.html"&gt;Conference day 1&lt;/a&gt; on Tuesday, &lt;a href="http://ctpjava.blogspot.com/2009/06/javaone-2009-summary-wednesday-day-2.html"&gt;Day 2&lt;/a&gt; on Wednesday, &lt;a href="http://ctpjava.blogspot.com/2009/06/javaone-2009-summary-thursday-day-3.html"&gt;Day 3&lt;/a&gt; on Thursday, and &lt;a href="http://ctpjava.blogspot.com/2009/06/javaone-2009-summary-friday-day-4.html"&gt;Day 4&lt;/a&gt; on Friday. Sun's website contains also a complete list of &lt;a href="http://java.sun.com/javaone/2009/articles/listing.jsp"&gt;conference articles&lt;/a&gt;. Pictures of the event are available on &lt;a href="http://photos.sun.com/page/3371"&gt;Sun's Photo Center website&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
I went there with two objectives:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;See JavaFX in action;&lt;/li&gt;
&lt;li&gt;Look at all efforts around JavaME and the MSA initiative.&lt;/li&gt;
&lt;/ul&gt;&lt;span style="font-size: large;"&gt;JavaFX technology stack&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div style="float: right; font-size: smaller; margin: 0pt 0pt 5px 5px; text-align: center;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_VZZAFHl2_Og/SjAKyZCwEhI/AAAAAAAACtY/2xkfUnw3gdQ/s320/_DSC1018.1024x768.jpg" /&gt;&lt;br /&gt;
Eric Klein, Vice President, Java Marketing, Sun Microsystems&lt;/div&gt;I came without preconceived idea around JavaFX, just with my background as a JavaScript/Java developer and my knowledge of Flex and AIR.&lt;br /&gt;
&lt;br /&gt;
The first deception came from looking at the scripting language: Man! they invented yet another language :( For sure, the JavaFX scripting language is nicely handled by NetBeans 6.5+ (except the code formatting) but new paradigms and new conventions are a big barrier to adoption to me. Can you figure out what the following code is doing?&lt;br /&gt;
&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;&lt;/div&gt;&lt;pre class="prettyprint"&gt;public class Button extends CustomNode {
  public var up: Node;
  content: Node = up;
  public override function create(): Node {
    return Group {
      content: bind content
    }
}&lt;/pre&gt;If the visual effects to animate texts, pictures, and video are really great, the native support of a sound library is really missing! For example, I would expect to be able to synchronize &lt;code&gt;KeyFrame&lt;/code&gt; objects with sound tracks but the &lt;code&gt;KeyFrame.time&lt;/code&gt; attribute has to be set manually—not very flexible when it's time to change the sound track...&lt;br /&gt;
&lt;br /&gt;
The pros are:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;A coming visual editor to prepare clips;&lt;/li&gt;
&lt;li&gt;A large library of image and video effects;&lt;/li&gt;
&lt;li&gt;The multi-platform support, especially for mobile devices.&lt;/li&gt;
&lt;/ul&gt;Platform dependent packaging is nicely handled: NetBeans project properties pane provides choices among {Standard Execution, Web Start Execution, Run in Browser, Run in Mobile Emulator}. As a Web developer, I am just sorry to see that the application window size cannot be expressed in percentage, that the auto-resizing is handled transparently, which is not better than usual Flex applications.&lt;br /&gt;
&lt;br /&gt;
Last point: I have not seen how to invoke JavaFX handlers from JavaScript ones, and &lt;i&gt;vice-versa&lt;/i&gt;, when the application is deployed to run in browsers. If you have a source for these information, please, drop the link in a comment.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;JavaME technology stack&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="float: right; font-size: smaller; margin: 0pt 0 5px 5px; text-align: center;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_VZZAFHl2_Og/SjAiRM5ZcsI/AAAAAAAACuI/EN72W-xNdt4/s320/sonyericsson.jpg" /&gt;&lt;br /&gt;
Christopher David, Rikko Sakaguchi and Patrik Olsson&lt;br /&gt;
during Sony Ericsson General Session&lt;/div&gt;This was definitively the most interesting domain to me. During one session, it has been announced that 60% of shipped mobile devices in 2008 are Java-enabled. In 2009, the market share should grow up to 70%. In relation with the iPhone, &lt;a href="http://photos.sun.com/download?acton=download&amp;amp;id=16892"&gt;Scott McNeally did this joke&lt;/a&gt;: the possible future Sun owner Larry Ellison might succeed to open the iPhone platform to Java because he is a well known friend of Steve Jobs.&lt;br /&gt;
&lt;br /&gt;
Compared to the Java Standard Edition (J2SE) and the Java Enterprise Edition (J2EE), the Java Mobile Edition (J2ME) has more external contributors. Under the &lt;a href="http://developers.sun.com/mobility/midp/articles/msaintro/"&gt;Mobile Service Architecture&lt;/a&gt; (MSA) initiative, a lot of mobile device manufacturers and telecommunication operators participate to the Java Community Process (JCP) to deliver Java Specification Requests (JSRs). Note that MSA itself is defined as a JSR: &lt;a href="http://jcp.org/en/jsr/detail?id=248"&gt;JSR 248&lt;/a&gt;. As of today, most of the recent phones are MSA 1.1 compliant (this is a mandatory requirement for the telco Orange, for example). Nokia and Sony Ericsson have shipped a lot of MSA-compliant handsets, LG, Samsung, and Motorola shipped very few ones. The standard MSA 2 (&lt;a href="http://jcp.org/en/jsr/detail?id=249"&gt;JSR 249&lt;/a&gt;) is being finalized and it contains the promising JSRs:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://jcp.org/en/jsr/detail?id=256"&gt;JSR 256 Sensor API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jcp.org/en/jsr/detail?id=293"&gt;JSR 293 Location API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jcp.org/en/jsr/detail?id=239"&gt;JSR 239 OpenGL ES API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jcp.org/en/jsr/detail?id=180"&gt;JSR 180 SIP API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jcp.org/en/jsr/detail?id=177"&gt;JSR 177 Security and trust services API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jcp.org/en/jsr/detail?id=205"&gt;JSR 205 Wireless messaging API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;Additional APIs I imagine many developers are looking forward: &lt;a href="http://jcp.org/en/jsr/detail?id=257"&gt;JSR 257 Contactless communication API&lt;/a&gt; and &lt;a href="http://jcp.org/en/jsr/detail?id=229"&gt;JSR 229 Payment API&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="font-size: smaller; margin: 0pt 5px 5px 0pt; text-align: center;"&gt;&lt;a title="MSA evolution and its JSR set" xDojoType="dojox.image.Lightbox" href="http://2.bp.blogspot.com/_VZZAFHl2_Og/SjE2RAaG1hI/AAAAAAAACuQ/2kbzmM8EpPY/s1600-h/MSA-JSR%20set.png"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_VZZAFHl2_Og/SjE2RAaG1hI/AAAAAAAACuQ/2kbzmM8EpPY/s320/MSA-JSR%20set.png" width="320" /&gt;&lt;/a&gt;&lt;br /&gt;
MSA evolution and its JSR set&lt;br /&gt;
(from the &lt;a href="http://cds-esd.sun.com/ESD6/JSCDL/msa/0.19-pr/msa-0_19-pr-spec.pdf"&gt;MSA specification documentation&lt;/a&gt;)&lt;br /&gt;
(click to enlarge)&lt;/div&gt;&lt;br /&gt;
All major manufacturers have opened or are opening "App Stores" a-la Apple. They open also their development platforms. More companies will be able to adapt their software offering to mobile devices. Even Sony allows anyone to write application to run in Blu-ray Disc players. The main difficulty on developer-side is the fragmentation: there is no standard API allowing to discover the features supported by a device! Developers have to rely on each manufacgturer's feature list and on exception handling :(&lt;br /&gt;
&lt;br /&gt;
The Blackberry platform is pretty well controlled and should be easy to develop on. Then follows Sony Ericsson which provides consistent phone classes (&lt;i&gt;i.e.&lt;/i&gt; what works for one phone in the JP 8.4 class work for all phones in that class). The delivery of the Sun &lt;a href="http://java.sun.com/javame/downloads/sdk30.jsp"&gt;JavaME SDK 3.0&lt;/a&gt; containing many third-party emulators (even one for Windows Mobile devices) added to better on-device deployment and on-device debugging capabilities, should motivate more and more developers.&lt;br /&gt;
&lt;br /&gt;
I have not enough experience with &lt;a href="http://developer.android.com/"&gt;Android&lt;/a&gt; (just got one &lt;a href="http://domderrien.blogspot.com/2009/06/android-dev-phone-1-setup.html"&gt;Android dev phone&lt;/a&gt; two weeks ago) to compare it to the JavaME technology stack. I don't know neither about &lt;a href="http://www.symbian.org/"&gt;Symbian&lt;/a&gt; (Nokia devices) or &lt;a href="http://www.limofoundation.org/"&gt;LiMo&lt;/a&gt; (Motorola devices) platforms.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Exhibition hall&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Besides the visit of mobile device manufacturers (RIM and Ericsson) booths, I visited:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Sun's project &lt;a href="https://fuji.dev.java.net/"&gt;Fuji&lt;/a&gt; (open ESB) with a Web console using &lt;code&gt;&amp;lt;canvas/&amp;gt;&lt;/code&gt; from HTML5, like Yahoo! Pipes.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.sun.com/software/convergence/"&gt;Convergence&lt;/a&gt;, the Web client for Sun's communication suite, built on the top of Dojo toolkit ;)&lt;/li&gt;
&lt;li&gt;INRIA (French national R&amp;D lab) for its static code analysis &lt;a href="http://nit.gforge.inria.fr/eclipse"&gt;Nit&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Isomorphic Software for its &lt;a href="http://www.smartclient.com/"&gt;SmartClient Ajax RIA System&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;eXo Platform (on OW2 booth) for its &lt;a href="http://www.exoplatform.com/portal/public/website/product/exoproducts/portal/portaloverview"&gt;eXo Portal&lt;/a&gt; offering.&lt;/li&gt;
&lt;li&gt;Liferay, Inc. for its &lt;a href="http://www.liferay.com/web/guest/products/portal"&gt;eponymous portal&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;&lt;span style="font-size: large;"&gt;Other discoveries&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="float: right; font-size: smaller; margin: 0pt 0pt 5px 5px; text-align: center;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_VZZAFHl2_Og/SjAMbSNPYwI/AAAAAAAACtg/-Bl9IGayNmM/s320/dom-at-javaone-with-goshling-2.png" /&gt;&lt;br /&gt;
James Gosling and myself ;)&lt;/div&gt;I attended very good presentations, like the opening keynote which was fun. Among the good presenters, I can mention (ordered alphabetically):&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://benzilla.galbraiths.org/"&gt;Ben Galbraith&lt;/a&gt; and &lt;a href="http://almaer.com/blog/"&gt;Dion Almaer&lt;/a&gt; (see also &lt;a href="http://ajaxian.com/"&gt;Ajaxian.com&lt;/a&gt;), Mozilla.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.bjhargrave.com/"&gt;BJ Hargrave&lt;/a&gt;, IBM, and &lt;a href="http://www.aqute.biz/Main/HomePage"&gt;Peter Kriens&lt;/a&gt;, aQute,  about OSGi.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://twitter.com/doug_tidwell"&gt;Doug Tidwell&lt;/a&gt;, IBM,  who gave a funny speech about &lt;a href="http://blogs.sun.com/javaone2009/entry/using_rest_and_ws_services"&gt;REST-WS* in the cloud&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blogs.sonyericsson.com/erikhellman/"&gt;Erik Hellman&lt;/a&gt;, Sony Ericsson.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blogs.sun.com/jag/"&gt;James Gosling&lt;/a&gt;, Sun Microsystems.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://wordpress.chanezon.com/"&gt;Patrick Chanezon&lt;/a&gt;, Google, about Open Web.&lt;/li&gt;
&lt;/ul&gt;If you have a Sun Developer Network (SDN) account (by the way, it's free), you can view the slides of the technical sessions at: &lt;a href="http://developers.sun.com/learning/javaoneonline/"&gt;http://developers.sun.com/learning/javaoneonline/&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Special mention&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
I want also to mention the call to developers by &lt;a href="http://www.mifos.org/"&gt;MifOS&lt;/a&gt; people who have been awarded by James Gosling during the Friday morning general session. This organization develops open source software for microfinance institutions (MFIs) to help them managing loans and borrowers (see &lt;a href="http://www.mifos.org/product/demo-the-software"&gt;demo&lt;/a&gt;). Really nice initiative started by the Grameem Bank!&lt;br /&gt;
&lt;br /&gt;
Excerpt from &lt;a href="http://java.sun.com/javaone/2009/articles/toyshow.jsp"&gt;James Gosling Toy Show report&lt;/a&gt;:&lt;br /&gt;
&lt;blockquote&gt;&lt;b&gt;Microfinancing Through Java EE Technology&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Gosling next introduced a group whose great innovation with Java technology was social and not technical. Sam Birney, engineering manager and Mifos alumnus, and Van Mittal-Hankle, senior software engineer at the Grameen Foundation, took the stage to receive &lt;a href="http://java.sun.com/javaone/2009/articles/2009dukeschoiceawards.jsp"&gt;Duke's Choice&lt;/a&gt; awards for their work using Java EE to serve 60,000 clients worldwide in microfinancing, a highly successful means of helping poor people get small loans and start businesses.&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.mifos.org/developers" target="_blank"&gt;Mifos&lt;/a&gt; is open-source technology for microfinance that is spearheaded by the &lt;a href="http://www.grameenfoundation.org/" target="_blank"&gt;Grameen Foundation&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
"Sometimes excellence comes not from technical innovation but in how technology is used," explained Gosling. "This is an example of using Java technology to really improve people's lives."&lt;br /&gt;
&lt;br /&gt;
With an estimated 1.6 billion people left in the world who could benefit from microfinance, the men put out a call for volunteers to contribute to the Mifos project.&lt;span&gt;.&lt;/span&gt;&lt;/blockquote&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;What's next?&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
What are my resolutions? Get a Mac as the development platform (Eclipse works on MacOS and I can use a Win7 image within VirtualBox), and start development on Java enabled phone (at least MSA 1.1 compliant).&lt;br /&gt;
&lt;br /&gt;
A+, Dom&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-7579446453191855570?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=r762uciQV3M:9MBXOsWEf0E:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=r762uciQV3M:9MBXOsWEf0E:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=r762uciQV3M:9MBXOsWEf0E:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=r762uciQV3M:9MBXOsWEf0E:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=r762uciQV3M:9MBXOsWEf0E:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/r762uciQV3M" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/7579446453191855570/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/06/javaone-conference.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/7579446453191855570?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/7579446453191855570?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/r762uciQV3M/javaone-conference.html" title="JavaOne Conference" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_VZZAFHl2_Og/SjAPUre00fI/AAAAAAAACto/DcNkqJVwssc/s72-c/dom-at-javaone-with-duke-2.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/06/javaone-conference.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cNQn0zfCp7ImA9WxBTGE4.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-2566717152095533715</id><published>2009-06-10T15:08:00.000-04:00</published><updated>2009-12-14T18:58:13.384-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-14T18:58:13.384-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Technology" /><title>Internationalization of GAE applications</title><content type="html">&lt;span style="font-size: large;"&gt;Costs of badly planned internationalization&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
In my experience, internationalizing an application is very expensive if it is not planned upfront.&lt;br /&gt;
&lt;br /&gt;
The first source of costs is due to developers who are used to lazily hard-coding labels. Extracting them at the end of the development process is always error prone because developers may have done assumptions on exact labels. Good regression test suites can help detecting such situations but they cannot avoid the cost of the required fix and its corresponding test runs. With late label extraction, developers without enough context tend to add extra dictionary entries. With the label extraction near the release milestone, developers in a rush and without the initial context tend also to produce non documented dictionaries—that is limit their re-usability and increase the difficulty of possible defect fixings.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;Non localized Java code&lt;/div&gt;&lt;pre class="prettyprint"&gt;protected String formulatePageIndex(int index, int total) {
    String out = "Page " + index;
    if(0 &amp;lt; total) {
        out += " of " + total;
    }
    return out;
}&lt;/pre&gt;&lt;br /&gt;
In the example above, I have seen the extraction of the labels &lt;code&gt;Page&lt;/code&gt; and &lt;code&gt;of&lt;/code&gt; instead of &lt;code&gt;Page %0&lt;/code&gt; and &lt;code&gt;Page %0 of %1&lt;/code&gt;. The quick extraction leads to the impossibility to invert the two arguments! Think about the people naming conventions: in many countries, the last name is displayed before the first name, in others the first name precedes the last name (&lt;code&gt;%last %first&lt;/code&gt; compared to &lt;code&gt;%first %last&lt;/code&gt;), and in Japan both names are printed without separator in between (&lt;code&gt;%last%first&lt;/code&gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;Localized Java code&lt;/div&gt;&lt;pre class="prettyprint"&gt;protected String formulatePageIndex(int index, int total) {
    // Get the resource bundle already initialized for the correct locale
    ResourceBundle rb = &lt;i&gt;getCurrentResourceBundle();&lt;/i&gt;
    // Prepare values
    Object[] values = Object[] {Integer.valueOf(index), Integer.valueOf(total)};
    // Get the right localized label
    String label = rb.getString("PageIndexLabel_Page");
    if(0 &amp;lt; total) {
        label = rb.getString("PageIndexLabel_PageOf");
    }
    // Return the localized label with injected values
    return Message.format(label, values);
}&lt;/pre&gt;&lt;br /&gt;
The second source of costs is due to the missed opportunities of deploying localized builds early in the development process. In Agile environments, we expect to get runnable builds on regular basis (at the end of each sprints, each 4 to 6 weeks, for example). And these fool-proof builds can be demoed to customers to get early feedback. If the development organization can work with translators iteratively, there are a lot of chance to detect localization defects while their fixing cost is not too high. In the past, I have seen product developments hugely hit when bi-directional languages (like Arabic and Hebrew) had been introduced...&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Different aspects of the internationalization&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Internationalization (i18n) [1] has two aspects:  &lt;br /&gt;
&lt;ul&gt;&lt;li&gt;The translation of the labels;&lt;/li&gt;
&lt;li&gt;The localization (l10n) of these labels.&lt;/li&gt;
&lt;/ul&gt;The localization takes into account the language and the country, sometimes with variants in a country. For example, the Spanish language spoken 19 identified countries. In Mexico (&lt;code&gt;ES_MX&lt;/code&gt;), the language is slightly different from the one generally spoken in Spain (&lt;code&gt;ES&lt;/code&gt; or &lt;code&gt;ES_ES&lt;/code&gt;). In Spain, there are many regional languages like the Catalan (&lt;code&gt;CA_ES&lt;/code&gt;).  The different locales are normalized by the Unicode consortium (ISO-639 and ISO-3166). Codes are composed of a sequence of two letters for the language plus two letters for the country plus two letters for the region. If letters are missing after the language, most of programming languages fallback on common defaults.&lt;br /&gt;
&lt;br /&gt;
In order to ease application localizations, Unicode references a Common Locale Data Repository (CLDR) [2]. This repository is used and updated by many companies like IBM, Sun, Microsoft, Oracle, etc. The repository describes rules on how to:  &lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Localize currencies;&lt;/li&gt;
&lt;li&gt;Localize metrics (distance, speed, temperature, etc.);&lt;/li&gt;
&lt;li&gt;Localize dates and calendars.&lt;/li&gt;
&lt;/ul&gt;As of today, I think only timezone definitions are still not centrally managed... This is especially bad because conversions between Universal Time (UTC) dates and local dates are operating system dependent (Sun Solaris have small differences with Microsoft Windows, for example).  Many tools use the Unicode CDLR information. For example, each release of the Dojo toolkit use its information to provide the Calendar widget for 27 locales [3].&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Internationalization with different programming languages&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Almost all programming languages have ways to facilitate application globalization. Java provide resource bundles (&lt;code&gt;*.properties&lt;/code&gt; file), Microsoft .Net has resource files (&lt;code&gt;.rc&lt;/code&gt; files), Python has dictionaries, etc. If JavaScript lacks of native support for globalization, some libraries offer various support. To my knowledge, Dojo toolkit is the first providing a full support.&lt;br /&gt;
If developing an application on Google App Engine infrastructure can be done with only one programming language, Python or Java as this time of writing, it is highly possible that developers will use some JavaScript libraries to speed up their development. This is without counting the delivery of a similar program front-end as a native application (made with Adobe AIR, Microsoft .Net, C/C++, Groovy, etc.).&lt;br /&gt;
&lt;br /&gt;
In different situations, I have seen developers moving manually label definitions from one environment to another one. Sometimes, definitions were left over, cluttering the system. In Agile environments, developers should focus on the requirements for the current sprint, leaving some tuning for later sprints. For example, at one point during the development, some labels defined in a JavaScript bundle might be moved to a Java bundle because the localization will be done server-side into a JSP file.&lt;br /&gt;
&lt;br /&gt;
My solution is to put all labels in one localized central repository. The dispatch among the different programming languages is done at build time. When I looked for this repository format, my solution was selected against the following criteria:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Easily editable;&lt;/li&gt;
&lt;li&gt;Has a standard format;&lt;/li&gt;
&lt;li&gt;Usable by static validation processes;&lt;/li&gt;
&lt;li&gt;Has excellent re-usability factors;&lt;/li&gt;
&lt;li&gt;Easily extensible to new programming languages.&lt;/li&gt;
&lt;/ul&gt;I chose the &lt;code&gt;TMX&lt;/code&gt; format (TMX for Translation Memory eXchange [4]). This is an XML based format (good for edition, extensibility, and use by static validation tools) which has been defined to allow translation memory export/import between different translation tools like DejaVu. The &lt;code&gt;XlDiff&lt;/code&gt; format would have been another good candidate.&lt;br /&gt;
&lt;br /&gt;
The following table illustrates the flow of interactions between the different actors in a development team. This sequence diagram shows that, once the developers have delivered a first TMX file, testers and translators can work independently to push tested and localized builds to the customer. As explained later, if developers tune the TMX entries without updating the labels themselves, translators and testers (at least from the l10n point-of-view) can stay out of the loop—only steps [1, 7, 8] are replayed.&lt;br /&gt;
&lt;br /&gt;
&lt;center class="sequenceDiagram"&gt;&lt;table border="0" cellmargin="0" cellspacing="0"&gt;&lt;caption&gt;Simplified view of the overall interaction flow &lt;/caption&gt; &lt;thead&gt;
&lt;tr&gt; &lt;th&gt;Developers&lt;/th&gt; &lt;th&gt;Testers&lt;/th&gt; &lt;th&gt;Translators&lt;/th&gt; &lt;th&gt;Build process&lt;/th&gt; &lt;th&gt;End-users&lt;/th&gt; &lt;/tr&gt;
&lt;/thead&gt; &lt;tbody&gt;
&lt;tr&gt; &lt;td&gt;1. Write labels in one language into the TMX file. These labels are extracted from design documents.&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;2. Generate the application with for one locale.&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;3. Produce a generic bundle to identify non extracted labels.&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;4. Generate the application with for two locales.&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;5. Use the application in one locale (switching to the &lt;code&gt;test&lt;/code&gt; language is hidden).&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;6. Use the initial TMX to produce &lt;code&gt;n&lt;/code&gt; localized TMXs.&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;7. Generate the application with for &lt;code&gt;2 + n&lt;/code&gt; locales.&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;/tr&gt;
&lt;tr&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;&lt;/td&gt; &lt;td&gt;8. Can use the application in &lt;code&gt;1 + n&lt;/code&gt; locales.&lt;/td&gt; &lt;/tr&gt;
&lt;/tbody&gt; &lt;/table&gt;&lt;/center&gt;&lt;br /&gt;
&lt;br /&gt;
The following code snippet shows  how an entry into the base TMX file is defined.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;Snippet of a translation unit definition for a TMX formatted file&lt;/div&gt;&lt;pre class="prettyprint"&gt;&amp;lt;tu tuid="&lt;span style="color: red;"&gt;entry identifier&lt;/span&gt;" datatype="Text"&amp;gt;
 &amp;lt;tuv xml:lang="locale identifier"&amp;gt;
  &amp;lt;seg&amp;gt;localized content&amp;lt;/seg&amp;gt;
 &amp;lt;/tuv&amp;gt;
 &amp;lt;note&amp;gt;contextual information on the entry and relations with other entries&amp;lt;/note&amp;gt;
 &amp;lt;prop type="x-tier"&amp;gt;dojotk&amp;lt;/prop&amp;gt;
 &amp;lt;prop type="x-tier"&amp;gt;javarb&amp;lt;/prop&amp;gt;
&amp;lt;/tu&amp;gt;&lt;/pre&gt;&lt;br /&gt;
The key features of the TMX format are:  &lt;br /&gt;
&lt;ul&gt;&lt;li&gt;The format can be validated with an external XSD (XML Schema Description);&lt;/li&gt;
&lt;li&gt;One entry (&lt;code&gt;tu&lt;/code&gt;: translation unit) can contain many localized contents (&lt;code&gt;tuv&lt;/code&gt;: translation unit value);&lt;/li&gt;
&lt;li&gt;Developers have a normalized placeholder (&lt;code&gt;&amp;lt;note/&amp;gt;&lt;/code&gt;) to register contextual information;&lt;/li&gt;
&lt;li&gt;Extensions are used by the build process to target the type of resource bundle to receive the localized label.&lt;/li&gt;
&lt;/ul&gt;With such an approach, I have seen a drastic reduction of translation mistakes, especially thanks to the &lt;code&gt;&amp;lt;note.&amp;gt;&lt;/code&gt; tag. Sometimes, graphical elements contain inter-related labels that cannot be grouped under a generic entity. The following set of elements illustrates the situation. The TMX approach saves translators headaches because they are simply informed about the relation between four entities.  &lt;br /&gt;
&lt;br /&gt;
&lt;center&gt; &lt;label for="testInputField"&gt;Search:&lt;/label&gt; &lt;input id="testInputField" style="color: lightgrey;" type="text" value="keyword" /&gt; &lt;button&gt;Go&lt;/button&gt; &lt;button&gt;Advanced&lt;/button&gt; &lt;/center&gt;&lt;br /&gt;
The conversion from the TMX to the various resource bundles is done by an XSL-Transform. With the continuous integration handled by &lt;code&gt;ant&lt;/code&gt;, the corresponding task generates the output after having appended the XSLT file coordinates to a copy of the TMX file and after asked for the transformation with the corresponding &lt;code&gt;&amp;lt;xsl/&amp;gt; ant&lt;/code&gt; task. Depending on the machine performance, depending on the TMX file size, I found that the process can be time consuming. If this is your case too, I suggest you write your own little Java program to handle it. You can also use &lt;a href="http://github.com/DomDerrien/two-tiers-utils/tree/master"&gt;mine&lt;/a&gt; ;)&lt;br /&gt;
&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;Stylesheet transforming label definitions for the Dojo toolkit&lt;/div&gt;&lt;pre class="prettyprint"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;
&amp;lt;xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&amp;gt;
 &amp;lt;xsl:output method="text" /&amp;gt;
 &amp;lt;xsl:template match="/tmx/body"&amp;gt;
  {
  &amp;lt;xsl:for-each select="tu"&amp;gt;
    &amp;lt;xsl:for-each select="prop"&amp;gt;
      &amp;lt;xsl:if test="@type='x-tier' and .='dojotk'"&amp;gt;
        "&amp;lt;xsl:value-of select="../@tuid" /&amp;gt;":"&amp;lt;xsl:value-of select="../tuv/seg" /&amp;gt;",
      &amp;lt;/xsl:if&amp;gt;
    &amp;lt;/xsl:for-each&amp;gt;
  &amp;lt;/xsl:for-each&amp;gt;
  "build", "@rwa.stageId@"}
 &amp;lt;/xsl:template&amp;gt;
&amp;lt;/xsl:stylesheet&amp;gt;&lt;/pre&gt;&lt;br /&gt;
&lt;div class="codeSnippetTitle"&gt;Use of the stylesheet above to convert Dojo toolkit related definitions from the TMX files by an &lt;code&gt;Ant&lt;/code&gt; task [5]&lt;/div&gt;&lt;pre class="prettyprint"&gt;&amp;lt;target name="convert-tmx"&amp;gt;
  &amp;lt;style
    basedir="src/resources"
    destdir="src/resources"
    extension=".js"
    includes="*.tmx"
    style="src/resources/tmx2dojotkxsl"
  /&amp;gt;
&amp;lt;/target&amp;gt;&lt;/pre&gt;&lt;br /&gt;
A+, Dom&lt;br /&gt;
--&lt;br /&gt;
Sources:  &lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Introduction to &lt;a href="http://en.wikipedia.org/wiki/Internationalization_and_localization"&gt;internationalization and localization&lt;/a&gt; on Wikipedia.&lt;/li&gt;
&lt;li&gt;Unicode &lt;a href="http://cldr.unicode.org/"&gt;Common Locale Data Repository&lt;/a&gt; (CLDR).&lt;/li&gt;
&lt;li&gt;Dojo toolkit API: &lt;a href="http://api.dojotoolkit.org/jsdoc/1.3/dojo.cldr"&gt;dojo.cldr&lt;/a&gt;, &lt;a href="http://api.dojotoolkit.org/jsdoc/1.3/dojo.i18n"&gt;dojo.i18n&lt;/a&gt;, &lt;i&gt;private&lt;/i&gt; &lt;a href="http://api.dojotoolkit.org/jsdoc/1.3/dijit._Calendar"&gt;dijit._Calendar&lt;/a&gt;, &lt;a href="http://api.dojotoolkit.org/jsdoc/1.3/dojox.widget.Calendar"&gt;dojox.widget.Calendar&lt;/a&gt;, and &lt;a href="http://api.dojotoolkit.org/jsdoc/1.3/dojox.widget.DailyCalendar"&gt;dojox.widget.DailyCalendar&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Definition of the &lt;a href="http://www.lisa.org/Translation-Memory-e.34.0.html"&gt;Translation Memory eXchange&lt;/a&gt; (TMX) format.&lt;/li&gt;
&lt;li&gt;Reference of the &lt;a href="http://ant.apache.org/manual/CoreTasks/style.html"&gt;XSLT/tyle&lt;/a&gt; task for Ant scripts.&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-2566717152095533715?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=mKw8K58qZJU:pHh06_z85QE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=mKw8K58qZJU:pHh06_z85QE:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=mKw8K58qZJU:pHh06_z85QE:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=mKw8K58qZJU:pHh06_z85QE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=mKw8K58qZJU:pHh06_z85QE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/mKw8K58qZJU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/2566717152095533715/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/06/internationalization-of-gae.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/2566717152095533715?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/2566717152095533715?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/mKw8K58qZJU/internationalization-of-gae.html" title="Internationalization of GAE applications" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/06/internationalization-of-gae.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0YHRXk9eCp7ImA9WxBTGE4.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-3708522889159842069</id><published>2009-06-05T18:05:00.004-04:00</published><updated>2009-12-14T18:58:54.760-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-14T18:58:54.760-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Technology" /><category scheme="http://www.blogger.com/atom/ns#" term="Experience" /><category scheme="http://www.blogger.com/atom/ns#" term="Community" /><title>Android Dev Phone 1 Setup</title><content type="html">&lt;img border="0" src="http://4.bp.blogspot.com/_VZZAFHl2_Og/SiYXuubp1wI/AAAAAAAACtI/QhnBCgmluLY/s320/android_vector_small.png" style="float:right;margin: 0 0 5px 5px;" /&gt;To start investigations on mobile application development for Compuware, I have just acquired a first Android Dev Phone, also known as G1 [1]. Last week at Google I/O, Vic Gundotra delivered an Oprah event by offering to the audience a second generation Android phone, also known as G2 or HTC Magic [2, 3]. The G1 is more limited but it is still the only Android platform legally available. &lt;br /&gt;
&lt;br /&gt;
With a bit of luck, few of 18 new phones Google expects [4] will be made available to developers during the year.&lt;br /&gt;
&lt;br /&gt;
I have been able to activate the phone with the Fido pre-paid plan (10 $/month) [5]:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;I inserted the SIM card as illustrated into the documentation, put the the battery in place, and connected the phone to the AC adapter.&lt;/li&gt;
&lt;li&gt;Before signing in with my Google account, I had to create an Access Point Network (APN) entry:&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;Name: Fido&lt;/li&gt;
&lt;li&gt;APN: internet.fido.ca&lt;/li&gt;
&lt;li&gt;Username: fido&lt;/li&gt;
&lt;li&gt;Password: fido&lt;/li&gt;
&lt;li&gt;MCC: 302&lt;/li&gt;
&lt;li&gt;MNC: 37&lt;/li&gt;
&lt;/ul&gt;&lt;li&gt;In some forums, it is reported that new Fido SIM cards use 370 as the MNC value.&lt;/li&gt;
&lt;li&gt;A post of Olivier Fisher's blog [6] gives also the coordinates to connect to Rogers network, another GSM provider in Canada.&lt;/li&gt;
&lt;li&gt;To limit interference, I deleted all pre-loaded APN entries (related to T-Mobile networks).&lt;/li&gt;
&lt;li&gt;At one point, a popup asked me to enable data transfers. It is important to enable it and to activate the Data roaming, disregard how expensive are the costs for a prepaid plan.&lt;/li&gt;
&lt;li&gt;Then I specified my Google account credentials and let the phone contacting Google servers via Fido network.&lt;/li&gt;
&lt;li&gt;Once the activation has been successfully reported, I disabled the Data roaming, even before the synchronization of the applications {GMail, Contacts, Calendar} ended. The impact on my plan should be limited ;)&lt;/li&gt;
&lt;li&gt;Then I added the description of my home Wi-Fi network.&lt;/li&gt;
&lt;li&gt;I found the MAC address of the phone in the menu &lt;code&gt;Settings &amp;gt; About phone &amp;gt; Status&lt;/code&gt;, with the entry near the end of the list. I used it to let my Wi-Fi controller accepting connections from the phone.&lt;/li&gt;
&lt;li&gt;At this step, I was able to use my phone for regular calls over Fido network, and for data transfers over my Wi-Fi network.&lt;/li&gt;
&lt;/ul&gt;The phone comes installed with Android 1.0 installed. I will blog later about updating the phone OS to the 1.5 version (also known as Cupcake)...&lt;br /&gt;
&lt;br /&gt;
&lt;div class="updateNotice"&gt;&lt;u&gt;Update 2009/06/16:&lt;/u&gt;&lt;br /&gt;
Instructions on how to upgrade the Android dev phone to Android 1.5 is pusblished on HTC website: &lt;a href="http://www.htc.com/www/support/android/adp.html"&gt;Flashing your Android Dev Phone with a Factory System Image&lt;/a&gt;.&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div class="updateNotice"&gt;&lt;u&gt;Update 2009/07/15&lt;/u&gt;&lt;br /&gt;
Because of some restrictions to access Internet from the office, I have decided to pay for a 1GB/month data plan with Fido (30$/month). The activation has been made pretty quickly but none mentionned the following limitation:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;On HTC website, you can see the &lt;a href="http://www.htc.com/us/product/g1/specification.html"&gt;network specifications&lt;/a&gt; for the G1: HSPA/WCDMA (US) on 1700/2100Mhz.&lt;/li&gt;
&lt;li&gt;Fido/Rogers GSM only operates on 850/1900Mhz, so there's no possibility to go at a 3G speed in Canada!&lt;/li&gt;
&lt;/ul&gt;Using this phone mainly for development purposes, it is not a blocking issue. It is just sad to not benefit from a better bandwidth...&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
A+, Dom&lt;br /&gt;
--&lt;br /&gt;
Sources:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Order the &lt;a href="http://android.brightstarcorp.com/"&gt;Android dev phone 1&lt;/a&gt; from Android Market.&lt;/li&gt;
&lt;li&gt;Techcrunch reports the &lt;a href="http://www.techcrunch.com/2009/05/27/googles-oprah-moment-an-android-phone-for-everyone-at-google-io/"&gt;Oprah moment by Vic Gundotra&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.techcrunch.com/2009/05/30/htc-killed-the-physical-keyboard-smart-move/"&gt;G2 review&lt;/a&gt; by MobileCrunch&lt;/li&gt;
&lt;li&gt;&lt;a href="http://bits.blogs.nytimes.com/2009/05/27/google-expect-18-android-phones-by-years-end/"&gt;Google expects 18 to 20 new phones&lt;/a&gt; on the market by the end of 2009.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://fido.ca/web/page/portal/Fido/PrepaidPlans?forwardTo=prepaidPlans"&gt;Fido pre-paid plan&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://oliverfisher.blogspot.com/2008/10/android-g1-phone-in-canada-on-rogers.html"&gt;Android G1 Phone in Canada on Rogers&lt;/a&gt; by Olivier Fisher. Posted comments are especially useful.&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-3708522889159842069?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=F0sZVgZ1ZBk:fjyJGnHWlUs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=F0sZVgZ1ZBk:fjyJGnHWlUs:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=F0sZVgZ1ZBk:fjyJGnHWlUs:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=F0sZVgZ1ZBk:fjyJGnHWlUs:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=F0sZVgZ1ZBk:fjyJGnHWlUs:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/F0sZVgZ1ZBk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/3708522889159842069/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/06/android-dev-phone-1-setup.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/3708522889159842069?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/3708522889159842069?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/F0sZVgZ1ZBk/android-dev-phone-1-setup.html" title="Android Dev Phone 1 Setup" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_VZZAFHl2_Og/SiYXuubp1wI/AAAAAAAACtI/QhnBCgmluLY/s72-c/android_vector_small.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/06/android-dev-phone-1-setup.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cGR38-eCp7ImA9WxBTGE4.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-7612210585954274135</id><published>2009-05-31T23:34:00.015-04:00</published><updated>2009-12-14T18:57:06.150-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-14T18:57:06.150-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Experience" /><title>Le cap des 40 ans !</title><content type="html">&lt;div style="border: 1px dotted rgb(136, 136, 136); color: #888888; float: right; font-size: 32pt; margin: 0pt 0px 5px 5px;"&gt;1969-2009&lt;/div&gt;Me voilà 40 ans révolu&amp;nbsp;! Ce 30 mai, j'ai eu le plaisir de recevoir de proches amis que j'ai rencontrés au long de mes 10 années passées à Montréal. Ce n'est pas tant le chiffre des 40 ans qui est magique, c'est plus celui des 10 ans et tous les événements qui se sont produits depuis.&lt;br /&gt;
&lt;br /&gt;
En effet il y a 10 ans, ma femme Sophie et moi avons pris un aller simple Nantes-Montréal avec 2 valises, pendant que le reste de nos affaires traversait l'atlantique en bateau. Rapidement, nous avons loué un haut de duplex à Ville LaSalle. Et après quelques temps de vacances au Lac Saint Jean et dans le Saguenay, nous nous sommes mis à la recherche d'un boulot.&lt;br /&gt;
&lt;br /&gt;
Pour moi, c'est la compagnie CS&amp;amp;T (plus tard renommée en Steltor) qui a décidé de me faire confiance. J'y ai d'abord réalisé une console d'administration Web pour le serveur de calendrier, un outil de collaboration instantanée et distribué avant l'heure. Je dois en partie mon recrutement à &lt;a href="http://www.linkedin.com/pub/patrice-lapierre/2/1a6/531"&gt;Patrice Lapierre&lt;/a&gt;, toujours employé par Oracle à Montréal ;)&lt;br /&gt;
&lt;br /&gt;
&lt;img align="left" border="0" src="http://1.bp.blogspot.com/_VZZAFHl2_Og/SiNRVrlJq6I/AAAAAAAACsc/6zX65wuMWCc/s320/orcl.png" style="margin: 0pt 5px 5px 0pt;" /&gt;Une fois acquise Steltor par Oracle, j'ai travaillé pour une équipe californienne. Mon expérience des applications Web a retenue d'&lt;a href="http://www.linkedin.com/pub/attila-bodis/0/749/54"&gt;Attila Bodis&lt;/a&gt;. Avec quelques autres, nous avons construit un environnement pour une application Web 2.0 avant même que le &lt;i&gt;buzz&lt;/i&gt; existe&amp;nbsp;! Une première version a été commercialisé. Les débuts de la seconde version étaient très prometteurs, notamment grâce à la vision d'&lt;a href="http://www.linkedin.com/pub/amir-borna/0/2b4/108"&gt;Amir Borna&lt;/a&gt;, et avec la bonne coordination de &lt;a href="http://www.linkedin.com/in/vincewu"&gt;Vince Wu&lt;/a&gt;. Mais des aléas politiques ont cependant plombé le projet et l'équipe s'est quasiment dissoute...&lt;br /&gt;
&lt;br /&gt;
Quand la semaine dernière, j'ai vu la présentation de &lt;a href="http://wave.google.com/"&gt;Google Wave&lt;/a&gt; par Lars Rasmussen et Stephanie Hannon, j'ai trouvé beaucoup de similitudes avec ce que nous avions sur la planche de travail pour OCS (Oracle Collaboration Suite) en 2005-2006. Parce qu'Oracle évolue dans le monde de l'entreprise, les médias comme le courriel ou l'événement de calendrier devaient perdurer—j'attends à ce propos de voir quelle stratégie Google va offrir aux entreprises pour migrer leur &lt;i&gt;legacy systems&lt;/i&gt;. Il y a sûrement des concepts OCSiens de l'époque qui s'appliqueraient à Wave aujourd'hui. Chapeau bas les gens d'en bas ;) car vous avez réussi où ceux d'en haut n'ont pas su persévérer&amp;nbsp;!&lt;br /&gt;
&lt;br /&gt;
&lt;img align="right" border="0" src="http://1.bp.blogspot.com/_VZZAFHl2_Og/SiNHxV4GQcI/AAAAAAAACrs/GspjAtpzWiA/s320/rtnl.png" style="margin: 0pt 0pt 5px 5px;" /&gt;C'est alors qu'IBM Rational m'a offert un poste d'architecte technique. Le projet n'était pas sensationnel (il est même mort depuis), mais les gens rencontrés et l'expérience de &lt;i&gt;Big Blue&lt;/i&gt; ont été sans pareil. Chapeau à &lt;a href="http://stevenmilstein.com/"&gt;Steven Milstein&lt;/a&gt;, à &lt;a href="http://www.linkedin.com/pub/toufik-bahloul/2/2a0/95a"&gt;Toufik Bahloul&lt;/a&gt; et &lt;a href="http://www.eclipse.org/webtools/people/person.php?name=ryman"&gt;Arthur Ryman&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;img border="0" src="http://3.bp.blogspot.com/_VZZAFHl2_Og/SiNQg2kuOcI/AAAAAAAACsU/olM0Xytc6Kg/s320/cpwr.png" style="float: left; margin: 0pt 5px 5px 0pt;" /&gt;Présentement, je suis chez Compuware dans un groupe d'experts multi-disciplinaires et j'aide à définir les stratégies de l'entreprise dans les domaines des applications Web et des mobiles. Évoluant dans une compagnie très conservatrice, certaines situations ont tendance à me frustrer royalement, mais les résultats que j'arrive à obtenir par ma persévérance font que finalement l'équilibre est positif. Je ne sais pas combien de temps cela va durer, mais j'en apprécie la valeur. Et je remercie &lt;a href="http://www.compuware.com/corporate/796_ENG_HTML.htm#CZARNIK"&gt;Paul Czarnik&lt;/a&gt;, &lt;a href="http://www.linkedin.com/pub/mathieu-pageau/0/7a8/ab8"&gt;Mathieu Pageau&lt;/a&gt; et &lt;a href="http://www.linkedin.com/pub/abdelkahlek-belkasri/13/587/562"&gt;Abdel Belkarsi&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;img border="0" src="http://4.bp.blogspot.com/_VZZAFHl2_Og/SiNVX8Mzk9I/AAAAAAAACsk/d6r_yIawpZ8/s320/rrc.png" style="float: left; margin: 0pt 5px 5px 0pt;" /&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_VZZAFHl2_Og/SiNWH9WxRsI/AAAAAAAACs8/EJ0NrhhSRJQ/s320/logo-150x142.png" style="float: right; margin: 0pt 0pt 5px 5px;" /&gt;Du côté extra-professionnel, il y a eu mon passage dans le groupe RÉSULTATS, merci &lt;a href="http://www.linkedin.com/pub/sunnie-kim/2/238/46a"&gt;Sunnie Kim&lt;/a&gt;, pour lequel l'action des citoyens fait pression sur le gouvernement fédéral pour que l'aide au développement vise les plus pauvres. Maintenant, je suis impliqué dans Diku Dilenga au Canada, dont je remercie le co-fondateur de l'organisation en République démocratique du Congo &lt;a href="http://diku-dilenga.org/lang-fr/apropos/contacts/12-contacts/3-rev-tambwe-musangelu"&gt;révérend Tambwe Musangelu&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;img align="left" border="0" src="http://3.bp.blogspot.com/_VZZAFHl2_Og/SiNJplhbiQI/AAAAAAAACsM/FU3GQUokIsc/s320/chito-ryu.png" style="margin: 0 5px 5px 0;"/&gt;Je n'oublie pas non plus ma relativement récente entrée dans le monde du karaté au Dojo de &lt;u&gt;Don Lorenzetti&lt;/u&gt;, pour le style Chito Ryu. C'est d'autant plus passionnant que toute la famille Derrien y participe&amp;nbsp;: &lt;u&gt;Sophie&lt;/u&gt;, &lt;u&gt;Erwan&lt;/u&gt;, &lt;u&gt;Goulven&lt;/u&gt; et moi-même chacun à des horaires différentes deux fois par semaine.&lt;br /&gt;
&lt;br /&gt;
Merci Sophie, mes enfants, et mes amis pour votre amitié et les richesses que vous m'apportez. J'espère être à la hauteur et vous donner autant de plaisir.&lt;br /&gt;
&lt;br /&gt;
A+, Dom&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-7612210585954274135?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=hRByThy7slU:pUiIRPk5vXg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=hRByThy7slU:pUiIRPk5vXg:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=hRByThy7slU:pUiIRPk5vXg:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=hRByThy7slU:pUiIRPk5vXg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=hRByThy7slU:pUiIRPk5vXg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/hRByThy7slU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/7612210585954274135/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/05/le-cap-des-40-ans.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/7612210585954274135?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/7612210585954274135?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/hRByThy7slU/le-cap-des-40-ans.html" title="Le cap des 40 ans !" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_VZZAFHl2_Og/SiNRVrlJq6I/AAAAAAAACsc/6zX65wuMWCc/s72-c/orcl.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/05/le-cap-des-40-ans.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cGR38-eCp7ImA9WxBTGE4.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-19611854339244593</id><published>2009-05-06T22:25:00.005-04:00</published><updated>2009-12-14T18:57:06.150-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-14T18:57:06.150-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Experience" /><title>Revue du livre « le dip » de Seth Godin</title><content type="html">&lt;div style="float: right; text-align: center; margin: 0 0 10px 10px;"&gt;&lt;img src="http://www.tresorcache.com/images/dip.jpg"&gt;&lt;br /&gt;
Image des &lt;a href="http://www.tresorcache.com/"&gt;Éditions du trésor caché&lt;/a&gt;.&lt;/div&gt;Une fois n'est pas coutume, je prends le parti d'écrire une entrée de blogue en français. Ce qui me motive à le faire c'est la récente lecture du livre de Seth Godin qui n'était disponible qu'en français à la bibliothèque de mon quartier. Depuis quelques années, j'utilise la langue de Shakespeare mise au goût du jour par Ron McDonald pour mon travail. En plus, 95 % de mes sources d'information sont anglophones. C'est donc assez déroutant de lire du Seth Godin en français, mais aussi très rafraîchissant.&lt;br /&gt;
&lt;br /&gt;
Le thème de ce court livre publié en 2007 (100 pages au format d'un livre de poche) traite de la description de différents profils d'activité et sur les stratégies à adopter pour avoir du succès. Seth est très honnête sur la notion de succès&amp;nbsp;: s'il incite le lecteur à être le « meilleur du monde », il précise que ce « monde » est propre à chacun et qu'il peut varier au court du temps. Voici les trois profils d'activités qu'il identifie&amp;nbsp;:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Il y a le profil que tous connaissent quand ils démarrent une nouvelle activité, où l'excitation rend les choses faciles. Cette phase est suivie d'un creux où l'évolution est lente et pénible. Quand l'obstination porte ses fruits, la sortie de ce creux est souvent couronnée de succès. Seth appelle ce creux le dip.&lt;/li&gt;
&lt;li&gt;Il y a le profil de la falaise où les activités progressent bien jusqu'à s'écrouler totalement. Seth fait le parallèle avec le monde de la presse écrite&amp;nbsp;: tout allait bien jusque récemment mais la démocratisation d'Internet a tout chamboulé. Plus besoin d'attendre le quotidien du lendemain pour connaître les nouvelles car la plupart des grands médias [2] diffusent sur Internet. Plus besoin du journal local pour vendre ou acheter un bien car les services comme craigList [3] offre de meilleures couvertures. Plus besoin du mensuel pour voir des photographies extraordinaires, il suffit de se rendre sur Flickr [4]...&lt;/li&gt;
&lt;li&gt;Il y a enfin le profil de la progression plate, infiniment plate, sans perspective de succès. C'est le chemin vers une voie sans issue.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Seth explique que les deux derniers profils sont à abandonner rapidement, car il n'y a que de la médiocrité à en retirer. Le premier profil, celui avec le dip, est à évaluer consciencieusement.&lt;br /&gt;
&lt;br /&gt;
Il arrive des situations, ou malgré les perspectives de réussite évidentes, le palier à traverser pour atteindre le succès est trop pénible. En fait, Seth écrit que la péniblité du palier est proportionnel au succès à atteindre. Si ce n'était pas pénible tout le monde serait couronné de succès, ce qui n'est évidement pas le cas. Parmi ses exemples, Seth cite le cas des grands sportifs, des dirigeants de grandes sociétés, des créateurs, etc. Il dit, par exemple, que c'est facile d'être un grand patron, mais c'est difficile de gravir les échelons pour arriver à ce poste.&lt;br /&gt;
&lt;br /&gt;
La partie qui m'interpelle particulièrement, c'est son discours sur la nécessité d'identifier les situations de dip que l'on peut traverser et celles qui sont insurmontables compte tenu de nos propres contraintes. Quand une situation de dip trop difficiles, tout comme celle de la falaise ou de la progression, il est important d'y renoncer tôt. Il affirme même qu'il est important d'identifier les critères de renonciation avant d'être dans la situation de blocage pour être sûr de quitter pour les bonnes raisons. Si les raisons sont trouvées alors qu'on est dans le trouble, elles provoqueront des remords par la suite. Avec l'analogie d'un marathon, Seth dit que par exemple se mettre des objectifs de temps de parcours et de s'évaluer par rapport à eux plutôt qu'aux sensations du moment (crampes, fringale, etc.) donne de meilleurs chances de succès. Si on déjà parcouru 35 km, les sensations rendront la fin plus pénible à supporter s'il n'y a pas l'estimation initiale de succès établie en fonction de temps établis par avance.&lt;br /&gt;
&lt;br /&gt;
Seth dit que le renoncement à des situations trop difficiles laisse la chance à la réalisation d'autres défis plus à sa mesure. Comme le critère de réussite est d'être « le meilleur de son monde », peu importe que d'autres pensent que l'abandon d'un situation soit un échec. Il arrive même que ceux qui vous jugeront mal sont eux-mêmes incapable de sortir du dip, qu'ils nagent dans une médiocrité relative.&lt;br /&gt;
&lt;br /&gt;
Si je fais un peu d'introspection, j'en arrive aux constats suivants&amp;nbsp;:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Autant mon immigration au Canada, mes derniers changements d'emploi (de Oracle à IBM Rational, puis à Compuware [5]), ainsi que le déplacement de mes activités para-sociales (de RÉSULTATS à Diku Dilenga [6]) ont été motivés par des constats de dip devenus infranchissables (en tout cas, avec des perspectives moindres lorsque comparées à celles offertes par les changements).&lt;/li&gt;
&lt;li&gt;J'aime les difficultés, les challenges qui sont rudes, dans la mesure où la perspective de grandir est bonne. Instinctivement avant, clairement maintenant, j'abandonne les situations qui sont sans issue, ou pour lesquelles les compromis à faire sont sans commune mesure avec la satisfaction à en retirer. Cette attitude peut paraître fruste et égoïste mais c'est relatif&amp;nbsp;: j'imagine qu'en étant le « meilleur de mon monde » cela bénéficie aux gens de « mon monde ». Ce qui est mieux, à mon avis, que d'affecter mon entourage parce que je reste « un médiocre dans mon monde ».&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Étonnant comme un petit livre peut faire gamberger, n'est-ce pas ? À votre tour d'y consacrer quelques heures et de partager votre propre cheminement en me laissant un commentaire.&lt;br /&gt;
&lt;br /&gt;
Pour le plaisir, voici la vidéo d'une présentation donnée par Seth Godin en 2003 [7]. Tout ce qui dit est du « gros bon sens » et c'est ce qui le rend pertinent. Le livre est du même acabit.&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;p&gt;&lt;object width="400" height="300"&gt;&lt;param name="allowfullscreen" value="true" /&gt;&lt;param name="allowscriptaccess" value="always" /&gt;&lt;param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=4246943&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" /&gt;&lt;embed src="http://vimeo.com/moogaloop.swf?clip_id=4246943&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=0&amp;color=&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="300"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;
&lt;a href="http://vimeo.com/4246943"&gt;Seth Godin at Gel 2006&lt;/a&gt; from &lt;a href="http://vimeo.com/gelconference"&gt;Gel Conference&lt;/a&gt; on &lt;a href="http://vimeo.com"&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;&lt;/center&gt;&lt;br /&gt;
&lt;br /&gt;
A+, Dom&lt;br /&gt;
--&lt;br /&gt;
Sources&amp;nbsp;:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Le &lt;a href="http://sethgodin.typepad.com/the_dip/"&gt;livre décrit sur le site de Seth&lt;/a&gt;, et la &lt;a href="http://www.tresorcache.com/ouvrages/Dip.html"&gt;présentation francophone sur le site des Éditions du trésor caché&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://news.google.com/"&gt;Google News&lt;/a&gt;, &lt;a href="http://www.ap.org/"&gt;Associated Press&lt;/a&gt; (AP), &lt;a href="http://www.afp.fr"&gt;Agence France Presse&lt;/a&gt; (AFP), &lt;a href="http://www.cnn.com"&gt;Cable News Network&lt;/a&gt; (CNN), &lt;a href="http://www.radio-canada.ca/rdi/"&gt;Radio de l'information&lt;/a&gt; (RDI, du réseau de Radio Canada), &lt;a href="http://www.france24.com/"&gt;France24&lt;/a&gt;, &lt;a href="http://english.aljazeera.net/"&gt;Al-Jazeera&lt;/a&gt;, etc.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.cragilist.org"&gt;craiglist&lt;/a&gt;, &lt;a href="http://www.kijiji.com"&gt;kijij&lt;/a&gt;, &lt;a href="http://www.lespac.com"&gt;lespac&lt;/a&gt;, etc.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.flickr.com/"&gt;Flickr&lt;/a&gt;, &lt;a href="http://picasaweb.google.com"&gt;PicasaWeb&lt;/a&gt;, &lt;a href="http://photobucket.com/"&gt;PhotoBucket&lt;/a&gt;, etc.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www/oracle.com"&gt;Oracle&lt;/a&gt;, &lt;a href="http://www-01.ibm.com/software/rational/"&gt;IBM Rational&lt;/a&gt;, &lt;a href="http://www.compuware.com"&gt;Compuware&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.results-resultats.ca"&gt;RÉSULTATS&lt;/a&gt;, &lt;a href="http://www.diku-dilenga.org/"&gt;Diku Dilenga&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Entrée sur le blog de Seth&amp;nbsp;: &lt;a href="http://sethgodin.typepad.com/seths_blog/2009/04/this-is-broken.html"&gt;This is broken&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-19611854339244593?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=hzBWi2Mp9oM:D1SXi5zv0NU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=hzBWi2Mp9oM:D1SXi5zv0NU:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=hzBWi2Mp9oM:D1SXi5zv0NU:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=hzBWi2Mp9oM:D1SXi5zv0NU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=hzBWi2Mp9oM:D1SXi5zv0NU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/hzBWi2Mp9oM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/19611854339244593/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/05/revue-du-livre-le-dip-de-seth-godin.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/19611854339244593?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/19611854339244593?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/hzBWi2Mp9oM/revue-du-livre-le-dip-de-seth-godin.html" title="Revue du livre « le dip » de Seth Godin" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/05/revue-du-livre-le-dip-de-seth-godin.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0YHRXk9eSp7ImA9WxBTGE4.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-6754400924574856289</id><published>2009-04-29T17:45:00.000-04:00</published><updated>2009-12-14T18:58:54.761-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-14T18:58:54.761-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Technology" /><category scheme="http://www.blogger.com/atom/ns#" term="Community" /><title>Meet you at JavaOne Conference</title><content type="html">&lt;a href="http://java.sun.com/javaone" target="_blank"&gt;&lt;img align="left" alt="Rockstar" border="0" height="111" src="http://www.cplan.com/javaone2009/creativetoolbox/images/rockstar-icon.jpg" style="margin-right: 10px;" width="130" /&gt;&lt;/a&gt;As the title let you imagine, I will be in San Francisco the week of June 2-5 for the &lt;a href="http://java.sun.com/javaone" target="_blank"&gt;JavaOne 2009 conference&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
It will be my first visit to the event, not to the Moscone Center. While working for Oracle, I attended one Open World event there. With the recent acquisition (not officially closed yet) of Sun by Oracle, I am going to go in California for Oracle again ;)&lt;br /&gt;
&lt;br /&gt;
With another Compuware colleague, we will mainly focus on mobile related sessions, but cloud computing and rich interactive application related ones will have my attention too. With sessions finishing at 10:20 PM, days will be surely long. I expect a fruitful trip.&lt;br /&gt;
&lt;br /&gt;
Are you going to attend too?&amp;nbsp;&lt;a href="http://www.twitter.com/home?status=Meet%20you%20at%20JavaOne%20on..." target="_blank"&gt;Tweet me your schedule&lt;/a&gt; to meet you there ;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;a href="http://java.sun.com/javaone" target="_blank"&gt;&lt;img alt="JavaOne June 2-5, 2009" height="280" src="http://www.cplan.com/javaone2009/creativetoolbox/images/09J1_336x280_EBird.gif" width="336" /&gt;&lt;/a&gt;&lt;/center&gt;&lt;br /&gt;
&lt;br /&gt;
A+, Dom&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-6754400924574856289?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=ozAsgIF21l0:Uq9n39yWg9I:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=ozAsgIF21l0:Uq9n39yWg9I:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=ozAsgIF21l0:Uq9n39yWg9I:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=ozAsgIF21l0:Uq9n39yWg9I:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=ozAsgIF21l0:Uq9n39yWg9I:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/ozAsgIF21l0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/6754400924574856289/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/04/meet-you-at-javaone-conference.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/6754400924574856289?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/6754400924574856289?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/ozAsgIF21l0/meet-you-at-javaone-conference.html" title="Meet you at JavaOne Conference" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/04/meet-you-at-javaone-conference.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak8DR3Y5eyp7ImA9WxVaGUo.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-4079994759625229846</id><published>2009-04-13T19:52:00.001-04:00</published><updated>2009-04-17T10:34:36.823-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-17T10:34:36.823-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Technology" /><category scheme="http://www.blogger.com/atom/ns#" term="Experience" /><title>Agile: SCRUM is Hype, but XP is More Important...</title><content type="html">(This post is part of the series &lt;a href="http://domderrien.blogspot.com/2009/01/web-application-on-resources-in-cloud.html"&gt;Web Application on Resources in the Cloud&lt;/a&gt;.)&lt;br /&gt;
&lt;br /&gt;
I have been doing “Agile development” for more than 5 years. I am used to saying that an organization is Agile at the level of its weakest element. So I cannot claim having worked on any fully Agile projects. However, I have always tried to apply as many as possible Agile principles to my work. This blog entry goes over different practices and identifies the ones that worked best for me and my teams.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Agile&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
The Agile methodology is a &lt;i&gt;not&lt;/i&gt; pure invention, this is the compilation of best directives gathered from various practices:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;Individuals and interactions&lt;/b&gt; over processes and tools&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Working software&lt;/b&gt; over comprehensive documentation&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Customer collaboration&lt;/b&gt; over contract negotiation&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Responding to change&lt;/b&gt; over following a plan&lt;/li&gt;
&lt;/ul&gt;Agile principles and sub-principles have been defined by a group of technical leaders: Beck from eXtreme Programming (XP), Schwaber (Scrum), etc. The Agile Manifesto [1] is the result of their collaboration.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Scrum&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
“Scrum is a lightweight Iterative and Incremental (Agile) Development Method that focuses on delivering rapidly the highest priority features based on business value.” It has been defined by Ken Schwaber and Jeff Sutherland in early 1990s.&lt;br /&gt;
&lt;br /&gt;
Scrum promotes high collaboration and transparency. There are different backlogs helping delivering the best business values at each iteration. Capturing and integrating feedback (from business users, stakeholders, developers, testers, etc.) is a recurrent task. Deliveries occur often and their progression is continuously monitored.&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;br /&gt;
&lt;object height="295" width="480"&gt; &lt;param name="movie" value="http://www.youtube.com/v/Q5k7a9YEoUI&amp;hl=en&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/Q5k7a9YEoUI&amp;hl=en&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="295"&gt;&lt;/embed&gt; &lt;/object&gt;&lt;br /&gt;
&lt;br /&gt;
Scrum in Under 10 Minutes by Hamid Shojaee&lt;/center&gt;&lt;br /&gt;
&lt;br /&gt;
The points I really like about Scrum:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Task reviews done with all actors, in Poker Planning [2] sessions, for example.&lt;/li&gt;
&lt;li&gt;Product designed, coded AND tested during the Sprint.&lt;/li&gt;
&lt;li&gt;Sprint deliveries are workable products, with limited/disabled features, but working without blocking issues.&lt;/li&gt;
&lt;li&gt;Defined roles: Product Owner, Scrum Master (aka Project Manager), and Project Team (composed of cross-functional skills: dev., QA, DBA, Rel. Eng., etc.).&lt;/li&gt;
&lt;/ul&gt;Pig and Chicken are traditional roles in the Agile teams [3].&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;eXtreme Programming&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
While Scrum is mainly managers (chicken) oriented, eXtreme Programming (XP) focuses more on do-ers (pigs).&lt;br /&gt;
&lt;br /&gt;
XP is more a matter of having the right tools and having real technical exchanges within the Scrum team. For example, XP strongly suggests the adoption of peer-programming: two developers per computers, one coding and the other thinking about the coding and correcting the code on-the-fly.&lt;br /&gt;
&lt;br /&gt;
Applying peer programming in teams with actors from various backgrounds is sometimes too constraining. Matching peers is a difficult exercise. However, enforcing peer code reviews allows to get almost the same benefits without too much frustration. With code reviews, junior developers can see seniors' work in action, and senior developers can learn new programming paradigms. I found it's good also for the team cohesion, because team members really know about each others' work.&lt;br /&gt;
&lt;br /&gt;
Among the practices XP incites to follow, there are:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;b&gt;Continuous Integration:&lt;/b&gt; every time a developer or a tester delivers new materials, a complete build process starts to compile, package and test the entire application. Ideally, the build time is short enough to prevent committers to start any other tasks, so they can fix it right away. A safe strategy is to put “fixing the build” as the top priority whenever a problem occurs.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Unit testing and code coverage:&lt;/b&gt; when developers write unit tests, they provide the first piece of code consuming their own code, and experience shows that it really helps delivering better code. Unit tests without code coverage measurements does not mean much. And not trying to reach 100% coverage leaves too much space to defective code... Using &lt;i&gt;mock&lt;/i&gt; objects [4] is an essential tool to test accurately. Test Driven Development (TDD) methodology is pushing this practice up to writing the tests before the code.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Continuous refactoring:&lt;/b&gt; during each &lt;i&gt;sprint&lt;/i&gt;, developers should focus on the immediate requirements, because they have very little control on future sprints (the &lt;i&gt;product owner&lt;/i&gt; can adjust the development plan anytime). This is sometimes difficult to limit them to their immediate tasks because many do not like the perspective of having to rewrite their code later. Investing in tools like IntelliJ IDEA which provides extended refactoring features is really worth it because developers can adapt their code efficiently while being secured by the continuously growing regression test suites.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Best of both approaches&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
In medium to big companies, they are often many layers of management. In such environments, when managers should be facilitators[5], they often add weight to the processes.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="updateNotice" style="float:right;width:40%;padding:0 5px;margin-left:10px;margin-bottom:10px;"&gt;About the issues in shipped products, here is an anecdote about IBM:&lt;br /&gt;
&lt;blockquote&gt;An internal team reviewed the quality of the released products and came to the initial conclusion that minor and maintenance releases contain more flaws than major releases. The conclusion was made after studying the number of defects reported by customers: this number was sometimes twice higher for intermediate releases. But the team pushed its investigation further and polled many customers. At the end, it appears that very few customers were installing major releases immediately, most of them would wait for the first maintenance release to deploy in pre-production environments (one stage before production one)&lt;span&gt;.&lt;/span&gt;&lt;/blockquote&gt;In this story, IBM used the results of this study to size and train the support teams according to the product release plans. As you can expect, more support people are trained and made available on releases following major ones. It did not help IBM delivering better products up front, it mostly smoothed the experience of customers reporting problems ;)&lt;br /&gt;
&lt;/div&gt;Development labs are often known for delivering over the budget, over the allocated time, and with too many issues. Many times, I have seen the maintenance being operated by specific teams, without relation with the development ones. In such environments, development teams focus on delivering features and maintenance teams fix issues: each team has its own budget and life goes on!&lt;br /&gt;
&lt;br /&gt;
The combination of the relatively poor delivered software, the accumulation of managers, and the Scrum burn-down chart (the chart that shows how the work progress on a daily basis [6]) favors Scrum adoption in IT organizations.&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;br /&gt;
&lt;img src="http://lh4.ggpht.com/_VZZAFHl2_Og/SeOq8Z-fzjI/AAAAAAAACrE/UeMsW1B-gJ8/burn-down%20chart.png"&gt;&lt;br /&gt;
&lt;br /&gt;
Burn down chart sample&lt;/center&gt;&lt;br /&gt;
&lt;br /&gt;
My problem with Scrum as I see it in action is related to its usage by managers: it is a one-way communication channel for them to put the pressure on Scrum teams. And because Scrum is task oriented, if the task set is incomplete (or deliberately cut through), these managers mostly follow the feature completion rate, and sometimes the defect detection and fixing rates.&lt;br /&gt;
&lt;br /&gt;
In my experience, with organizations transitioning from waterfall methodologies to Scrum, the feature check list has always precedence on the quality check list! If tasks have a risk to break the deadline, the test efforts are cut. And because these organizations have very few ways to measure the delivered quality (because they adopted Scrum but refused to invest in XP), results are not really better for customers...&lt;br /&gt;
&lt;br /&gt;
This is why I think it is important to balance the importance of Scrum with the one of XP, why as the same time managers should tools to monitor the work progress, Scrum teams should publish quality metrics about all delivered pieces of code. With both sides being instrumented, it is be easier to identify decision impacts and product owners can make informed decisions.&lt;br /&gt;
&lt;br /&gt;
A+, Dom&lt;br /&gt;
--&lt;br /&gt;
Sources:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Principles of the &lt;a href="http://agilemanifesto.org/"&gt;Agile Manifesto&lt;/a&gt;, and definition of &lt;a href="http://en.wikipedia.org/wiki/Agile_software_development"&gt;Agile methodology&lt;/a&gt; on Wikipedia.&lt;/li&gt;
&lt;li&gt;Description of &lt;a href="http://en.wikipedia.org/wiki/Planning_poker"&gt;Poker Planing&lt;/a&gt; on Wikipedia.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.implementingscrum.com/2006/09/11/the-classic-story-of-the-pig-and-chicken/"&gt;The Classic Story of the Chicken and Pig&lt;/a&gt; on ImplementingScrum.com, and the role definition by &lt;a href="http://blogs.msdn.com/nickmalik/archive/2006/01/23/Chicken-And-Pigs.aspx"&gt;Nick Malik&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Mock_object"&gt;Mock object&lt;/a&gt; definition on Wikipedia, and &lt;a href="http://www.manning-source.com/books/massol/massol_ch07.pdf"&gt;Chapter 7: Testing in isolation with mock objects&lt;/a&gt; from the book &lt;a href="http://www.manning.com/massol/"&gt;JUnit In Action&lt;/a&gt;, by Vincent Massol.&lt;/li&gt;
&lt;li&gt;My personal view on the facilitator role managers should have: &lt;a href="http://domderrien.blogspot.com/2008/12/manager-attitude.html"&gt;Manager Attitude&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Scrum_(development)"&gt;Burn-down chart&lt;/a&gt; described as a Scrum artifact on Wikipedia and &lt;a href="http://www.implementingscrum.com/2006/12/26/burn-baby-burn/"&gt;Burn Baby Burn&lt;/a&gt; on ImplementingScrum.com.&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-4079994759625229846?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=HmG2IUPj-fI:ym_Ah4oJU2c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=HmG2IUPj-fI:ym_Ah4oJU2c:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=HmG2IUPj-fI:ym_Ah4oJU2c:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=HmG2IUPj-fI:ym_Ah4oJU2c:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=HmG2IUPj-fI:ym_Ah4oJU2c:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/HmG2IUPj-fI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/4079994759625229846/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/04/agile-scrum-is-hype-but-xp-is-more.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/4079994759625229846?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/4079994759625229846?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/HmG2IUPj-fI/agile-scrum-is-hype-but-xp-is-more.html" title="Agile: SCRUM is Hype, but XP is More Important..." /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/04/agile-scrum-is-hype-but-xp-is-more.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0YCQX87fip7ImA9WxBTGE4.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-1750575646543249261</id><published>2009-04-10T19:12:00.011-04:00</published><updated>2009-12-14T18:59:20.106-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-14T18:59:20.106-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Technology" /><title>Google App Engine Meets Java</title><content type="html">&lt;a href="http://2.bp.blogspot.com/_dLfQMJsmsaI/SdvwPx8hz5I/AAAAAAAAACY/I_DEfn6nQjc/s1600-h/ae_gwt_java.png"&gt;&lt;img align="left" border="0" src="http://3.bp.blogspot.com/_VZZAFHl2_Og/Sd_WGUS8IkI/AAAAAAAACqk/_ayMUzSXYoQ/s320/s200_h_ae_gwt_java.png" style="margin-right:10px;margin-bottom:10px;margin-top:10px;"/&gt;&lt;/a&gt;On April 7, three days ago, Google people announced and demonstrated the new support of the Java programming language in Google App Engine ecosystem [1].&lt;br /&gt;
&lt;br /&gt;
Before starting my side project [2], I was mostly a Java[3] adopter on back-end servers. Java is widely supported and have a large and active contributing community (to its core &lt;i&gt;via&lt;/i&gt; the Java Community Process (JCP) [3] or to 3rd party libraries).&lt;br /&gt;
&lt;br /&gt;
&lt;img align="right" src="http://www.python.org/images/python-logo.gif" /&gt;Once I decided to go with GAE, I invested a bit in improving my knowledge of Python [4], for example by looking at the WSGI specification [4] and at Django [4]. I have been impressed about the integration done by GAE people, about how easy it is to program complex steps in very few lines! My favorite part is the main function to dispatching events:&lt;br /&gt;
&lt;pre class="prettyprint"&gt;# -*- coding: utf-8 -*-

# Handlers
...

# Dispatcher
application = webapp.WSGIApplication(
    [
        ('/API/requests', RequestList),
        (r'^/API/requests/(.+)$', Request),
    ],
    debug=True
)

def main():
    run_wsgi_app(application)

if __name__ == "__main__":
    main()&lt;/pre&gt;&lt;br /&gt;
Implementing a REST API, the &lt;code&gt;RequestList&lt;/code&gt; class defines &lt;code&gt;get(self)&lt;/code&gt; to return selected resources, and &lt;code&gt;put(self)&lt;/code&gt; to create the proposed resource. The &lt;code&gt;Request&lt;/code&gt; class defines &lt;code&gt;get(self, key)&lt;/code&gt; for the identified resource retrieval, &lt;code&gt;post(self, key)&lt;/code&gt; to update the identified resource, and &lt;code&gt;delete(self, key)&lt;/code&gt; to delete the identified resource.&lt;br /&gt;
&lt;br /&gt;
&lt;img align="right" height="143" src="http://blogs.sun.com/jonathan/resource/java_smi_logo_rgb.jpg" width="80" style="margin-left: 10px;margin-bottom:10px;"/&gt;In the J2EE world, with the &lt;code&gt;web.xml&lt;/code&gt; file forwarding &lt;code&gt;/requests&lt;/code&gt; URLs to a servlet (as done in the &lt;code&gt;app.yaml&lt;/code&gt; file), the servlet code will have to get the URI (with &lt;code&gt;HttpServletRequest.getPathInfo()&lt;/code&gt;) and will have to parse it in order to detect the possible request identifier and the possible version number. IMO, Python offers slicker interface.&lt;br /&gt;
&lt;br /&gt;
Another example is the support of the JPA and the JDO [5] specifications: few annotations decorating the Data Transfer Object (DTO) class definitions allow GAE/J to deal with the persistence layer (&lt;i&gt;i.e.&lt;/i&gt; BigTable). Compared with the Python model definitions, the &lt;i&gt;getter&lt;/i&gt;s and &lt;i&gt;setter&lt;/i&gt;s plus the annotations seem overkill, but are necessary.&lt;br /&gt;
&lt;br /&gt;
With Python allowing to rely on a more compact code, why would I switch to Java?&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Even if I gave directions on how to test GAE/P applications [6], I should admit testing GAE/J code is easier: JUnit is &lt;i&gt;de facto&lt;/i&gt; standard copied by many frameworks, and JCoverage is the tool helping to determine the quality of these unit tests. While working on an open source project, with possibly contributors from various horizons, relying on a strong testing infrastructure is a top priority. It is then possible I will go over the Java tradeoff in a near future...&lt;/li&gt;
&lt;li&gt;The Java Virtual Machine (JVM) ported on GAE opens the door to many other languages, as reported by App Engine Fan [7]. I have a personal interest in the port of JavaScript language, processed by Rhino, the Mozilla JavaScript engine. I would be nice to be able to run the Dojo build process on GAE itself ;)&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
A+, Dom&lt;br /&gt;
--&lt;br /&gt;
Sources:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;&lt;a href="http://googleblog.blogspot.com/2009/04/new-features-and-early-look-at-java-for.html"&gt;New features and an early look at Java for App Engine&lt;/a&gt; on Google official blog and &lt;a href="http://googleappengine.blogspot.com/2009/04/seriously-this-time-new-language-on-app.html"&gt;Seriously this time, the new language on App Engine: Java™&lt;/a&gt; of Google App Engine Blog.&lt;/li&gt;
&lt;li&gt;Announcement in preparation this time.&lt;/li&gt;
&lt;li&gt;Java &lt;a href="http://en.wikipedia.org/wiki/Java_%28programming_language%29"&gt;history&lt;/a&gt; on Wikipedia, on &lt;a href="http://java.sun.com/"&gt;Sun microsystems&lt;/a&gt; website, on &lt;a href="http://www.ibm.com/developerworks/java"&gt;IBM developerWorks&lt;/a&gt; website; site of the &lt;a href="http://jcp.org/"&gt;Java Community Process&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Key components of GAE/P: &lt;a href="http://www.python.org/"&gt;Python&lt;/a&gt;, &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt; and its &lt;a href="http://docs.djangoproject.com/en/dev/topics/templates/"&gt;template language&lt;/a&gt;, &lt;a href="http://www.wsgi.org/wsgi/"&gt;WSGI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Description of standards supported on GAE/J: &lt;a href="http://google-code-updates.blogspot.com/2009/04/standards-based-persistence-for-java.html"&gt;Standards-based Persistence For Java™ Apps On Google App Engine&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://domderrien.blogspot.com/2009/01/automatic-testing-of-gae-applications.html"&gt;Automatic Testing of GAE Applications&lt;/a&gt; from the series &lt;a href="http://domderrien.blogspot.com/2009/01/web-application-on-resources-in-cloud.html"&gt;Web Application on Resources in the Cloud&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.appenginefan.com/2009/04/hand-me-kool-aid.html"&gt;Hand me the Kool-Aid :-)&lt;/a&gt; by App Engine Fan.&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-1750575646543249261?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=8dZFP7McMbc:D-MLYK4joPc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=8dZFP7McMbc:D-MLYK4joPc:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=8dZFP7McMbc:D-MLYK4joPc:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=8dZFP7McMbc:D-MLYK4joPc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=8dZFP7McMbc:D-MLYK4joPc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/8dZFP7McMbc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/1750575646543249261/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/04/google-app-engine-meets-java.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/1750575646543249261?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/1750575646543249261?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/8dZFP7McMbc/google-app-engine-meets-java.html" title="Google App Engine Meets Java" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_VZZAFHl2_Og/Sd_WGUS8IkI/AAAAAAAACqk/_ayMUzSXYoQ/s72-c/s200_h_ae_gwt_java.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/04/google-app-engine-meets-java.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEINRH4zeip7ImA9WxVbEU8.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-4466477430404647888</id><published>2009-03-26T21:19:00.014-04:00</published><updated>2009-03-26T22:56:35.082-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-26T22:56:35.082-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Experience" /><category scheme="http://www.blogger.com/atom/ns#" term="Community" /><title>Guy Kawasaki's keynote in Montréal</title><content type="html">Yesterday, I attended a keynote presented by Guy Kawasaki in Montréal. It was a real fun to listen to him. He is a great communicator.&lt;br /&gt;
&lt;br /&gt;
I found many commonalities with my blog post &lt;a href="http://domderrien.blogspot.com/2008/12/career-advice.html"&gt;Career Advice'08&lt;/a&gt;, and with Tim O'Reilly's message “Work On Stuff That Matters.” So the gap to adhere to Guy's recommendations was small.&lt;br /&gt;
&lt;br /&gt;
Here is a report written by Jean-François Ferland, for the magazine Direction Informatique. If I want to reproduce it here, it's mainly because it is then ad-free ;) You can find the original version on &lt;a href="http://www.directioninformatique.com/DI/client/fr/DirectionInformatique/Nouvelles.asp?sub=true&amp;id=52570"&gt;Direction Informatique&lt;/a&gt; website.&lt;br /&gt;
&lt;br /&gt;
Good reading,&lt;br /&gt;
A+, Dom&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: lightyellow; margin:0 30px; padding: 10px; border: 1px solid lightgrey;"&gt;&lt;div style="text-align:center;"&gt;&lt;a href="http://www.directioninformatique.com/DI/client/fr/DirectionInformatique/Nouvelles.asp?sub=true&amp;id=52570"&gt;&lt;img border="0" src="http://www.directioninformatique.com/DI/image/fr/logo-emailartcile.gif"/&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size:larger;"&gt;Kawasaki: innover est un art... sous le signe de l'humour&lt;/span&gt;&lt;br /&gt;
26/03/2009 - &lt;i&gt;Jean-François Ferland&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Guy Kawasaki, un ancien «&amp;nbsp;évangéliste&amp;nbsp;» d'Apple, suggère aux entreprises en démarrage dix règles pour se démarquer auprès des consommateurs et se faire remarquer par les anges investisseurs. Compte-rendu d'une allocution qui a bien fait rire l'auditoire.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="float:right;margin-left: 10px;border: 1px solid lightgrey; padding: 5px;background-color:white;"&gt;&lt;img src="http://www.directioninformatique.com/upload/DI/News/zGuy_K396.jpg"&gt;&lt;br /&gt;
Guy Kawasaki&lt;br /&gt;
Photo: David Sifry.&lt;br /&gt;
Licence: CC-by-2.0&lt;br /&gt;
&lt;/div&gt;La plupart des allocutions se suivent et se ressemblent. Or, il arrive qu'un conférencier se démarque par ses propos, par son ton et par la forme de son allocution, sans causer l'ennui ou un sentiment de déjà-vu. &lt;br /&gt;
&lt;br /&gt;
Au Club St-James de Montréal, dans le cadre de la deuxième édition de l'événement &lt;a class="red" target="_blank" href="http://www.capitalinnovation.ca/"&gt;Capital Innovation&lt;/a&gt; qui réunissait des entreprises en démarrage du Québec et des investisseurs, le conférencier Guy Kawasaki a décidément retenu l'attention des invités.&lt;br /&gt;
&lt;br /&gt;
M. Kawasaki, un Californien d'origine hawaïenne, est le fondateur de &lt;a class="red" target="_blank" href="http://www.garage.com"&gt;Garage Technology Ventures&lt;/a&gt;, une entreprise qui fait du maillage entre les anges investisseurs et les entreprises en démarrage, en cherchant «&amp;nbsp;deux gars, un gars et une fille ou deux filles dans un garage qui développent 'la prochaine chose importante'&amp;nbsp;». &lt;br /&gt;
&lt;br /&gt;
Il est surtout connu pour son ancien rôle «&amp;nbsp;d'évangéliste&amp;nbsp;» pour les nouvelles technologies chez Apple lors de son deuxième séjour chez le fabricant de produits de 1995 à 1997. Lors de son premier passage, de 1983 à 1987, dans la division Macintosh, son rôle était de convaincre les gens d'écrire des logiciels pour les ordinateurs d'une entreprise «&amp;nbsp;qui comptait le plus grand nombre d'égomaniaques, un record qui a été depuis battu par Google&amp;nbsp;». &lt;br /&gt;
&lt;br /&gt;
Après avoir clamé son amour pour le hockey, un sport qu'il a commencé à pratiquer en Californie en même temps que ses fils à l'âge de 48 ans (!), M. Kawasaki a entamé sa conférence qui consistait en dix recommandations à l'intention des entreprises en démarrage dans le domaine des TIC. &lt;br /&gt;
&lt;br /&gt;
Ses propos étaient parsemés d'humour, ce qui a plu à la foule de plus d'une centaine de personnes. «&amp;nbsp;J'ai écouté bien des chefs de la direction lors de conférences comme le Comdex. Souvent ils étaient 'poches' et prenaient beaucoup de temps&amp;nbsp;», a-t-il lancé en riant.&lt;br /&gt;
&lt;br /&gt;
Voici brièvement ses dix recommandations portant sur l'art de l'innovation, accompagnées de courtes explications (et de remarques amusantes).&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;1. Faire quelque chose qui a du sens&lt;/b&gt; M. Kawasaki affirme qu'une entreprise en démarrage ou un innovateur doit vouloir faire quelque chose en premier lieu avec l'intention que cela fera du sens, en opposition à vouloir faire de l'argent avant tout, ce qui sera une conséquence naturelle de la première intention.&lt;br /&gt;
&lt;br /&gt;
«&amp;nbsp;Si une entreprise est démarrée avant tout pour faire de l'argent, elle attirera les mauvais cofondateurs, et les détenteurs de MBA sont les pires, a dit M. Kawasaki. Comment évalue-t-on la valeur d'une entreprise en prédémarrage? Ma règle est que chaque ingénieur à temps plein fait monter sa valeur d'un demi-million, mais chaque MBA la fait baisser d'un demi-million.&amp;nbsp;» &lt;br /&gt;
&lt;b&gt;&lt;br /&gt;
2. Se faire un mantra&lt;/b&gt; M. Kawasaki s'est demandé à voix haute pourquoi les entreprises ne pouvaient décrire leur raison d'être en deux ou trois mots. Il a décrit la méthode nord-américaine de création d'un énoncé de mission, où les dirigeants d'une entreprise de réunissent deux jours dans un hôtel près d'un terrain de golf, avec un consultant en motivation «&amp;nbsp;parce que personne dans l'équipe ne sait comment communiquer&amp;nbsp;». La première journée est consacrée à faire des activités de mise en confiance et la deuxième à écrire des idées au crayon feutre sur du papier adossé à un présentoir.&lt;br /&gt;
&lt;br /&gt;
«&amp;nbsp;On tente alors d'énoncer ce qui est bon pour les actionnaires, les dirigeants, les employés, les consommateurs, les baleines et les dauphins. C'est souvent trop long, il y a trop d'expertise et on ne peut comprendre si on enlève le nom de l'entreprise. Il faut dire en trois mots ce que l'on fait&amp;nbsp;», a-t-il dit.&lt;br /&gt;
&lt;p&gt;&lt;b&gt;3. Sauter sur la prochaine courbe&lt;/b&gt; M. Kawasaki a affirmé que l'innovation survient lorsqu'une organisation sort de la trajectoire qu'elle suit ou qu'elle saute dans une nouvelle courbe. Il a donné l'exemple des coupeurs de glace des années 1900, de la version 2.0 à l'ère des usines de fabrication de glace, puis de la version 3.0 des réfrigérateurs à la maison. «&amp;nbsp;Aucun des coupeurs de glace n'a bâti de fabrique de glace&amp;nbsp;», a-t-il souligné, et sont carrément disparus.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;4. Rouler les dés&lt;/b&gt; L'innovation prend forme lorsque l'entreprise prend le risque de faire le saut vers une autre courbe. En faisant un acronyme avec le mot Dicee - une altération inventée du mot «&amp;nbsp;dé&amp;nbsp;» en anglais, dont toutes les définitions sur Internet réfèrent au conférencier - M. Kawasaki a suggéré que l'innovation impliquait de la profondeur (Deep) par l'ajout de fonctions, de l'Intelligence lorsqu'on soulage une difficulté pour le consommateur, une expérience totale (Complete), de l'Élégance parce que le produit fonctionne lorsqu'on le branche et de l'Émotivité parce que les personnes l'aiment ou le détestent, sans zone grise.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;5. Lancer maintenant, corrigez plus tard&lt;/b&gt; C'est ainsi qu'on pourrait traduire l'expression Don't worry, be crappy - inspirée par la chanson de Bobby McFerrin. M. Kawasaki a affirmé qu'une innovation a forcément des défauts et que ceux qui attendent qu'elle soit parfaite ne font pas de ventes entre-temps. «&amp;nbsp;Le produit mis en marché ne doit pas être tout mauvais (crap), mais avoir juste un peu de mauvais. Le Apple 128 était un mauvais produit révolutionnaire!&amp;nbsp;»&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;6. Polariser les gens&lt;/b&gt; M. Kawasaki a répété qu'une innovation audacieuse sera inévitablement aimée ou détestée par les gens, en donnant l'exemple de l'enregistreur numérique personnel Tivo que n'aiment pas les agences de pubs parce qu'elle permet d'éviter de regarder des messages publicitaires. «&amp;nbsp;Le véhicule Scion de Toyota est vu comme étant cool par les gens de 27 ans et comme un réfrigérateur par les gens de 55 ans. On ne peut pas plaire à tout le monde, mais il ne faut pas en faire fâcher de façon intentionnelle. Cela n'arrive jamais que tout le monde aime un produit.&amp;nbsp;»&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;7. Laisser cent fleurs éclore&lt;/b&gt; M. Kawasaki a indiqué qu'un produit innovant peut mener à des utilisations non intentionnelles, par des utilisateurs qui n'étaient pas ciblés à l'origine. Il donne l'exemple d'une crème de la compagnie Avon qui rend la peau douce, mais que les mères utilisent... comme chasse-insectes! Il a aussi évoqué la console de jeu vidéo Wii de Nintendo, destiné aux enfants, qui fait un malheur auprès des personnes âgées.&lt;br /&gt;
&lt;br /&gt;
«&amp;nbsp;Si cela vous arrive, prenez l'argent!, dit-il en riant. En 1984, Apple pensait que le Macintosh servirait au calcul dans les chiffriers, aux bases de données et au traitement de texte. Arrive PageMaker, qui a créé l'éditique et a sauvé Apple. Sans l'éditique, nous écouterions encore de la musique sur des cassettes de 60 minutes!&amp;nbsp;»&lt;br /&gt;
&lt;br /&gt;
«&amp;nbsp;En ingénierie, je recommande d'aller voir ceux qui achètent les produits pour savoir ce qu'ils veulent. Chez Apple nous avions demandé aux entreprises Fortune 500 pourquoi elles n'achetaient pas nos ordinateurs. Nous leur avons créé un pilote d'impression, comme ils avaient suggéré, mais ensuite ils ont trouvé d'autres excuses...&amp;nbsp;», a-t-il ajouté.&lt;br /&gt;
&lt;/p&gt;&lt;p&gt;&lt;b&gt;8. Vivre dans le déni&lt;/b&gt; M. Kawasaki a indiqué que la chose la plus difficile à faire en innovation est de refuser d'écouter ceux qui diront que c'est impossible à faire, que personne n'achètera le produit ou que personne ne fournira du financement. «&amp;nbsp;On vous donnera 60 raisons. Ignorez-les. Mais une fois que le produit est lancé, virez votre capot et passez en mode 'écoute'. [Entre ces deux approches,] c'est le passage en zone neutre qui est le plus difficile&amp;nbsp;», a-t-il confié. Comme au hockey.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;9. Trouvez votre niche&lt;/b&gt; M. Kawasaki a évoqué un graphique pour une innovation où l'axe vertical décrit son niveau d'unicité et l'axe horizontal sa valeur, en affirmant que l'entreprise veut se situer en haut et à droite. «&amp;nbsp;Un produit qui est unique et n'a pas de valeur ne doit pas exister. C'est comme offrir le curling aux États-Unis!&amp;nbsp;»&lt;br /&gt;
&lt;br /&gt;
Pour décrire une innovation qui n'a ni valeur ni unicité, M. Kawasaki a relaté le cas de Pets.com qui vendait en ligne de la nourriture pour chien. «&amp;nbsp;L'enjeu en était un de gestion de la chaîne d'approvisionnement. Ils se disaient capables d'éliminer les magasins, cet intermédiaire qui prenait une marge de 25 %, en livrant directement aux propriétaires de chiens. Mais des vaches mortes en conserve pèsent lourd [en frais de livraison]. C'était plus cher et pas plus pratique...&amp;nbsp;»&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;10. La règle du 10-20-30&lt;/b&gt; La dernière règle suggérée par M. Kawasaki aux entreprises en TIC en est une qui servira lors des présentations aux anges investisseurs. «&amp;nbsp;Utilisez 10 diapositives. Ne lisez pas vos diapositives - les gens savent lire. Le mieux est de ne pas avoir de diapositives! Aussi, expliquez votre produit ou votre projet en 20 minutes. De toute façon, 95 % des gens prennent 40 minutes d'une présentation d'une heure pour brancher leur portable avec leur projecteur.&amp;nbsp;»&lt;br /&gt;
&lt;br /&gt;
«&amp;nbsp;Enfin, utilisez une taille de caractères de 30 points. Prenez la plus vieille personne dans l'auditoire, divisez son âge en deux et vous aurez la taille idéale. Comme les anges investisseurs deviennent plus jeunes, bientôt vous utiliserez une taille de 8 points!&amp;nbsp;» a ajouté le conférencier, ce qui a suscité l'hilarité dans la salle.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;(En bonus) 11. Ne laissez pas les «&amp;nbsp;bozos&amp;nbsp;» vous décourager&lt;/b&gt; En terminant, M. Kawasaki a suggéré aux entrepreneurs de ne pas se laisser abattre par les clowns qui les décourageront. &lt;br /&gt;
&lt;br /&gt;
«&amp;nbsp;Il y a deux types de clowns : le premier est mal coiffé, n'a pas d'aptitudes sociales et démontre qu'il est un perdant. Le deuxième, qui conduit une voiture allemande et porte un beau complet, est le plus dangereux. La moitié du temps, il est devenu riche et célèbre par chance&amp;nbsp;», a-t-il déclaré.&lt;br /&gt;
&lt;br /&gt;
Au terme de cette allocution, nous pourrions recommander aux entreprises une douzième règle : faites des présentations amusantes et animées comme celle de M. Kawasaki!&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&lt;a href="mailto:jfferland@directioninformatique.com"&gt;&lt;font color="RED"&gt;Jean-François Ferland&lt;/font&gt;&lt;/a&gt; est journaliste au magazine&lt;/i&gt; Direction informatique.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-4466477430404647888?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=8D7v02Zccto:eAFQBHGFJBc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=8D7v02Zccto:eAFQBHGFJBc:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=8D7v02Zccto:eAFQBHGFJBc:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=8D7v02Zccto:eAFQBHGFJBc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=8D7v02Zccto:eAFQBHGFJBc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/8D7v02Zccto" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/4466477430404647888/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/03/guy-kawasakis-keynote-in-montreal.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/4466477430404647888?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/4466477430404647888?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/8D7v02Zccto/guy-kawasakis-keynote-in-montreal.html" title="Guy Kawasaki's keynote in Montréal" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/03/guy-kawasakis-keynote-in-montreal.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUEERnc8eyp7ImA9WxJWFkU.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-8483852735939545674</id><published>2009-03-17T21:35:00.006-04:00</published><updated>2009-06-22T11:13:27.973-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-22T11:13:27.973-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Technology" /><category scheme="http://www.blogger.com/atom/ns#" term="Experience" /><title>MVC Pattern and REST API Applied to GAE Applications</title><content type="html">(This post is part of the series&amp;nbsp;&lt;a href="http://domderrien.blogspot.com/2009/01/web-application-on-resources-in-cloud.html" style="color: #de7008;"&gt;Web Application on Resources in the Cloud&lt;/a&gt;.)&lt;br /&gt;
&lt;br /&gt;
I have been developing applications for various categories of end-users since 1990. I coded front-ends in X/Motif [1] for Solaris, then in Borland OWL and Windows MFC for Windows [2], then HTML/JavaScript for Web browsers. Most of the time for good reasons, JavaScript has been considered as a hacking language: to do quick and dirty fixes. Anyway, I have always been able to implement the MVC pattern:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;My first enterprise Web applications was relying on a back-end written in C++ for a FastCGI run by Apache [3]. I wrote a HTML template language which, in some ways, was similar to the JSP concept [4].&lt;/li&gt;
&lt;li&gt;The second version of this administrative console was relying on JavaScript for the rendering (a-la Dojo parser) and was using frames to keep context and to handle asynchronous communication.&lt;/li&gt;
&lt;li&gt;Then I learned about XMLHttpRequest [5], and with a great team, I started building a JavaScript framework to be able to handle complex operations and screen organizations within an unique Web page. We came up with a large widget library and a custom set of data models.&lt;/li&gt;
&lt;li&gt;After a job change, I discovered Dojo [6] in its early days (0.2 to 0.4) and I closely followed the path to get to 1.0. With Dojo, I am now able to relax client-side because the widget library is really huge, while still easy to extend, and it has advanced data binding capabilities. Now, I can focus on the middle-tier to build efficient REST APIs.&lt;/li&gt;
&lt;/ul&gt;Among the design patterns [7],&amp;nbsp;Model-View-Controller (MVC) is maybe one of the most complex (it is a combination of many basic patterns: Strategy, Composite, Observer) and maybe the one with the most various interpretations. I did write my own guidelines when I ported the MVC pattern browser-side (proprietary work). Today, Kris Zip blog entry on SitePen side summarizes nicely my approach: &lt;a href="http://www.sitepen.com/blog/2008/07/18/clientserver-model-on-the-web/"&gt;Client/Server Model on the Web&lt;/a&gt;. The following diagrams illustrate the strategy evolution.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;img src="http://www.sitepen.com/blog/wp-content/uploads/2008/06/clientserver.png" title="Traditional Web Applications" /&gt;&amp;nbsp; &amp;nbsp;&lt;img src="http://www.sitepen.com/blog/wp-content/uploads/2008/06/clientserver2.png" title="Evolution of the MVC pattern browser-side" /&gt;&lt;br /&gt;
Credits: &lt;a href="http://www.sitepen.com/blog/2008/07/18/clientserver-model-on-the-web/"&gt;SitePen&lt;/a&gt;.&lt;/div&gt;In Google App Engine documentation, Django [8] is the template language proposed to separate the View building from the Model manipulation. Django implements the “Traditional Web Application” approach illustrated above.&lt;br /&gt;
&lt;br /&gt;
My initial concern about the traditional approach is the absence of a clean and public API to control the Model. It is not rare that APIs are considered as add-ons, as optional features. IMHO, APIs should be among the first defined elements: it helps defining the scope of the work, it helps defining iterations (in the Agile development spirit), it helps writing tests up-front, it helps isolating bottlenecks.&lt;br /&gt;
&lt;br /&gt;
With the move of the MVC pattern browser-side, the need to define a server-side API becomes obvious. The Model is now ubiquitous: interactive objects client-side have no direct interaction with the back-end server, they just interact with the Model proxy. This proxy can fetch data on demand, can pre-fetch data, forwards most of the update requests immediately but can delay or abort (to be replayed later) idempotent ones.&lt;br /&gt;
&lt;br /&gt;
My favorite API template for the server-side logic is the RESTful API [9]. It is simple to implement, simple to mock, and simple to test. For my side project [10], the repository contains descriptions of products made available by micro entrepreneurs (see table 1).&lt;br /&gt;
&lt;br /&gt;
&lt;table&gt;&lt;caption&gt;Table 1: Samples of RESTful HTTP requests&lt;/caption&gt; &lt;tbody&gt;
&lt;tr style="background-color: black; border: 1px solid black;"&gt; &lt;th style="color: white; font-weight: bold; text-align: center;padding: 0 10px;"&gt;Verb&lt;/th&gt; &lt;th style="color: white; font-weight: bold; text-align: center;padding: 0 10px;"&gt;URL pattern&lt;/th&gt; &lt;th style="color: white; font-weight: bold; text-align: center;padding: 0 10px;"&gt;Description&lt;/th&gt; &lt;/tr&gt;
&lt;tr style="background-color: grey; border: 1px solid black;"&gt; &lt;td style="padding: 0pt 10px;"&gt;GET&lt;/td&gt; &lt;td style="padding: 0pt 10px;"&gt;&lt;code style="color:darkgreen;"&gt;/API/products&lt;/code&gt;&lt;/td&gt; &lt;td style="padding: 0pt 10px;"&gt;Return HTTP code 200 and the list of all products, or the list of the ones matching the specified criteria.&lt;/td&gt; &lt;/tr&gt;
&lt;tr style="background-color: grey; border: 1px solid black;"&gt; &lt;td style="padding: 0pt 10px;"&gt;GET&lt;/td&gt; &lt;td style="padding: 0pt 10px;"&gt;&lt;code style="color:darkgreen;"&gt;/API/products/{productId}&lt;/code&gt;&lt;/td&gt; &lt;td style="padding: 0pt 10px;"&gt;Return HTTP code 301 with the versioned URL for the identified product, or HTTP code 404 if the identified product is not found.&lt;/td&gt; &lt;/tr&gt;
&lt;tr style="background-color: grey; border: 1px solid black;"&gt; &lt;td style="padding: 0pt 10px;"&gt;GET&lt;/td&gt; &lt;td style="padding: 0pt 10px;"&gt;&lt;code style="color:darkgreen;"&gt;/API/products/{productId}/{version}&lt;/code&gt;&lt;/td&gt; &lt;td style="padding: 0pt 10px;"&gt;Return HTTP code 200 and the attributes of the identified product for the specified version, or HTTP code 301 "Move Permanently" with a URL containing the new &lt;code&gt;version&lt;/code&gt; information, or HTTP code 404 if the product is not found.&lt;/td&gt; &lt;/tr&gt;
&lt;tr style="background-color: grey; border: 1px solid black;"&gt; &lt;td style="padding: 0pt 10px;"&gt;DELETE&lt;/td&gt; &lt;td style="padding: 0pt 10px;"&gt;&lt;code style="color:darkgreen;"&gt;/API/products/{productId}/{version}&lt;/code&gt;&lt;/td&gt; &lt;td style="padding: 0pt 10px;"&gt;Return HTTP code 200 if the deletion is successful, or HTTP code 303 or 404 if needed.&lt;/td&gt; &lt;/tr&gt;
&lt;tr style="background-color: grey; border: 1px solid black;"&gt; &lt;td style="padding: 0pt 10px;"&gt;POST&lt;/td&gt; &lt;td style="padding: 0pt 10px;"&gt;&lt;code style="color:darkgreen;"&gt;/API/products&lt;/code&gt;&lt;/td&gt; &lt;td style="padding: 0pt 10px;"&gt;Return HTTP code 201 if the creation is successful with the new product identifier and its version number.&lt;/td&gt; &lt;/tr&gt;
&lt;tr style="background-color: grey; border: 1px solid black;"&gt; &lt;td style="padding: 0pt 10px;"&gt;PUT&lt;/td&gt; &lt;td style="padding: 0pt 10px;"&gt;&lt;code style="color:darkgreen;"&gt;/API/products/{productId}/{version}&lt;/code&gt;&lt;/td&gt; &lt;td style="padding: 0pt 10px;"&gt;Return HTTP code 200 if the update is successful with the new product version number, or HTTP codes 303 or 404 if needed.&lt;/td&gt; &lt;/tr&gt;
&lt;/tbody&gt; &lt;/table&gt;&lt;br /&gt;
&lt;table style="width: 400px;"&gt;&lt;tbody&gt;
&lt;tr style="background-color: black; border: 1px solid black;padding: 0 10px;"&gt;&lt;th style="color: white; font-weight: bold; text-align: center;padding: 0 10px;"&gt;HTTP Code&lt;/th&gt;&lt;th style="color: white; font-weight: bold; text-align: center;"&gt;Description&lt;/th&gt;&lt;/tr&gt;
&lt;tr style="background-color: grey; border: 1px solid black;"&gt;&lt;td style="padding: 0pt 10px;"&gt;200&lt;/td&gt;&lt;td style="padding: 0pt 10px;"&gt;OK&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="background-color: grey; border: 1px solid black;"&gt;&lt;td style="padding: 0pt 10px;"&gt;201&lt;/td&gt;&lt;td style="padding: 0pt 10px;"&gt;Created&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="background-color: grey; border: 1px solid black;"&gt;&lt;td style="padding: 0pt 10px;"&gt;301&lt;/td&gt;&lt;td style="padding: 0pt 10px;"&gt;Moved Permanently&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="background-color: grey; border: 1px solid black;"&gt;&lt;td style="padding: 0pt 10px;vertical-align:top;"&gt;303&lt;/td&gt;&lt;td style="padding: 0pt 10px;"&gt;See Other&lt;br /&gt;
&lt;span style="background-color: lightgrey;"&gt;“The response to the request can be found under another URI using a GET method. When received in response to a PUT or POST, it should be assumed that the server has received the data and the redirect should be issued with a separate GET message.”&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="background-color: grey; border: 1px solid black;"&gt;&lt;td style="padding: 0pt 10px;"&gt;304&lt;/td&gt;&lt;td style="padding: 0pt 10px;"&gt;Not Modified&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="background-color: grey; border: 1px solid black;"&gt;&lt;td style="padding: 0pt 10px;"&gt;307&lt;/td&gt;&lt;td style="padding: 0pt 10px;"&gt;Temporary Redirect&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="background-color: grey; border: 1px solid black;"&gt;&lt;td style="padding: 0pt 10px;"&gt;400&lt;/td&gt;&lt;td style="padding: 0pt 10px;"&gt;Bad Request&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="background-color: grey; border: 1px solid black;"&gt;&lt;td style="padding: 0pt 10px;"&gt;401&lt;/td&gt;&lt;td style="padding: 0pt 10px;"&gt;Unauthorized&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="background-color: grey; border: 1px solid black;"&gt;&lt;td style="padding: 0pt 10px;"&gt;404&lt;/td&gt;&lt;td style="padding: 0pt 10px;"&gt;Resource Not Found&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="background-color: grey; border: 1px solid black;"&gt;&lt;td style="padding: 0pt 10px;"&gt;410&lt;/td&gt;&lt;td style="padding: 0pt 10px;"&gt;Gone&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="background-color: grey; border: 1px solid black;"&gt;&lt;td style="padding: 0pt 10px;"&gt;500&lt;/td&gt;&lt;td style="padding: 0pt 10px;"&gt;Internal Server Error&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="background-color: grey; border: 1px solid black;"&gt;&lt;td style="padding: 0pt 10px;"&gt;501&lt;/td&gt;&lt;td style="padding: 0pt 10px;"&gt;Not Implemented&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt; &lt;caption&gt;Table 2: Partial list of HTTP status codes (see details in [11]).&lt;/caption&gt;   &lt;/table&gt;&lt;br /&gt;
Parsing RESTful API for Google App Engine application is not difficult. It is just a matter of using regular expressions in the &lt;code&gt;app.yaml&lt;/code&gt; configuration file and in the corresponding Python script file.&lt;br /&gt;
&lt;pre class="prettyprint"&gt;application: prod-cons
version: 1
runtime: python
api_version: 1

handlers:
- url: /API/products.*
  script: py/products.py

- url: /html
  static_dir: html

- url: /.*
  static_files: html/redirect.html
  upload: html/redirect.html&lt;/pre&gt;&lt;div style="text-align:center;"&gt;Code 1: Excerpt of the &lt;code&gt;app.yaml&lt;/code&gt; configuration file.&lt;/div&gt;&lt;pre class="prettyprint"&gt;# -*- coding: utf-8 -*-

import os

from google.appengine.api import users
from google.appengine.ext import db
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app

from prodcons import common
from prodcons import model

class ProductList(webapp.RequestHandler):
    def get(self):
        # Get all products
        # ...
    def post(self, productId, version):
        # Create new product
        # ...

class Product(webapp.RequestHandler):
    def get(self, productId, version):
        # Get identified product
        # ...
    def delete(self, productId, version):
        # Delete identified product
        # ...
    def put(self, productId, version):
        # Update identified product
        # ...

application = webapp.WSGIApplication(
    [
        ('/API/products', ProductList),
        (r'^/API/products/(\w+)/(\d+)$', Product),
    ],
    debug=True
)

def main():
    # Global initializations
    # ...
    run_wsgi_app(application)

if __name__ == "__main__":
    main()&lt;/pre&gt;&lt;div style="text-align:center;"&gt;Code 2: Excerpt of the Python file processing product-related requests&lt;/div&gt;&lt;br /&gt;
Note that the second code sample shows an ideal situation. In reality, I had to change the verb &lt;code&gt;PUT&lt;/code&gt; when updating product definitions because the method &lt;code&gt;self.request.get()&lt;/code&gt; cannot extract information from the stream&amp;mdash;it does only  work for &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt; verbs. The corresponding client-side code relies on &lt;code&gt;dojo.xhrPost()&lt;/code&gt; instead of &lt;code&gt;dojo.xhrPut()&lt;/code&gt;. If you know the fix or a work-around, do not hesitate to post a comment ;)&lt;br /&gt;
&lt;br /&gt;
While developing application front-ends, developers should always rely on the MVC pattern to separate the data from user interface, to separate the data flows from the interaction processing. IMHO, organizing the server-side interface as a RESTful API is very clean and efficient. If you use Dojo to build your JavaScript application, you can even rely on their implementation of various RESTful data sources [12] to simplify your work.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align:center;"&gt;&lt;img src="http://www.sitepen.com/blog/wp-content/uploads/2008/06/jsonrest-servicestore.png" title="JsonRestStore and ServiceStore Organization"&gt;&lt;br /&gt;
Credits: &lt;a href="http://www.sitepen.com/blog/2008/06/13/restful-json-dojo-data/"&gt;SitePen&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Pushing the MVC pattern browser-side has nasty side-effects when too much information are managed by the Model proxy:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Large data sets consume a lot of memory.&lt;/li&gt;
&lt;li&gt;HTTP connections being a rare resource sometimes unreliable, rescheduling requests (important ones first, non important to be replayed later) or replaying requests (because Microsoft Internet Explorer status reports &lt;code&gt;WSAETIMEDOUT&lt;/code&gt; for example) complexify the data flows.&lt;/li&gt;
&lt;li&gt;Fine grain API consumes a lot of bandwidth especiallywhen the ratio data &lt;i&gt;vs&lt;/i&gt; envelope is negative).&lt;/li&gt;
&lt;li&gt;Applications have often too few entry points, hiding then the benefit of one URI per resource (intrinsic REST value).&lt;/li&gt;
&lt;li&gt;In highly volatile environments, data synchronization become rapidly a bottleneck if there is no &lt;i&gt;push&lt;/i&gt; channel.&lt;/li&gt;
&lt;/ul&gt;So the application performance (response time and memory consumption) should be carefully monitored during the development. If applications with the MVC pattern organized browser-side and relying on RESTful APIs cannot do everything, they are definitively worth prototyping before starting the development of any enterprise application or application for high availability environments.&lt;br /&gt;
&lt;br /&gt;
A+, Dom&lt;br /&gt;
--&lt;br /&gt;
Sources:&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Motif_(widget_toolkit)"&gt;Motif definition&lt;/a&gt; on wikipedia and online book introducing &lt;a href="http://www.cs.cf.ac.uk/Dave/X_lecture/"&gt;X/Motif programming&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;History of &lt;a href="http://en.wikipedia.org/wiki/Object_Windows_Library"&gt;Borland Object Windows Library&lt;/a&gt; (OWL) on wikipedia and its positioning against Microsoft Foundation Class (MFC) library.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.fastcgi.com/"&gt;FastCGI&lt;/a&gt; website, and its &lt;a href="http://en.wikipedia.org/wiki/FastCGI"&gt;introduction&lt;/a&gt; on wikipedia.&lt;/li&gt;
&lt;li&gt;Presentation of the &lt;a href="http://java.sun.com/products/jsp/"&gt;JavaServer Pages&lt;/a&gt; (JSP) technology on SUN website.&lt;/li&gt;
&lt;li&gt;History of &lt;a href="http://en.wikipedia.org/wiki/XMLHttpRequest"&gt;XMLHttpRequest&lt;/a&gt; on wikipedia, and its &lt;a href="http://www.w3.org/TR/XMLHttpRequest/"&gt;specification&lt;/a&gt; on W3C website&lt;/li&gt;
&lt;li&gt;Dojo resources: &lt;a href="http://en.wikipedia.org/wiki/Dojo_Toolkit"&gt;introduction&lt;/a&gt; on wikipedia,&amp;nbsp;&lt;a href="http://dojotoolkit.org/"&gt;Dojo Toolkit&lt;/a&gt; official website, &lt;a href="http://dojocampus.org/"&gt;Dojo Campus&lt;/a&gt; for tutorials and live demos, &lt;a href="http://dojodocs.uxebu.com/"&gt;online documentation&lt;/a&gt; by Uxebu.&lt;/li&gt;
&lt;li&gt;Introduction of the &lt;a href="http://en.wikipedia.org/wiki/Design_pattern_(computer_science)"&gt;Design Patterns&lt;/a&gt; on wikipedia and reference to the &lt;a href="http://en.wikipedia.org/wiki/Design_Patterns_(book)"&gt;“Gang of Four” book&lt;/a&gt; (Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides). Specific presentation of the &lt;a href="http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller"&gt;Model View Controller&lt;/a&gt;&amp;nbsp;(MVC) pattern on wikipedia.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt;&amp;nbsp;: default &lt;a href="http://docs.djangoproject.com/en/dev/topics/templates/"&gt;template language&lt;/a&gt; available in &lt;a href="http://code.google.com/intl/en/appengine/articles/django.html"&gt;Google App Engine development environment&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Definition of the&lt;a href="http://en.wikipedia.org/wiki/Representational_State_Transfer"&gt; Representational State Transfer&lt;/a&gt; (REST) architecture on wikipedia.&lt;/li&gt;
&lt;li&gt;Future post will describe the nature of this project ;)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/List_of_HTTP_status_codes"&gt;HTTP status codes&lt;/a&gt; on wikipedia, and section 10 of the &lt;a href="http://tools.ietf.org/html/rfc2616#section-10"&gt;RFC2616&lt;/a&gt; for the full status code list. Don't forget to look at the &lt;a href="http://www.flickr.com/photos/apelad/sets/72157594388426362/"&gt;illustrations of the HTTP errors codes&lt;/a&gt; by the artist &lt;a href="http://adamkoford.com/"&gt;Adam "Ape Lad" Koford&lt;/a&gt; (license CC-by).&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.sitepen.com/blog/2008/06/13/restful-json-dojo-data/"&gt;RESTful JSON + Dojo Data&lt;/a&gt; by Kris Zyp, with details on the &lt;a href="http://dojodocs.uxebu.com/#dojox.data.JsonRestStore"&gt;dojox.data.JsonRestStore&lt;/a&gt; introduced in Dojo 1.2.&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-8483852735939545674?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=IjKFySh0DJ0:o4y609LPclI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=IjKFySh0DJ0:o4y609LPclI:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=IjKFySh0DJ0:o4y609LPclI:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=IjKFySh0DJ0:o4y609LPclI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=IjKFySh0DJ0:o4y609LPclI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/IjKFySh0DJ0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/8483852735939545674/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/03/mvc-pattern-and-rest-api-applied-to-gae.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/8483852735939545674?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/8483852735939545674?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/IjKFySh0DJ0/mvc-pattern-and-rest-api-applied-to-gae.html" title="MVC Pattern and REST API Applied to GAE Applications" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/03/mvc-pattern-and-rest-api-applied-to-gae.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak4BRns_fip7ImA9WxVVGUk.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-4461728269824189797</id><published>2009-03-12T20:25:00.003-04:00</published><updated>2009-03-13T08:55:57.546-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-13T08:55:57.546-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Technology" /><title>Telcos vs Internet providers</title><content type="html">What a big break, isn't it? I did not give up ;) I was just busy at work to help tuning the performance of a product which is going to be “GA” this month. I mostly focused on the browser-side code, trying to mitigate effects of flawed designs. Anyway, I'll try to use some of the collected materials in a future post.&lt;br /&gt;
&lt;hr /&gt;&lt;div style="float: right; font-size: smaller; padding: 0pt 0pt 10px 10px; text-align: center;"&gt;&lt;img src="http://farm1.static.flickr.com/29/95012525_e1e16e608c_o.jpg" /&gt;&lt;br /&gt;
From &lt;a href="http://www.flickr.com/photos/jopemoro/95012525/"&gt;jopemoro&lt;/a&gt;, with CC-ByND.&lt;/div&gt;Telecommunication operators (telcos) used to have a captive market:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Land lines subscribers do not switch very often from one provider to its competitor, even for long distance call plans. There is some inertia that helps securing their investments in other technologies.&lt;/li&gt;
&lt;li&gt;Cellular phone subscribers are more susceptible to change, especially now that they can keep their number when subscribing to another operator. But 3-years plans are efficient tools used by operators to keep their subscribers under control.&lt;/li&gt;
&lt;li&gt;Usage of the communication bandwidth is very much predictable. Companies have sized the minutes allocated to each plan so they can get the most from users who do not consume their quotas.&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;In this industry, the rule of “segment the market to maximize your revenues” is well applied.&lt;br /&gt;
&lt;br /&gt;
Late last year, few operators [1, 2] started offering month-to-month plans, without term contract. Why? Because subscribers want more than just voice communication, they want more flexibility at a reasonable price.&lt;br /&gt;
&lt;br /&gt;
With services like Twitter [3] or Google Calendar [4], any cellphone users can get notifications by SMS. When incoming SMS are billed, the incentive to look for an alternative is big!&lt;br /&gt;
&lt;br /&gt;
Nowadays, a growing number of people have (or will to have) smart phones with multiple communications capabilities: to send pictures, to get live information, to access a map and benefit from their embedded GPS, to use VOIP services, etc. [5]&lt;br /&gt;
&lt;br /&gt;
If local communication plans have usually a fair price (not the long distance plans or the fees when on roaming), prices of the “data” plans are usually crazy. With a smartphone equipped with a 8 MegaPixel digital camera, sending quite a few images over the telco networks is prohibitive...&lt;br /&gt;
&lt;br /&gt;
&lt;div style="float: left; font-size: smaller; padding: 0pt 10px 10px 0pt; text-align: center;"&gt;&lt;img src="http://farm1.static.flickr.com/87/217471066_445d500cef_m.jpg" /&gt;&lt;br /&gt;
From &lt;a href="http://www.flickr.com/photos/mag3737/217471066/in/set-72157594214706701/"&gt;mag3737&lt;/a&gt;, with CC-BA-NC-SA&lt;/div&gt;So people tend to use more and more direct Internet accesses, in the offices, at home, in cafes, libraries, etc. It so demanded, that non-profit organizations offers networks of Internet hotspots [6].&lt;br /&gt;
&lt;br /&gt;
Thanks to direct Internet accesses which provide better bandwidth than broadband ones, smartphone users can use long distance calls (with Skype [7]), get their voicemail (GrandCentral [8]), stream videos (Qik [9]).&lt;br /&gt;
&lt;br /&gt;
If I can see the month-to-month plan offering as a tentative to keep their customers, telcos should also revisit the data plan offering to avoid more customer base erosion! Because carrying data means carrying almost anything, I think should transform themselves from pure telecommunication operators to Internet providers.&lt;br /&gt;
&lt;br /&gt;
&lt;fuite&gt;A+, Dom&lt;br /&gt;
--&lt;br /&gt;
Sources:&lt;br /&gt;
&lt;/fuite&gt;&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;&lt;a href="http://news.vzw.com/news/2008/09/pr2008-09-22b.html"&gt;No Contract Required — New Month-To-Month Agreement Gives Verizon Wireless Customers Even More Freedom&lt;/a&gt;, on Verizon website.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://news.vzw.com/news/2008/09/pr2008-09-22b.html"&gt;Fido removing system access fees&lt;/a&gt;, by on CBCNews website.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.twitter.com/"&gt;Twitter&lt;/a&gt; is a free social software where people post updates (limited to 140 characters, same limitation with SMS) and that followers can get automatically.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/calendar"&gt;Google Calendar&lt;/a&gt; is time management platform where people can manage their agendas and invite other people. Event reminders can be sent by e-mail and by SMS for free.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;For a better description of possible services, see my post: &lt;a href="http://domderrien.blogspot.com/2008/11/hand-held-devices-and-sensors.html"&gt;Hand held devices and sensors&lt;/a&gt;.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Free Wifi initiatives: &lt;a href="http://www.ilesansfil.org/welcome/"&gt;Île Sans Fil&lt;/a&gt; of Momtréal, &lt;a href="http://wirelesstoronto.ca/"&gt;Wireless Toronto&lt;/a&gt;, etc. More in this &lt;a href="http://www.wififreespot.com/can.html"&gt;directory&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.skype.com/"&gt;Skype&lt;/a&gt; is a service allowing users to make phone calls over Internet. This popular service belongs to eBay (acquired in Sept. 2005).&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.grandcentral.com/"&gt;GrandCentral&lt;/a&gt;: see the recent update posted on &lt;a href="http://www.techcrunch.com/2009/03/11/grand-central-to-finally-launch-as-google-voice-its-very-very-good/"&gt;TechCrunch&lt;/a&gt;, about GrandCentral which is going to reborn as Google Voice.&lt;br /&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-4461728269824189797?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=fBfRMHVajr0:iT6Vcz5AFsk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=fBfRMHVajr0:iT6Vcz5AFsk:4cEx4HpKnUU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=fBfRMHVajr0:iT6Vcz5AFsk:4cEx4HpKnUU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/SharingTechnologies?a=fBfRMHVajr0:iT6Vcz5AFsk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/SharingTechnologies?i=fBfRMHVajr0:iT6Vcz5AFsk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/fBfRMHVajr0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/4461728269824189797/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/03/telcos-vs-internet-providers.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/4461728269824189797?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/4461728269824189797?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/fBfRMHVajr0/telcos-vs-internet-providers.html" title="Telcos vs Internet providers" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/03/telcos-vs-internet-providers.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UDQnc6fip7ImA9WxVXGU4.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-7186147490942945985</id><published>2009-02-09T22:42:00.028-05:00</published><updated>2009-02-17T23:27:53.916-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-17T23:27:53.916-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Technology" /><title>Google App Engine: Free Hosting and Powerful SDK</title><content type="html">(This post is part of the series &lt;a href="http://domderrien.blogspot.com/2009/01/web-application-on-resources-in-cloud.html"&gt;Web Application on Resources in the Cloud&lt;/a&gt;.)&lt;br /&gt;
&lt;br /&gt;
&lt;img align="right" src="http://lh5.ggpht.com/_VZZAFHl2_Og/SZJKLxJPa4I/AAAAAAAACes/LdJlfcZ-aVE/GAE-toLeft.png" /&gt;Google App Engine (GAE) [1] is an open platform made available by Google to host Web applications:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;It can serve static pages (HTML, CSS, JavaScript, images, etc.).&lt;/li&gt;
&lt;li&gt;It can serve dynamic pages. The programming language is Python [2] (with limited features). The default template framework is Django [3].&lt;/li&gt;
&lt;li&gt;It can persist data in Google BigTable (with a query language similar to SQL, but with restricted features).&lt;/li&gt;
&lt;li&gt;It offers transparent scaling and load-balancing.&lt;/li&gt;
&lt;li&gt;Its sources are open and freely available. Google allows to host up to three applications by account, as sub-domains of &lt;a href="http://www.appspot.com/"&gt;appspot.com&lt;/a&gt; (at least during the preview period).&lt;/li&gt;
&lt;/ul&gt;Some people, like Dare Obasanjo [4], consider GAE as implementing “Platform as a Service” paradigm. I agree and think GAE offers a core element to implement “Software as a Service” (the hype &lt;i&gt;SaaS&lt;/i&gt;). In general, I think that SaaS can help IT companies delivering value to their customers at a better quality/price ratio. Understanding GAE strengths should encourage development teams to give a close look at the entire SaaS concept.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Free Service&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
GAE is offered free of charges during the preview period. In the future, customers will be billed only for what they have consumed (disk space, bandwidth, CPU time, etc.). This practice has been adopted by many providers of services in the cloud, like Amazon [5] and it Amazon Web Services (AWS) offer.&lt;br /&gt;
&lt;br /&gt;
The Software Development Kit (SDK) [1] is open, and anyone can take a look at it, can customize it for his own needs, and can even submit patches. For now, only one programing language is supported: Python [2]. The SDK is delivered with a standalone runtime environment.&lt;br /&gt;
&lt;br /&gt;
Python is also an open system, created by Guido van Rossum who has been working for Google since 1995. In my opinion, this combination is an argument against developers complaining about the need to learn yet another language: Python is a really powerful language and will continue to have a full support by Google as their favorite language. &lt;br /&gt;
&lt;br /&gt;
In association to Python, Django [3] is the template language helping to create applications compliant with the Model-View-Controller (MVC) pattern [6]. Django is also an open source software.&lt;br /&gt;
&lt;br /&gt;
To get the best of the languages and of the standalone GAE runtime, I strongly suggest setting up Eclipse (another open-source software) [7, 8]. Eclipse might not be the ideal candidate for GAE application development, but it provides an extensible platform easy to leverage. For example, egit [9] is a Eclipse plug-in handling transactions with Git repositories (like Github.com [10]).&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Servicing static and dynamic pages&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
GAE can host 1,000 files, each one smaller than 1Mb, for a grand total of 500 Mb per application [11]. Usually, the static files are accessories: images, style sheets, etc. But the offered space allied to Google's scalable infrastructure can be also leverage to host almost any file (HTML, FLV (Flash), CSS, JavaScript, etc.). App Engine Fan describes how to setup GAE for this usage [12], as Matt Riggott [13].&lt;br /&gt;
&lt;br /&gt;
The following handler definition, which should be located into the &lt;code&gt;app.yaml&lt;/code&gt; configuration file, indicates that all requests should be served from the corresponding files located in the directory &lt;code&gt;static&lt;/code&gt;.&lt;br /&gt;
&lt;pre stype="prettyprint"&gt;handlers:
- url: /
&amp;nbsp;&amp;nbsp;static_dir: static/&lt;/pre&gt;Dynamically generated content, like developers are used to producing with PHP for example, can be implemented with Django templates [3]. The following template defines the general Web page pattern. And the second template is just extending it by overriding the extension points.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;&lt;img src="http://2.bp.blogspot.com/_VZZAFHl2_Og/SYZibm6TLuI/AAAAAAAACWE/mYjx-VrlrIU/s800/common.png" style="border: 1px solid black;" /&gt;&lt;br /&gt;
&lt;code&gt;Common.html&lt;/code&gt; template with the Web page organization and the extension points.&lt;br /&gt;
&lt;br /&gt;
&lt;img src="http://3.bp.blogspot.com/_VZZAFHl2_Og/SYZiiNBmDzI/AAAAAAAACWM/KKCEJVMFO84/s800/consumer.png" style="border: 1px solid black;" /&gt;&lt;br /&gt;
&lt;code&gt;Producer.html&lt;/code&gt; template overriding the extension points with the page specific elements.&lt;/div&gt;&lt;br /&gt;
Note: because of internationalization concerns, I strongly recommend to NOT code Web pages as the ones above. Refer to my post on Internationalization of GAE Applications [14] for a better implementation.&lt;br /&gt;
&lt;br /&gt;
Quickly, it is possible to use GAE to host static and dynamic pages on the domain &lt;code&gt;appspot.com&lt;/code&gt; (pattern is &lt;code&gt;http://[application-name].appspot.com/&lt;/code&gt;). Integrating these pages transparently in your own domain allows future updates without having your readers to point to a new Web address. You need to setup Google Apps for your Domain and follow their instructions [15].&lt;br /&gt;
&lt;br /&gt;
App Engine Fan explains how to prevent access to your application from unknown domains [16]. In a private network, you can even open the GAE server to remote access [17].&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Access to Google BigTable&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
In the Web application world, data persist mainly in databases. Databases scale, maintain indexes (providing quickly search results), support transaction (&lt;code&gt;update&lt;/code&gt;, then &lt;code&gt;commit&lt;/code&gt; or &lt;code&gt;revert&lt;/code&gt;). Most databases are relational databases [18]. Among the well know relational databases, there are: Derby, Oracle, DB2, MySQL. SQL (Structured Query Language) is often the query language of relational databases.&lt;br /&gt;
&lt;br /&gt;
GQL (Google Query Language) is very similar to SQL [19]. The discrepancies are due to GAE architecture. For example, to preserve its scalability of the underneath database, GQL does not offer the possibility to &lt;code&gt;JOIN&lt;/code&gt; tables. I am not  database expert, but I consider all limitations being workable and some of them are very sane.&lt;br /&gt;
&lt;br /&gt;
One important issue with database is related to their central place: if they are corrupted, system can stop working. Being able to backup and restore them is critical. In April 2008, Google communicated about possible export file formats [20]. I have not found if this feature has been published... However, I found Aral Balkan's Gaebar application (GAE Backup And Restore) [21] which covers the basic functionality and even more (like the &lt;i&gt;staging&lt;/i&gt; concept).&lt;br /&gt;
&lt;br /&gt;
&lt;div class="updateNotice"&gt;&lt;u&gt;Update 2009/02/10:&lt;/u&gt;&lt;br /&gt;
In the SDK release 1.1.9, Google describes ways to upload data from a CSV into BigTable, and to download data into a local development server. Refer to the &lt;a href="http://code.google.com/appengine/docs/python/tools/uploadingdata.html"&gt;documentation&lt;/a&gt; on GAE Website [1].&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Going further&lt;/span&gt;  &lt;br /&gt;
&lt;br /&gt;
Google has developed a GAE application that is gallery for other GAE applications [22]. Many applications are described there. Interviews of successful implementers are also available on GAE Website [1].&lt;br /&gt;
&lt;br /&gt;
On April 10, 2008, Niall Kennedy posted a detailed article describing GAE architecture [23]. Many others people continue to publish on GAE and on Cloud computing issues in general [24]. It is a really hot topic ;)&lt;br /&gt;
&lt;br /&gt;
&lt;div class="updateNotice"&gt;&lt;u&gt;Update 2009/02/10:&lt;/u&gt;&lt;br /&gt;
Dare Obasanjo published another post on Dare Obasanjo: &lt;a href="http://www.25hoursaday.com/weblog/2009/02/09/GoogleAppEngineOnTheRoadToBecomingUsefulForBuildingRealWebApplications.aspx"&gt;Google App Engine on the road to becoming useful for building real web applications&lt;/a&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
A+, Dom&lt;br /&gt;
--&lt;br /&gt;
Sources: &lt;br /&gt;
&lt;ol&gt;&lt;li&gt;&lt;a href="http://code.google.com/appengine"&gt;Google App Engine&lt;/a&gt; Website, and &lt;a href="http://code.google.com/intl/en/appengine/docs/python/apis.html"&gt;GAE Service API documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Official &lt;a href="http://www.python.org/"&gt;Python&lt;/a&gt; Website. &lt;a href="http://en.wikipedia.org/wiki/Python_%28programming_language%29"&gt;Python history&lt;/a&gt; on Wikipedia. &lt;a href="http://neopythonic.blogspot.com/"&gt;Guido van Rossum&lt;/a&gt;'s blog (Python inventor).&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt; Website, with the section on its &lt;a href="http://docs.djangoproject.com/en/dev/topics/templates/"&gt;template language&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.25hoursaday.com/weblog/2009/01/22/CloudComputingConundrumPlatformAsAServiceVsUtilityComputing.aspx"&gt;Cloud Computing Conundrum: Platform as a Service vs. Utility Computing&lt;/a&gt; by Dare Obasanjo.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://aws.amazon.com/"&gt;Amazon Web Services&lt;/a&gt; Website.&lt;/li&gt;
&lt;li&gt;MVC Pattern applied to GAE Applications... (another post to be published soon).&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.eclipse.org/"&gt;Eclipse&lt;/a&gt; Website.&lt;/li&gt;
&lt;li&gt;Article &lt;a href="http://code.google.com/intl/en/appengine/articles/eclipse.html"&gt;Configuring Eclipse on Windows to Use With Google App Engine&lt;/a&gt; from GAE documentation site.&lt;/li&gt;
&lt;li&gt;Eclipse plug-in for Git repositories: &lt;a href="http://repo.or.cz/w/egit.git"&gt;egit&lt;/a&gt;. Check &lt;a href="http://repo.or.cz/w/egit.git?a=blob_plain;f=EGIT_INSTALL;hb=HEAD"&gt;egit short installation guide&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;My post on &lt;a href="http://domderrien.blogspot.com/2009/01/as-developer-in-collaborative.html"&gt;Git as my New SCM Solution&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Quota description on &lt;a href="http://code.google.com/appengine/articles/quotas.html"&gt;GAE Website&lt;/a&gt;, on &lt;a href="http://googleappengine.blogspot.com/2008/12/system-status-dashboard-quota-details.html"&gt;GAE blog&lt;/a&gt;, and on &lt;a href="http://en.wikipedia.org/wiki/Google_App_Engine"&gt;Wikipedia&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.appenginefan.com/2008/04/free-webhosting-google-app-engine-style.html"&gt;Free Webhosting, Google App Engine style&lt;/a&gt;, by App Engine Fan.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://24ways.org/2008/using-google-app-engine-as-your-own-cdn"&gt;Using Google App Engine as your own Content Delivery Network&lt;/a&gt; by Matt Riggott.&lt;/li&gt;
&lt;li&gt;Internationalization of GAE Applications... (another post to be published soon).&lt;/li&gt;
&lt;li&gt;Access to the &lt;a href="http://www.google.com/apps/intl/en/group/index.html"&gt;Standard Edition of Google Apps for Your Domain&lt;/a&gt; (GYAD) service and instruction on how to &lt;a href="http://code.google.com/appengine/articles/domains.html"&gt;setup a GAE application for your domain&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.appenginefan.com/2008/05/darker-side-of-multiplexing-or-how-to.html"&gt;The darker side of multiplexing, or how to prevent site hijacking&lt;/a&gt; by App Engine Fan.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.cuberick.com/2008/11/access-google-app-engine-development.html"&gt;Access Google App Engine Development Server Remotely&lt;/a&gt;, by Josh Cronemeyer.&lt;/li&gt;
&lt;li&gt;Definition of &lt;a href="http://en.wikipedia.org/wiki/Relational_database"&gt;relational database&lt;/a&gt; by Wikipedia.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://code.google.com/appengine/docs/python/datastore/gqlreference.html"&gt;GQL reference&lt;/a&gt; page on GAE Website.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://googleappengine.blogspot.com/2008/04/getting-your-data-on-and-off-of-google.html"&gt;Getting your data on, and off, of Google App Engine&lt;/a&gt; on GAE official blog.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://aralbalkan.com/1784"&gt;Google App Engine Backup and Restore (Gaebar)&lt;/a&gt; by Aral Balkan&lt;/li&gt;
&lt;li&gt;Google &lt;a href="http://appgallery.appspot.com/"&gt;GAE Application Gallery&lt;/a&gt;, being itself a GAE application.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.niallkennedy.com/blog/2008/04/google-app-engine.html"&gt;Google App Engine for Developers&lt;/a&gt;, by Niall Kennedy.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.ibm.com/developerworks/web/library/ar-archman10/index.html?ca=drs-"&gt;Architectural manifesto: An introduction to the possibilities (and risks) of cloud computing&lt;/a&gt; on developerWorks.&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-7186147490942945985?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=8fkA87S9"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=0xou2PGd"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=0xou2PGd" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=QbhgD1kc"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=QbhgD1kc" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/xne5KyomFiY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/7186147490942945985/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/02/google-app-engine-free-hosting-and.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/7186147490942945985?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/7186147490942945985?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/xne5KyomFiY/google-app-engine-free-hosting-and.html" title="Google App Engine: Free Hosting and Powerful SDK" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_VZZAFHl2_Og/SYZibm6TLuI/AAAAAAAACWE/mYjx-VrlrIU/s72-c/common.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/02/google-app-engine-free-hosting-and.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEUHQXwzfip7ImA9WxNbF0s.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-8553875180865293273</id><published>2009-01-25T21:35:00.030-05:00</published><updated>2009-11-20T19:10:30.286-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-20T19:10:30.286-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Technology" /><category scheme="http://www.blogger.com/atom/ns#" term="Experience" /><title>Automatic Testing of GAE Applications</title><content type="html">(This post is part of the series &lt;a href="http://domderrien.blogspot.com/2009/01/web-application-on-resources-in-cloud.html"&gt;Web Application on Resources in the Cloud&lt;/a&gt;.)&lt;br /&gt;
&lt;br /&gt;
I am not a purist when it is time to apply a development method, I am a practical guy!&lt;br /&gt;
&lt;br/&gt;
&lt;div class="updateNotice"&gt;
&lt;u&gt;Update 2009/11/20&lt;/u&gt;&lt;br/&gt;
At one point, I switched to App Engine Java (see my post &lt;a href="http://domderrien.blogspot.com/2009/04/google-app-engine-meets-java.html"&gt;Google App Engine Meets Java&lt;/a&gt;). One of my argument at that time was the lack of tools Python-side to produce code coverage numbers... I've just posted a lengthy article about &lt;a href="http://domderrien.blogspot.com/2009/11/unit-tests-mock-objects-and-app-engine.html"&gt;Unit tests, Mock objects, and App Engine&lt;/a&gt; for the Java back-end. The techniques and the code I share in this post allow me to reach the mystical 100% of code coverage, for a project with over 10,000 lines for the business code. See you there ;)
&lt;/div&gt;
&lt;br /&gt;
For example, I know by experience how important testing code as soon it is produced. And these tests must run after each code delivery to detect defects and regressions as soon as possible [1]. I allocate as much time to write tests (unit tests most of the time, functional tests occasionally) as I allocate to write code. And no task is considered complete if the corresponding tests do not cover 100%* of its code! I admire adopters of the Test Driven Development (TDD [2]) approach.&lt;br /&gt;
&lt;br /&gt;
&lt;img align="left" src="http://lh3.ggpht.com/_VZZAFHl2_Og/SZJKMKPkCEI/AAAAAAAACe0/WTNIqtqXbrE/GAE-toRight.png" style="margin: 0pt 10px 10px 0pt;" /&gt;When searching information to test Google App Engine (GAE) applications, I was happy to find a post [3] written by Josh Cronemeyer who says:&lt;br /&gt;
&lt;blockquote&gt;My favorite way to start any project is by doing TDD.&amp;nbsp;&lt;/blockquote&gt;If you follow GAE tutorial [4], you can create a correctly designed application implementing the Model-View-Controller (MVC) pattern [5]. Testing such an application which organizes its behavior in different logical area means testing each areas independently:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Testing Python models&lt;/li&gt;
&lt;li&gt;Testing Python business logic&lt;/li&gt;
&lt;li&gt;Testing data injection in Django templates&lt;/li&gt;
&lt;li&gt;Testing rendered HTML pages&lt;/li&gt;

&lt;li&gt;Verifying the use-cases' implementation&lt;/li&gt;
&lt;/ol&gt;In the following sections, I am going to summarize information I gathered. If I missed any element, please, let me know by posting a comment ;)&lt;br /&gt;
&lt;br /&gt;
&lt;img align="right" src="http://www.python.org/images/python-logo.gif" /&gt;&lt;span style="font-size: large;"&gt;Testing Python models&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Verifying that your models work as expected is really important. If we can rely on the robustness of Google Big Database implementation (after all, more and more of their applications run on App Engine), you need at least to detect regressions that our future refactoring operations might introduce.&lt;br /&gt;
&lt;br /&gt;
To learn how to setup your environment, read the detailed post of Josh Cronemeyer: &lt;a href="http://www.cuberick.com/2008/11/unit-test-your-google-app-engine-models.html"&gt;Unit Test Your Google App Engine Models&lt;/a&gt;.&lt;br /&gt;
&lt;blockquote&gt;What follows is some information to get you started writing unit tests against a GAE model. First, a list of the tools you need to install.&lt;br /&gt;

&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.somethingaboutorange.com/mrl/projects/nose/"&gt;Nose&lt;/a&gt; is a tool for running your python unit tests.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pypi.python.org/pypi/NoseGAE"&gt;NoseGAE&lt;/a&gt; is a plugin for nose that bootstraps the GAE environment.&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/blockquote&gt;An alternative is to use &lt;a href="http://code.google.com/p/gaeunit/"&gt;gaeunit&lt;/a&gt; [6] but tests might impact the persistence layer.&lt;br /&gt;
&lt;br /&gt;
Josh Cronemeyer suggests to create a new stub data store before running all tests (function called in your test &lt;code&gt;setUp()&lt;/code&gt;):&lt;br /&gt;

&lt;br /&gt;
&lt;pre class="prettyprint"&gt;from google.appengine.api import apiproxy_stub_map
from google.appengine.api import datastore_file_stub

def clear_datastore(self):
   # Use a fresh stub datastore.
   apiproxy_stub_map.apiproxy = apiproxy_stub_map.APIProxyStubMap()
   stub = datastore_file_stub.DatastoreFileStub('appid', '/dev/null', '/dev/null')
   apiproxy_stub_map.apiproxy.RegisterStub('datastore_v3', stub)&lt;/pre&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Testing Python business logic&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
What do I mean by Python business logic? This is the piece of code that deals with the end-user requests and that does some computations before pinging the persistence layer. For example, a function verifying the format of e-mail addresses (using regular expressions) belongs to that category.&lt;br /&gt;
&lt;br /&gt;
This last 6 years, I have mainly used Java as the programming language to develop the server-side logic. Java is a &lt;i&gt;simple and powerful&lt;/i&gt; programming language. Java benefits from big companies' support and has a large set of helper tools. As helpers, I can count: ant and maven, cruisecontrol and hudson, junit and code coverage, tools for static and dynamic code reviews, powerful IDEs, etc.&lt;br /&gt;
&lt;br /&gt;
To developers starting to write unit tests with the target of covering 100% of the code, I have always suggested to read at least the chapter 7 of the book &amp;#8220;JUnit in Action&amp;#8221; [7], written by Vincent Massol. He introduces the Inversion Of Control (IOC) pattern and the Mock object concept:&lt;br /&gt;

&lt;blockquote&gt;Mock objects (or mocks for short) are perfectly suited for testing a portion of code logic in isolation from the rest of the code. Mocks replace the objects with which your methods under test collaborate, thus offering a layer of isolation.&amp;nbsp;&lt;/blockquote&gt;Python has also many frameworks to &lt;i&gt;mock&lt;/i&gt; objects. Among them, &lt;a href="http://labix.org/mocker"&gt;Python Mocker&lt;/a&gt; seems to be very popular: it consists in recording behaviors and setting expectations on mock object, before letting them being used by real functions. See [9] for a detailed &amp;#8220;how to use Mocker.&amp;#8221; &lt;br /&gt;
&lt;br /&gt;
Reminder: with the tip from Cronemeyer (see above with the stub for the data store, for more details look at [10]), there is no need to mock the data store.&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Unit Test Sample in Python&lt;/span&gt;&lt;br /&gt;

&lt;br /&gt;
The following piece of code defines utility methods which return 1) a list of supported languages and 2) a dictionary with localized labels (fallback on English one).&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;# -*- coding: utf-8 -*-

import en
import fr

def getLanguages():
    return {
        "en": en._getDictionary()["_language"],
        "fr": fr._getDictionary()["_language"],
    }

def getDictionary(locale):
    global dict
    if locale == "fr":
        dict = fr._getDictionary()
    else:
        dict = en._getDictionary()
    return dict
&lt;/pre&gt;&lt;br /&gt;
The series of tests in the following pieces of code verifies the list of languages contains at least English and French, verifies that the expected dictionaries contains the mandatory key with their name (&amp;#8220;English&amp;#8221; and &amp;#8220;Français&amp;#8221;), and that requiring an unexpected dictionary gives the English one.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;# -*- coding: utf-8 -*-

import unittest
from prodcons.i18n import accessor

class SuccessFailError(unittest.TestCase):

    def test_getLanguages_I(self):
        """Verify at least 2 languages {en, fr} are in the dictionary"""
        self.assertTrue(len(accessor.getLanguages()) &amp;gt;= 2)
        self.assertEqual("English", accessor.getLanguages()["en"])
        self.assertEqual("Français", accessor.getLanguages()["fr"])

    def test_getDictionary_I(self):
        """Verify we can get a valid {en} dictionary"""
        self.assertTrue(accessor.getDictionary("en"))
        self.assertEqual("English", accessor.getDictionary("en")["_language"]) # Mandatory key

    def test_getDictionary_II(self):
        """Verify we can get a valid {fr} dictionary"""
        self.assertTrue(accessor.getDictionary("fr"))
        self.assertEqual("Français", accessor.getDictionary("fr")["_language"]) # Mandatory key

    def test_getDictionary_III(self):
        """Verify the fallback on the English dictionary"""
        self.assertTrue(accessor.getDictionary("no_NO"))
        self.assertEqual(accessor.getDictionary("en"), accessor.getDictionary("no_NO"))
&lt;/pre&gt;&lt;br /&gt;

&lt;img align="right" src="http://media.djangoproject.com/img/site/hdr_logo.gif" /&gt;&lt;span style="font-size: large;"&gt;Testing data injection in Django templates&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Django comes with its own test runner! So its templates can be simulated in a stand alone mode.&lt;br /&gt;
&lt;br /&gt;
With the help of Mocker [8], as described in [10], it is relatively easy to verify that your templates extract data as expected. If there is an unexpected data access to the Mock object, or if one attribute has been forgotten, the mock object will report it (a call to &lt;code&gt;verify()&lt;/code&gt; ensure that all expectations were met.)&lt;br /&gt;
&lt;br /&gt;
&lt;img align="right" height="90" src="http://seleniumhq.org/images/big-logo.png" width="100" /&gt;&lt;span style="font-size: large;"&gt;Testing rendered HTML pages&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
To verify that Django templates display the data as expected. Selenium [11] offers probably the best framework (and it's free):&lt;br /&gt;

&lt;ul&gt;&lt;li&gt;Selenium IDE which runs as a Firefox extension and that can record, edit, and debug test scripts.&lt;/li&gt;
&lt;li&gt;Selenium Remote Control (RC): it is a server that starts/stops browsers and that makes them running test scripts.&lt;/li&gt;
&lt;li&gt;Selenium Grid: to control and run tests on remote Selenium RC instances (on WinXP, Win7, RedHat, Suse, etc.)&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;At that step, Selenium tests are considered being functional tests because they involve many parts of the application (do not work in isolation). It's fine to run them extensively in development environment, but should be carefully used in production (see next section).&lt;br /&gt;
&lt;br /&gt;
The following presentation (3:30) shows how I write a test against my local deployment. The basic test ensure the language switcher works correctly:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Starting from the English homepage, it checks page title (in &lt;code&gt;head&amp;gt;title&lt;/code&gt; and in &lt;code&gt;div#title&lt;/code&gt;) against the label &amp;#8220;Producer-Consumer&amp;#8221;.&lt;/li&gt;

&lt;li&gt;After having switched to the French page, it verifies that the URL has been updated correctly (no more &lt;code&gt;lang=en&lt;/code&gt;, but &lt;code&gt;lang=fr&lt;/code&gt; in place). It checks also the page title against &amp;#8220;Producteur-Consommateur&amp;#8221;.&lt;/li&gt;
&lt;li&gt;After having switched back to the English page, it verifies the URL has been updated correctly.&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;center&gt;&lt;object width="552" height="550"&gt; &lt;param name="movie" value="http://content.screencast.com/users/domderrien/folders/Blogger/media/4e1fe51f-8a5b-475f-8c40-07ade18b4e7b/jingswfplayer.swf"&gt;&lt;/param&gt; &lt;param name="quality" value="high"&gt;&lt;/param&gt; &lt;param name="bgcolor" value="#FFFFFF"&gt;&lt;/param&gt; &lt;param name="flashVars" value="thumb=http://content.screencast.com/users/domderrien/folders/Blogger/media/4e1fe51f-8a5b-475f-8c40-07ade18b4e7b/FirstFrame.jpg&amp;containerwidth=552&amp;containerheight=550&amp;content=http://content.screencast.com/users/domderrien/folders/Blogger/media/4e1fe51f-8a5b-475f-8c40-07ade18b4e7b/2009-01-25_2037.swf&amp;advseek=true"&gt;&lt;/param&gt; &lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt; &lt;param name="scale" value="showall"&gt;&lt;/param&gt; &lt;param name="allowScriptAccess" value="always"&gt;&lt;/param&gt; &lt;param name="base" value="http://content.screencast.com/users/domderrien/folders/Blogger/media/4e1fe51f-8a5b-475f-8c40-07ade18b4e7b/"&gt;&lt;/param&gt;  &lt;embed src="http://content.screencast.com/users/domderrien/folders/Blogger/media/4e1fe51f-8a5b-475f-8c40-07ade18b4e7b/jingswfplayer.swf" quality="high" bgcolor="#FFFFFF" width="552" height="550" type="application/x-shockwave-flash" allowScriptAccess="always" flashVars="thumb=http://content.screencast.com/users/domderrien/folders/Blogger/media/4e1fe51f-8a5b-475f-8c40-07ade18b4e7b/FirstFrame.jpg&amp;containerwidth=552&amp;containerheight=550&amp;content=http://content.screencast.com/users/domderrien/folders/Blogger/media/4e1fe51f-8a5b-475f-8c40-07ade18b4e7b/2009-01-25_2037.swf&amp;advseek=true" allowFullScreen="true" base="http://content.screencast.com/users/domderrien/folders/Blogger/media/4e1fe51f-8a5b-475f-8c40-07ade18b4e7b/" scale="showall"&gt;&lt;/embed&gt; &lt;/object&gt;&lt;br /&gt;
Rapid definition of a test case with Selenium IDE.&lt;br /&gt;
&lt;br /&gt;

&lt;img border="0" src="http://1.bp.blogspot.com/_VZZAFHl2_Og/SX0lAsCX02I/AAAAAAAACVs/9GdnMsOnJ4I/s320/2009-01-25_2149.png" /&gt;&lt;br /&gt;
Check points defined with Selenium IDE.&lt;/center&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Verifying the use-cases' implementation&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
In Agile development, a sprint is a period of time allocated to complete development tasks. Each task or group of tasks implement a use-case, a story. Use-cases are used to validate the deliveries. Here is a simple story:&lt;br /&gt;
&lt;blockquote&gt;End-users fine-tune searches with the prefixes &lt;code&gt;name:&lt;/code&gt;, &lt;code&gt;producer:&lt;/code&gt;, and &lt;code&gt;unit-price:&lt;/code&gt;&amp;nbsp;&lt;/blockquote&gt;At the beginning of a project, use cases are simple and can be covered by automatic tests. After a while, use cases become more complex and running them takes quite a long time and requires a heavy setup. These complex use cases are usually processed manually by human operators (Quality Engineers).&lt;br /&gt;

&lt;br /&gt;
If these qualified workers can focus on complex use cases (all dumb ones are processed automatically), they have more possibility to find real &lt;i&gt;bugs&lt;/i&gt;, I mean behaviors that coders forgot to cover, that product owners forgot to specify, etc. Sooner these bugs are discovered lower is their cost in terms of engineer time spent to fix them and in term of lost credibility!&lt;br /&gt;
&lt;br /&gt;
I hope this helps!&lt;br /&gt;
&lt;br /&gt;
&lt;div class="updateNotice"&gt;&lt;u&gt;Update 2009/01/30:&lt;/u&gt;&lt;br /&gt;
Josh, alias Shlomo, updated his post with an excellent reference of a discussion thread in Google App Engine group: &lt;a href="http://groups.google.com/group/google-appengine/browse_thread/thread/9bf8102ae975c94c/9132b44026040498?#9132b44026040498"&gt;Testing Recommendations&lt;/a&gt;. Look specifically at two messages posted by &lt;a href="http://groups.google.com/groups/profile?enc_user=J74shBsAAAB7fo38o2YN3rpByXG0Qzg04EyT7iaEhgecmLSoVQ6o2Q"&gt;Andy&lt;/a&gt; about using Selenium tools, like this one:&lt;br /&gt;

&lt;blockquote&gt;Selenium-RC is not necessary since Selenium core can be added to your App Engine project directory and run from there. Collected steps below to save you time:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Download the core: http://selenium-core.openqa.org/download.jsp&lt;/li&gt;
&lt;li&gt;Unzip selenium core zip file&lt;/li&gt;
&lt;li&gt;Copy this selenium core directory into your App path somewhere.&lt;/li&gt;
&lt;li&gt;Edit your app.yaml file to permit static access (static because it doesn't need a sever interpreter. selenium is written in javascript, so it runs in your browser.) Under "handlers:", add something like this:&lt;br /&gt;
&lt;code&gt;- url: /selenium&lt;br /&gt;
&amp;nbsp;&amp;nbsp;static_dir: ./tests/SeleniumTests/selenium-core-0.8.3&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;code&gt;static_dir&lt;/code&gt; is where I copied my selenium-core directory. To access selenium, I now open the app engine url, &lt;code&gt;http://localhost:8080/selenium/index.html&lt;/code&gt; and run the TestRunner. From there, open your test suite and go. I had trouble loading individual tests for some reason, but suites work.&lt;br /&gt;

&lt;br /&gt;
I could have of course done all of this using the Firefox Selenium-IDE plugin with fewer steps, but using the core approach does make it cross browser supporting.&lt;br /&gt;
&lt;br /&gt;
I'm still trying to figure out how to use Python for this. I'll continue that in a separate message.&amp;nbsp;&lt;/blockquote&gt;&lt;/div&gt;&lt;br /&gt;
A+, Dom&lt;br /&gt;
--&lt;br /&gt;
Note:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Providing 100% of code coverage by unit or functional tests is sometimes not possible. The test case shutting down remotely the application server to verify that pending transactions are persisted correctly cannot, for example, be scripted for automation. In such a situation, we should rely on manual testing. The goal of test automation is to provide the best coverage possible, so manual testers can focus on edge cases and on trying to discover unexpected issues.&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;--&lt;br /&gt;

Sources&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Agile: SCRUM is hype, but XP is as important... (another post to be published soon) &lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Test-driven_development"&gt;Test Driven Development&lt;/a&gt; approach description on Wikipedia, and information on the book &lt;a href="http://books.google.ca/books?id=gFgnde_vwMAC"&gt;Test Driven Development&lt;/a&gt; by Kent Beck&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.cuberick.com/2008/11/unit-test-your-google-app-engine-models.html"&gt;Unit Test Your Google App Engine Models&lt;/a&gt; by  Josh Cronemeyer, and &lt;a href="http://conferences.oreillynet.com/cs/user/view/e_spkr/3916"&gt;Josh's short bio&lt;/a&gt; from a speech he gave at OSCON in 2007.&lt;/li&gt;

&lt;li&gt;&lt;a href="http://code.google.com/appengine/docs/python/gettingstarted/"&gt;Google App Engine tutorial&lt;/a&gt; on Google Code. &lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;MVC Pattern applied to GAE Applications... (another post to be published soon)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://code.google.com/p/gaeunit/"&gt;gaeunit&lt;/a&gt; is a test environment that runs on development environment (not on Google infrastructure).&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.manning.com/massol/"&gt;JUnit in Action&lt;/a&gt;, by Vincent Massol, edited by Manning Publications Co. &lt;a href="http://www.manning-source.com/books/massol/massol_ch07.pdf"&gt;Chapter 7&lt;/a&gt;, freely available, explains the IOC pattern and the benefits of using Mock objects. Vincent Massol is now technical lead of the open source project XWiki.&lt;/li&gt;

&lt;li&gt;&lt;a href="http://labix.org/mocker"&gt;Python Mocker&lt;/a&gt;: Mock object framework which allows to record behaviors and expectations before replaying them with real functions. &lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.appenginefan.com/2008/06/unit-tests-for-google-app-engine-apps.html"&gt;Unit tests for Google App Engine apps&lt;/a&gt;, by App Engine Fan.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://appengineguy.com/2008/06/proper-unit-testing-of-app-enginedjango.html"&gt;Proper Unit Testing of App Engine/Django&lt;/a&gt;, by App Engine Guy&lt;/li&gt;
&lt;li&gt;The open-source framework for Web application automatic testing: &lt;a href="http://seleniumhq.org/projects/ide/"&gt;Selenium IDE&lt;/a&gt;, &lt;a href="http://seleniumhq.org/projects/remote-control/"&gt;Selenium RC&lt;/a&gt;, and &lt;a href="http://selenium-grid.seleniumhq.org/how_it_works.html"&gt;Selenium Grid&lt;/a&gt;. Check the &lt;a href="http://seleniumhq.org/projects/core/usage.html"&gt;core features&lt;/a&gt; for information on the automating the tests -- See also a Japanese wiki on Selenium: &lt;a href="http://wiki.javascud.org/display/SEL/Selenium+IDE+-+Wiki"&gt;JavaScud / Selenium IDE&lt;/a&gt;.&lt;br /&gt;

&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-8553875180865293273?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=EX20uUae"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=Wr40YzNh"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=Wr40YzNh" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=8FArtdzU"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=8FArtdzU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/qUva9QWwxE4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/8553875180865293273/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/01/automatic-testing-of-gae-applications.html#comment-form" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/8553875180865293273?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/8553875180865293273?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/qUva9QWwxE4/automatic-testing-of-gae-applications.html" title="Automatic Testing of GAE Applications" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_VZZAFHl2_Og/SX0lAsCX02I/AAAAAAAACVs/9GdnMsOnJ4I/s72-c/2009-01-25_2149.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/01/automatic-testing-of-gae-applications.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkYHQn84eCp7ImA9WxVRFUU.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-5523123582801889960</id><published>2009-01-21T07:20:00.004-05:00</published><updated>2009-01-21T20:35:33.130-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-21T20:35:33.130-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Experience" /><title>Book "Power of Surprise" by Andy Nulman</title><content type="html">Because I read the announcement of Six Pixels of Separation "&lt;a href="http://www.twistimage.com/blog/archives/surprise-andy-nulman-is-giving-away-copies-of-his-new-book/"&gt;Surprise! Andy Nulman Is Giving Away Copies Of His New Book&lt;/a&gt;", a blog I have been following for a long time, I decided to give a try ;)&lt;br /&gt;
&lt;blockquote&gt;Hey Andy Nulman, here an address for another Montreal tech guy:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;div style="text-align: center;"&gt;7943, Duranceau, LaSalle (Qc) H8P 3R8.&lt;/div&gt;&lt;/blockquote&gt;Don't hesitate to post it yourself, Andy gives away 200 copies of his book! Check his blog &lt;a href="http://powrightbetweentheeyes.typepad.com/"&gt;powrightbetweentheeyes.typepad.com&lt;/a&gt;  or his &lt;a href="http://powrightbetweentheeyes.typepad.com/pow_right_between_the_eye/2009/01/200-free-pow-booksan-offer-you-cant-refuse.html"&gt;post on the offer&lt;/a&gt;. Don not forget to link &lt;a href="http://www.andynulman.com/"&gt;www.andynulman.com&lt;/a&gt; for him to track you back ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-5523123582801889960?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=5CLEGOmv"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=Ni0eWbgf"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=Ni0eWbgf" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=CIGUxjP4"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=CIGUxjP4" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/zkCgsnvgXBg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/5523123582801889960/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/01/because-i-read-announcement-of-six.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/5523123582801889960?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/5523123582801889960?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/zkCgsnvgXBg/because-i-read-announcement-of-six.html" title="Book &quot;Power of Surprise&quot; by Andy Nulman" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/01/because-i-read-announcement-of-six.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0QAR3oyfCp7ImA9WxNQE08.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-8425911684542546146</id><published>2009-01-13T23:50:00.008-05:00</published><updated>2009-09-18T21:55:46.494-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-09-18T21:55:46.494-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Technology" /><category scheme="http://www.blogger.com/atom/ns#" term="Experience" /><category scheme="http://www.blogger.com/atom/ns#" term="Community" /><title>Web Application on Resources in the Cloud</title><content type="html">“What? Why? When? How?” are the four questions I am going to answer to introduce my first series of posts.&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;img src="http://lh5.ggpht.com/_VZZAFHl2_Og/SZJKLxJPa4I/AAAAAAAACes/LdJlfcZ-aVE/GAE-toLeft.png" align="right"&gt;What? I am going to build a modern Web application using resources on the Cloud. Specifically, I am going to build an open Web application for consumers to find and review products in a big database, and for producers to offer products and find consumers. The infrastructure will use Google App Engine infrastructure [1].&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Why? There are many aspects:&lt;/li&gt;
&lt;ul&gt;&lt;li&gt;There is the professional benefit: In my post about Gary Reynolds' presentation “Career Advice '08” [2], or as posted by Tim O'Reilly in his post “Work on Stuff that Matters: First Principles” [3], it is mentioned that delivering value is a key differentiator. Building this working application will demonstrate my various expertise.&lt;/li&gt;
&lt;li&gt;As an active member of Diku Dilenga [4] which delivers microloans to small enterprises in Democratic Republic of the Congo, I know that such application will help microentrepreneurs finding customers, and vice-versa. This project helps sharing my expertise with people who need help.&lt;/li&gt;
&lt;li&gt;This project gives me also a chance to contribute to the open source community which has already given so much to me, my life, and my work.&lt;/li&gt;
&lt;/ul&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;When? I have already played with the Google App Engine SDK on my machine. I wanted to be sure no blocking issue would prevent me building the application. The application is already available at: &lt;a href="http://prod-cons.appspot.com/"&gt;http://prod-cons.appspot.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;How? I am a Agile Methodology Adopter [5] so I do not plan far ahead. I am going to prepare a backlog with the tasks to implement, and I am going to address them according to their priority order. The code is regularly pushed on github [6]: &lt;a href="http://github.com/DomDerrien/diku-dilenga/tree"&gt;http://github.com/DomDerrien/diku-dilenga/tree&lt;/a&gt;.&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;If you like the idea, if you want to learn new mechanisms, if you are OK with writing lots of unit tests, contact me. Because I am pretty busy at work, and I have to assume responsibilities for Diku Dilenga, the project will move slowly. But it will move and it will be fun!&lt;br /&gt;
&lt;br /&gt;
Hints on the coming post in that series:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://domderrien.blogspot.com/2009/01/as-developer-in-collaborative.html"&gt;Git as my SCM Solution&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://domderrien.blogspot.com/2009/04/agile-scrum-is-hype-but-xp-is-more.html"&gt;Agile: SCRUM is hype, but XP is more important...&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://domderrien.blogspot.com/2009/02/google-app-engine-free-hosting-and.html"&gt;Google App Engine: free hosting and powerful SDK&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://domderrien.blogspot.com/2009/06/internationalization-of-gae.html"&gt;Internationalization of GAE Applications&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://domderrien.blogspot.com/2009/03/mvc-pattern-and-rest-api-applied-to-gae.html"&gt;MVC Pattern and REST API applied to GAE Applications&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://domderrien.blogspot.com/2009/01/automatic-testing-of-gae-applications.html"&gt;Automatic Testing within GAE Environment&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;A+, Dom&lt;br /&gt;
--&lt;br /&gt;
Sources:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;&lt;a href="http://code.google.com/appengine/"&gt;Google App Engine&lt;/a&gt; website.&lt;/li&gt;
&lt;li&gt;My post on &lt;a href="http://domderrien.blogspot.com/2008/12/career-advice.html"&gt;Career Advice '08&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Tim O'Reilly post &lt;a href="http://radar.oreilly.com/2009/01/work-on-stuff-that-matters-fir.html"&gt;Work on Stuff that Matters: First Principles&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.diku-dilenga.org/"&gt;Diku Dilenga&lt;/a&gt; website.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://agilemanifesto.org/"&gt;Agile Manifesto&lt;/a&gt;, and &lt;a href="http://en.wikipedia.org/wiki/Agile_software_development"&gt;Agile Methodology&lt;/a&gt; description on Wikipedia&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/"&gt;Github.com&lt;/a&gt; offers free hosting of open sources (charges applied to personal and commercial hosting).&lt;br /&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-8425911684542546146?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=DQQ5THH8"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=Kiy3txQ2"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=Kiy3txQ2" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=c621HZDN"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=c621HZDN" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/YhlsLvthcDE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/8425911684542546146/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/01/web-application-on-resources-in-cloud.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/8425911684542546146?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/8425911684542546146?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/YhlsLvthcDE/web-application-on-resources-in-cloud.html" title="Web Application on Resources in the Cloud" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/01/web-application-on-resources-in-cloud.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak4ERXw5eSp7ImA9WxVUGU8.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-2163989038875106906</id><published>2009-01-09T06:19:00.012-05:00</published><updated>2009-03-24T17:08:24.221-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-24T17:08:24.221-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Technology" /><title>Git as my New SCM Solution</title><content type="html">As a developer in collaborative environments, I am used to relying on source control management systems [1]. In different companies, I worked with CVS [1], ClearCase [1], and subversion [2]. For my side projects (personal ones and ones related to my social involvements), I was a big fan of subversion.&lt;br /&gt;
&lt;br /&gt;
&lt;img align="right" src="http://github.com/images/modules/header/logo.png" /&gt;But subversion has limitations, like the importance of the connectivity with the subversion server whenever you want to gain access a file history or to revert an update. Because I have just started a new side project [3], I have decided to go with git and the hosting service &lt;a href="http://github.com/"&gt;github&lt;/a&gt; [4].&lt;br /&gt;
&lt;br /&gt;
I am going to describe the straightforward steps to setup, connect, and get working with git/github.&lt;br /&gt;
&lt;br /&gt;
First thing: install git runtime. git has been developed in replacement to a tools used to manage linux kernel code. It has been preliminary built on linux. For Windows users, you can install it over cygwin or use a fork built over MSys. I am setup with &lt;a href="http://code.google.com/p/msysgit/"&gt;msysgit&lt;/a&gt;  [5].&lt;br /&gt;
&lt;br /&gt;
The authentication mechanism on git repositories relies on SSH [6]. When creating an account on github, a public key is asked. Then anytime, the git runtime on your machine operates with the github server, it signs commands with your private key, and your public key is remotely used to verify the git runtime works on your behalf. To generate a pair of keys, just type the following command in a git bash window:&lt;br /&gt;
&lt;br /&gt;
&lt;code style="background-color: black; color: yellow; font-weight: bold; margin-left: 25px; padding: 2px 50px 2px 5px;"&gt;&lt;span style="color: lightgreen;"&gt;$&lt;/span&gt; ssh-keygen -C "your@email.com" -t rsa&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
In order to use git on another machine, you have to copy over the generated SSH file (&lt;code&gt;id_rsa&lt;/code&gt; and &lt;code&gt;id_rsa.pub&lt;/code&gt;, from &lt;code&gt;%USERDIR%/.ssh&lt;/code&gt;). To backup them, I suggest two services I mentioned in my list &lt;a href="http://feeds.feedburner.com/%7Er/SharingTechnologies/%7E3/504040673/2009-products-i-cant-leave-without.html"&gt;2009 Products I Cannot Live Without&lt;/a&gt;: KeePass (as a personal encrypted repository) and DropBox (as the replicator from the cloud).&lt;br /&gt;
&lt;br /&gt;
The first time, it is easier to use &lt;a href="http://github.com/"&gt;github&lt;/a&gt; website to create an initial repository. You can verify that your SSH key is correctly configure.&lt;br /&gt;
&lt;br /&gt;
&lt;code style="background-color: black; color: yellow; font-weight: bold; margin-left: 25px; padding: 2px 50px 2px 5px;"&gt;&lt;span style="color: lightgreen;"&gt;$&lt;/span&gt; ssh git@github.com&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
I have created the project &lt;code&gt;diku-dilenga&lt;/code&gt;. If the SSH key is recognized, you can ready to clone (checkout equivalent for subversion) any project you have access to, like mine:&lt;br /&gt;
&lt;br /&gt;
&lt;code style="background-color: black; color: yellow; font-weight: bold; margin-left: 25px; padding: 2px 50px 2px 5px;"&gt;&lt;span style="color: lightgreen;"&gt;$&lt;/span&gt; git clone git://github.com/DomDerrien/diku-dilenga.git&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Adding file in your own project is easy. Note that the &lt;code&gt;add&lt;/code&gt; is recursive (so adding &lt;code&gt;.&lt;/code&gt; (dot) from the root folder will add all files for the next commit).&lt;br /&gt;
&lt;br /&gt;
&lt;code style="background-color: black; color: yellow; font-weight: bold; margin-left: 25px; padding: 2px 50px 2px 5px;"&gt;&lt;span style="color: lightgreen;"&gt;$&lt;/span&gt; git add doc/README&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Persisting an addition or an update is simply done with the following command. Note that giving a meaningful comment or a project task identifier is highly recommended ;)&lt;br /&gt;
&lt;br /&gt;
&lt;code style="background-color: black; color: yellow; font-weight: bold; margin-left: 25px; padding: 2px 50px 2px 5px;"&gt;&lt;span style="color: lightgreen;"&gt;$&lt;/span&gt; git commit -a -m "..."&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
For additional commands (to remove files, to create branches, to merge branches, etc.), you have to refer to reference sites like:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://github.com/guides/git-cheat-sheet"&gt;Cheat sheet on github&lt;/a&gt;.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://linux.yyz.us/git-howto.html"&gt;Kernel Hackers' Guide to git&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Once all additions, updates, and removal have been locally done, updating the remote server (github in my case), is fairly simple:&lt;br /&gt;
&lt;br /&gt;
&lt;code style="background-color: black; color: yellow; font-weight: bold; margin-left: 25px; padding: 2px 50px 2px 5px;"&gt;&lt;span style="color: lightgreen;"&gt;$&lt;/span&gt; git push&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Getting updates made by others, or from another computer, are also very simple:&lt;br /&gt;
&lt;br /&gt;
&lt;code style="background-color: black; color: yellow; font-weight: bold; margin-left: 25px; padding: 2px 50px 2px 5px;"&gt;&lt;span style="color: lightgreen;"&gt;$&lt;/span&gt; git pull&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class="updateNotice"&gt;&lt;u&gt;Update 2009/01/13:&lt;/u&gt;&lt;br /&gt;
This post is now part of the series &lt;a href="http://domderrien.blogspot.com/2009/01/web-application-on-resources-in-cloud.html"&gt;Web Application on Resources in the Cloud&lt;/a&gt;.&lt;br /&gt;
I recommend you read the introduction of my side project which is going to be visible on &lt;a href="http://github.com/DomDerrien/diku-dilenga/tree"&gt;github.com/DomDerrien/diku-dilenga/tree&lt;/a&gt;.&lt;/div&gt;&lt;br /&gt;
&lt;div class="updateNotice"&gt;&lt;u&gt;Update 2009/01/15:&lt;/u&gt;&lt;br /&gt;
An illustrated guide to git on Windows [7] has been published on github website. I am not a big fan of complex graphical user interfaces (GUIs) where end-users loose the focus of their current task! I think pushing/pulling are relatively rare operations (compared to commit/revert/history) and should have a very light interface... My two cents&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div class="updateNotice"&gt;&lt;u&gt;Update 2009/03/24:&lt;/u&gt;&lt;br /&gt;
Thanks to some follower's feedback, it appears that dealing with Git commands is still fuzzy. Here is aSequence diagram initially produced by &lt;a href="http://osteele.com/archives/2008/05/my-git-workflow"&gt;Olivier Steele&lt;/a&gt; and described on &lt;a href="http://gitready.com/beginner/2009/01/21/pushing-and-pulling.html"&gt;git ready&lt;/a&gt; blog.&lt;br /&gt;
&lt;center&gt;&lt;img src="http://osteele.com/images/2008/git-transport.png"&gt;&lt;/center&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
A+, Dom&lt;br /&gt;
--&lt;br /&gt;
Sources:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Revision_control"&gt;Source Control Management&lt;/a&gt; description, &lt;a href="http://en.wikipedia.org/wiki/Concurrent_Versions_System"&gt;CVS&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Rational_ClearCase"&gt;ClearCase&lt;/a&gt; histories on Wikipedia.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://subversion.tigris.org/"&gt;subversion&lt;/a&gt; is a popular cross platforms open source replacement to the aging CVS.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Future posts will describe the nature of this project ;)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Official &lt;a href="http://git-scm.com/"&gt;git website&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Git_%28software%29"&gt;git history&lt;/a&gt; on Wikipedia, and &lt;a href="http://www.github.com/"&gt;github&lt;/a&gt; hosting service.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;Package of git for Windows: &lt;a href="http://code.google.com/p/msysgit/"&gt;msysgit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Secure_Shell"&gt;SSH network protocol&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Public-key_cryptography"&gt;public-key cryptography&lt;/a&gt; principles on Wikipedia&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://nathanj.github.com/gitguide/"&gt;An Illustrated Guide to Git on Windows&lt;/a&gt; on github website.&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-2163989038875106906?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=CvYmYMxg"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=OrEaTEy2"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=OrEaTEy2" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=EMyw3qo6"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=EMyw3qo6" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/uOXOlJzczhc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/2163989038875106906/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/01/as-developer-in-collaborative.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/2163989038875106906?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/2163989038875106906?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/uOXOlJzczhc/as-developer-in-collaborative.html" title="Git as my New SCM Solution" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/01/as-developer-in-collaborative.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkcFQHY8eip7ImA9WxVSFkw.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-2565771806693665955</id><published>2009-01-05T12:36:00.019-05:00</published><updated>2009-01-10T14:00:11.872-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-10T14:00:11.872-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Technology" /><category scheme="http://www.blogger.com/atom/ns#" term="Experience" /><title>2009 Products I Can't Leave Without</title><content type="html">Today, I saw Michael Arrington blog post about his annual list of &lt;a href="http://www.techcrunch.com/2009/01/04/2009-products-i-cant-live-without/"&gt;products he can't live without&lt;/a&gt;. As a &lt;a href="http://www.techcrunch.com/"&gt;TechCrunch &lt;/a&gt;reader, I read Michael list few times in the past and have been maintaining my own list of favorite applications. Because of the success of Michael's post and because I use different tools, I have decided to publish my list too!&lt;br /&gt;
&lt;br /&gt;
Michael and I have different backgrounds: he is the &lt;a href="http://www.techcrunch.com/about-techcrunch/"&gt;founder and the editor&lt;/a&gt; of a popular technical site and I am just a &lt;a href="http://dominique.derrien.googlepages.com/resume-en.html"&gt;developer&lt;/a&gt; ;) So do not compare lists.&lt;br /&gt;
&lt;br /&gt;
Here is my list of applications, in alphabetical order, I used often. And to make it consistent with Michael's post, the list is followed by a comment for each tool.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="float: left;"&gt;&lt;div style="background-color: black; border: 1px solid black; color: white; font-weight: bold; text-align: center;"&gt;2009&lt;/div&gt;&lt;div style="background-color: grey; border: 1px solid black; padding: 0pt 10px;"&gt;AllChars&lt;br /&gt;
Blogger&lt;br /&gt;
Dabbleboard&lt;br /&gt;
Dropbox&lt;br /&gt;
Eclipse&lt;br /&gt;
Firefox&lt;br /&gt;
FriendFeed (private room)&lt;br /&gt;
Gimp&lt;br /&gt;
Git&lt;br /&gt;
GMail&lt;br /&gt;
Google Calendar&lt;br /&gt;
Google Reader&lt;br /&gt;
Google Search&lt;br /&gt;
KeePass&lt;br /&gt;
LinkedIn&lt;br /&gt;
VirtualBox&lt;br /&gt;
YouTube and Google Video&lt;/div&gt;&lt;/div&gt;&lt;div style="clear: both;"&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;AllChars&lt;/span&gt;&lt;br /&gt;
For programmers or English writers, keyboards with the US layout are just fine. If you use another layout, then it is a compromise between being able to generate specific characters and staying efficient. AllChars is a Windows tool that can generate any Unicode character with few key sequences (like Ctrl+e+e for €). It is fully customizable and support even macros.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: white; border: 1px solid black; padding: 5px 10px; font-size: smaller;"&gt;&lt;table style="border: 0; padding: 0; margin: 0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;Company:&lt;/td&gt;&lt;td&gt;&lt;i title="Free and Libre Open Source Software"&gt;FLOSS&lt;/i&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Website:&lt;/td&gt;&lt;td&gt;&lt;a href="http://allchars.zwolnet.com/"&gt;allchars.zwolnet.com&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
Interesting post from Jeff Atwood: &lt;a href="http://www.codinghorror.com/blog/archives/001188.html"&gt;We Are Typist First, Programmers Second&lt;/a&gt;.&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Blogger&lt;/span&gt;&lt;br /&gt;
This is the tool used to publish this blog. I have not invest enough time in customizing the page layout, but I know I can easily do it later and updates will be propagated to all posts. A good and efficient tool, IMHO.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: white; border: 1px solid black; padding: 5px 10px; font-size: smaller;"&gt;&lt;img src="http://www.crunchbase.com/assets/images/resized/0001/2809/12809v2-max-150x150.jpg" style="float: right;" /&gt;&lt;table style="border: 0; padding: 0; margin: 0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;Company:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.crunchbase.com/company/google"&gt;Google&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Website:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.google.com/"&gt;blogger.com&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Launch Date:&lt;/td&gt;&lt;td&gt;August 18, 2007&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
Blogger is a blog publishing platform formerly known as Pyra Labs before Google acquired it in February 2003. Blogger blogs are mostly hosted internally with the “dot Blogspot” domain but they can also be hosted externally on a user’s own server.&lt;br /&gt;
&lt;br /&gt;
Blogger provides bloggers with a WYSIWYG editor that allows them to drag-and-drop widgets, change fonts and edit page elements. Also, Feedburner’s feed management tools are tightly integrated with Blogger blogs due to Google’s recent acquisition.&lt;br /&gt;
&lt;div style="float: right; padding: 0 10px; background-color: lightgrey;"&gt;Credits: &lt;a href="http://www.crunchbase.com/"&gt;CrunchBase&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Dabbleboard&lt;/span&gt;&lt;br /&gt;
DabbleBoard is a tool I blogged about in a post about &lt;a href="http://domderrien.blogspot.com/2008/10/effective-communication.html"&gt;Effective Communication&lt;/a&gt; principles.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: white; border: 1px solid black; padding: 5px 10px; font-size: smaller; min-height: 55px;"&gt;&lt;img src="http://www.dabbleboard.com/images/dabbleboard_logo.png" style="float: right;" /&gt;&lt;table style="border: 0; padding: 0; margin: 0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;Company:&lt;/td&gt;&lt;td&gt;Dabbleboard Inc&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Website:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.dabbleboard.com/"&gt;dabbleboard.com&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Dropbox&lt;/span&gt;&lt;br /&gt;
Dropbox is a composed of plugins to install on your machines (Windows and MacOS) and a website which host your &lt;i&gt;virtual folders&lt;/i&gt;. It is a silent tool, working smoothly, and synchronizing folders in background. I use it in conjunction with KeePass to &lt;i&gt;backup&lt;/i&gt; my sensitive information.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: white; border: 1px solid black; padding: 5px 10px; font-size: smaller; min-height: 51px;"&gt;&lt;img src="http://www.crunchbase.com/assets/images/resized/0002/7265/27265v1-max-150x150.png" style="float: right;" /&gt;&lt;table style="border: 0; padding: 0; margin: 0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;Company:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.crunchbase.com/company/plum"&gt;Plum&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Website:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.getdropbox.com/"&gt;getdropbox.com&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Eclipse&lt;/span&gt;&lt;br /&gt;
For an early adopter of IntelliJ IDEA by JetBrains, I had to use Eclipse (company's tool when working with IBM Rational, cheap when working with Compuware). I should recognize that it is going better and better (especially with the refactoring features and the JavaScript support) and it has more plugins than IntelliJ. It is also a platform for OSGi and for Rich Applications.&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.eclipse.org/"&gt;Eclipse Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://draft.blogger.com/www.jetbrains.com/idea/"&gt;IntelliJ IDEA Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.osgi.org/"&gt;OSGi Alliance Website&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/OSGi"&gt;OSGi introduction&lt;/a&gt; on Wikipedia.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;div style="background-color: white; border: 1px solid black; padding: 5px 10px; font-size: smaller; min-height: 73px;"&gt;&lt;img src="http://www.eclipse.org/eclipse.org-common/themes/Phoenix/images/eclipse_home_header.jpg" style="float: right;" /&gt;&lt;table style="border: 0; padding: 0; margin: 0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;Company:&lt;/td&gt;&lt;td&gt;&lt;i title="Free and Libre Open Source Software"&gt;FLOSS&lt;/i&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Website:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.eclipse.org/"&gt;eclipse.org&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Firefox&lt;/span&gt;&lt;br /&gt;
Having been a Web application developer for a long time, I adopted Firefox (then know as Firebird) in 2003. With the introduction of the Firebug extension (in 2005), it became with primary browser and it had never lost this status. Its early integration of Google search was also a serious advantage. These days, with the &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/3780"&gt;faviconize extension&lt;/a&gt; and Firefox ability to start with the previous configuration, my browser always starts with: iGoogle, GMail, Google Calendar.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: white; border: 1px solid black; padding: 5px 10px; font-size: smaller;"&gt;&lt;img src="http://www.crunchbase.com/assets/images/resized/0001/3109/13109v1-max-150x150.png" style="float: right;" /&gt;&lt;table style="border: 0; padding: 0; margin: 0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;Company:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.crunchbase.com/company/mozilla"&gt;Mozilla&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Website:&lt;/td&gt;&lt;td&gt;&lt;a href="http://getfirefox.com/"&gt;getfirefox.com&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Launch Date:&lt;/td&gt;&lt;td&gt;November 9, 2004&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
In February 2008 Mozilla announced that they had reached 500 million downloads of Firefox, and 150 million active users.&lt;br /&gt;
&lt;div style="float: right; padding: 0 10px; background-color: lightgrey;"&gt;Credits: &lt;a href="http://www.crunchbase.com/"&gt;CrunchBase&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;FriendFeed&lt;/span&gt;&lt;br /&gt;
I started to use FriendFeed at its early stages, mainly because it offered the possibility to share information from Web page I can visit randomly. Because few months after its introduction, Google Reader added the &lt;a href="http://googlereader.blogspot.com/2008/05/share-anything-anytime-anywhere.html"&gt;Share with note&lt;/a&gt; function, I stopped using FriendFeed... until recently when I have invited to a &lt;a href="http://blog.friendfeed.com/2008/05/get-room.html"&gt;private room&lt;/a&gt;: this is a pretty nice service for offline chats. It is not as heavy as e-mails and not as disruptive as instant messages.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: white; border: 1px solid black; padding: 5px 10px; font-size: smaller;"&gt;&lt;img src="http://www.crunchbase.com/assets/images/resized/0000/1096/1096v1-max-150x150.png" style="float: right;" /&gt;&lt;table style="border: 0; padding: 0; margin: 0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;Company:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.crunchbase.com/company/friendfeed"&gt;FriendFeed&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Website:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.friendfeed.com/"&gt;friendfeed.com&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Launch Date:&lt;/td&gt;&lt;td&gt;October 1, 2007&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
In February 2008 Mozilla announced that they had reached 500 million downloads of Firefox, and 150 million active users.&lt;br /&gt;
&lt;div style="float: right; padding: 0 10px; background-color: lightgrey;"&gt;Credits: &lt;a href="http://www.crunchbase.com/"&gt;CrunchBase&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Gimp&lt;/span&gt;&lt;br /&gt;
I never the budget and training for Adobe Photoshop. So I started using Gimp. If you can pass over its weird interface (too many windows, IMO), Gimp offer tons of features for Web application developers: to adjust pictures, to generate textures, to resize images, etc. And there are plenty of free tutorials on the Web.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: white; border: 1px solid black; padding: 5px 10px; font-size: smaller; min-height: 45px;"&gt;&lt;img src="http://www.gimp.org/images/title.png" style="float: right;" /&gt;&lt;table style="border: 0; padding: 0; margin: 0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;Company:&lt;/td&gt;&lt;td&gt;&lt;i title="Free and Libre Open Source Software"&gt;FLOSS&lt;/i&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Website:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.gimp.org/"&gt;gimp.org&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
My favorite video series on Photoshop, starting with the first episode: &lt;a href="http://www.youtube.com/watch?v=U_X5uR7VC4M"&gt;You Suck at Photoshop #1: Distort, Warp, &amp;amp; Layer Effects&lt;/a&gt;.&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Git&lt;/span&gt; As a developer, I always want to put my code into a source control system. It is not just because I am afraid that my laptop crashes, then wasting hours of work. It is mainly because I want to keep track of the update history. At work, over the years, I used ClearCase, CVS, and Subversion. For my personal development, I used Subversion a lot and now I use Git.  &lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: white; border: 1px solid black; padding: 5px 10px; font-size: smaller; min-height: 55px;"&gt;&lt;table style="border: 0; padding: 0; margin: 0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;Company:&lt;/td&gt;&lt;td&gt;&lt;i title="Free and Libre Open Source Software"&gt;FLOSS&lt;/i&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Website:&lt;/td&gt;&lt;td&gt;&lt;a href="http://git-scm.com/"&gt;git-scm.com&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
Free hosting service of open-sources &lt;a href="http://www.github.com/"&gt;Github&lt;/a&gt; - Charges applied for private hostings.&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;GMail&lt;/span&gt; When I started working, I dealt with many machines and I hated having to start one just to look at a specific inbox. With GMail, my account is available anywhere. When I read &lt;a href="http://www.micropersuasion.com/2007/02/transform_gmail.html"&gt;Turn Gmail Into Your Personal Nerve Center&lt;/a&gt;, I started to use GMail as my knowledge database.  &lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: white; border: 1px solid black; padding: 5px 10px; font-size: smaller;"&gt;&lt;img src="http://www.crunchbase.com/assets/images/resized/0001/2806/12806v2-max-150x150.jpg" style="float: right;" /&gt;&lt;table style="border: 0; padding: 0; margin: 0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;Company:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.crunchbase.com/company/google"&gt;Google&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Website:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.gmail.com/"&gt;gmail.com&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Launch Date:&lt;/td&gt;&lt;td&gt;April 1, 2004&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
Gmail, also known as Google Mail, is a free email service with innovative features like “conversation view” email threads, search-oriented interface and plenty of free storage (almost 7GB). Gmail opened in private beta mode in April 2004 by invite only. At first, invites were hard to come by and were spotted up for sell on auction sites like eBay. The email service is now open to everyone and is part of Google Apps. Paul Buchheit, an early employee at Google, is given credit for building the product.&lt;br /&gt;
&lt;br /&gt;
Another Gmail feature is the organization, tracking and recording users’ contact lists. For instance, if you start typing the letter C into the “To” field Gmail will bring up a list of every email address and contact name starting with the letter. This feature helps when you can’t quite remember a name. Plus, Gmail automatically adds and updates email addresses and names to your contact list when you write emails.&lt;br /&gt;
&lt;div style="float: right; padding: 0 10px; background-color: lightgrey;"&gt;Credits: &lt;a href="http://www.crunchbase.com/"&gt;CrunchBase&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Google Calendar&lt;/span&gt; My first job in Montréal, Canada, was with a small company named Steltor (bought few years later by Oracle). The core business was the development of a distributed calendar system (servers in cluster, native clients, web client, mobile client, etc.). Since then, I am used to tracking my work with an electronic calendar. Google Calendar and its ability to mix many agendas is excellent.  &lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: white; border: 1px solid black; padding: 5px 10px; font-size: smaller;"&gt;&lt;img src="http://www.crunchbase.com/assets/images/resized/0001/2812/12812v1-max-150x150.png" style="float: right;" /&gt;&lt;table style="border: 0; padding: 0; margin: 0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;Company:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.crunchbase.com/company/google"&gt;Google&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Website:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.google.com/calendar"&gt;google.com/calendar&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Launch Date:&lt;/td&gt;&lt;td&gt;August 21, 2007&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
Google Calendar lets users create events, manage multiple calendars and share calendars with teams and groups. Users can view their calendar by day, week or month. Calendar has a “Quick Add”� feature that lets you input natural language entries fast. For instance, you can type “Dinner with Michael 7pm tomorrow” into the entry box and Calendar will add “Dinner with Michael” into tomorrow’s agenda at 7pm without needing a specific date. Calendar can also be set-up to send you SMS or email alerts for upcoming calendar entries.&lt;br /&gt;
&lt;div style="float: right; padding: 0 10px; background-color: lightgrey;"&gt;Credits: &lt;a href="http://www.crunchbase.com/"&gt;CrunchBase&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Google Reader&lt;/span&gt; In the old day, reading blogs was time consuming and annoying because of the ad banners. With the introduction of Google Reader, reading them from one central place while just using keystrokes was a pleasure. With the introduction of the &lt;a href="http://googlereader.blogspot.com/2006/03/reader-learns-to-share.html"&gt;Share this&lt;/a&gt; feature, I became to be a &lt;a href="http://www.google.com/reader/shared/02343169150872088595"&gt;media myself&lt;/a&gt;. The &lt;a href="http://googlereader.blogspot.com/2008/05/share-anything-anytime-anywhere.html"&gt;Share with note&lt;/a&gt; function is an quite recent addition that allows me to point posts that are more important to me.  &lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: white; border: 1px solid black; padding: 5px 10px; font-size: smaller;"&gt;&lt;img src="http://www.crunchbase.com/assets/images/resized/0001/2818/12818v1-max-150x150.png" style="float: right;" /&gt;&lt;table style="border: 0; padding: 0; margin: 0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;Company:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.crunchbase.com/company/google"&gt;Google&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Website:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.google.com/reader"&gt;google.com/reader&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Launch Date:&lt;/td&gt;&lt;td&gt;October 1, 2005&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
Google Reader is an online RSS feed reader.&lt;br /&gt;
&lt;div style="float: right; padding: 0 10px; background-color: lightgrey;"&gt;Credits: &lt;a href="http://www.crunchbase.com/"&gt;CrunchBase&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;Google Search&lt;/span&gt; Google Search is an amazing tool: recently, I was trying to find a solution to a tough technical problem and I found it thanks to Google Search which pointed toward a blog post written the same day, just few hours before, in Europe! Incredible... When I give a conference into universities, I often say: “If I asked a question today and you have no clue about the response, that's fine. If you still have no clue tomorrow, you're in trouble...”   &lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: white; border: 1px solid black; padding: 5px 10px; font-size: smaller;"&gt;&lt;img src="http://www.crunchbase.com/assets/images/resized/0002/9578/29578v7-max-150x150.jpg" style="float: right;" /&gt;&lt;table style="border: 0; padding: 0; margin: 0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;Company:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.crunchbase.com/company/google"&gt;Google&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Website:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.google.com/"&gt;google.com&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Launch Date:&lt;/td&gt;&lt;td&gt;September 4, 1998&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
Search is Google’s core product and is what got them an official transitive verb addition to the Merriam Webster for “google”. The product is known for its Internet-crawling Googlebots and its PageRank algorithm influenced heavily by linking.&lt;br /&gt;
&lt;br /&gt;
When users type keywords into the home page search box they are returned with relevant results that they can further refine. Google also has more specific search for blogs, images, news and video. Google will also return search results from your own computer files and emails via Google Desktop.&lt;br /&gt;
&lt;div style="float: right; padding: 0 10px; background-color: lightgrey;"&gt;Credits: &lt;a href="http://www.crunchbase.com/"&gt;CrunchBase&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;KeePass&lt;/span&gt; KeePass is an open source Password Safe. I use it in conjunction with Dropbox. Much usable that PGP/GPG in the sense I don't have to save the decrypted file and then being at risk if I forget to wipe this copy from disk.  &lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: white; border: 1px solid black; padding: 5px 10px; font-size: smaller; min-height: 80px;"&gt;&lt;img src="http://keepass.info/images/plockb75.gif" style="float: right;" /&gt;&lt;table style="border: 0; padding: 0; margin: 0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;Company:&lt;/td&gt;&lt;td&gt;&lt;i title="Free and Libre Open Source Software"&gt;FLOSS&lt;/i&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Website:&lt;/td&gt;&lt;td&gt;&lt;a href="http://keepass.info/"&gt;keepass.info&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;LinkedIn&lt;/span&gt; I started using LinkedIn when a wonderful team I worked with at Oracle exploded because of stupid political decision. Then some friends left to go with Google, one colleague went to Adobe, etc., and LinkedIn was the tool to stay connected. Since then, LinkedIn allowed to get many job propositions, like Compuware's one I accepted. I have been also able to retrieve friends I had in France, even one I may engage a partnership with.  &lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: white; border: 1px solid black; padding: 5px 10px; font-size: smaller;"&gt;&lt;img src="http://www.crunchbase.com/assets/images/resized/0001/1055/11055v1-max-150x150.png" style="float: right;" /&gt;&lt;table style="border: 0; padding: 0; margin: 0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;Company:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.crunchbase.com/company/linkedin"&gt;LinkedIn&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Website:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.linkedin.com/"&gt;linkedin.com&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Launch Date:&lt;/td&gt;&lt;td&gt;May, 2003&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
LinkedIn is a free business social networking site that allows users who register to create a professional profile visible to others. Through the site, individuals can then maintain a list of known business contacts, known as Connections. LinkedIn users can also invite anyone to join their list of connections. LinkedIn offers an effective way by which people can develop an extensive list of contacts, as your network consists of your own connections, your connections’ connections (2nd degree connections), as well as your 2nd degree’s connections (called your 3rd degree connections). From this network, individuals can learn of and search for jobs, business opportunities, and people. LinkedIn also serves as an effective medium by which both employers and job seekers can review listed professional information about one another. LinkedIn follows strict privacy guidelines wherein all connections made are mutually confirmed and individuals only appear in the LinkedIn network with their explicit consent. Other LinkedIn features include paid accounts that offer more tools to find people, and “LinkedIn Answers” developed in January 2007. A free feature, “LinkedIn Answers” allows registered users to post business-related questions that anyone else can answer.&lt;br /&gt;
&lt;div style="float: right; padding: 0 10px; background-color: lightgrey;"&gt;Credits: &lt;a href="http://www.crunchbase.com/"&gt;CrunchBase&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;VirtualBox&lt;/span&gt; Developing software requires sometimes specific configurations. Testing them requires always specific configurations (at least to replay always the same test cases every time the source control system, like Git, is updated). There are the famous VMWare products (Workstation, Player, ESX) and Microsoft VirtualPC. VirtualBox is an open source product provided by SUN Microsystems, and it has nice features while being powerful.  &lt;br /&gt;
&lt;br /&gt;
&lt;div style="background-color: white; border: 1px solid black; padding: 5px 10px; font-size: smaller; min-height: 185px;"&gt;&lt;img src="http://www.virtualbox.org/graphics/vbox_logo2_gradient.png" style="float: right;" /&gt;&lt;table style="border: 0; padding: 0; margin: 0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;Company:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.sun.com/"&gt;Sun Microsystems&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Website:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.virtualbox.org/"&gt;virtualbox.org&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
VirtualBox is a family of powerful x86 virtualization products for enterprise as well as home use. Not only is VirtualBox an extremely feature rich, high performance product for enterprise customers, it is also the only professional solution that is freely available as Open Source Software under the terms of the GNU General Public License (GPL).&lt;br /&gt;
&lt;br /&gt;
Presently, VirtualBox runs on Windows, Linux, Macintosh and OpenSolaris hosts and supports a large number of guest operating systems including but not limited to Windows (NT 4.0, 2000, XP, Server 2003, Vista), DOS/Windows 3.x, Linux (2.4 and 2.6), Solaris and OpenSolaris, and OpenBSD.&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;span style="font-size: large;"&gt;YouTube and Google Video&lt;/span&gt; YouTube is famous because of fun videos. But it also hosts technical videos.  &lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://research.google.com/video.html"&gt;Tech Talk at Google&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.youtube.com/user/GoogleDevelopers"&gt;Google Developer Channel&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
&lt;div style="background-color: white; border: 1px solid black; padding: 5px 10px; font-size: smaller;"&gt;&lt;img src="http://www.crunchbase.com/assets/images/resized/0001/0724/10724v1-max-250x250.png" style="float: right;" /&gt;&lt;table style="border: 0; padding: 0; margin: 0" cellspacing="0"&gt;&lt;tr&gt;&lt;td&gt;Company:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.crunchbase.com/company/youtube"&gt;Youtube&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Website:&lt;/td&gt;&lt;td&gt;&lt;a href="http://www.youtube.com/"&gt;youtube.com&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Launch Date:&lt;/td&gt;&lt;td&gt;December 11, 2005&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;br /&gt;
YouTube was founded in 2005 by Chad Hurley, Steve Chen and Jawed Karim, who were all early employees of PayPal. YouTube is the leader in online video, sharing original videos worldwide through a Web experience. YouTube allows people to easily upload and share video clips across the Internet through websites, mobile devices, blogs, and email.&lt;br /&gt;
&lt;br /&gt;
Everyone can watch videos on YouTube. People can see first-hand accounts of current events, find videos about their hobbies and interests, and discover the quirky and unusual. As more people capture special moments on video, YouTube is empowering them to become the broadcasters of tomorrow.&lt;br /&gt;
&lt;br /&gt;
In November 2006, within a year of its launch, YouTube was purchased by Google Inc. in one of the most talked-about acquisitions to date.&lt;div style="float: right; padding: 0 10px; background-color: lightgrey;"&gt;Credits: &lt;a href="http://www.crunchbase.com/"&gt;CrunchBase&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;
I hope it helps,&lt;br /&gt;
A+, Dom&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-2565771806693665955?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=FFJG8iFL"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=g4dKgei7"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=g4dKgei7" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=b2hevKDM"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=b2hevKDM" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/_MgblbXhU_s" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/2565771806693665955/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2009/01/2009-products-i-cant-leave-without.html#comment-form" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/2565771806693665955?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/2565771806693665955?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/_MgblbXhU_s/2009-products-i-cant-leave-without.html" title="2009 Products I Can't Leave Without" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2009/01/2009-products-i-cant-leave-without.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkQERn86fSp7ImA9WxVRFUU.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-2601575032529536751</id><published>2008-12-28T21:10:00.009-05:00</published><updated>2009-01-21T20:38:27.115-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-21T20:38:27.115-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Experience" /><title>Career Advice '08</title><content type="html">In &lt;a href="http://domderrien.blogspot.com/2008/12/manager-attitude.html"&gt;my previous post&lt;/a&gt;, I wrote mostly about how managers should deal with their subordinates. I think most of the time the &lt;i&gt;real&lt;/i&gt; work is achieved by regular employees and the delivered quality depends on how the management support the &lt;i&gt;do-ers&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
At the same time, having subordinates just doing their job and waiting for their management to come with all solutions is not realistic. I was trying to organize a post on how subordinates should differentiate themselves from the mass when I came across this presentation (thank you Steven[1]): it's a presentation by Gary Reynolds about Dave Pink's bool “Six Career Lessons”.&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;br /&gt;
&lt;div id="__ss_372443" style="text-align: left; width: 425px;"&gt;&lt;a href="http://www.slideshare.net/garr/career-advice-08?type=powerpoint" style="display: block; font-family: Helvetica,Arial,Sans-serif; font-size-adjust: none; font-size: 14px; font-stretch: normal; font-style: normal; font-variant: normal; font-weight: normal; line-height: normal; margin: 12px 0pt 3px; text-decoration: underline;" title="Career Advice '08"&gt;Career Advice '08&lt;/a&gt;&lt;object height="355" style="margin: 0px;" width="425"&gt;&lt;param name="movie" value="http://static.slideshare.net/swf/ssplayer2.swf?doc=careeradvice-1209142144854362-8&amp;rel=0&amp;stripped_title=career-advice-08" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slideshare.net/swf/ssplayer2.swf?doc=careeradvice-1209142144854362-8&amp;rel=0&amp;stripped_title=career-advice-08" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;
&lt;div style="font-family: tahoma,arial; font-size: 11px; height: 26px; padding-top: 2px;"&gt;View SlideShare &lt;a href="http://www.slideshare.net/garr/career-advice-08?type=powerpoint" style="text-decoration: underline;" title="View Career Advice '08 on SlideShare"&gt;presentation&lt;/a&gt; or &lt;a href="http://www.slideshare.net/upload?type=powerpoint" style="text-decoration: underline;"&gt;Upload&lt;/a&gt; your own. (tags: &lt;a href="http://slideshare.net/tag/presentation" style="text-decoration: underline;"&gt;presentation&lt;/a&gt; &lt;a href="http://slideshare.net/tag/pink" style="text-decoration: underline;"&gt;pink&lt;/a&gt;)&lt;/div&gt;&lt;/div&gt;&lt;/center&gt;&lt;br /&gt;
&lt;br /&gt;
The slide 174 summarizes the six lessons:&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_VZZAFHl2_Og/SVg12RRbvkI/AAAAAAAACUA/NkdS9MWTmeQ/s400/2008-12-28_2108.png" /&gt;&lt;br /&gt;
Slide 174 from &lt;a href="http://www.slideshare.net/garr/career-advice-08?type=powerpoint" style="text-decoration: underline;" title="View Career Advice '08 on SlideShare"&gt;Gary Reynolds' presentation&lt;/a&gt;.&lt;/center&gt;&lt;br /&gt;
&lt;br /&gt;
Being a technician in a domain with a fantastic innovation trend, I have to emphasize on lessons 2 to 4:&lt;br /&gt;
&lt;blockquote&gt;Go beyond being just good at something: become an expert! For example, you can be a proficient developer, push to cover everything you produce with unit tests: you will be able to prove that your production is rock solid. If you know many natural languages, develop easily localizable applications (we produce for a global market).&lt;br /&gt;
&lt;br /&gt;
Work to maintain the excellency of your expertise! Most companies do not let employees &lt;i&gt;thinking freely&lt;/i&gt; during the regular hour - to my knowledge, only Google clearly allows it [2]. So you will have to invest your personal time to stay up-to-date.&lt;br /&gt;
&lt;br /&gt;
Share your expertise! Your expertise is useless without you sharing it. Sharing it does not expose you dangerously because potential thieves will not have your experience and because they will not stay up-to-date. In reverse, sharing it will expose you to valuable experiences and feedback from your audience, adding up to your existing sources of information.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/blockquote&gt;These days, there are so many ways to build and share an expertise:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Write an insightful blog;&lt;/li&gt;
&lt;li&gt;Participate to an open-source project;&lt;/li&gt;
&lt;li&gt;Publish technical articles (developerWorks [3], MSDN [4], OTN [5], etc.);&lt;/li&gt;
&lt;li&gt;Speak to conferences (require a lot of energy and often a lot of money);&lt;/li&gt;
&lt;li&gt;Build a successful project which delivers values to your customers!&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;Everyone should make his own path, whatever the environment is. If conditions are too tough (because the management is not supportive, for example), look for another place. If they are not so bad, find any occasion to build your expertise and grow yourself ;)&lt;br /&gt;
&lt;br /&gt;
Happy new year 2009!&lt;br /&gt;
&lt;br /&gt;
&lt;div style="border: 1px solid darkgrey; background-color: lightgrey;"&gt;&lt;u&gt;Update:&lt;/u&gt;&lt;br /&gt;
Tim O'Reilly, on O'Reilly Radar blog, has published a post aligned with my position. Here is principles:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;Work on something that matters to you more than money.&lt;/li&gt;
&lt;li&gt;Create more value than you capture.&lt;/li&gt;
&lt;li&gt;Take the long view.&lt;/li&gt;
&lt;/ol&gt;What? You haven't started demonstrating your value? Just kidding...&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;div style="border: 1px solid darkgrey; background-color: lightgrey;"&gt;&lt;u&gt;Second update:&lt;/u&gt;&lt;br /&gt;
Tim O'Reilly has been interviewed on the top &lt;a href="http://radar.oreilly.com/2009/01/work-on-stuff-that-matters-interview-tim-oreilly.html"&gt;Work On Stuff That Matters&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;embed src="http://blip.tv/play/gpl_5rIMko8o" type="application/x-shockwave-flash" width="640" height="390" allowscriptaccess="always" allowfullscreen="true"&gt;&lt;/embed&gt;&lt;/center&gt;&lt;br /&gt;
The video is on mutliple parts. Check &lt;a href="http://radar.oreilly.com/"&gt;O'Reilly radar&lt;/a&gt; webiste for additional parts.&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
A+, Dom&lt;br /&gt;
--&lt;br /&gt;
Sources:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;&lt;a href="http://stevenmilstein.com/"&gt;Steven Milstein&lt;/a&gt;'s blog&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.google.com/support/jobs/bin/static.py?page=diversity.html&amp;amp;sid=workenvironment"&gt;Google Jobs: Work Environment: 20% project concept&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.ibm.com/developerworks/"&gt;IBM developerWorks&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-ca/default.aspx"&gt;Microsoft Developer Network&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.oracle.com/technology/index.html"&gt;Oracle Technology Network&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Tim O'Reilly post on &lt;a href="http://radar.oreilly.com/2009/01/work-on-stuff-that-matters-fir.html"&gt;Work on Stuff that Matters: First Principles&lt;/a&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-2601575032529536751?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=tRMvgPUz"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=KTf0Diwq"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=KTf0Diwq" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=0l3nozvz"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=0l3nozvz" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/Q10QVSJwqdw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/2601575032529536751/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2008/12/career-advice.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/2601575032529536751?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/2601575032529536751?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/Q10QVSJwqdw/career-advice.html" title="Career Advice '08" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_VZZAFHl2_Og/SVg12RRbvkI/AAAAAAAACUA/NkdS9MWTmeQ/s72-c/2008-12-28_2108.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2008/12/career-advice.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU4DRXgzcSp7ImA9WxVSEkQ.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-2705960893858036775</id><published>2008-12-10T09:15:00.001-05:00</published><updated>2009-01-06T21:06:14.689-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-06T21:06:14.689-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Experience" /><title>Manager Attitude</title><content type="html">A long time ago, I read the famous Joel Spolsky [1] entries on management:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.joelonsoftware.com/items/2006/08/08.html" target="_blank"&gt;The Command and Control management method &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.joelonsoftware.com/items/2006/08/09.html" target="_blank"&gt;The Econ 101 management method&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.joelonsoftware.com/items/2006/08/10.html" target="_blank"&gt;The Identity management method&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;As an experienced worker, I know my limits: for example, I do not think I will be a good &lt;u&gt;typical&lt;/u&gt; manager... With my expertise based on emerging technologies (read “Web 2.0+” and “mobile”), I lost sometimes my patience while trying to explain new concepts or convince &lt;i&gt;conservative&lt;/i&gt; or &lt;i&gt;ignorant&lt;/i&gt; people. When it is time to deal with personal problems of your subordinates, I really think that such attitudes are absolutely unacceptable.&lt;br /&gt;
&lt;br /&gt;
Despite this &lt;i&gt;fear&lt;/i&gt;, I really like mentoring people. I can focus on transferring knowledge (what is the point of being an expert if you do not share your knowledge?) without having to deal with risky personal situations! I act as a mentor in different situations:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;With new employees and interns: to teach them the best practices (efficiency is not that important at the beginning), to have them fully understanding the requirements before thinking about implementation details (to avoid the risk of delivering something that does not match the requirements), etc.&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;With experienced developers having a different technical background: to identify their strengths and to make them more productive (better designer, delivering high quality code, documenting their production, more &lt;i&gt;agile&lt;/i&gt;).&lt;/li&gt;
&lt;li&gt;And with managers for reasons I am going to developed below.&lt;/li&gt;
&lt;/ul&gt;I have been introduced to the formal process of pairing mentors and &lt;i&gt;mentees &lt;/i&gt;while working for IBM Rational. I would say that IBM has the best personal development program I have ever seen. And the mentorship is a corner stone of that program. This was the first time I had a formal mentor (Arthur Ryman, IBM Distinguished Engineer [2, 3]). Because it was a successful experience, I started then to become a mentor myself.&lt;br /&gt;
&lt;br /&gt;
Usually, implementers (or do-ers, or pigs [4, 5]) are receptive to suggestions. Managers (or chickens [4,5]) are much less willing to listen. In my experience, I met many people that followed the path governed by the Peter Principle [6]. Usually, the only way to get promoted is to become a manager; very few people start their career as managers. Promoted managers often lack of training, and they mostly following the pattern managers have serve to them.&lt;br /&gt;
&lt;br /&gt;
What is the big difference among managers and regular employees? The first ones have been empowered to take decisions and the second ones usually follow orders. Many managers I worked and I work with have a technical expertise reversely proportional to their management experience. And they have most of the time a better salary than their reports.&lt;br /&gt;
&lt;br /&gt;
Managers have many responsibilities, and there is one that is often incompletely assumed: ensure their reports can deliver their best.&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;I find dangerous when decisions are taken without having the &lt;i&gt;big picture&lt;/i&gt;. Some managers follow Joel Spolsky's advice and delegate the decision instrumentation.&lt;/li&gt;
&lt;li&gt;At the same way, managers should delegate, I think reports should be able to do the same. For example, a developer needing a second hard drive to host big virtual machines should be able to go to his manager, to expose his requirement, and then go back working while the manager fills up the purchase request. How many times have you seen such a situation? Personally too rarely, and just from &lt;i&gt;junior&lt;/i&gt; managers who had still fresh in mind some past frustrations. Most of the time, managers think their time is too expensive for such basic tasks and they prefer wasting the time of their smart reports.&lt;/li&gt;
&lt;li&gt;A good manager should delegate to their reports and accept delegation from their reports. Each aspect of the delegation makes the reports more motivated and then producing a better job. I think benefits gained by applying only one delegation aspect are easily compensated by the frustration generated the non application of the other aspect.&lt;/li&gt;
&lt;/ul&gt;For the fun of it, and because I endorsed most of lessons described in the article &lt;a href="http://webworkerdaily.com/2008/07/24/14-things-corporations-can-learn-from-seasoned-web-workers/"&gt;14 Things Corporations Can Learn from Seasoned Web Workers&lt;/a&gt;, I sent it to many managers (development managers, human resources manager, product managers, etc.). Was it because they are “control freaks”, because they are going to lost their power, because they cannot do basic things anymore for others (especially for reports), but none came back saying: “Good article. Let's see what we can make happening.”&lt;br /&gt;
&lt;br /&gt;
This conclusion is another argument why I do not want to be another manager. Hopefully, my current expertise allows me to focus on technical works, to be just a mentor, to give advice and to accept suggestions in return, and to stay on the implementers' side where true collaboration is common.&lt;br /&gt;
&lt;br /&gt;
A+, Dom&lt;br /&gt;
--&lt;br /&gt;
Sources:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;&lt;a href="http://joelonsoftware.com/"&gt;Joel on Software blog&lt;/a&gt; by Joel Spolsky&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.eclipse.org/webtools/people/person.php?name=ryman"&gt;Arthur Ryman's profile&lt;/a&gt; on eclipse.org&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.eclipsewtp.org/"&gt;Eclipse Web Tool Plateform&lt;/a&gt;: book co-authored by Arthur Ryman.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blogs.msdn.com/nickmalik/archive/2006/01/23/Chicken-And-Pigs.aspx"&gt;Chickens and pigs in situation&lt;/a&gt; by Nick Malik&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Scrum_%28development%29"&gt;Chicken and pig roles in SCRUM context&lt;/a&gt; on wikipedia&lt;/li&gt;
&lt;li&gt;Description of the &lt;a href="http://en.wikipedia.org/wiki/Peter_Principle"&gt;Peter Principle&lt;/a&gt; on wikipedia -- read the part on Dilbert Principle ;)&lt;br /&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-2705960893858036775?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=DdrMUY3W"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=Rm429Tl9"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=Rm429Tl9" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=7kRWrMSJ"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=7kRWrMSJ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/pLInwebnaaM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/2705960893858036775/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2008/12/manager-attitude.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/2705960893858036775?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/2705960893858036775?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/pLInwebnaaM/manager-attitude.html" title="Manager Attitude" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2008/12/manager-attitude.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUMAQnk9fCp7ImA9WxRUFko.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-1119397851014166149</id><published>2008-11-25T23:24:00.000-05:00</published><updated>2008-11-25T23:24:03.764-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-11-25T23:24:03.764-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Technology" /><title>Mobile devices and mobile Web applications</title><content type="html">Beginning of 2000, I had colleagues developing applications for mobile phones. The calendar service offered by the company then named CS&amp;amp;T (renamed in Steltor later, and then acquired by Oracle in 2003) was using the Wireless Access Protocol (WAP [1, 2]) and SyncML [3] to convey scheduling information up to mobile devices and to return end-users' updates. Event notifications were sent by SMS [4]. Because WAP and SMS are standards implemented by most of the wireless networks (GSM, CDMA, PDC, DECT, etc. [5]), and because they can be processed by many devices (mobile phones, pagers, smartphones, etc.), it was a successful feature.&lt;br /&gt;
&lt;br /&gt;
Today, mobile devices are not just connected to one Telecommunication Operator (telco) network: they can be connected to computers &lt;i&gt;via&lt;/i&gt; Bluetooth [6, 7] and directly to Ethernet networks by Wi-Fi [8, 9] and soon by WiMAX [10].&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;img border="0" height="76" src="http://upload.wikimedia.org/wikipedia/en/thumb/5/5d/GSMLogo.svg/200px-GSMLogo.svg.png" width="96" /&gt; &lt;img border="0" height="30" src="http://upload.wikimedia.org/wikipedia/en/thumb/d/da/Bluetooth.svg/300px-Bluetooth.svg.png" width="128" /&gt;&lt;br /&gt;
&lt;img border="0" height="61" src="http://upload.wikimedia.org/wikipedia/en/thumb/3/32/Wi-Fi_Logo.svg/180px-Wi-Fi_Logo.svg.png" width="96" /&gt; &lt;img border="0" height="72" src="http://www.digitalworldtokyo.com/entryimages/2007/10/071019_WiMAX_Forum.jpg" width="128" /&gt;&lt;/center&gt;&lt;br /&gt;
&lt;br /&gt;
And these additional networks offer more bandwidth to mobile applications.&lt;br /&gt;
&lt;br /&gt;
At the same time networks offer a better service, the power of mobile devices increases [11]. With their relatively wide screens, there is less and less reason to define specific User Interfaces (UI) for the mobile applications. What we did in the past with SynchML can be easily achieved with a modern browser (Webkit based for the iPhone and Android smartphones) running a JavaScript engine. In that sense, I would say like others [12, 13] that the “Mobile Web is dead”.&lt;br /&gt;
&lt;br /&gt;
Web applications are good because they provide a sandbox (no general file system access, limited connection capabilities) and because they can be rendered seamlessly almost everywhere thanks to the browser Firefox [14]. A key element of Web applications is the URL addressing: this piece of information can be embedded everywhere (in an e-mail, in a document, in a Web page, etc.). URLs can be bookmarked by the browser, by a remote service, or as a desktop shortcut. End-users can check the navigation history, can go back and forth, can reload, can open in a new tab or a new window. Thanks to their ubiquity, their safety, and their usability, Web applications deliver really good user experiences.&lt;br /&gt;
&lt;br /&gt;
Because rich feature set of the new handheld devices [11], there are new integrations that Web applications cannot deliver! Consider Google Maps on the iPhone [15] or its equivalent Map View on Android [16]: there are both native applications that use the GPS, the Compass, the multi-touch screen (to zoom in and out, for example). A Web applications can hardly do it today without requiring the end-user to download a browser plugin.&lt;br /&gt;
&lt;br /&gt;
It seems that Web applications will have a hard time competing with native applications on top handheld platforms. If browsers on such platforms do not evolve, all the benefits of Web applications (as mentioned above for end-users, but also for service providers and development teams) will be lost because end-users will mostly look for fully integrated applications!&lt;br /&gt;
&lt;br /&gt;
Does it means that “Mobile Web is dead” can be transformed in “Web is dead on Mobile”? I hope not. What is your opinion?&lt;br /&gt;
&lt;br /&gt;
A+, Dom&lt;br /&gt;
--&lt;br /&gt;
Sources:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Wireless_Application_Protocol"&gt;Wireless Access Protocol (WAP)&lt;/a&gt; by Wikipedia&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.iec.org/online/tutorials/wap/index.asp"&gt;WAP&lt;/a&gt; by the International Engineering Consortium&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/SyncML"&gt;SyncML&lt;/a&gt; by Wikipedia&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Short_message_service"&gt;Short Messaging Service (SMS)&lt;/a&gt; by Wikipedia&lt;/li&gt;
&lt;li&gt;Global Service for Mobile communications (GSM), Code Division Multiple Access (CDMA), Personal Digital Cellular (PDC), Digital Enhanced Cordless Telecommunication (DECT): &lt;a href="http://en.wikipedia.org/wiki/List_of_mobile_phone_standards"&gt;list of mobile phone standards&lt;br /&gt;
&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Bluetooth"&gt;Bluetooth&lt;/a&gt; by Wikipedia&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.bluetooth.com/Bluetooth/Technology/Works/"&gt;How Bluetooth works&lt;/a&gt; by the Bluetooth Special Interest Group (SIG)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Wi-Fi"&gt;Wi-Fi&lt;/a&gt; by Wikipedia&lt;/li&gt;
&lt;li&gt;&lt;a href="http://wi-fi.org/"&gt;Wi-Fi Alliance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Wimax"&gt;WiMAX&lt;/a&gt; by Wikipedia&lt;/li&gt;
&lt;li&gt;&lt;a href="http://domderrien.blogspot.com/2008/11/hand-held-devices-and-sensors.html"&gt;Handheld devices and sensors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.russellbeattie.com/blog/the-end-of-mowser"&gt;End of the mowser&lt;/a&gt; by Russel Beattie&lt;/li&gt;
&lt;li&gt;&lt;a class="TitleLinkStyle" href="http://www.25hoursaday.com/weblog/2008/10/31/RussellBeattieWasRightTheMobileWebIsDead.aspx" rel="bookmark"&gt;Russell Beattie was Right, the Mobile Web is Dead&lt;/a&gt; by Dare Obasandjo&lt;/li&gt;
&lt;li&gt;&lt;a href="http://getfirefox.com/"&gt;Get Firefox&lt;/a&gt; ;)&lt;/li&gt;
&lt;li&gt;iPhone3G: &lt;a href="http://www.apple.com/iphone/features/maps.html"&gt;Maps with GPS&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://googlemobile.blogspot.com/2008/10/google-on-android-maps.html"&gt;Android Map View&lt;/a&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-1119397851014166149?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=N6bAJjH5"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=vbqlCnts"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=vbqlCnts" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=wxmSAsup"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=wxmSAsup" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/ZMe7QXkpv6E" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/1119397851014166149/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2008/11/mobile-devices-and-mobile-web.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/1119397851014166149?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/1119397851014166149?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/ZMe7QXkpv6E/mobile-devices-and-mobile-web.html" title="Mobile devices and mobile Web applications" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2008/11/mobile-devices-and-mobile-web.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkYERnc-cSp7ImA9WxRVGUo.&quot;"><id>tag:blogger.com,1999:blog-168828253523263225.post-202834462341196242</id><published>2008-11-17T12:17:00.001-05:00</published><updated>2008-11-17T22:15:07.959-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-11-17T22:15:07.959-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Community" /><title>OLPC XO available on Amazon</title><content type="html">I blogged before about the One Laptop per Child [1] initiative and I am pleased to remind you that the computer is available on Amazon starting today [2]!&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.amazon.com/b/ref=amb_link_82461111_2?ie=UTF8&amp;amp;node=721521011&amp;amp;pf_rd_m=ATVPDKIKX0DER&amp;amp;pf_rd_s=top-1&amp;amp;pf_rd_r=1B46044E0QSJQ0TVY7Y8&amp;amp;pf_rd_t=301&amp;amp;pf_rd_p=463812031&amp;amp;pf_rd_i=olpc" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://g-ecx.images-amazon.com/images/G/01/00/00/02/86/05/22/286052270._V242930507_.jpg" /&gt;&lt;/a&gt;&lt;br/&gt;Image from Amazon.com website [2]&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
A+, Dom&lt;br /&gt;
--&lt;br /&gt;
Sources:&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;&lt;a href="http://domderrien.blogspot.com/2008/10/olpc-back-with-get-oncegive-one-program.html"&gt;OLPC back with Get Once/Give One program starting Nov. 17&lt;/a&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.amazon.com/b/ref=amb_link_82461111_2?ie=UTF8&amp;amp;node=721521011&amp;amp;pf_rd_m=ATVPDKIKX0DER&amp;amp;pf_rd_s=top-1&amp;amp;pf_rd_r=1B46044E0QSJQ0TVY7Y8&amp;amp;pf_rd_t=301&amp;amp;pf_rd_p=463812031&amp;amp;pf_rd_i=olpc"&gt;OLPC XO available on Amazon&lt;/a&gt;&lt;br /&gt;
&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/168828253523263225-202834462341196242?l=domderrien.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=D7nO4V01"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=tJSBdaKH"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=tJSBdaKH" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/SharingTechnologies?a=nx6bHvfW"&gt;&lt;img src="http://feeds.feedburner.com/~f/SharingTechnologies?i=nx6bHvfW" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/SharingTechnologies/~4/eA-7rSVpWWU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://domderrien.blogspot.com/feeds/202834462341196242/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://domderrien.blogspot.com/2008/11/olpc-xo-available-on-amazon.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/202834462341196242?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/168828253523263225/posts/default/202834462341196242?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/SharingTechnologies/~3/eA-7rSVpWWU/olpc-xo-available-on-amazon.html" title="OLPC XO available on Amazon" /><author><name>Dom Derrien</name><uri>http://www.blogger.com/profile/15197441189507302313</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11701455507852737325" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://domderrien.blogspot.com/2008/11/olpc-xo-available-on-amazon.html</feedburner:origLink></entry></feed>
