Archive

Archive for October, 2009

Bootstrapping the ArcGIS Server JavaScript API

October 26th, 2009 1 comment

On a project my team is currently working on with we came across the need to bootstrap the ArcGIS Server JavaScript API.  What I mean by ‘bootstrapping’ is the ability to load the JavaScript API during script execution after page load without loading it declaratively in the <head> of the HTML page.

To better describe the need for this here is a summary of our requirements:

  1. We wanted the ability to embed our live maps (and map related capabilities) as widgets in other HTML pages throughout our company website
  2. We wanted the ability to embed these live maps as a stand-alone snippets of HTML without having to modify the page <head>.  This would allow content authors to embed maps without having access to modify anything but a container element on the page.
  3. We wanted the ability to wrap these up in a container (in our case this will probably be a DotNetNuke module)
  4. We didn’t want the content author to have to know anything about the actual implementation of the map engine.  This future-proofs the implementation as the content author does not have to refer to a specific version of the JavaScript API or even know that the JavaScript API is the engine behind the map.
  5. We didn’t want the loading of the embedded map to have direct impact on the loading of the parent page (asynchronous loading)
  6. We didn’t want to deal with iframes for embedded map widgets

What we wanted was the ability to include a snippet like the following in any page and get a fully dynamic map widget (Note: I have renamed the objects/namespaces to make this description generic. myMapApi is used as the base namespace for these examples):

<!-- Start map widget -->
<script language="javascript" src="http://www.website.com/maps/api.js">
<div id="map" style="width: 600px; height: 400px;"></div>
<script type="text/javascript">
    var map = new myMapApi.Map("map");
</script><br />
<!-- End map widget -->

The ArcGIS Server Javascript API is based on Dojo. When the Javascript API is normally loaded (as a script in the page header) the script will automatically load Dojo and Dojo will then bootstrap the resources that it needs. Dojo includes the ability to load scripts on the fly (using dojo.require) which is the method that is used to load the modules that are required for the current page.

Because Dojo is bootstrapped and modules can be loaded on demand, Dojo provides an addOnLoad method which allows you to ensure that everything has been loaded before proceeding with the execution of code that depends on Dojo components.

The addOnLoad method accepts a callback argument that is used to ‘call back’ when the following conditions are met:

  1. The DOM is loaded
  2. All Dojo modules are loaded (and their recursive dependencies)

If you take a look at the basic map sample from the Javascript API docs you will see the general sequence of events:

  1. Add the Javascript API script reference to the page head
  2. Run dojo.require for all necessary Dojo modules
  3. Create an init method to be called back when everything is loaded
  4. Pass this init method to dojo.addOnload to kick off the execution of the script when the page is loaded.

This works great when you include the ArcGIS Server Javascript API directly in the page head but we wanted to do this by wrapping the Javascript API in our own application API. As noted above, consumers of our maps would then not have to know anything about the ArcGIS Server Javascript API or Dojo.

To get around the async loading that occurs when scripts are included dynamically we implemented a mechanism that is similar to the Dojo addOnLoad.

Here is a sample snippet that would appear in a web page to include our map widget:

<!-- Start map widget -->
<script language="javascript" type="text/javascript" src="api.js"></script>	
<div id="map" style="width: 600px; height: 400px;"></div>
    <script type="text/javascript">
        function init() {
            var map = new myMapApi.Map("map");
        }
        myMapApi.onLoad(init);
</script>
<!-- End map widget -->

Similar to Dojo, the onLoad method accepts a callback method that our API can call when everything it needs has been loaded. The code in our API can then call the callback whenever the ArcGIS Javascript API has been loaded dynamically and whenever Dojo is fully loaded.

The basic challenge at this point was to determine how to load the ArcGIS Server Javascript API dynamically and then determine when it was fully loaded so that the callback method could be called.

Here is what we came up with:

// Create the namespace
if (myMapApi == null || typeof (myMapApi) == 'undefined') { var myMapApi = {}; }

// ESRI Javascript API bootstrapper
(function() {

    // Configure Dojo onLoad so that it works after the page's
	// onload event has already occurred
    djConfig = {
        afterOnLoad: true,
        addOnLoad: function() {
            myMapApi.scriptsLoaded = true;
            if (typeof (myMapApi.onLoadCallback) != 'undefined') {
                myMapApi.onLoadCallback();
            }
        }
    };

    // Dynamically load the Javascript API
    var scriptElement = document.createElement('script');
    scriptElement.type = 'text/javascript';
    scriptElement.src = 'http://serverapi.arcgisonline.com/jsapi/arcgis/?v=1.5';
    document.getElementsByTagName('head')[0].appendChild(scriptElement);
	
	// Dynamically load a Dojo stylesheet
    var linkElement = document.createElement("link");
    linkElement.type = 'text/css';
	linkElement.rel = 'stylesheet';
	linkElement.media = 'screen';
    linkElement.href = 'http://serverapi.arcgisonline.com/jsapi/arcgis/1.5/js/dojo/dijit/themes/tundra/tundra.css';
    document.getElementsByTagName('head')[0].appendChild(linkElement);

})();

// Create an onLoad event to call the client back on when
// dependant scripts have been loaded 
myMapApi.onLoad = function(onLoadCallback) {
    myMapApi.onLoadCallback = onLoadCallback;
    if (myMapApi.scriptsLoaded) { myMapApi.onLoadCallback(); }
}

// The Map class creates and loads the actual map in the parent container
myMapApi.Map = function(containerId) {
	
	// Get the container in which to create the map
	var container = dojo.byId(containerId);
	
    // Create a div for the map
    var mapDiv = document.createElement("div");
    mapDiv.className = "tundra";
    mapDiv.id = "mapdiv";
	container.appendChild(mapDiv);
    mapDiv.style.width = container.offsetWidth;
    mapDiv.style.height = container.offsetHeight;

    // Create the map
    var map = new esri.Map("mapdiv");

	// Add a service to the map
	var service = "http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer";
    var tiledMapServiceLayer = new esri.layers.ArcGISTiledMapServiceLayer(service);
    map.addLayer(tiledMapServiceLayer);
	
	return this;
}

Here is a quick breakdown of how this works:

Line 2: Set up the myMapApi namespace.

Line 5: This code is implemented entirely as an immediately executable anonymous function to avoid creating any variables within the scope of the page. You can see a description of this technique here.

Line 9-17: The djConfig object is the key to getting this technique to work. The default behavior of addOnLoad is to fire when all dependencies are loaded (including the page DOM). As a result, if the DOM is already loaded the addOnLoad event will not occur. In many cases with a widget (sometimes depending on the browser) the DOM may already be considered to be loaded and the addOnLoad will not fire. The afterAddOnLoad property allows this behavior to be ignored and addOnLoad will fire whenever Dojo dependencies are loaded.

Line 11-16: This anonymous functions defines the addOnLoad behavior. In our case we note that the Javascript API is loaded and then we call the callback (if it is has been provided). Depending on the timing of the page load the callback may or may not have been provided at this point.

Line 19-23: Dynamically load the JavaScript API

Line 26-31: Dynamically load the tundra theme

Line 37-40: This anonymous function allows the consuming page (the page the contains the widget) to provide the callback function. A reference to the callback is kept in the event that the JavaScript API has not been loaded yet (at which point it will then be called on line 14. If the Javascript API is already loaded (as evaluated on line 39, the callback will be called.

Line 43-65: This class creates the div that will be used for the map, news up an esri.Map, and loads a map service into the div.

And that is basically it..

Here is the output from Firebug showing the loading sequence:

Bootstrapping the ESRI Javascript API - Firebug Output

I have also posted a working example of this technique. This has been tested to work in IE 7, FireFox 3.x and Chrome 3.x. If you find that it works (or doesn’t work) please let me know. Suggestions or other ideas are also welcome!

Certified ScrumMaster Training

October 19th, 2009 Comments off

Certified ScrumMaster

I recently had the opportunity to attend a Certified ScrumMaster (CSM) training/certification course at the Rally Software Development Headquarters in Boulder, Colorado.  I have been using Scrum for over a year now and this was an excellent opportunity to refine skills and to get real-world questions answered.

If you follow the activities of the Scrum Alliance (the group that administers the Scrum certification process) you will know that a test is now required to obtain ScrumMaster Certification.

Previously you only had to take the course to become certified.  As of October 1, 2009 the test is in ‘beta testing’ to allow the Scrum Alliance to validate the quality of the test questions before implementing the final pass/fail test.  The test is based on the Scrum Guide.

The course that I attended was instructed by Tamara Sulaiman.  The training was excellent and Tamara did an excellent job of illustrating the concepts with real-world examples. Tamara’s in-depth knowledge and hands-on experience added a lot of depth to the course.

Key Take-Aways

Product Owner Role

The Product Owner Role is critical to the success of a Scrum project.  The Product Owner must be very involved in the project and must be highly available to the team.

Sprint Retrospective

Sprint Retrospectives are the key to frequent inspection and adaptation. This ultimately is the whole point of Scrum – the ability to manage and control projects by inspecting and adapting frequently. Insufficient use the Retrospective was identified as one of the primary reasons for Scrum failure.

Product Backlog Grooming

I hadn’t actually heard of this specific process and I have frequently encountered challenges ensuring that the Product Backlog is “ready” prior to the next Sprint. While not a formal part of Scrum, Product Backlog Grooming is the activity of cleaning the Product Backlog during the sprint.

This ensures that the Delivery Team and the Product Owner know what is coming next (in advance) and ensures that the Product Backlog is in a clean state prior to each Sprint Planning meeting.

It was suggested that about 5% of the sprint capacity be allocated to this activity.  Product Backlog Grooming meetings should be scheduled in the same way that the other Scrum meetings are scheduled.

Levels of Agile Planning

This was another area that is not formally a part of Scrum but that I found to be very helpful.  The idea is that agile planning happens at multiple levels and that ‘sprinting’ on a Scrum project is only one of those levels.  Here is a breakdown of the different levels of planning that were suggested:

  • Product Vision – Defining the high-level vision for a product (By the Product Owner approx. 1-2 times per year)
  • Roadmap – Defining the product roadmap and creating the initial Product Backlog (By the Product Owner/Architect approx. 2-4 times per year)
  • Release Planning – Planning of product releases (By the Product Owner, Team & Stakeholders approx. 3-4 times per year)
  • Sprint Planning – The Scrum process of planning for each sprint (By the Product Owner and Delivery Team for every sprint)
  • Daily Scrum – The Scrum process of the daily stand-up meeting (By the Delivery Team)

Here are some additional resources about the topic of agile planning:

Five Levels of Planning: To Agility and Beyond! (RallyDev, 2006)

Scaling Agile Processes: Five Levels of Planning (Agile Journal, 2007)

Resources

Several books were mentioned during the training.  Here is a listing for reference:

The Software Product Manager’s Bridge to Agility (Michele Sliger, Stacia Broderick, 2008)

Scrum and XP from the Trenches (Henrik Kniberg, 2007)

Agile Retrospectives (Esther Derby, Diana Larsen, Ken Schwaber, 2006)

Agile Estimating and Planning (Mike Cohn, 2005)

User Stories Applied (Mike Cohn, 2004)

Teamwork is an Individual Skill: Getting Your Work Done When Sharing Responsibility (Christopher M. Avery, Meri Aaron Walker, Erin O’Toole Murphy, 2001)

ArcGIS Server JavaScript API 1.5 Released

October 2nd, 2009 Comments off

An update to the ArcGIS Server Javascript API has been released.

Of the most notable updates, this release fixes the Firefox 3.5 picture marker bug and updates the Dojo toolkit to version 1.3.2.

Read the what’s new for more details.