Salesforce.com Workflow to the Second

December 22nd, 2011

I recently came across the requirement for a workflow rule to fire on the update of a record but only if the update occurred more than a couple seconds after the record was created. Why this crazy requirement? Here is a example of the problem I was faced with.

Image you have two custom objects, Exam and Question. There is a master detail relationship between the two where many Questions can be associated with one Exam. There are also some roll-up summary fields on the Exam that count number of questions, number answered correctly, etc. Now also image (lots of imagining today so I hope you can harness your inner child imagination skills) you have a Visualforce page that assigns exams to users. This Visualforce page essentially clones a an Exam and Questions and assigns these to a user. First it inserts the Exam and then all related Questions. On the Exam object there is a workflow rule that need to execute when an Exam is updated. The problem is this workflow rule kept firing every time I inserted Exams and Questions for a user. Why is this happening? I am only inserting records, right? Wrong-a-long-a-ding-dong!!!

So what is happening here? Why is an update occurring on the Exam record when all I am doing is inserting records? The culprit are those very cool, but pesky, roll-up summary fields. When you have a roll-up summary field on a record any time you insert or update a child record an update will occur on the parent. So in the example above every time I would insert the the Questions it would cause on update action on the Exam. This is documented but it might not be something you come across every day. It’s also not obvious as everything happens so fast in the code the Created Date and Last Modified Date on the Exam show the same values in the user interface. If you queried these two date fields you would see they are milliseconds apart.

So how to solve this? There are a few options. We could set a flag, a checkbox field, on the Exam called Disable Workflow that we set to true on the insert of the Exam and then after inserting the Questions we could uncheck this box. In our workflow rule we could prevent the rule from executing by referencing this field. This would work but I don’t like it for a couple reasons. The first is that I hate adding fields to the database that aren’t really needed. Secondly, it’s less efficient as it requires multiple DML (update) operations to make everything flow smoothly. Another options is to get super crafty with our workflow rule.

The insert of the Exam and Questions is going to be finished in milliseconds. What if we make the rule fire on updates but only on updates a few seconds after the record is created. What we need to do is determine the time between the created date of the record and now in seconds. When working with formula fields or validations rules the duration of one day is represented as the value of 1. If we know this we can use our superior deductive reasoning skills to figured out the value for one second.

1 / 24 = 0.0416667 is one hour
0.0416667 / 60 = .00069444 is one minute
0.00001157 = one second

Now in our workflow rule we have have a formula like this:

…and it will evaluate to true on updates but only if those updates are greater than 1 second after the record was created.

Categories: Apex, salesforce 5 comments

F5 Looking for a Salesforce.com Solution Developer

November 17th, 2011

So I work at a little company called F5 Networks…well we just had a $1 billion dollar year so I guess it is not that small, but we are looking for a Salesforce.com Solution Developer. Salesforce.com Solution Developer? What the heck is that? Knowing Apex, Visualforce, APIs, web services, JSON, XML, AJAX, databases, etc are all perfect skills for this position. Yet this position is not all development all the time. It is about developing full well rounded solutions. This means in addition to some of the more technical skills I already listed you also should know and enjoy working with custom objects, workflows, validation rules, formula fields etc. Heck, let’s throw in some integration work as well while we’re at it. A big piece of this role involves working directly with business units to understand their requirements, guide them at times, and quickly build applications that can be tweaked and adjusted based on feedback (think super agile). This also involves post deployment support. We also run very efficiently here as we currently have two admins/analysts and myself managing 1200+ users. This means there is also some day-to-day admin duties as well. As you can see this isn’t a pure development role so if you are looking for that… keep looking.

If this is something that sounds exciting to you please apply below and reach out to me with the contact form link above.

Salesforce.com Solution Developer Job Posting

And if you are wondering what F5 Networks as a company is like…it’s pretty cool…

http://www.f5.com/about/careers/benefits.html
http://blog.nwjobs.com/peoples_picks_2010/large_company/best_benefits_1.html?lid=710023
http://blog.nwjobs.com/peoples_picks_2010/large_company/coolest_office_space_1.html?lid=710024
http://blog.nwjobs.com/peoples_picks_2010/large_company/favorite_seattle-area_company_1.html?lid=710019
http://blog.nwjobs.com/peoples_picks_2010/large_company/most_family-friendly_company_1.html?lid=710026
http://blog.nwjobs.com/peoples_picks_2010/large_company/most_unusual_perks_1.html?lid=710027
http://blog.nwjobs.com/peoples_picks_2010/industry/favorite_technology_company.html?lid=710006
http://best.king5.com/f5-networks/biz/123372

Categories: salesforce No comments

The Most Important Feature of Salesforce Winter ’12

October 7th, 2011

Starting this weekend salesforce.com will begin the seasonal upgrade to Winter ’12. As usual this release is packed with tons of great new features. So what is the best new feature? Chatter approvals, nope. Native JSON support, nope. Schema builder, nope. API improvements, nope. By far the most important feature of the Winter 12 release is this:

General Availability During Major Release Upgrades

Starting with Winter ’12, Salesforce will be generally available during major release upgrades.
General availability means you should only expect to experience up to a five minute disruption of service as your Salesforce
organization is upgraded. Users trying to access Salesforce during this time receive an error message that the service is unavailable
and they can log back in momentarily. In addition, users logged into Salesforce during a major release upgrade may be
temporarily logged out.

This may not seem like a big deal but it is (insert Boston accent here) absolutely frickin HUGE! You may think that 6 hours of downtime three times a year is not that much, and honestly its not, but 6 hours in a row is a big deal. Also, assuming salesforce.com has no other downtime (we can wish, right?) this still only gets you between two and three 9s up uptime. This is a huge problem for customer service call centers. Having your customer service system go down for 6 hours is simply not an option and is a deal breaker for large enterprise companies. There are many examples of salesforce.com not being able to successfully close Service Cloud deals because of this one issue alone. Reducing these upgrades times to less than five minutes places salesforce.com in the elite 4-5 9s range of uptime.

This change is important because it brings down one of the few remaining, and legitimate, barriers to cloud adoption. Sure there will still be unscheduled downtime and emergency maintenance but if you have noticed in the communications from salesforce.com a lot of these are also being performed under that status of being “General Available”. salesforce.com and cloud computing in general definitively has it’s weaknesses. Most of these are minor and feature specific weaknesses yet downtime during upgrades was a weakness that could totally prevent the adoption of salesforce.com. Now this will no longer be an issue… and I’m sure the salesforce.com account executives will have a much easier conversation with potential customers when asked about down time for upgrades.

Categories: salesforce No comments

August Force.com Developer Meetup

August 1st, 2011

The Seattle Force.com User Group is back in business. Let’s get together to discuss anything related to force.com/salesforce.com development.

When: Thursday, Auguest 4th, 4:00pm

Where:
F5 Networks
401 Elliott Avenue West
4th Floor, Einstein conference room
Seattle, WA 98119

Google maps link

I wanted to get this notice out as soon as possible and currently there are no specific demos or speakers planned so it will be more of an open forum. If you have something awesome you’d like to show off please let me know. I could always whip something up as well if we want to get down and dirty with some code dives.

Hope to see you there!

Dynamic Visualforce Components, why they scare the ish out of me

June 8th, 2011

Dynamic Visualforce Components are coming and they scare me…a lot. Before we can even begin to discuss why we need to review the basics of the model-view-controller pattern. If you aren’t familiar with the MVC pattern here is the basic run down when it comes to web apps that use MVC. Model, this represents your database and contains information on they fields in your database, validation rules, relationships, etc. View, this is the visual display of a model or many models. It says output the fields of a record in HTML on some web page and style them this way. This is where you can visually control how the data is displayed to the user. Controller, this is the code that retrieves and manipulates data from the Model and then prepares it for the View to use. A web app will most likely consist of many Models, Views, and Controllers. Some people may want to overcomplicated the MVC pattern, and it does vary slightly based on the platform or framework, but for the most part this is exactly how it works 97% of the time. So in the force.com world it looks a little like this:

Model
These would be custom objects, you can add fields, create validation rules, and build relationships with other objects.

View
Visualforce pages are the view and allow you to output information from the model as an HTML webpage.

Controller
One or many Apex classes associated with a Visualforce page. Here you can query and manipulate data before it is sent to the view for output.

So what does any of this have to do with Dynamic Visualforce Components (DVCs)? The reason is that DVCs allow developers to completely mangle and destroy the model-view-controller design pattern. They allow you to completely define the display from the controller. So basically MVC becomes M(VehCiv) or perhaps Model Viewroller as the View and the Controller start to get all mixed up. Big flipping deal you might say, all of the other hip cool web technologies (Rails) allow you to inject markup from the controller. Yes, they do, and there are people in those communities that feel the exact same way I do about mixing aspects of MVC, just because you can doesn’t mean you should.

Here is a very basic example of how mixing up the MVC can cause trouble. Let’s say you are working on a project where you have a web designer who is great at making spiffy looking websites and a developer that understands all the back end work. If you keep the View and the Controller separate these people can work individually on their part of the project. When you start to combine the View and the Controller the web design guy might be waiting for the developer to get the output setup so he can style it. Or maybe even worse you end up have a web designer starting to poke around in controller code, not ideal.

Mixing the View and the Controller also makes things more complicated and difficult for others to understand. When looking through a controller you now have to start mentally separating the view code and the logic code. For the consultants out there that sometimes have to inherit other’s code I do not envy you when you have to dig through someone else messy code, DVCs will make it messier.

Okay Jason, we get the point, but there are times when we need DVCs to meet the project requirements! Are there? Do you really need to use them? Doubtful. Yes, there are some use cases out there that can only be solved with DVCs but these are actually pretty rare. So if you think you need to use DVC’s, think again, and the ask someone else, perhaps on the force.com developer forums, and then if you still think you need them go for it. Personally, I still can’t think of a super great example for DVCs, but I’m sure after this post I’ll be inundated with use cases where only DVCs can save the day!

So here is an example of using DVC vs not using them. This is actually the example taken from the recent Force.com Summer 11 webinar. The goal is to get an output that looks like this:

An unknown number of tabs is the dynamic piece that needs to be solved. Here is one way to do it with DVCs. First the page. One thing I will point out right way is that when you look at this page you have no idea what constitutes the dynamic components. There is nothing that lets you know if they are a table, a div, text, etc. You would need to go look in the controller to see exactly what the dynamic component is made of. It is less markup but it is also inherently less descriptive and as mentioned before more difficult to understand. This is one of the core advantages to staying true to the MVC pattern. On a View it should be dead simple to understand the generated markup and output.

<apex:page controller="TopOpportunityController">
    <apex:stylesheet value="{!$Resource.CustomTableCSS}"/>
    <apex:sectionHeader title="Top 10 Open Opprtunities"/> 
    <h1>Total Expected Revenue from Top 10 Opportunities:</h1> $
    <apex:dynamicComponent componentValue="{!OppTotal}"/><br/><br/>
    <apex:dynamicComponent componentValue="{!tabbedView}"/>
</apex:page>

Next the controller. Notice that we are querying the data but also directly manipulating and defining the view in this controller. For me, when these two areas start to combine it can become blurring on exactly what code is interacting with the Model and what code is interacting with the View.

public with sharing class TopOpportunityController {
 
    private List<Opportunity> topOpportunities;
    public Double opportunityTotal {get;set;}
 
    public TopOpportunityController (){
        topOpportunities = [SELECT closeDate, TotalOpportunityQuantity, Id, Name,
                            AccountId, Account.Name, Probability, ExpectedRevenue, 
                            stageName, Amount, Account.Open_Opportunities_Total__c FROM 
                            Opportunity where isClosed=false ORDER BY  
                            Account.Open_Opportunities_Total__c DESC, Account.Name, 
                            ExpectedRevenue DESC LIMIT 10]; 
    }
 
    public Component.Apex.TabPanel getTabbedView(){
        Component.Apex.TabPanel panel = new Component.Apex.TabPanel(
                                                       switchType = 'client',
                                                       title = 'Top 10 Opportunities');
 
        String lastAccountId;
        opportunityTotal = 0;
 
        for (Integer i = 0; i< topOpportunities.size(); i++){
            Opportunity o = topOpportunities[i];
            opportunityTotal += o.ExpectedRevenue;
 
            //If we have a new Account record, need to create a new Tab
            if (lastAccountId != o.AccountId){
                Component.Apex.Tab acctTab = new Component.Apex.Tab();
                acctTab.label = o.Account.Name;
                panel.childComponents.add(acctTab);
            }    
 
            Component.Apex.OutputText oppText = new Component.Apex.OutputText(escape = false);
 
            oppText.value = '';
 
            //If this is a new tab, start a new <table>
            if (lastAccountId != o.AccountId){
                oppText.value += '<table class="customT"><thead class="customT"><tr class="customT"><th class="customT">Opportunity Name</th><th class="customT">Probability</th><th class="customT">Stage</th><th class="customT">Expected Revenue</th></tr><tBody class="customT"></thead><tBody class="customT">';
            }
 
            oppText.value += '<tr><td class="customT">' + o.Name + '</td>';
            oppText.value += '<td class="customT">' + o.Probability + '</td>';
            oppText.value += '<td class="customT">' + o.StageName + '</td>';
            oppText.value += '<td class="customT">' + o.ExpectedRevenue + '</td>';
            oppText.value += '</tr>';            
 
            if ( (i == topOpportunities.size() -1) || o.AccountId != topOpportunities[i+1].AccountId ){
                 oppText.value += '</tBody></table>';     
            } 
 
            panel.childComponents.get(panel.childComponents.size() -1 ).childComponents.add(oppText);
 
            lastAccountId = o.AccountId;
        }
        return panel;
    }
 
    public Component.Apex.OutputText getOppTotal(){
         Component.Apex.OutputText oppTotal = new Component.Apex.OutputText();
         oppTotal.expressions.value='{!opportunityTotal}';
         return oppTotal;
    }
}

So how would you do it mister smarty pants? Oh, I’m glad you asked. I would still use Dynamic Visualforce, just not Dynamic Visualforce Components. In my approach I want to look at the controller first. Notice that this controller has nothing related to the structure and style of the View. It only queries and process information from the Model. This should make it easier to understand exactly what the code is doing from a logic standpoint as you do not need to mentally separate the View logic. Some of the variables control how the information will be displayed on the page and this is okay, this is exactly what a controller should do. One thing to notice is the use of Maps. Map support was recently added to Visualforce as Dynamic Visualforce and is it is fan-freakin-awesome. I would bet it will solve 95% of your dynamic Visualforce needs. The other 5% is for Dynamic Visualforce Components.

public class TopOppsController {
 
    public List<Id> accountIds {get; set;}
    public Map<Id,String> acctIdNameMap {get; set;}
    public Map<Id,List<Opportunity>> acctIdToOppsMap {get; set;}
    public Opportunity totalOppAmount {get; set;} //User Opportunity object amount field as wrapper for total, outputField will format currency
 
    public TopOppsController(){
        buildOppList();
    }
 
    public void buildOppList(){
        //Instantiate variables
        accountIds = new List<Id>();
        acctIdNameMap = new Map<Id,String>();
        acctIdToOppsMap = new Map<Id,List<Opportunity>>();
        totalOppAmount = new Opportunity(Amount = 0);
 
        //Query the Opps
        List<Opportunity> opps =    [SELECT CloseDate, Id, Name, AccountId, Account.Name, Probability, StageName, Amount 
                                    FROM Opportunity 
                                    WHERE isClosed=false ORDER BY Account.Open_Opportunities_Total__c DESC, Account.Name, Amount DESC LIMIT 10]; 
 
        //Process the opps
        for(Opportunity opp : opps){
            //Increment total amount
            totalOppAmount.Amount += opp.Amount;
 
            //Add accountId and Name to map, these Id -> Name map values can be used in Visualforce page
            acctIdNameMap.put(opp.AccountId,opp.Account.Name); 
 
            //Add Opps to Account ID -> List<Opps> map, the List values in this map can be use in Visualforce datatables
            if(acctIdToOppsMap.get(opp.AccountId) == null){
                acctIdToOppsMap.put(opp.AccountId,new List<Opportunity>());   
                accountIds.add(opp.AccountId); //We add account Ids to list and then we can iterate over this in page and pull values from Maps in the controller
            }
 
            acctIdToOppsMap.get(opp.AccountId).add(opp);
        } 
    }
}

Next up is my Visualforce page. One of the first things you will notice is that I had to use a little bit if jQuery magic. In my first attempt I tried to use an apex:repeat component inside of an apex:tabPanel but this simply does not work. So a bit unwillingly I turned to jQueryUI to address the tab issue. The good news is that using the jQuery UI tab panel is ridiculous easy: 1) Create a div that will represent the tab panel. 2) In this div create list of <a> links where href is the Id of a seperate div representing the corresponding panel. 3) Four lines of jQuery javascript. I’ll admit this is not 100% native where as DVCs are but this approach is actually very simple. It also makes it easier to see what the view is doing, and actually provides complete control over the tab panel style, and interaction. Even if you did use the native tab panel, it is doing the tab switching with javascript anyway ;-P .

So all that aside the page should be pretty easy to understand. With out any type of inline comments you’d be able to see we have a list of <a> links that is outputting an account name. Then for each one of these names we also have a corresponding data table. Keeping the View out of the controller makes it much easier to see how the page is formatted….or at least I think it makes it easier. You lose this type of natural documentation when using DVCs.

You can see a working example by clicking here.

<apex:page controller="TopOppsController" >
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js"/>
    <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.12/jquery-ui.min.js"/>
    <apex:stylesheet value="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/themes/ui-lightness/jquery-ui.css"/>
 
    <script type="text/javascript">
         var j$ = jQuery.noConflict();
 
        j$(document).ready(function() {
            j$("#tabs").tabs();
        });
    </script>
 
    <apex:sectionHeader title="Top 10 Opps!"/>
 
    <h1>Total Amount from Top 10 Opportunities: </h1> <apex:outputField value="{!totalOppAmount.Amount}"/><br/><br/>
 
    <div id="tabs">
        <ul>
            <apex:repeat value="{!accountIds}" var="acctId"> <!-- Loop through list of account Ids -->
                <li><a href="#tabs-{!acctId}">{!acctIdNameMap[acctId]}</a></li> <!-- use account Id to get values from acctIdNameMap -->
            </apex:repeat>
         </ul>
           <apex:repeat value="{!accountIds}" var="acctId"> <!-- Look through list of account Ids -->
               <div id="tabs-{!acctId}">
                   <apex:pageBlock mode="edit">
                       <apex:pageBlockTable value="{!acctIdToOppsMap[acctId]}" var="opp" width="100%" > <!-- use account Id to get list of opps from acctIdToOppsMap -->
                           <apex:column value="{!opp.Name}"/>
                           <apex:column value="{!opp.Probability}"/>
                          <apex:column value="{!opp.StageName}"/>
                          <apex:column value="{!opp.Amount}"/>
                     </apex:pageBlockTable>  
                 </apex:pageBlock>
             </div>
         </apex:repeat>
    </div>
 
</apex:page>

So in the end DVCs have a purpose but more often then not you will probably not need them to meet your specific requirements. The real danger is using them when you really don’t need to and I’m hoping everything I’ve listed in this post explains why you should make a conscious effort to only use them when absolutely necessary. In the end this will make your apps easier to understand and then when you leave your company to go start the next million dollar start up the poor sap that inherits your code won’t go insane trying to understand the mess that is your controllers.

Getting Crafty with Queries

May 12th, 2011

I’ve recently found myself running into several pain points when it came to extracting data from salesforce.com using SOQL. Since salesforce.com/force.com runs on a shared infrastructure they don’t allow all the bells and whistles of traditional SQL as they need to protect their resources and prevent some crazy guy like me from bringing down then entire system with some redonkulous query. You may be thinking by now that I am referring to the specific governor limits salesforce.com imposes on your queries but I am actually talking about fairly simple extractions that don’t always have the most straight forward solution.

Let’s say that you have a table of data like this:

Now let’s also say the requirement is to query items from this table but only return items based on a unique Order_Number__c. If there are duplicate Order Numbers in the table return the oldest record based on create date. The records we need to return would be the ones highlighted green.

What some of you are probably thinking is this is a totally unrealistic example because in any well designed system a field like Order Number should be unique. Well guess what? Not everyone gets to live this this happy database fairly land where duplicates don’t exist. If you you, whoop-di-do, hooray for you, click here for your prize. If you don’t live in fairy database land this example could be a totally realistic problem.

So how to solve it? Out of the box SOQL doesn’t have a solution for this problem (if it does I just wasted some time writing this) so we need to get crafty! You could maybe use aggregate queries to group by Order Number and then determine the oldest record. Or maybe query records, add them to unique Lists based on Order Number, sort these, and then return the oldest record. These are all good…well…they would work, not so sure about the “good” part. Below is the way I approached this problem and I’m sure there may be better ways to do this but I thought it was pretty slick.

We know one of the requirement is to use the oldest records if there is a duplicate. In our query we can sort by Created Date ascending so the oldest records a processed first. Before running this query we will also create a Map where the key is a Integer representing the Order Number and the value is a salesforce object, in this example Opportunity. Data returned would be processed in this order top to bottom:

As we process the returned results we will check to see if the Map contains a value for the given Order Number on the record we are currently processing. If it does not, it means this is the oldest record for this Order Number and we add it to the map. If the map does return a value for any given Order Number it means there was already an older record found and this record should not be used. In the end with have a nice clean map with the keys being the Order Number and the values being the oldest record with this Order Number. If we then need to add all these records to a list we can do that with a simple values() method called on the Map. Below is the code for this, it assumes the object being queried is an Opportunity but this logic could be applied to any object/table.

//Create the map Order => Opportunity
Map<Integer,Opportunity> oppMap = new Map<Integer,Opportunity>();
 
//Query the records and sort by CreatedDate ascending so oldest records are returned first
for(Opportunity opp : [select Id, Name, Order_Number__c, CreatedDate from Opportunity order by CreatedDate asc]){
 
    //Check if map contains Opportunity for given Order Number
    if(oppMap.get(opp.Order_Number__c) == null){
	//If null add opp to map, it is the oldest
	oppMap.put(opp.Order_Number__c,opp);
    }
 
    //Else do nothing, ignore the record as we already found an older one.
}
 
//If we need the opps in a list just do this	
List<Opportunity> opps = oppMap.values();

The one down side to this approach is that you are querying duplicate records that will never be used. Ideally you would only query the exact records needed without the duplicates even returned at all. I know of no way to do this but if you do please leave a comment below. Even with this added overhead of returned records that are never used I like this approach over the other described earlier because it is super simple and I am a big fan of simple.

UPDATE:
Based on some great comments below Greg has pointed that if you sort in desc order you don’t need the if() condition because the oldest records will be processed last and when you add them to the map it will replace any value that is currently there for the given key. The for loop could be simplified to this:

//Query the records and sort by CreatedDate descend so oldest records are processed last
for(Opportunity opp : [select Id, Name, Order_Number__c, CreatedDate from Opportunity order by CreatedDate desc]){
 
    //Add opp to map, it will replace any existing value in the map with the same key
    oppMap.put(opp.Order_Number__c,opp);
 
}
Categories: Apex, salesforce 6 comments

Introducing UnicornBLAST!!!

May 2nd, 2011

I’ve always wanted to create a jQuery plugin but what to build? There are plugins out there for nearly everything…except for one. Unicorns and rainbows! That’s right, my first jQuery plugin combines the awesome powers of jQuery, unicorns, and rainbows to provide an awe inspiring internet experience. I’ve whipped up a dedicated page for this plugin and you can check it out with the link below:

Click here for UnicornBLAST

This blog also focuses a lot on salesforce.com/force.com development and for the visitors familiar with these products you’ll be happy to know that I plan to create an installable package for salesforce.com that will enable use of UnicornBLAST inside salesforce.com.

Categories: jQuery 4 comments

Seattle Force.com Meetup – April 2011

April 6th, 2011

It’s that time again and as usual I am posting this way too late but tomorrow there is a force.com meetup in Seattle.

DocuSign Headquarters
Thursday, April 7
4p-5p

1301 2nd Ave., Suite 2000
Seattle, WA, 98101

Unlike the salesforce.com meetups that focus on the out of the box functionality these meetings tend to focus on Apex code, Visualforce, APIs, custom app development, and much more.

All skill levels are welcome to attended. I believe this will be an open meetup where any topic related to force.com open for discussion.

There is also this linkedIn group you can join to keep up to date on Seattle Force.com happenings, it’s where all the cool kids hang out.

Categories: salesforce 1 comment

IE9 & salesforce.com: When the cloud rains

April 1st, 2011

UPDATE: See below.

If you don’t know already Internet Explorer 9 and Visualforce are a complete train wreck. Every single Visualforce page that performs a rerender (ajax operation) will not work with IE9. The operation appears to start and then never finishes. This has probably led to thousands of force.com developers scrambling around to find and implement a fix. The good news is fixes are pretty easy, you just need to force IE9 to run in IE8 compatibly mode. This page on developer.force.com has all of the dirty details.

So who’s is at fault for this? Microsoft’s IE9 or salesforce.com? Read more…

Force.com Rage

February 25th, 2011

If you develop apps on force.com you have surely experienced this at least once in your life……

template

Oh, and don’t worry, I’m not an overly angry person. This is just a funny internet meme. You can learn more here.

Categories: salesforce 9 comments

To Query or to Loop, that is the question

February 23rd, 2011

I know what you thinking. Where have you been!?! No decent posts in over three months! Nothing but promoting yourself and posting advertisements. What happen to the guy that used to post all sorts of sweet nuggets of goodness on his blog? Dreamforce 2010, the holidays, a ton of real job work, and this little guy….

photo

…all got in the way, but enough with the lame excuses. Let’s get down to business.

WARNING: This post is a bit long but I think it’s a good read so grab a coffee, get comfortable, and start making your brain grow.

I’m going to cover a topic I have wanted to look at in more detail for a long time. It revolves around Visualforce and more specifically the performance of Visualforce. Visualforce is great in that it allows you to build front end pages connected to a huge scalable database in less than a day. This ease of use does comes with a price. Visualforce is slow. Rerender operations can take way too long and latency to the servers is definitely not amazing. Depending on the use case latency may not be a huge problem but slow rerenders can make your app feel really sluggish. There are several reasons for this but the main issue is something called the viewstate. Queue ominous music now. Read more…

Looking for a Salesforce.com Superstar

February 3rd, 2011

I haven’t posted much good content over the past few months and now I am posting advertisements. What have I become?!? The company I work at, F5 Networks, is looking for a Business Systems Analyst. This is basically a fancy name for one that administers salesforce.com but it is more than being an just an admin resetting passwords all day.

We are looking for someone that can handle the day to day requirements of being an admin; workflow rules, approval processes, validation rules, custom objects/fields, profiles/role setup, partner portal, etc. Day to day operations will be the focus but we are growing like mad and there will be plenty of opportunities to work with the business units to solve real problems using salesforce.com and this is where the analyst piece comes into play.

One thing to note is that while I post a lot of developer examples on this blog this is not a developer role (Apex/Visualforce). It’s for someone that loves delivering value with the point and click setup areas of salesforce.com.

You can check out the official job posting here: Business Systems Analyst

If you have any questions you can reach me through my contact form here.

Categories: salesforce 4 comments

How to be Successful with Salesforce

January 28th, 2011

It’s easy…

success

…read 3,000 pages of documentation.

Categories: salesforce 10 comments

Dreamforce 2010, Meet jQuery

November 11th, 2010

Many people reading this may already know what I am about to say but I’d like to announce some really exciting news. I will be co-presenting (with @JoshBirk) a session at Dreamforce 2010 on how you can use Visualforce with jQuery to build some wickedly awesome web apps.

I think this is really exciting for a few reasons. The first is that this particular session was chosen by the people for the people. On the Dreamforce Ideas website it is the most up voted session and all around idea. This means there are a lot of other people besides me excited about jQuery and how it can be used with the force.com platform.

Another reason I find this really exciting is that this will be my 4th Dreamforce and the first one I recall having a dedicated session to a JavaScript library like jQuery. One reason is that in the past 4 years JavaScript libraries have made HUGE gains in features and functionality. It will be great to see some alternatives to the typical *insert product name that rhymes with t-rex* session about building rich internet apps as I personally feel there are very few things *it* can do that most JavaScript libraries can’t.

I used to hate and despise JavaScript but jQuery has made be a believer. Rumor has it this session is filling up fast so if you are at all interested in learning more look for the session titled “Developing Applications with jQuery” in the Dreamforce agenda builder.

You can also follow the session in the Dreamforce Chatter app here: https://dreamevent.my.salesforce.com/a0930000006YhRa

UPDATE: Here is a package that includes all of the demos shown in this seesion.

UPDATED #2: Video has been posted here: http://www.youtube.com/watch?v=6je8AV6NuPM

Greasemonkey Script for Salesforce.com Setup and Apps Links

October 4th, 2010

So…uh…who wants to tell salesforce.com that performing an operation that required one click and now requires two clicks is movement in the wrong direction on the click-o-meter productivity scale?

With the Winter 11 release they did this to admins the world over. To access the setup menu you must first click your name in the header and then click setup, system log, or log out. Why the extra click? I don’t know, it baffles me as they usually get the user interface and experience stuff right. Fear not for I provide a solution that will hopefully be included out of the box in the next release.

It is a Greasemonkey script where all you need to do is hover your mouse over your name and the options become visible. I tested in both Firefox and Chrome. You can download it by clicking here.

UPDATED: Hover support also added to App links, use same install link above.

Categories: salesforce 7 comments