# Sunday, 27 March 2011
JAWS is "Just A Web Shell" framework developed by the Facebook IT group for running Force.com web applications on iOS (iPhone/iPad) devices.

JAWS is a "hybrid" mobile application framework that provides a native iOS application on the mobile desktop that instantiates a web browser to a Force.com web page.

The Force.com-Toolkit-JAWS-for-iOS project on GitHub includes all of the following steps and source code for building a mobile iOS app on Force.com.

1) Start in XCode by creating a new View-based iPad or iPhone application.

2) Define a UIWebView controller with a default URL of https://login.salesforce.com.
Append the retURL parameter to the URL to define which Visualforce page to load upon authentication.

3) Launch the Interface Designer and create a simple toolbar with UIWebView to emulate a basic browser UI.

4) Build and launch the iOS simulator from XCode to view the Salesforce login page loaded within the UIWebView

5) Upon login, the return URL (retURL) Visualforce page is loaded. In this case, using the jQuery Mobile framework to display a simple mobile UI.

That's it! The native web shell runs the Visualforce directly on iOS. With some crafty mobile-friendly UI design in HTML5, the end-user may not even detect the app is actually running entirely in the cloud on Force.com!
Sunday, 27 March 2011 10:38:30 (Pacific Standard Time, UTC-08:00)
# Saturday, 09 January 2010
With the economy being what it is, I can think of no better resolution for a small business owner/entrepreneur than to focus on creating jobs.
Ideally these jobs will be created in the Portland, OR metro area, but we're accustomed to operating with distributed teams and are happy to continue doing so.

Web Application Design / Development
With our shift away from .NET and onto the Force.com platform, a person in this role will need to be competent with:
  • Salesforce API and custom/native objects
  • Apex Controllers and Classes / Object modeling
  • Visualforce Pages / Eclipse
  • Javascript / JQuery / AJAX
Possible job creation triggers:
We're actively involved in re-architecting the i-Dialogue platform to run on Force using the above technologies. This product will be launched on the AppExchange with a Freemium business model. As we start to see adoption, the long-term strategy of the product will be to develop and offer add-on premium application modules.
Demand for custom module development, such as custom shopping carts or product configurators, will also spark growth.

Professional Services Developer / Project Manager
The Pro Service Developer is competent with what's available "out of the box" from Salesforce and our core products, and offers last mile customization and development services in direct response to customer and project requirements.

Responsibilities include:
  • Custom Visualforce template design and branding
  • Custom layout
  • Configuration and implementation services
  • Weekly progress meetings. Customer facing support and requirements gathering.
Desired skills:
  • JQuery UI / Themeroller / Custom Themes
  • HTML / Javascript
  • Visualforce (UI emphasis - no custom controller development)
Possible job creation triggers:
  • Clients and customers requiring custom branding of Salesforce Sites and Portal templates.
  • Custom website, landing page, and portal development on Force.com
  • Multi-channel campaigns executed across email and landing page sites
  • Integration projects involving Sites, Customer/Partner Portal, and Ideas

Account / Sales Manager
The AppExchange coupled with our concept of a Site Gallery will automate much of the Sales and Marketing process, however an Account/Sales Manager will be required to assist current and prospective clients assemble the right mix of software and services for their solution and provide quotes.

Possible job creation triggers:
Once the free version is released, we'll shift to offering premium add-on modules within 2 months.

Risks in 2010
The freemium model is somewhat new to us. We're giving away significant value and functionality in the free version, so it's very likely that only 5-20% of all customers will require our premium services, which in turn will enable new job growth. However, this model leverages the scalability and distribution of the cloud and requires no additional effort on our part to provision new computing resources.

The Web Application Design and Development position requires a Software Engineering approach to using Javascript. This is a common skill found in Silicon Valley, but not so much in Portland, OR. It may be difficult to find just the right person(s) for this role.

Most support functions are handled by Pro Service and Account Managers today, but there may be a need for a specific support role in the future.


The actual number of jobs in each position may vary, but these are the 3 primary job functions we'll seek to create in 2010. The products and features we have planned in 2010 are embracing the cloud in ways unimaginable a couple years ago and I'm very excited to wake up each day in pursuit of these solutions. For me, software development has always been about the journey, and surrounding myself with creative, innovative, and passionate individuals on this journey is important.

If past success is any indicator of the future, then I think our new direction will be successful. Of the 60,000+ customers on Salesforce, many are always seeking to gain more value from their CRM investment by deploying Sites and Portals. By running natively and offering services directly on the Force.com platform, rather than at arms length in a hybrid configuration, we're now able to offer much richer applications and solutions.

If you know of anyone in the Portland, OR area that has these particular skill sets, please have them contact me at mike@cubiccompass.com.

Saturday, 09 January 2010 14:11:55 (Pacific Standard Time, UTC-08:00)
# Sunday, 13 December 2009
Update Jan 2012: This article is way out of date. I've since moved to a MacPro for development, using VMWare Fusion to run some Windows apps.

What would be your ultimate machine for developing applications in the cloud?

I've been mulling over this question for a few weeks and finally got around to putting a solution together over a weekend. There are both hardware and software components:

  • Something in between a netbook and laptop, around 4 pounds.
  • 8+ hour battery life
  • 1" thin (Easy to tote)
  • SSD (Solid State Disk 256 GB+)
  • 4 GB RAM
  • 2 GHz CPU+
  • ~$700
I settled on a new Acer 4810 Timeline which met most of my requirements. The exceptions being the Acer has a 1.3 GHz CPU and doesn't have SSD. I wanted the SSD primarily for a speedy boot time, but some tuning of the Win7 sleep options along with the Acer's 8+ hour battery life means the laptop is rarely ever turned off and can quickly recover from sleep mode.


Next up was the software required to fully embrace the cloud. My list of essential cloud tools is no where near as prolific as Scott Hanselman's tool list. But hey, this is a nascent craft and we're just getting started. These tools are essential, in my opinion, for doing development on the leading cloud platforms.

Windows 7
Whoa! I can already hear my Mac toting friends clicking away from this blog post. "WTF? Why Windows 7 for a cloud development machine?" Well, there are several reasons:
  • First of all, even if you do develop on a Mac you likely have a Windows VM or dual boot configured for Windows anyway.
  • Windows has been running on x86 architecture for years. Mac only made the jump a few years ago and is still playing catch up on peripheral device and driver support.
  • Even Google, a huge cloud player, consistently will develop, test, and release all versions of Chrome and Google App Engine tools on Windows before any other platform. Windows developers typically get access to these tools months in advance of Mac users.
  • Eclipse is another tool that is well supported on Windows, above all other platforms.
  • Silverlight support. This is my RIA environment of choice going forward.

Visual Studio 2010 Beta 2
By the time you read this blog, perhaps this version of Visual Studio will be outdated, but it is the first release of VS designed with complete support for Azure.

Windows Azure
You'll need an Azure account to upload your application to the cloud for hosting.

Azure SDK
Great article here for getting started on installing/configuring your machine for the latest Azure bits

Azure Storage Explorer
Azure Storage Explorer is a useful GUI tool for inspecting and altering the data in your Azure cloud storage projects including the logs of your cloud-hosted applications.

Eclipse is a Java-based IDE that requires the Java runtime

Rather than downloading the latest and greatest version of Eclipse, I recommend downloading whatever version is currently supported by the next essential cloud development tool (below)...

Force IDE
Eclipse Plug-in that supports development and management of Apex/Visualforce code on Salesforce.com's platform (aka Force.com)

Google App Engine
Currently, there are both Python and Java development environments for GAE. Like Azure, GAE supports development and debugging on localhost before uploading to the cloud, so the installation package provides a nice local cloud emulation environment.

I have a need for both the Windows Explorer Tortoise shell plug-in and the Eclipse plug-in. You may need only one or the other. All the Force.com open source projects are accessible via SVN.

Git on Windows (msysgit)
It seems gitHub is becoming the defacto standard for managing the source code for many web frameworks and projects. Excellent article here on how to install and configure Git on Windows

Amazon Web Services (AWS) Elastic Fox
Nice Firefox plug-in for managing EC2 and S3 instances on AWS. I mostly just use it for setting up temporary RDP whitelist rules on EC2 instances as I connect remotely from untrusted IP addresses (like airports/hotels/conferences).

I highly recommend using the browser based AWS console for all other provisioning and instance management. There's also an AWS management app for Android users called decaf.

If you're doing real world web development, then you already know the drill. Download and install Internet Explorer 8, Firefox, and Chrome at minimum. In addition to the Elastic Fox plug-in (above) you'll want to install Firebug. IE 8 now has Firebug-like functionality built-in, called the Developer Toolbar. Just hit F12 to access it (see comparison with Firebug here).

I personally use JQuery for all web development that requires DOM manipulation to handle cross-browser incompatibilities and anomalies.

There are 6-10 other utilities and tools I installed on this machine that aren't specific to the cloud. Installing everything on this list took about 90 minutes (plus a couple hours to pull down all my SVN project folders for Passage and other related projects I manage).

Given that cloud development is all about distributing resources over servers and clients, I like to take a minimalist approach and reduce the surface area and drag of my local environment as much as possible. This improves OS and IDE boot time as well as eliminates a lot of common debugging issues as a result of version incompatibilities.

What about you? What hardware/tools/applications are essential to your cloud development projects?

Sunday, 13 December 2009 12:01:04 (Pacific Standard Time, UTC-08:00)
# Saturday, 07 November 2009
Update 2/22/2010 See this article for a better way of using Ajax with Visualforce/Apex.

JQuery and JSON have become my tools of choice for designing and developing Single Page Applications (or SPA). Why?
  1. The user experience is better if the entire page is not refreshed when executing a single action
  2. There's a vast library of JQuery plug-ins and a Developer community to tap into.
  3. Using JSON as the standard object model and separating the UI from the database allows me to design a UI only once and port the application to other cloud platforms (for example, the VF code below can run on i-Dialogue, Google Apps Engine, or Azure by only changing a few lines of code).

Credit goes to Ron Hess for showing me this pattern.I've made very little changes to his Apex code example, except to add JQuery and handling actionFunction rerender callbacks slightly differently.

The basic pattern I'm using for developing Single Page Applications for Visualforce is to call actionFunctions from JQuery, which in turn call Apex controller methods that construct JSON strings. The web page then handles the JSON formatted response in re-rendered outputPanels. The code below demonstrates a simple auto complete function that searches Salesforce Accounts that match a user entered input on each keypress. Clicking on an Account drills down to Account details by calling another actionFunction that retrieves specific Account information.

Some Caveats

  • The outputPanel scripts will execute the first time the page is loaded, so a check for null is required in the callback to prevent first-time execution
  • The dynamic re-rendering of script within an outputPanel makes it difficult to do true functional programming and create closures that elegantly handle the callbacks. More complex applications may have to utilize global state variables, increasing the mutability of the application (and potential for bugs)
  • The mutability of Apex controller properties requires a one-to-one relationship between actionFunction handlers and their corresponding response strings.
  • actionFunctions send the page ViewState in the AJAX XmlHttpRequest and return a blob of XML (apparently using the Sarissa open source library) in the response, which has a slightly slower performance than what you'd get using JQuery's native AJAX utility methods.

Source Code

  1. <apex:page sidebar="false" showHeader="false" standardStylesheets="false" title="AJAX Development Harness" controller="exampleCon">
  2. <style>
  3. body {font-family: Verdana;}
  4. .apexTable { width: 600px;}
  5. .evenTableRow {background-color: #eee;}
  6. .defaultHidden {display: none;}
  7. style>
  8. <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js">script>
  9.     <h3>Using JQuery and JSON with Visualforceh3>
  10.     <apex:form >
  11.         <apex:actionFunction name="apex_searchAccounts" action="{!SearchAccounts}" immediate="true" rerender="searchResultsPanel">
  12.             <apex:param name="searchTerm" value="" />
  13.         apex:actionFunction>
  14.         <apex:actionFunction name="apex_getAccountDetails" action="{!GetAccountDetails}" immediate="true" rerender="accountDetailsPanel">
  15.             <apex:param name="accountid" value="" />
  16.         apex:actionFunction>
  17.     apex:form>
  19.     Enter Account Name: <input type=text id='accountInput' /> (type the letters 'uni' to test)<br/>
  20.     <div id="accountsListView" class="view">div>
  21.     <div id="accountDetailsView" class="view defaultHidden">div>
  23.     <script type="text/javascript">
  24.         $(function() {
  25.             $("#accountInput")
  26.                 .focus()
  27.                 .keyup( function (e) {
  28.                     var searchTerm = $("#accountInput").val();
  29.                     if( searchTerm != ''){
  30.                         apex_searchAccounts(searchTerm);
  31.                     }
  32.             });
  34.             $(".accountDetailsLink").live('click', function() {
  35.                 apex_getAccountDetails( $(this).attr('id') );
  36.             });
  37.         });
  39.         function clearAllViews(){
  40.             $(".view").html('');           
  41.         }
  43.         function renderAccountsListView(accounts){         
  44.             if(accounts.length === 0){
  45.                 $("#accountsListView").html("no accounts matching that query").fadeIn();
  46.                 return;
  47.             }
  48.             var tableHTML = '';
  49.             for(var i=0; i < accounts.length; i++){
  50.                 tableHTML += '
  51. ';
  52.             }
  53.             tableHTML += '
  54. + accounts[i].id + '" href="#" class="accountDetailsLink">' + accounts[i].name + '
  55.             $("#accountsListView").html(tableHTML).fadeIn();
  56.             $("table tr:nth-child(even)").addClass("evenTableRow");
  57.         }
  59.         function renderAccountDetailView(account){         
  60.             var tableHTML = '

    Account Details for ' + account.name + '

  61.             tableHTML += '';         
  62.             tableHTML += '
  63. ';
  64.             tableHTML += '
  65. ';
  66.             tableHTML += '
  67. ';
  68.             tableHTML += '
  69. ';           
  70.             tableHTML += '
  71. Name' + account.name + '
    Type' + account.type + '
    Description' + account.description + '
    Website+ account.website + '" target=_blank>' + account.website + '
  72.             $("#accountDetailsView").hide().html(tableHTML).slideDown();
  73.             $("table tr:nth-child(even)").addClass("evenTableRow");
  74.         }
  75.     script>
  76.     <apex:outputPanel id="searchResultsPanel" layout="block" rendered="true">
  77.         <script>
  78.         function apex_searchAccounts_callback(jsonResponse){           
  79.             if(jsonResponse === null || jsonResponse === ''){
  80.                 return;
  81.             }
  83.             var accounts;
  84.             eval('accounts = ' + jsonResponse);
  85.             if(accounts !== null){
  86.                 renderAccountsListView(accounts);
  87.             }
  88.         }
  89.         clearAllViews();
  90.         apex_searchAccounts_callback('{!JSONSearchAccounts}');
  91.         script>
  92.     apex:outputPanel>    
  94.     <apex:outputPanel id="accountDetailsPanel" layout="block" rendered="true">
  95.         <script>       
  96.         function apex_getAccountDetails_callback(jsonResponse){        
  97.             if(jsonResponse === null || jsonResponse === ''){
  98.                 return;
  99.             }
  101.             var account;
  102.             eval('account = ' + jsonResponse);
  103.             if(account !== null){
  104.                 renderAccountDetailView(account);
  105.             }
  106.         }
  107.         apex_getAccountDetails_callback('{!JSONAccountDetails}');
  108.         script>
  109.     apex:outputPanel>    
  110. apex:page>
  112. //Controller
  114. public class exampleCon {                  
  115.     public String JSONSearchAccounts{ get; set; }
  117.     public PageReference SearchAccounts() {
  118.         String searchTerm = Apexpages.currentPage().getParameters().get('searchTerm');         
  119.         String soql = 'SELECT Id, Name FROM Account WHERE Name like \'' + searchTerm + '%\'';              
  120.         List<Account> accountList = Database.query(soql);          
  122.         string json = '[';
  123.         for(Account acct : accountList){
  124.             json += '{"id": "' + acct.Id + '", ' +
  125.             '"name": "' + acct.Name + '"},';
  126.         }
  127.         json += ']';
  128.         json = json.replace('},]', '}]');
  130.         JSONSearchAccounts = json.replace('\'', '');
  131.         return null;
  132.     }
  134.     public String JSONAccountDetails{ get; set;}
  136.     public PageReference GetAccountDetails() {
  137.         String accountid = Apexpages.currentPage().getParameters().get('accountid');           
  138.         String soql = 'SELECT Id, Name, Type, AccountNumber, Description, Website FROM Account WHERE Id=\'' + accountid + '\'';            
  139.         List<Account> accountList = Database.query(soql);
  141.         if(accountList.size() != 1){
  142.             JSONAccountDetails = '{"error": "Expected only 1 account"}';
  143.             return null;
  144.         }          
  146.         string json = '{';     
  147.         json += '"id": "' + accountList[0].Id + '", ';     
  148.         json += '"name": "' + accountList[0].Name + '", ';
  149.         json += '"type": "' + accountList[0].Type + '", ';
  150.         json += '"accountNumber": "' + accountList[0].AccountNumber + '", ';
  151.         json += '"description": "' + accountList[0].Description + '", ';
  152.         json += '"website": "' + accountList[0].Website + '" ';
  153.         json += '}';       
  155.         JSONAccountDetails = json.replace('\'', '');
  156.         return null;
  157.     }
  158. }
Saturday, 07 November 2009 13:55:33 (Pacific Standard Time, UTC-08:00)
# Wednesday, 04 November 2009

I'm hooked on Single Page Applications (or SPA for short). If you work in Google Apps everyday, then you know what I mean. Open up GMail, Calendar, or even a Google map, and there's just a single page load. All subsequent interactions occur asynchronously via AJAX, producing a fluid, responsive user interface.

Contrast this with a traditional web application where you fetch a page and are given a master list of records. Click on a record and a completely new page loads containing record details (aka Master-Detail pattern).

Visualforce and Dialogue Script are inherited from a paradigm that mostly encouraged multi-page apps. I've spent the greater part of 2009 re-writing just about every single DScript app to be a SPA, and now that I'm developing applications for Force.com I'm going through the same exercise.

First, don't make the same mistake I did and assume that an AJAX application using Visualforce is as simple as using the AJAX Toolkit. It'll work as a VF page within Salesforce, but can't be published to Sites for security reasons. I found this fact most unfortunate since the Salesforce AJAX API is one of the best AJAX frameworks I've worked with as it encourages functional programming (FP) and embraces all the good parts about Javascript (yes, I am trying to shed my 15 years of Object-Oriented programming and learn FP... a blog entry for another day).

A SPA treatment can be given to a Visualforce page through the use of the <apex:actionFunction /> and <apex:outputPanel /> controls, which I'll cover in detail in Part 2.

The swim lanes diagram below (click here for the full version) demonstrates the lifecyle of a Visualforce SPA page.

1) The browser requests the web page which is rendered with default data.
2) Subsequent page clicks call Apex controller methods via actionFunction.
3) The controller methods construct JSON formatted strings. 3) When the request is complete, actionFunctions re-render outputPanels that contain script templates for processing the returned JSON arrays.

Wednesday, 04 November 2009 21:42:09 (Pacific Standard Time, UTC-08:00)