# Saturday, 14 November 2009

I hope the buzz is true. If so, I plan to setup a netbook specifically for running Chrome OS. Even better if the netbook/OS can run Eclipse. I'll make it my "cloud machine" :-).

Saturday, 14 November 2009 11:13:25 (Pacific Standard Time, UTC-08:00)
# Wednesday, 11 November 2009
CodeRun is a fantastic site. I'm not sure how long it's been around, but sure wish I'd discovered it earlier.

While I'm impressed with any attempt to deploy a cloud-based IDE, most editors have their limitations, leaving me to fall back to using Visual Studio, Eclipse, or Notepad++ for 90% of all development work.

This leaves me to wonder if the web is so unique that the traditional IDE as a design metaphor perhaps shouldn't be carried forward. Since the cloud is a completely new way of managing IT assets and applications, should the development environment also be as innovative?

The CodeRun IDE first presents itself as a web version of Visual Studio.NET. It was almost scary to see such a faithful replication of the Windows based application entirely in HTML.

CodeRun has a fantastic Freemium model where you can start creating projects without even registering an account (I did in order to save my projects). When you're ready to deploy your application to the web, they provide paid services for hosting.

There are several project template options. It's weighted towards traditional C#/ASP.NET development, but there are options for both JQuery and PHP projects. I only played with the ASP.NET, ASP.NET Web Service Application, and JQuery templates.



I was most impressed by the built-in Intellisense. Just type a scoped entity and a drop down list of methods, properties, and interfaces appears (clicking tab to select an intellisense option didn't work like it does in VS). On the fly code highlighting is pretty good. I imagine tab and space management must be difficult to do in a browser IDE, and the code templates I played with had some problems with whitespace.

One use case I focused on was a State Tax webservice for an eCommerce shopping cart application. State sales tax rates don't change very often, which makes it easy to create a webservice that takes a US State input and returns a tax rate (I didn't delve too deep into return types. A production quality web service would be better off returning a more complete data structure).

Coding in C# then pressing "Build" to compile the project seemed very natural. Clicking on a build error took me to the offending line of code.

The "Debug" feature didn't work for me. Best I can tell, you're getting an actual virtualized ASP.NET instance for each project. I changed a namespace which resulted in a cryptic error, and when Debug didn't work I was able to access the actual ASMX file to update the namespace in code front.

The "Databases" feature didn't work either. It says it's in alpha, which I guess means it's a UI prototype (?). Anyway, most web apps would be better served to start from the ground up without a relational database. I would really like to see the concept of a cloud DB be something like CouchDB or a smart JSON store.

Overall, very amazing little tool. I think its borrowed enough from the old school to be familiar to many developers, and therefore easy to adopt. The challenge will be adding the cloud-specific features that help differentiate it from traditional IDEs.

The "I" in IDE is "Integrated". So, in a cloud context, I think this should mean exposing Google Code, Charts, Maps, Amazon S3, Force.com, StrikeIron, Facebook, Twitter, and any number of APIs directly in the IDE.
Wednesday, 11 November 2009 21:26:16 (Pacific Standard Time, UTC-08:00)
# Sunday, 08 November 2009

The term "Write Once, Run Anywhere" was Sun's slogan for illustrating a benefit of using Java. The justification being that Java runs on virtual machines, therefore not bound to any particular physical machines or hardware.

There are clear benefits to exploiting native features in cloud platforms today, but if a "Write Once, Run Anywhere" architectural strategy were available, what might that be?

The most basic components of an Internet application running in the cloud are JSON, Javascript, CSS, and HTML. There are, of course, abstraction development environments that automatically convert from a higher level language to one of these 4 formats.

Every storage solution in the cloud has their own approach to providing database services, but fundamentally they all manage Noun entities (aka tables) that have properties (columns). Cloud storage services also typically provide a web service, or controller tier for getting data out and putting data in.

Design considerations for "write one, run anywhere in the cloud" include:

  1. Embrace the core technologies freely found on the Internet and supported in all browsers
  2. Identify the fundamental Noun entities and properties. Keep it simple.
  3. Use multi columnar design over more complex 4NF schemas.
  4. Modularize the application functions that send/receive data to/from cloud services.
  5. Consider using a client-side database like TaffyDB for managing JSON in the browser.

This architectural pattern is more than a portability enabler. It's actually required for applications that aggregate multiple web services in a single application or use cross-site XHR.

Sunday, 08 November 2009 18:24:44 (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>
  18.    
  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>
  22.                  
  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.             });
  33.              
  34.             $(".accountDetailsLink").live('click', function() {
  35.                 apex_getAccountDetails( $(this).attr('id') );
  36.             });
  37.         });
  38.        
  39.         function clearAllViews(){
  40.             $(".view").html('');           
  41.         }
  42.        
  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.         }
  58.        
  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.             }
  82.            
  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>    
  93.    
  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.             }
  100.            
  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>
  111.  
  112. //Controller
  113.  
  114. public class exampleCon {                  
  115.     public String JSONSearchAccounts{ get; set; }
  116.    
  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);          
  121.        
  122.         string json = '[';
  123.         for(Account acct : accountList){
  124.             json += '{"id": "' + acct.Id + '", ' +
  125.             '"name": "' + acct.Name + '"},';
  126.         }
  127.         json += ']';
  128.         json = json.replace('},]', '}]');
  129.        
  130.         JSONSearchAccounts = json.replace('\'', '');
  131.         return null;
  132.     }
  133.    
  134.     public String JSONAccountDetails{ get; set;}
  135.        
  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);
  140.        
  141.         if(accountList.size() != 1){
  142.             JSONAccountDetails = '{"error": "Expected only 1 account"}';
  143.             return null;
  144.         }          
  145.        
  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 += '}';       
  154.        
  155.         JSONAccountDetails = json.replace('\'', '');
  156.         return null;
  157.     }
  158. }
Saturday, 07 November 2009 13:55:33 (Pacific Standard Time, UTC-08:00)
# Friday, 06 November 2009

So, an email arrives in my inbox today inviting me to try Windows Azure. I've tried Azure a couple times in the past with not much luck. I got the impression from reading some white papers that there was bottom-up innovation going on at the hardware and storage layer and that they had solved the scalability challenges first, but there wasn't much to show from the top-down (unfortunately, where first impressions are made).

But it is Microsoft, so if they're really serious about cloud computing, you got to at least sit up and listen. Here's my 5 minute unedited foray back into the world of Azure.

(Yes, I know the transparency of my video reveals management keys, yadda, yadda. It's a sandbox. I trust you...)

Friday, 06 November 2009 18:09:02 (Pacific Standard Time, UTC-08:00)

Because the format of Salesforce record identifiers are deterministic, there's always a concern when using them in Site URLs that someone will 'guess' record IDs and gain access to records.

If the data you're publishing is public anyway, like Solutions, Events, or Press Releases, then maybe it's no big deal. But when Sites are being used as landing pages for sensitive data, like Opportunities or Partner Accounts, then some more effort is required to protect the records.

Since most records correlate with an Account or Contact, in a portal context it's simple enough to check the record relationship. Otherwise, URL encryption is really the only option for anonymous visitors.

A couple blog entries here and here discuss the use of MD5 hash for creating encrypted URLs.

These solutions use custom fields and triggers to correlate a web page request with an originating request record.

With the recent release of custom settings in Winter 10, there's now the option of storing private keys and using PKI encryption to sign record identifiers and decrypt them.

Unfortunately, the Crypto class documentation is a bit 'cryptic' (pun intended) on how to implement full PKI encryption, since it only demonstrates how to sign strings, and not decrypt them. Hopefully, someone can enlighten me on how this might work. I have a C# RC4 encryption engine that I'm considering converting to Apex, but I obviously prefer to use the native Crypto class, if possible.

(Sample code from Apex Developers Guide)
  1. String algorithmName = 'RSA';
  2. String key = 'pkcs8 format private key';
  3. Blob privateKey = EncodingUtil.base64Decode(key);
  4. Blob input = Blob.valueOf('12345qwerty');
  5. Crypto.sign(algorithmName, input, privateKey);
Friday, 06 November 2009 00:34:25 (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)

If you need a primer on "what is the cloud" from a consumer perspective, my other blog has a good post that explains my definition.

When I talk about "development in the cloud", it basically means implies three things:

  • The application or service is available on the Internet
  • The code you develop is managed and hosted on an Internet server
  • The application is aggregating web services found on the Internet

I won't get into the specifics of multi-tenancy, or any other operational aspects of cloud computing, since there are many means to the same end of delivering services in the cloud.

Cloud services aren't always HTML web applications, although that's primarily what I focus on. Rich Internet Applications (RIA) built on frameworks such as Flash, Flex, and Silverlight are also strong components of the future of cloud computing.

Wednesday, 04 November 2009 15:37:51 (Pacific Standard Time, UTC-08:00)

Part of the reasoning behind the name "Embracing" the cloud is to capture the transformation taking place in my own product design and development methodology.

We've listed various apps on the Salesforce.com AppExchange since 2006, but none were what are called "native" apps running on the Force.com servers. One goal for 2010 is to develop and list up to 3 native apps on the AppExchange using Salesforce Sites.

My first application built using Sites can be found here. I'll write up a more detailed blog post in the next few days describing the process behind this site.

Wednesday, 04 November 2009 14:58:30 (Pacific Standard Time, UTC-08:00)
Running a small software company requires a healthy focus on communicating the value of your products and services without getting too technical. I founded Cubic Compass in 2001, where we continue to focus on creating great Service and Support portal solutions that are easy for Line of Business managers to deploy and use.

But Programmer-specific content is often too overwhelming for line of business managers, so at "Embracing the cloud", I'm carving out a little corner of the blogosphere where I can write about my passion of writing code for cloud services.

Some things I'll write about, in no particular order:
  • XOS and Dialogue Script (a server-side web framework I developed and maintain)
  • JQuery (my client-side language of choice)
  • Javascript (Assembly/C language for the Internet. Very powerful. I'm always looking to push the JS envelope)
  • Force.com Visual Force and Apex (Salesforce.com now offers much more than CRM)
  • Google Code API
  • Google Android (mobile devices are a key component of the cloud. I don't do iPhone development. Support the Droid!)
  • Softlayer (Where I host stuff)
  • Amazon EC2 (another place I host stuff)
  • Authorize.net (My preferred gateway for credit card processing)
  • Anything hosted in the cloud with a public API
If this sounds interesting to you, please take a moment to add me to your RSS reader. Also, if you write on a similar topic, please send me a link to your blog and I'll add it to my blogroll.

Happy coding in the cloud!
Wednesday, 04 November 2009 14:29:29 (Pacific Standard Time, UTC-08:00)