Friday, 28 November 2014

London Salesforce Developers - Certified Technical Architect Panel

Certified Technical Architect Panel

The November meetup of the London Salesforce Developers had a different format to usual, when a panel of Salesforce Certified Technical Architects convened to answer questions from the community about the Technical Architect certification process.

The meetup was hosted at Cloud Sherpas and MC’d by Francis Pindar, with most of the organisation coming (as usual) from Anup Jahdav.  The panel consisted of 6 CTAs - Luke Emberton, Wes Nolte, Andy Mahood, Seb Wagner, Francesco Iervolino and myself - Keir Bowden.

Ta1

Appearing at these events always requires a balancing act as the review board is subject to NDAs both from a candidate and judge perspective, so we aren’t able to go into any details of the board and have to make sure that we talk at a level that is useful but protects the certification - having worked so hard to achieve the credential the last thing any of us want is to devalue it.

We weren’t entirely sure how much interest there would be in an event of this nature, given that TA is the highest level of certification and not necessarily something everyone would have in their career plan.  As it turned out, this event had one of the best turnouts I can remember, as this shot from the back of the room shows.

Ta2

The key points from the panel with regard to preparation for the board were:

  • Identify the key areas from the study guide and try to get yourself on projects that have requirements of this nature - e.g. integration, complex security and sharing, single sign on
  • Its an intense experience to remember to take a step back and breathe from time to time
  • This isn’t something that you can prepare for simply by studying - you need real world experience
  • Pre-sales work is useful preparation for being peppered with questions on a solution you have just thought of!

Related Posts

Saturday, 22 November 2014

Responsive Images in Visualforce

Introduction

When building applications to run on the Salesforce1 platform across multiple devices, utilising responsive web design techniques is a must.  A responsive application adjusts its layout according to the capabilities of the device used to view.

One of the biggest challenges in responsive web design is image handling - how to efficiently display appropriately sized images. 

Download and Shrink

A 2012 survey found that 86% of sites delivered the same content regardless of the device. In my opinion one of the main reasons for this is the download and shrink approach to images. In this case, a single large image is embedded inside a block container (such as a <div> element) and styled to take up 100% of the width.  As the block container changes size based on the capabilities of the device, the browser will automatically scale the image. 

The following page is an example of download and shrink:

<apex:page sidebar="false" showheader="false">
  <style>
    .respImageContainer{
    	width:150px;
    	padding-top:10px;]
    }
    
	@media ( min-width: 768px ) {
    	.respImageContainer
    	{
    		width:320px;
    	}
	}
	
	@media ( min-width: 1024px ) {
    	.respImageContainer
    	{
    		width:677px;
    	}
	}
  </style>
  
  <div class="respImageContainer">
    <img style="width:100%" src="{!$Resource.S1DevWeekLarge}" />
  </div>
</apex:page>

If the device has a minimum width of 1024px, the <div> element containing the image has a width of 677px, which is the actual size of the image:

Screen Shot 2014 11 22 at 17 42 48

If the device has a minimum width of 768px, the <div> element containing the image has a width of 320px:

Screen Shot 2014 11 22 at 17 43 02

If the device has a minimum width of 320px, the <div> element containing the image has a width of 150px :

Screen Shot 2014 11 22 at 17 43 21

The original image is 677 x 259 pixels, 175343 in total. In the final screen shot, the image is resized to 150 x 57 pixels, 8550 in total.  This means that most of the image is discarded when displayed, which is extremely inefficient use of bandwidth. There is also another problem here, known as art direction - the map in the image in the final screenshot is really too small to be of any use, so it would be better to zoom in on the spaceman as the Salesforce1 developer week logo.

HTML5 Picture Element

In the fullness of time image handling will be provided by the HTML5 picture element, an example of which is:

<picture>
  <source media="(min-width: 1024px)" src=“large_image”></source>
  <source media="(min-width: 768px)" src=“med_image”></source>
  <source src=“small_image”></source>
  <img src="fallback_image"></img>
</picture>

as can be seen, the <picture> element contains a number of <source> elements, each of which refers to a different image. The <source> element optionally contains a media query which must be satisfied in order for the image to be chosen. In the example code above:

  • if the device has a minimum width of 1024px, the large_image file will be used. 
  • If the device has a minimum width of 768px, the medium_image file will be used.
  • Otherwise the small_image file will be used.

Note that the <picture> element also contains a regular HTML <img> element - if the browser doesn’t support the <picture> element, the fallback_image file will be used. The use of the fallback <img> element does present a challenge, as browsers typically try to pre-fetch images before the page has been completely loaded and parsed.  This can lead to the situation where the fallback image is downloaded, only to be discarded as the image file identified can be used instead.

Unfortunately browser support is still patchy for the <picture> element; at the time of writing (November 2014) only Chrome and Opera provide support by default. 

Picturefill

Picturefill, by Scott Jehl, is a Polyfill for the HTML5 picture element, that uses JavaScript to load the appropriate picture based on additional HTML5 data- elements on <div> or <span> elements:

<apex:page standardStyleSheets="false" showHeader="false">
  <style>
    .respImageContainer {
    	padding-top:10px;
    }
  </style>
<apex:includeScript value="{!$Resource.PictureFill_1_2}" /> <div class="respImageContainer"> <span data-picture="1" data-alt="S1 Dev Week"> <span data-src="{!$Resource.S1DevWeekSmall}"></span> <span data-src="{!$Resource.S1DevWeekMed}"
data-media="(min-width: 768px)"></span> <span data-src="{!$Resource.S1DevWeekLarge}"
data-media="(min-width: 1024px)"></span> </span> </div> <script> window.picturefill(); </script> </apex:page>

The image source is defined by the data-src attribute, while the media query is present in the data-media attribute.  I’ve included the Picturefill JavaScript as a static resource as I couldn’t find it on any of the major content delivery networks.  This adds a Picturefill function to the window element which is called to process the page and load any images. This results in appropriately sized images being delivered to each page, at 1024px:

Screen Shot 2014 11 22 at 17 49 29

at 768px:

Screen Shot 2014 11 22 at 17 44 12

and at 320px an image containing only the spaceman is rendered:

Screen Shot 2014 11 22 at 17 43 43

Picturefill has two versions - one that works against <div> elements and one that works against <span> elements.  I tend to use the latter as I've found that the <div> elements can interfere with the styling introduced by Bootstrap, which is my responsive framework of choice. The downside to this approach is that it introduces latency when loading images, as the page is rendered before the JavaScript executes, and only then are the images loaded.

Resources

Saturday, 15 November 2014

Visualforce, Required Fields and HTML5

A few weeks ago I encountered some unexpected behaviour around action regions and required fields which after some investigation turned out to be a consequence of using the HTML5 doctype. In this post I’ll present an example of the use of an action region in conjunction with required fields and show how it is impacted by HTML5.

Regular Form

As a very simple example, I have a page that allows the user to enter the name of an account and some additional information in a table.  The user can click the ‘Add Row’ button to add a new row to the additional information:

Screen Shot 2014 09 27 at 08 07 03

The markup for this page is a regular apex:form (the controller isn’t relevant to this post, but is available in the Resources section at the end of this post):

<apex:page controller="RequiredCtrl" tabstyle="Account">
  <apex:pageMessages id="msgs"/>
  <apex:form>
    <apex:pageBlock mode="maindetail">
      <apex:pageBlockButtons location="top">
        <apex:commandButton value="Save" action="{!save}" />
      </apex:pageBlockButtons>
      <apex:pageBlockSection title="Account Information">
        <apex:pageBlockSectionItem>
          <apex:outputlabel value="Name"/>
          <apex:inputfield value="{!Acc.Name}" />
        </apex:pageBlockSectionItem>
      </apex:pageBlockSection>
      <apex:pageBlockSection title="Related Information" columns="1">
        <apex:pageBlockSectionItem>
          <apex:commandButton value="Add Row" action="{!addRow}"/>
        </apex:pageBlockSectionItem>
        <apex:pageBlockTable value="{!rows}" var="row">
          <apex:column headerValue="Value 1">
            <apex:inputText value="{!row.val1}" />
          </apex:column>
          <apex:column headerValue="Value 2">
            <apex:inputText value="{!row.val1}" />
          </apex:column>
          <apex:column headerValue="Value 3">
            <apex:inputText value="{!row.val3}" />
          </apex:column>
        </apex:pageBlockTable>
      </apex:pageBlockSection>
    </apex:pageBlock>
  </apex:form>
</apex:page>

Clicking the 'Add Row’ button causes the post back to fail as there is a required field missing:

Screen Shot 2014 09 27 at 07 51 34

Adding an Action Region

An action region demarcates a limited section of the form to submit back with the post back. Note that this also requires a rerender component to turn the post back into an Ajax request.  By enclosing my table in an output panel containing an action region, the required field no longer has an impact as it is outside the action region (note that I’m also rerendering my page messages component, as without that any errors will be swallowed as detailed in this post):

<apex:outputPanel id="rows">
  <apex:actionRegion>
    <apex:pageBlockSection title="Related Information" columns="1">
      <apex:pageBlockSectionItem>
        <apex:commandButton value="Add Row" action="{!addRow}" rerender="rows,msgs"/>
      </apex:pageBlockSectionItem>
     ...
    </apex:pageBlockSection>
  </apex:actionRegion>
</apex:outputPanel>

I can now click the ‘Add Row’ button and a new row is generated without errors:

Screen Shot 2014 09 27 at 08 00 34

Using the HTML5 Doctype

If I then decide I’d like to take advantage of some HTML5 features and turn on the HTML5 doctype on the page:

<apex:page controller="RequiredCtrl" tabstyle="Account" doctype="html-5.0">
  ...
</apex:page>

Clicking the ‘Add Row’ button suddenly fails again, but with a different style of error decorator:

Screen Shot 2014 09 27 at 08 01 32

Digging into the rendered HTML shows that an HTML5 specific attribute has been generated:

<input id="..." required="required" size="20" type="text" value="">

this attribute is handled directly by the browser, which obviously has no idea that there is a bunch of JavaScript lying in wait to trap the post back and turn it into an Ajax request, so it just checks the input element and blocks the post back if it is blank.

immediate=“true"

 The same behaviour can be seen when the immediate attribute is set to true for a command button, action function etc., for exactly the same reasons described above.

Workarounds

  • The easiest workaround, if you aren’t relying on any HTML5 features, is to turn off the HTML5 doctype.
  • If you need HTML5 features, make the field non-required by specifying the required attribute as false in your Visualforce markup if you can (you can’t do this with standard object names unfortunately)
  • Manage validation and error messages yourself - see the Field Level Error Messages … links in the Resources section.
  • If neither of the above are suitable, use JavaScript to remove the required attribute from the rendered HTML. This is pretty fragile though, as it requires your JavaScript to know which fields are part of an action region and which aren’t.

Resources

Wednesday, 5 November 2014

Musings of a Trailheader

Screen Shot 2014 11 02 at 16 09 03

Introduction

Trailhead is a new interactive learning initiative for Salesforce developers - you can read more about it at my introductory post, or on any of what seems like hundreds of write ups in the developer community blogosphere. Having been through all of the available exercises and had a couple of days to reflect, here are a few of my thoughts on the system and some ideas for maximising the awesomeness.

Challenges

Challenges and automated checking are going to be key factors in the success of this program. The Salesforce developer community are a competitive bunch, and anything involving badges and points gets a lot of interest.  With 1.8 million developers already using the platform and more signing up on a daily basis, there’s no way a manual system would be able to scale, and any delays would likely lead to user frustration.  I’d like to find out more about how this works - it looks like it purely relies on API access to the developer edition rather than any Salesforce-only under the hood stuff, but I’d also be interested to know if there’s a package or framework that allows pure configuration, or if each challenge requires coding from scratch. Maybe a topic for a future Developerforce blog post.

Challenges that rely on having completed the follow-along exercises in the unit would make sure that even experienced developers had been through all of the details, rather than skipping straight ahead to the challenge.

A leaderboard would be a cool addition to this. I’d be inclined to avoid a lifetime top 10 type of board, as once a couple of months have passed it would become all but impossible for new Trailheaders to appear on it.  Instead, something that shows the top scorers for the last month, or biggest increase in points in the last week etc would give everyone a chance to see their name up in lights. An awesome spin on this would be to segment based on developer group membership, which would allow us to recognise the top performers in our groups each time we get together.

Another idea, which I’m still in two minds about myself, is timed challenges.  In this scenario, accessing the detail of a challenge starts a timer and the number of points available drops down over time. This should encourage Trailheaders to read all of the related material to ensure they are fully prepared for the challenge before attempting it, although if the points drop too quickly it might be off-putting.

Build a Complete Application by Following a Trail

A trail whose units/modules combined to leave the Trailheader with a complete and functional application would be amazing.  I’m well aware that the amount of effort and attention to detail involved would be enormous. It would also need to cover a wide range of topics, although judicious use of code shares/unmanaged packages could get the basics in place quickly.

Organised Trailhead Events

This covers a couple of scenarios:

  • Trailhead content and challenges specifically (or initially) produced for Developer Group Events. For example, last year we had Salesforce1 Developer Week across the globe, with mini-hacks for participants. Tying this into a new trail would help to drive interest and attendance.
  • Elevate/Hands On Workshops run via Trailhead - having run one of the Hands On Workshops at Dreamforce, it seems to me that this would be a good fit for the format.
I also think the existing content would be great for “Intro to Force.com” type events and I’m thinking about how we can leverage this in the London Salesforce Developer Group.

Get the Community (More) Involved

Judging by the number of tweets/blog posts/Facebook shares, the developer community are already pretty taken with Trailhead, but that’s purely from a consumer standpoint. Rather than just suggesting topics it would be great if we could build trails/modules/units (most likely the latter, as it looks like there’s a huge amount of effort involved in a trail!). With attribution for the author on the item, I’m sure there would be a deluge of submissions! This would also allow related technologies to be introduced, such as working with JavaScript frameworks or Responsive Design.

To be fair, I’d be amazed if this wasn’t already being considered at some level. It probably won’t happen for a little while, as Trailhead is shiny and new and I’m sure that the Salesforce developer relations team are learning as much from this as the Trailheaders. 

That’s my thinking for now - I’m sure other ideas will occur to me, in which case I’ll update this post if and when then do.

Related Posts

Tuesday, 4 November 2014

Apex Ternary Operator and Types

Recently I was refactoring some of my code that in a Visualforce controller that generated a list of select options to produce a custom picklist of records.  Depending on the use case, I needed the selectoption values to be either the id of the record or the name.  Initially I had two separate methods that did pretty much the same thing:

public List<SelectOption> getOptionsByName(List<Account> accs)
{
    List<SelectOption> results=new List<SelectOption>();
	for (Account acc : accs)
    {
        results.add(new SelectOption(acc.Name, acc.Name));
    }

    return results;
}

public List<SelectOption> getOptionsById(List<Account> accs)
{
    List<SelectOption> results=new List<SelectOption>();
	for (Account acc : accs)
    {
        results.add(new SelectOption(acc.Id, acc.Name));
    }

    return results;
}

as you can see, this isn’t a very good example of the principle of DRY, so it seemed a trivial task to alter these functions to delegate to a single optionBuilder that could handle either scenario:

public List<SelectOption> getOptionsByName(List<Account> accs)
{
	return buildOptions(accs, false);
}

public List<SelectOption> getOptionsById(List<Account> accs)
{
	return buildOptions(accs, true);
}

private List<SelectOption> buildOptions(List<Account> accs, boolean byId)
{
    List<SelectOption> results=new List<SelectOption>();
    for (Account acc : accs)
    {
        results.add(new SelectOption(byId?acc.Id:acc.Name, acc.Name));
    }

    return results;
}

This refactored code worked fine when I executed the getOptionsById method, but when I tried getOptionsByName, I got the following, unexpected error:

15:50:59.047 (47206263)|FATAL_ERROR|System.StringException: Invalid id: test

which indicated that the ternary operator:

byId?acc.Id:acc.Name

was trying to promote the acc.Name String to an Id. Looking in the Apex Developer’s Guide didn’t throw a whole lot of light on the issue: 

Screen Shot 2014 07 27 at 15 58 41

as always, when presented with behaviour in Apex which isn’t documented, I reverted to the Java documentation (Apex being based on Java), to see if there was any further information.  There is, but its not the most enthralling read - if you are interested in the fine detail, check out http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25. If that’s TL and you DR, what it boils down to is that the ternary operator has a single type and the operands are converted to this single type as required, which in my case appeared to mean that as the Id was the first type encountered, that was taken as the type of the ternary operator, even though the parameter type for the method call is a String. So while the ternary operator is a short-hand for an if-then-else statement, it is one that converts:

byId?acc.Id:acc.Name

to 

Id result;
if (byId)
{
    result=acc.id;
}
else
{
    result=acc.Name;
}

Swapping the operands round fixes the problem nicely - the type of the first operand encountered is a String and as the Id primitive supports conversion to a String, everything works as expected:

!byId?acc.Name:acc.Id, acc.Name

For the sake of completeness, this is now shorthand for:

String result;
if (!byId)
{
    result=acc.Name;
}
else
{
    result=acc.id;
}

Monday, 3 November 2014

Book Review - Salesforce.com Customization Handbook

5986EN Salesforce com Customization Handbook Cover

(Disclaimer : I didn’t purchase my copy of this book - I was sent a copy to review by Packt Publishing)

The Salesforce.com Customization Handbook is written by a couple of people whose names will be familiar to members of the Salesforce community - Rakesh Gupta and Sagar Pareek, who previously collaborated (see what I did there) on Developing Applications with Salesforce Chatter.

The book covers a number of common areas of configuration/customisation, including user management, security settings, email administration, business process automation, data management and reports and dashboards. From the perspective of someone getting started with Salesforce, (who has maybe been dropped in at the deep end and become the de facto administrator when their company decided to buy licenses) this is a useful guide to the setup areas that should be concentrated on, including some non-obvious candidates such as truncating custom objects and mass transferring approval processes.

Where the book doesn’t live up to expectation is explaining the concepts behind what is being configured, or work through much in the way of real world examples, especially where there are multiple options.  For example, the chapter on Setting Up Deployment Processes introduces change sets, the Force.com IDE, and packages (both managed and unmanaged). What it doesn’t do is explain in what circumstances each of these would be an appropriate choice, or cover the advantages/disadvantages of one mechanism over another.  There’s also too much content that looks to be directly dropped in from the Salesforce help, or that simply repeats itself (that the Account Mailing Address field is used to store the company’s Mailing Address, for example, doesn’t really add any value).

In summary, this is a useful book for those getting started with Salesforce setup and customisation. However, with a little more focus on educating as well as informing it could have been so much more.

You can find out more about this book and purchase a copy on the Packt website.

Sunday, 2 November 2014

Trailhead - Interactive Force.com Developer Training

Screen Shot 2014 11 02 at 16 09 03

One of the big announcements at the Dreamforce 14 Developer Keynote was Trailhead - interactive training for developers new to the platform or wanting to dig deeper.  Things at BrightGen are always a little hectic after Dreamforce, but as I’m now on a week’s vacation in beautiful North Norfolk I’ve finally had some time to take a look at it.

Overview

Trailhead consists of Trails that cover aspects of the Salesforce1 platform.  At the time of writing (November 2014) there are three Trails - Getting Started with the Force.com Platform, Intro to Visual App Development and Intro to Programmatic Development. Trails comprise of Modules (key topics for the trail - so Intro to Programmatic Development, for example, has modules for Apex Triggers and Apex Testing), which are in turn made up of Units. A Unit introduces a specific concept, such as a Visualforce Standard Controllers or Apex Bulk triggers, which is explained in depth in conjunction with follow along exercises.

Gamification

Most units finish with a challenge - an exercise to be completed in your developer edition which is then verified by the Trailhead system. You give Trailhead access to your developer edition as a connected application and grant access via oauth - this is the kind of functionality I’m always keen to see in these kind of systems, as it means it is able to scale without detracting from the user experience by making people wait to have their exercises assessed.  

Successful completion of a challenge gains you points, and once all units in a module have been completed you are awarded a badge. These appear on your Salesforce Developers profile page, gaining you bragging rights and displaying your expertise to potential employers.

Screen Shot 2014 11 02 at 16 04 21

So What’s it Like?

First off, its probably worth saying that the current Trailhead content isn’t really targeted at the likes of me - its more for people getting started with the area of the platform covered by the module.  That said, its important to me that I go through everything in detail, so that I can identify what the benefits are for our customers and staff.

In short, Trailhead is awesome. I wish there had been something like this available when I started out the with platform a shade over 6 years ago - I’d have been productive in an even shorter time (although at the time I’d have been skeptical that was possible!). At BrightGen we specialise in taking developers from .Net/Java and cross training them onto Salesforce and Trailhead will allow us to give them a flying start.

TIL

  • Follow the instructions to use a new developer edition - some challenges are documented as not possible with a namespace, but at least one other fails as well!
  • The Import Wizard really doesn’t like CSV files from a Mac - I tried everything I could think of to no avail, so I ended up cheating and loading the data using Jitterbit. It shows how long its been since I used the Import Wizard, as I’ve been on a Mac for around 3 years now!
    Update 04/11/2014 : this appears to have been a temporary problem - I’ve since been able to process the file in the same dev org via multiple browsers. If you encounter the same error try waiting a day or two!
  • The related resources are well worth a read before the challenge - they’ll cover the additional features that you need to use.
  • If you get the message ‘there was an error checking the challenge’, just try again - this never happened twice in a row for me.
  • If you switch to a  new developer edition part way through (because you didn’t follow the instructions and sign up for a new one, for example!), make sure to load any data from previous exercises, as a later challenge may rely on accessing it
  • If a challenge says it is relying on a specific number of records satisfying a set of criteria, make sure there are exactly that number.  I had one additional record and the challenge failed.
    Update 04/11/2014 : I’ve retested this in another developer edition and it is now working as expected.  Most odd as this failed easily 10 times in a row over the weekend until I deleted the additional record and then it worked first time.  Coincidence or magic?
  • Flow has come on a fair bit since I last used it.

In Conclusion

What are you waiting for?  Trailhead is a great way to learn so get started!

One More Thing

Don’t forget its Meet the BrightGen Team at Salesforce Tower on November 12th - we’ll have pizza, beer and some experts to chat with, so make sure to signup now to avoid disappointment.