Many teams will have different ideas on what the standard practices for a project should be and some debate might be needed to know where that line is to be drawn. For example, here at Software Allies, one practice we strongly believe that's critical is spending the extra time to automate testing and providing a user acceptance testing environment with continuous integration. We know that we get better results for a project when the customer tests features as released and not just at the end of an iteration. For this reasons we make sure all stakeholders are involved in our testing throughout the project to provide constant feedback. We make this point clear with our customers from the start of each project. If they are not willing to provide feedback and collaborate with us on a project, we don't accept the project. This is our line in the sand, because without it we know the project will suffer and the customer might not be satisfied unless they actively participate in their project.
Drawing a line can be difficult to sell and is often at odds with some stakeholders of a project. This is because they perceive that the overhead cost isn't worth it. However, too many examples of failed projects show that without good practices software projects don't meet the needs of the users and customers. Stakeholder buy-in to your practices is needed to ensure that everyone understands what it takes for your team to deliver a successful project. With clear explanations and examples most stakeholders will start to see the benefits of your experience and respect your line the sand. If not, then perhaps it is better to just walk away from the project before even starting. It is our opinion that it is better to say no to project without the proper support than just do it and leave the customer unhappy.
Find out what works for your team and set the standards for the practices that will be used for your projects. Don't be afraid draw your line in the sand and clearly explain your points to the project stakeholders. Always be prepared to walk away from a project if you know that you can't deliver it because the potential customer is not willing to follow your processes and practices. In most cases, you will find support and your projects will be more successful for standing up for what you know works.
Auto Refresh Dashboards every time you click the Home Tab.
Tired of seeing the wrong numbers displayed on the Dashboard? Oftentimes, users forget to hit the refresh button on the Home Page Dashboard. This can result in Salesforce users seeing inaccurate data which can be confusing and frustrating. This TIP will help keep your Dashboards refreshing with the most up to date information.
Go to the setup menu:
Click customize, Home, Homepage Components.
Edit Messages and Alert.
Paste this code anywhere in the data entry box:
<script type="text/javascript"> var run; function sa_refresh() { var dashboardButton = document.getElementById("db_ref_btn"); dashboardButton.click() } setTimeout(sa_refresh, 5000); //Runs the Refresh function every 5 minutes using Milliseconds (1minute = 60000) run = setInterval(sa_refresh,300000); </script>
SAVE.
The code will refresh the dashboard every time you click the home tab or every 5 minutes.
Cheers!!
LIVE WEBINAR EVERY DAY AT 1:00PM CST - SALESFORCE BEST PRACTICES
Software Allies | Wednesday, September 8, 2010 |
Best Practices Webinars are exclusively for salesforce.com customers. With thousands of companies using salesforce.com, there are a lot of great ideas out there. This is our opportunity to share best practices discovered and developed by customers just like you. These sessions are meant to be interactive, so come prepared to participate; ask questions and share your success stories.
To attend any of these meetings on the appropriate day:
1) Go to: https://www.gotomeeting.com/join/418660800
2) Enter the meeting number: 418-660-800
3) Enter your name, email, and the password: crmsuccess
4) Dial: 1-866-393-8073 (North America); Or: 7205871473 (International)
5) Meeting number *2582794*
FRIDAYS @ 11:00 a.m. PST
Topic: Tips & Tricks
Time Saving tips for Administrators and Users
Explore custom fields, mashups & buttons
Leverage efficiency tools to help increase adoption
Learn and get more from the AppExchange
I spent a little bit of time looking through the Quote fields with Eclipse's 'Content Assist' feature, but the closest thing I was able to find was the IsSyncing field. I tried setting that to true but knew of the error message that was surely about to pop up, "Field is not writeable." Like other Salesforce Is*Action* fields, Quote.IsSyncing is read only and you cannot write to it through Apex directly. I then tried to find a built in method that duplicated the "Start Sync" button found on a Quote's layout page, though I found no such functionality.
So how do you go about syncing? The secret to syncing a Quote with its Opportunity lies not in the Quote's fields, but in the Opportunty's fields. A quick glance through those fields reveals a look-up relationship called SyncedQuote, and this field (actually SyncedQuoteId) is what allows us to sync a Quote. The implementation is easy, just a simple assignment:
// Begin syncing Quote with Opportunity. Same as pressing the "Start Sync" button on Quote layout
parentOpp.SyncedQuoteId = quoteToSync.Id;
If you want to stop syncing the Quote or start syncing a different Quote, you simply adjust the Opportunity.SyncedQuoteId field accordingly.
A limitation that I want to note is that the above code only works in an Apex Class, at least as of API Version 19. This means that you can sync a Quote through Apex in an standard Apex Class or an Apex Test Class, but not through an Apex Trigger. If you try to sync a Quote in an Apex Trigger you will receive an error message explaining this functionality.
When a developer is writing a piece of software that interacts with a standard database outside of the cloud, the only limits that he typically considers are memory, hard drive space, and processor capability. When developing on the Salesforce.com platform, however, you have to seriously consider the "cloud limitations."
Even though they serve a useful purpose, the Governor Limits are really tough and really force a developer to alter how he writes software, especially Apex Triggers. Take for example the limit on DML statements (insert, update, upsert, etc.) of 20, a non-cloud acclimated programmer would scoff at the idea of only being able to do 20 inserts or updates in the entire scope of his software. The same goes for SOQL queries, you cannot exceed the limit of 20. While you may think that 20 DML statements are more than enough for your standard Apex Trigger which updates one record at a time, what happens when many records are updated all at once, calling that trigger dozens of times? This is where you have to start thinking about staying under the limits, otherwise your code will not work properly.
If your trigger does not take this fact into account, and you perform an SOQL statement for each affected record, then the Governor Limits will cause an error to occur if there are more than 20 affected records. This could cause major problems for your Org. Thankfully, solving this turns out to be really simple.
// Insert three rows one at a time, counts as 3 DML statements against the limits
Insert row1;
Insert row2;
Insert row3;
// Insert three rows all at once, counts as only 1 DML statement against the limits
Listrows = new List ();
rows.add(row1);
rows.add(row2);
rows.add(row3);
Insert rows;
As you can see, a simple Apex List allows us to add many values that will be updated or inserted, then we can perform the required DML statement on the List instead of each individual element.
Now let's apply the collection logic to the trigger as a whole.
for(sObject TriggeredVal : Trigger.new){
First you have to realize that this loops cycles through all affected records sent to the trigger. Instead of doing any SOQL or DML statements inside this loop, you can check for your trigger criteria, and add any records, ids, or criteria that you need to query for or update to your collection.
After this, you can perform SOQL statements based on your collection, using the IN statement.
trigger TestTrigger on Account (after update) {
/********************************************************************
* Variable initialization
*********************************************************************/
SetownerIds = new Set ();
ListaffectedCon = new List ();
Integer loopIn;
/********************************************************************
* Trigger criteria implementation
* We will check if the account type is Individual and set
* their contacts description to test
*********************************************************************/
loopIn = 0;
for(Account TriggeredAcc : Trigger.new){
if(TriggeredAcc.Type == 'Individual'){//check if type is individual
ownerIds.add(TriggeredAcc.Id);
}
loopIn++;
affectedCon[loopIn].Description = 'Test';//change the field value
loopIn++;
/********************************************************************
* Bulk Processing
*********************************************************************/
loopIn = 0;
affectedCon = [SELECT Id, Description FROM Contact WHERE AccountId in: ownerIds];//get the contacts for the accounts listing
while(loopIn <>
Triggers, Workflows, and Salesforce's Order of Execution
Jorge Valdivia | Saturday, August 14, 2010 | Labels: Tech
Let’s say that you have an Apex Trigger that runs before an update on the Contact object. This Trigger will send an email to the Contact to alert them of a change made to their record, The Trigger may look like the following:
trigger NotifyContactOfChange on Contact (before update) {
for(Contact triggered : Trigger.new){ // Get affected Contacts
// Add code to send email here ...
}
}
So nothing new here, it’s just a simple Apex Trigger which fires off an email every time a change is made, and it should work just fine. Now let’s say that we also want to add a Workflow to Contact with similar functionality. To keep it simple, lets just say that this hypothetical Workflow fires whenever a change to Contact.MobilePhone is made and sets the Contact.Phone field to this new value.
Now that everything is set up, lets run through a scenario that causes the Trigger to not work as intended. Assume that you have a Contact record for “John Doe” and he has just given you his new mobile phone number. You look up his Contact record and make the change. Now, you are expecting two things to happen, (1) John Doe will receive an email alerting him of this change (via the Trigger) and (2) the Contact’s Phone field will be updated to reflect the MobilePhone field (via the Workflow). Here’s where things go wrong, John Doe will not receive one email, he will receive two. Why is that? While at first it may not seem obvious, it is actually very simple if you take a look at SalesForce’s Order of Execution, specifically numbers 1, 7, 10, and 11 on the list.
1. Executes all before triggers.
7. Executes workflow rules.
10. If there are workflow field updates, updates the record again.
11. If the record was updated with workflow field updates, fires before and after triggers one more time (and only one more time).
Notice that before triggers execute at number 1, and workflows at number 7. The caveat comes when you look at number 11, which says that triggers will fire once more if there were Workflow updates. If you refer to the example Trigger code above, you’ll notice that the email will be sent as long as Trigger.new is not empty, meaning that if a Contact record is updated in such a way that the Workflow fires (updating MobilePhone), the email will be sent twice, once at execution stage number 1, and again at execution stage 11. The consequences in our example are more annoying than anything else, but consider what would happen if the Trigger performed other actions, such as creating or deleting records. The effects could be well beyond merely ‘annoying’.
A simple fix to this problem would be to create a static variable which detects whether the email has been sent. Static variables cannot be declared directly in a Trigger, so an outside class would have to be created. Here’s the updated code:
public class trackEmail {
public static Boolean sentEmail = false; // Tracks whether email has been sent
}
trigger NotifyContactOfChange on Contact (before update) {
for(Contact triggered : Trigger.new){ // Get affected Contacts
if(!sentEmail){ // Email has not been sent
// Add code to send email here ...
trackEmail.sentEmail = true; // Set static variable
}
}
}
The only downside to this solution is that an outside class has to be created to accommodate the sentEmail variable. Other than that, adding a static variable to track whether or not a Trigger has fired is simple and should be easy to implement in most Orgs.
More on Apex static variables can be found at Salesforce's developer docs.
Systems Integration and Custom App Development - Sofware Allies - AppExchange
Software Allies | Wednesday, August 11, 2010 |
Software Allies | | Labels: CIO
“While SFDC and other SaaS systems can be turned on in a day or so (the SFDC sales reps will have made sure to tell you that), the standard system that is delivered will be of no practical use until it is configured (somehow the SFDC reps may not have emphasized this point)” (Taber, 52)
Much like a car, if tuned and customized properly, you can unleash the power of salesforce.com to get your business driving deals much faster. Salesforce is not limited to just helping organizations increase sales but also helps cut costs, streamline business processes which help end-users become more efficient in managing their work load. The features and possibilities are endless. Many salesforce customers will experience that even after implementation, new internal business processes will develop, best practices will be set in place, and other integration may be needed to link between other systems allowing everything to be tracked and managed inside of salesforce. We believe that our success has been attributed to the personable approach we take when listening to our client’s specific needs and helping them adopt a solution to fit their business model regardless of industry. Do you want to gain the BEST BUSINESS VALUE with salesforce?? …tune your engine with us!
References:
Taber, David. Salesforce.Com Secrets of Success. Upper Saddle River: Prentice Hall PTR, 2009.




