Showing posts with label Google App Engine. Show all posts
Showing posts with label Google App Engine. Show all posts
Wednesday, October 23, 2013

Long Loading Requests in App Engine for Java

In this post, I revisit the loading requests in Google App Engine for Java. The test results are shown below. The following modes are:

Skeleton
Plain-vanilla skeleton webapp with SDK (1.8.2) dependencies.
With Spring Framework Web
Skeleton webapp plus Spring Framework Web (3.2.4.RELEASE) dependencies. This adds almost 3 MB of JARs.
spring-aop-3.2.4.RELEASE.jar335455
spring-beans-3.2.4.RELEASE.jar607755
spring-context-3.2.4.RELEASE.jar863688
spring-core-3.2.4.RELEASE.jar869674
spring-expression-3.2.4.RELEASE.jar196807
spring-web-3.2.4.RELEASE.jar625875
With Spring Web MVC
Webapp with Spring Framework Web MVC. This add one additonal JAR.
spring-webmvc-3.2.4.RELEASE.jar636993
With Spring Web MVC and applicationContext
Webapp with Spring Framework Web MVC and running an empty (zero beans) application context on startup via ContextLoaderListener.
With Google Guice
Skeleton webapp with Google Guice (3.0) dependencies.
With Google Guice (one servlet module)
Webapp with Google Guice servlet context listener, filter, loading a servlet module.
With Google Guice (one servlet module)
Same as before, but built without AOP. The following dependency declaration was used:
        <dependency>
            <groupId>com.google.inject</groupId>
            <artifactId>guice</artifactId>
            <version>${guice.version}</version>
            <classifier>no_aop</classifier>
            <exclusions>
             <exclusion>
              <groupId>aopalliance</groupId>
              <artifactId>aopalliance</artifactId>
             </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>com.google.inject.extensions</groupId>
            <artifactId>guice-servlet</artifactId>
            <version>${guice.version}</version>
            <exclusions>
             <exclusion>
              <groupId>com.google.inject</groupId>
              <artifactId>guice</artifactId>
             </exclusion>
            </exclusions>
        </dependency>  
  

Test Results (Summarized)

Times are measured by shutting down instance, hitting a URL, looking at request time in logs. All using a frontend instance class of F1 (600MHz, 128MB).

ModeAverage Time (ms)
Skeleton4322.6
With Spring Web4836.0
With Spring Web MVC4819.0
With Spring Web MVC and applicationContext8845.6
With Google Guice (no modules)4437.6
With Google Guice (one servlet module)8260.8
With Google Guice (one servlet module, no AOP)5332.2

Observations

  • Adding some JARs (dependencies) to the web application (even without using any of its classes) increases the time it takes to complete a loading request.
  • Adding an empty (zero beans) application context to the web application increases the time by about 4 seconds.
  • Using Google Guice to load servlets and provide dependency injection can add about 4 seconds (similar to using Spring Framework).
  • Removing AOP from the use of Google Guice can lower the additional loading request time.

Test Results (Raw)

ModeTryTime (ms)
Skeleton14050
Skeleton24384
Skeleton34305
Skeleton44609
Skeleton54265
SkeletonAverage4322.6
With Spring Web15001
With Spring Web25115
With Spring Web34783
With Spring Web44724
With Spring Web54557
With Spring WebAverage4836.0
With Spring Web MVC15205
With Spring Web MVC24900
With Spring Web MVC34486
With Spring Web MVC45164
With Spring Web MVC54340
With Spring Web MVCAverage4819.0
With Spring Web MVC and applicationContext19187
With Spring Web MVC and applicationContext28946
With Spring Web MVC and applicationContext38417
With Spring Web MVC and applicationContext48777
With Spring Web MVC and applicationContext58901
With Spring Web MVC and applicationContextAverage8845.6
With Google Guice (no modules)14578
With Google Guice (no modules)24473
With Google Guice (no modules)34480
With Google Guice (no modules)44223
With Google Guice (no modules)54434
With Google Guice (no modules)Average4437.6
With Google Guice (one servlet module)17845
With Google Guice (one servlet module)28426
With Google Guice (one servlet module)38476
With Google Guice (one servlet module)48394
With Google Guice (one servlet module)58163
With Google Guice (one servlet module)Average8260.8
With Google Guice (one servlet module, no AOP)15702
With Google Guice (one servlet module, no AOP)25020
With Google Guice (one servlet module, no AOP)36036
With Google Guice (one servlet module, no AOP)45223
With Google Guice (one servlet module, no AOP)54680
With Google Guice (one servlet module, no AOP)Average5332.2

Related Links

Sunday, September 29, 2013

Early UI, Early Feedback, Better Results

A few months back, I was reviewing some internal apps we had in our organization, and this thing we humbly call the "library app" got my attention. We have a lot of books (physical copies) lying around, and we encourage everyone in the organization to read and apply/share what they've read. So far, it seems to be working.

A group of young developers was learning Grails, and they built this "library app". I wanted to learn too, so I pushed myself to do something that ran on Google's App Engine, and I ended up learning more.

UI and User Experience

I started looking at the current user interface of the one built using Grails. Here's what I saw — a login page.

After logging in, I get the following.

Thanks to PJ for the screenshots.

I asked myself, "What would a typical user do if s/he was greeted with this landing page?" My first response was, I wouldn't even think of clicking any of the two icons. And here's what I saw after clicking on the "Book Listing" icon/link.

There was nothing there that "entices" me to explore and look at the available titles. So, I set out to create a landing page that would make we want to look at what's available.

Early Feedback

Here's what I came up with (largely inspired by iBooks and other similar apps).

libraryapp.onb-demo.appspot.com

I didn't build the code behind it (at least, not yet). I just started with some static HTML, deployed it to the cloud, and asked some colleagues to try it out. I was pleasantly surprised with their reaction. They asked if the app was a modified version of the one built using Grails. They also asked if I got help from our creatives team, and if it was written using Grails. Anyway, the early UI allowed me to get early feedback. And letting the landing page be seen without the need to login also helped (I guess everyone is too lazy busy to login).

So, I proceeded to turn the static HTML into something more dynamic. I started populating the database with book titles. Then, it occurred to me that I was spending so much time entering the titles, authors, publishers, etc. Even though we have about 50+ titles, it was taking too much time. So, I asked around how the current version was being maintained. I was surprised that they did it pretty much the same way I did (adding titles one by one, and typing everything in while looking at the physical copy). I started thinking of improving this. (Seems like an unarticulated need here)

I saw myself Googling the book's title every time I needed to enter its details. Light bulb moment! Why don't I enhance the entry form and allow the user to Google it up, and populate the entry form?

After some rough JavaScript, here's what I ended up with.

I added a "Search" button that would do the search (using Google Books API). The results are shown, and a button is added to use the book information to populate the form.

After I added this, I was able to add titles in no time! This would not have been possible for a user to articulate or express as a requirement. How would they know that APIs exist to help with finding book information? It's critical to observe and experience what the user goes through when using your app to achieve their goals and/or perform their tasks.

I'm no design guru. This simple enhancement is far from a breakthrough. I hardly observed our office admin team use the existing library app. But I'm glad I had this experience, and I hope sharing it here would help others. I indeed learned more than just building apps!

Future Enhancements

As you can see from the screenshot, I have not implemented the borrowing part of the app (yet). But I'm thinking of ways to add a "comments" section to allow users to post their comments about the book. I'm hoping that these comments shall further "entice" others to grab a copy, read, apply, and share.

Tuesday, November 13, 2012

Spring MVC Slow on Google App Engine for Java?

We previously tried deploying Spring-based Java web applications on Google's App Engine (GAE). And I remember abandoning it due to the time it takes to handle a loading request.

Now, I was able to get some time to create a minimal Spring MVC web application and see how it performs on GAE. Below is the result. The web.xml loads the ContextLoaderListener and DispatcherServlet. The application context is empty (i.e. no beans). The dispatcher-servlet.xml contains a <context:component-scan /> tag and a ViewResolver. It takes about 6.75 seconds for a loading request (approximately cpu_ms=3600).



6.75 seconds for a loading request is probably not much. But the 1100 cpu_ms by slim3 is sure enviable. I also found this article helpful in explaining the cause of increase in loading request time.

Here's some detailed log entries:

javax.servlet.ServletContext log: Initializing Spring root WebApplicationContext
…
org.springframework.web.context.ContextLoader initWebApplicationContext: Root WebApplicationContext:
initialization completed in 2420 ms
…
javax.servlet.ServletContext log: Initializing Spring FrameworkServlet 'dispatcher'
org.springframework.web.servlet.FrameworkServlet initServletBean: FrameworkServlet 'dispatcher': initialization started
…
org.springframework.web.servlet.FrameworkServlet initServletBean: FrameworkServlet 'dispatcher':
initialization completed in 2995 ms

Looks like the DispatcherServlet eats up some processing time. If we just use the ContextLoader, and plain-vanilla servlets, the loading request time should be tolerable.