<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>gokubi.com &#187; CRM</title>
	<atom:link href="http://gokubi.com/archives/category/technology/crm/feed" rel="self" type="application/rss+xml" />
	<link>http://gokubi.com</link>
	<description></description>
	<lastBuildDate>Sat, 16 Jan 2010 21:30:56 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>An Introduction to Exception Handling in Apex</title>
		<link>http://gokubi.com/archives/an-introduction-to-exception-handling-in-apex</link>
		<comments>http://gokubi.com/archives/an-introduction-to-exception-handling-in-apex#comments</comments>
		<pubDate>Tue, 12 Jan 2010 17:48:41 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[CRM]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://gokubi.com/?p=1095</guid>
		<description><![CDATA[I was privileged to get to write an article for DeveloperForce.com on exception handling in Apex. I wrote this article not from the perspective of an expert on the subject, but as someone who really wanted to learn more about my options for using exception handling in my Apex code.
I&#8217;ve always had a nagging feeling [...]]]></description>
			<content:encoded><![CDATA[<p>I was privileged to get to write an article for DeveloperForce.com on <a href="http://wiki.developerforce.com/index.php/An_Introduction_to_Exception_Handling">exception handling in Apex</a>. I wrote this article not from the perspective of an expert on the subject, but as someone who really wanted to learn more about my options for using exception handling in my Apex code.</p>
<blockquote><p>I&#8217;ve always had a nagging feeling that I wasn&#8217;t following best practices in my exception handling in Apex. In most cases I wasn&#8217;t doing any exception handling at all. I decided to write up what I have learned about error handling on the Force.com platform so that others could jump into it full-bore, and make their programs more robust and fault tolerant.</p></blockquote>
<p>I hope it&#8217;s helpful to Apex programmers out there. Let me know what you think!</p>
]]></content:encoded>
			<wfw:commentRss>http://gokubi.com/archives/an-introduction-to-exception-handling-in-apex/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>I&#8217;m going to Rwanda</title>
		<link>http://gokubi.com/archives/im-going-to-rwanda</link>
		<comments>http://gokubi.com/archives/im-going-to-rwanda#comments</comments>
		<pubDate>Wed, 30 Dec 2009 04:50:56 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[Africa]]></category>
		<category><![CDATA[CRM]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://gokubi.com/?p=1082</guid>
		<description><![CDATA[Today I got confirmation of some great news&#8211;in February I&#8217;ll be going to Rwanda for a week to help install an open source medical records system at a rural health clinic! I&#8217;ll be going with Lucky Gunasekara and meeting with Partners in Health.
I&#8217;m really excited to work with Lucky! This project will be amazing, and [...]]]></description>
			<content:encoded><![CDATA[<p>Today I got confirmation of some great news&#8211;in February I&#8217;ll be going to Rwanda for a week to help install an open source medical records system at a rural health clinic! I&#8217;ll be going with <a href="http://www.youtube.com/watch?v=Lm5Ep54IP9A">Lucky Gunasekara</a> and meeting with <a href="http://www.pih.org">Partners in Health</a>.</p>
<p>I&#8217;m really excited to work with Lucky! This project will be amazing, and Lucky has a longer-term vision. He wants to answer the question: does cloud computing have a role in health systems in rural Africa? He&#8217;s planning some really interesting efforts in Kenya later this year. In time, I think Salesforce.com can be a boon in rural Africa, and I&#8217;m really interested to start the work to figure out if that time is now, soon, or farther down the road. I see this trip as a great first step on that path.</p>
<p>When I started working with Salesforce.com five years ago, I felt part of my role was to go down the path of trying to deeply customize the platform for nonprofits, and then to report on that experience, warts and all. I really enjoyed that work, and I hope to do similar work and storytelling around Salesforce.com in parts of the world where people assume the cloud can&#8217;t work.</p>
<p>But most of all, I&#8217;m really excited to have all my assumptions and expectations blown out of the water! I can&#8217;t wait to walk the roads, meet folks, and most of all listen and learn. I will be arriving with no answers, and I don&#8217;t expect to leave with any. For me, it&#8217;s all about getting to the right questions. There will be so much to take in, to start orienting myself to this new set of challenges.</p>
<p>Only just a week ago a friend pointed me to this piece by David Brancaccio on Partners In Health&#8217;s work in Rwanda. I was floored by the outcomes they are getting, and the thoughtful design of the community health program. I recommend watching it&#8211;it&#8217;s amazing.</p>
<p align=center><embed src="http://www.pbs.org/now/media_player/flvplayer1.swf"; width="635" height="380" bgcolor="000000" allowfullscreen="true" allowscriptaccess="always" flashvars="file=http://www-tc.pbs.org/now/video/NOW-537-stream.mp4&#038;plugins=embed-1&#038;image=http://www-tc.pbs.org/now/shows/537/images/video-512.jpg"></embed></p>
<p>So many times people look to technology as a savior. That never works in my estimation&#8211;human systems are how problems are solved. Technology can augment and transform those solutions, but it isn&#8217;t the answer. I&#8217;m incredibly excited by what&#8217;s already working in Rwanda, and am fired up to start thinking about how technology can help extend that impact.</p>
<p>I watched this video and emailed the link to a friend of mine with the message, &#8220;this is the work I want to do with my life&#8211;helping people build community-based systems that really work.&#8221; Four days later I got an email from Lucky inviting me to Rwanda, to the very region where that video was filmed. Serendipity is a fabulous thing!</p>
<p>Ahh! I&#8217;m going to Rwanda! I still can&#8217;t really believe it. It all feels so fast and so amazingly exciting. Of course I&#8217;ll be writing about the experience, as well as taking tons of pictures and videos. So much to do to prepare!</p>
]]></content:encoded>
			<wfw:commentRss>http://gokubi.com/archives/im-going-to-rwanda/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>A great job opportunity</title>
		<link>http://gokubi.com/archives/a-great-job-opportunity</link>
		<comments>http://gokubi.com/archives/a-great-job-opportunity#comments</comments>
		<pubDate>Fri, 11 Dec 2009 15:37:56 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[CRM]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://gokubi.com/?p=1061</guid>
		<description><![CDATA[Groundwire is an organization near and dear to my heart. I spent many wonderful years there back when it went by the name ONE/Northwest. My Salesforce-related career got it&#8217;s start there. Some of my most cherished relationships began there. And I was given the space and encouragement to grow exponentially as a person, technologist, and [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://groundwire.org">Groundwire</a> is an organization near and dear to my heart. I spent many wonderful years there back when it went by the name ONE/Northwest. My Salesforce-related career got it&#8217;s start there. Some of my most cherished relationships began there. And I was given the space and encouragement to grow exponentially as a person, technologist, and agent of change. I look back on those years very fondly&#8211;the work, the nonprofits we worked with, but most importantly the people.</p>
<p><a href="http://groundwire.org/about/jobs/CRM-Consultant">Groundwire is looking for a top-notch CRM Consultant</a>. Opportunities to join this amazing team are rare. If you are at all interested in using your Salesforce.com skills to make a difference in this world, you should follow up with Groundwire and make sure you don&#8217;t miss this chance.</p>
]]></content:encoded>
			<wfw:commentRss>http://gokubi.com/archives/a-great-job-opportunity/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Add a Donor Status Funnel to the Nonprofit Starter Pack</title>
		<link>http://gokubi.com/archives/add-a-donor-status-funnel-to-the-nonprofit-starter-pack</link>
		<comments>http://gokubi.com/archives/add-a-donor-status-funnel-to-the-nonprofit-starter-pack#comments</comments>
		<pubDate>Wed, 09 Dec 2009 16:18:42 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[CRM]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://gokubi.com/?p=1027</guid>
		<description><![CDATA[The vision of the Nonprofit Starter Pack has always been that it would be a starting place for nonprofits. It&#8217;s not a &#8220;application&#8221; so much as it&#8217;s a &#8220;platform.&#8221; We&#8217;ve tried to architect it in a way that gives some immediate benefit, while not precluding the change and extension that I feel is necessary for [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://gokubi.com/wp-content/uploads/2009/12/donorstatusfunnel.png" alt="donorstatusfunnel" title="donorstatusfunnel" width="400" height="300" class="alignright"/>The vision of the Nonprofit Starter Pack has always been that it would be a starting place for nonprofits. It&#8217;s not a &#8220;application&#8221; so much as it&#8217;s a &#8220;platform.&#8221; We&#8217;ve tried to architect it in a way that gives some immediate benefit, while not precluding the change and extension that I feel is necessary for successful use. In that spirit, I want to show how to add some donor segmentation you might find interesting if you&#8217;re using the One-to-one Account model.</p>
<p>The image on the right is from a Dashboard showing all Contacts in an instance with the Nonprofit Starter Pack installed. All Contacts have been categorized by something called &#8220;Donor Status.&#8221; We&#8217;re looking at their giving and putting them in one of four categories&#8211;never a donor, a donor previous to last year, a donor last year, or a donor this year. Here&#8217;s how I created it.</p>
<p>First, we need to have 2 rollup summary fields on Account that calculate the Opportunity values over this year and last year. You could also add a third rollup to get the value from two years back:</p>
<ul>
<li>Total Giving Year To Date &#8211; (Won EQUALS true) AND (Close Date GREATER THAN 12/31/2008) AND (Close Date LESS THAN 1/1/2010)</li>
<li>Total Giving Last Year &#8211; (Won EQUALS true) AND (Close Date GREATER THAN 12/31/2007) AND (Close Date LESS THAN 1/1/2009)</li>
<li>Total Giving 2 Years Previous &#8211; (Won EQUALS true) AND (Close Date GREATER THAN 12/31/2006) AND (Close Date LESS THAN 1/1/2008)</li>
</ul>
<p>These dates need to be hard-coded for the rollup summaries to work. On Jan 1, you&#8217;ll need to add a year to all the dates. Don&#8217;t worry, all the rollups will then recalculate for you.</p>
<p>Now you want to show these Account fields on the Contact. Create three formulas that just show the Account field value:</p>
<ul>
<li>YTD Giving Total &#8211; Account.Total_Giving_Year_To_Date__c</li>
<li>Last Year Giving Total &#8211; Account.Total_Giving_Last_Year__c</li>
<li>2 Years Previous Giving Total &#8211; Account.Total_Giving_2_Years_Previous__c</li>
</ul>
<p>Once you have these summary values, you can use them in another Formula, our Donor Status formula:</p>
<p><code>IF( npe01__Lifetime_Giving_History_Amount__c >0, IF( YTD_Giving_Total__c =0, IF( Previous_Year_Giving_Total__c =0, "2. SYBUNT" , "3. LYBUNT") , "4. Current Donor") , "1. Not Donor")</code></p>
<p>Note that the npe01__Lifetime_Giving_History_Amount__c field is included in the Nonprofit Starter Pack. The others are fields you just created, so make sure the names match.</p>
<p>Now that you&#8217;ve got the formula field built, create a Contact and Organizations report that takes all Contacts and groups by Donor Status. Variations on this report can easily be used to send a letter to everyone who gave in the past but not this year. Once you save this report, you can build a funnel dashboard based on it and you&#8217;re done! You&#8217;ve now segmented your donors based on when they last gave.</p>
]]></content:encoded>
			<wfw:commentRss>http://gokubi.com/archives/add-a-donor-status-funnel-to-the-nonprofit-starter-pack/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>My Nonprofit Starter Pack Session from Dreamforce 2009</title>
		<link>http://gokubi.com/archives/my-nonprofit-starter-pack-session-from-dreamforce-2009</link>
		<comments>http://gokubi.com/archives/my-nonprofit-starter-pack-session-from-dreamforce-2009#comments</comments>
		<pubDate>Sun, 29 Nov 2009 01:10:27 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[CRM]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://gokubi.com/?p=989</guid>
		<description><![CDATA[Getting the Most of of the Nonprofit Starter Pack. We cover 3 main things:

Configuring the Starter Pack
Importing Contacts via the wizard
Upgrading a package

Feel free to fast forward through the first 4 minutes, where we&#8217;re getting 110 people logged into their orgs&#8230;

]]></description>
			<content:encoded><![CDATA[<p>Getting the Most of of the Nonprofit Starter Pack. We cover 3 main things:</p>
<ol>
<li>Configuring the Starter Pack</li>
<li>Importing Contacts via the wizard</li>
<li>Upgrading a package</li>
</ol>
<p>Feel free to fast forward through the first 4 minutes, where we&#8217;re getting 110 people logged into their orgs&#8230;</p>
<p align="center"><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/nOY7IHp38WA&#038;rel=0&#038;color1=0xb1b1b1&#038;color2=0xcfcfcf&#038;hl=en_US&#038;feature=player_profilepage&#038;fs=1&#038;hd=1"></param><param name="allowFullScreen" value="true"></param><param name="allowScriptAccess" value="always"></param><embed src="http://www.youtube.com/v/nOY7IHp38WA&#038;rel=0&#038;color1=0xb1b1b1&#038;color2=0xcfcfcf&#038;hl=en_US&#038;feature=player_profilepage&#038;fs=1&#038;hd=1" type="application/x-shockwave-flash" allowfullscreen="true" allowScriptAccess="always" width="425" height="344"></embed></object></p>
]]></content:encoded>
			<wfw:commentRss>http://gokubi.com/archives/my-nonprofit-starter-pack-session-from-dreamforce-2009/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Inflection Point</title>
		<link>http://gokubi.com/archives/inflection-point</link>
		<comments>http://gokubi.com/archives/inflection-point#comments</comments>
		<pubDate>Sun, 22 Nov 2009 20:21:34 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[Africa]]></category>
		<category><![CDATA[CRM]]></category>
		<category><![CDATA[Change]]></category>
		<category><![CDATA[Civics]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://gokubi.com/?p=968</guid>
		<description><![CDATA[Dreamforce is a 4 day software user conference. It&#8217;s easy to look at it from afar and see only that&#8211;money to be made, customers to retain, sales to be won. And it&#8217;s absolutely true that Dreamforce is about all of that. Customers want value. Salesforce.com wants to give it to them. Partners want to get [...]]]></description>
			<content:encoded><![CDATA[<p>Dreamforce is a 4 day software user conference. It&#8217;s easy to look at it from afar and see only that&#8211;money to be made, customers to retain, sales to be won. And it&#8217;s absolutely true that Dreamforce is about all of that. Customers want value. Salesforce.com wants to give it to them. Partners want to get the word out about their solutions. All of that is true.</p>
<p>But I left Dreamforce feeling transformed&#8211;personally and professionally. I didn&#8217;t expect it. And I&#8217;m not exactly sure what to do with it.</p>
<p>I realized last week the reason I took my current job. People ask me all the time. It was clearly a good fit for my skills. The people are great. And it&#8217;s a lot of fun. But I realized the real reason last week.</p>
<p><strong>I took this job so that I can help create better lives for millions of people</strong>.</p>
<p>Not tens, not hundreds, but millions. Even hundreds of millions. That&#8217;s why I&#8217;m on this earth. That&#8217;s what I think I can contribute to our shared existence. And I think I can do that in my job.</p>
<p>What brought about this clarity? I met some amazing people. I met one woman who has an amazingly clarity of her purpose in life, and that purpose is to help Africa transform itself. To break the colonial, top-down models and return to self-organized, systemic change, completely in partnership with Africans. No more $1M schools dropped from the sky. Holistic, collaborative, community-based change. Generational change. She burns with this goal, and nothing will stand in her way.</p>
<p>Her passion lit a fire in me. And caused me to ask questions of myself. How does my bug fixing contribute to the reemergence of Africa? Am I making the kind of difference I need to make? What can I do differently?</p>
<p>I met a man who has a full-time job and volunteers with a group working in the Sudan. They are building a school from compressed soil, hand dug, hand compressed, and it will be hand built. I had talked to him about his Salesforce needs before I realized he was a volunteer. I thought he was an employee. But it turns out his organization only has one employee. He quietly does this work in his spare time, because he can&#8217;t possibly not do it. That wouldn&#8217;t make sense to him. And his work is infectious. He asked me, &#8220;do you want to go to the Sudan?&#8221; Hell yes I want to go to the Sudan.</p>
<p>I met a woman who is taking a holistic approach to education in Tanzania. Children found abandoned in garbage heaps find a home with her organization. They learn and grow because of her work. Their lives are forever changed. She does this work which has nothing to do with her professional history. She was called to it. And is phenomenal.</p>
<p>These people showed me their fire, their passion, the absolute unacceptability of doing nothing. The necessity of action today. The absolute need for impatience and patience all at once. It bowled me over. I&#8217;m reeling from it still.</p>
<p>It has caused me to look at my work differently. I will continue to do the best work I possibly can with the responsibilities I have. And I feel compelled to start initiatives of my own. The first thoughts I&#8217;ve had is to make Salesforce.com the absolute standard for use in Africa. Here&#8217;s what I think needs to be done to show that Salesforce.com can excel for nonprofits in Africa:</p>
<h2>Nonprofit Starter Pack</h2>
<p>I need to make this code base the best it can be. I want no software bugs standing in the way of this work. It&#8217;s the easiest place for me to make an impact on Monday, and I will.</p>
<h2>Language Support</h2>
<p>Salesforce is translatable into many languages. At this writing, that list includes 20 languages. English, French and Spanish are official languages in many African countries, and those languages are supported currently. I want Salesforce.com to be available in the next tier of African languages: <a href="http://en.wikipedia.org/wiki/Arabic_language">Arabic</a>, <a href="http://en.wikipedia.org/wiki/Swahili_language">Swahili</a>, <a href="http://en.wikipedia.org/wiki/Portuguese_language">Portuguese</a> (Brazilian Portuguese is currently available, and maybe that&#8217;s close enough?), and perhaps <a href="http://en.wikipedia.org/wiki/Afrikaans">Afrikaans</a>. There are over 2000 languages spoken in Africa, so we may never get to support <a href="http://en.wikipedia.org/wiki/Berber_languages">Berber</a>, <a href="http://en.wikipedia.org/wiki/Hausa_language">Hausa</a>, <a href="http://en.wikipedia.org/wiki/Xhosa_language">Xhosa</a>, and the countless others.</p>
<p>Are these the right languages? I&#8217;m new to this, but Arabic, Swahili, and Portuguese seem like the place to start. Arabic is a right to left language, so Salesforce.com first must be able to be switched to that mode, but once that&#8217;s possible, I want Arabic the next day.</p>
<ul>
<li><a href="http://ideas.salesforce.com/article/show/10093498">Vote for Arabic support</a> on the Idea Exchange.</li>
<li><a href="http://ideas.salesforce.com/article/show/10098690">Vote for Swahili support</a> on the Idea Exchange.</li>
</ul>
<p>And as soon as Salesforce.com supports a language, we&#8217;ll start the work to translate the Nonprofit Starter Pack to that language.</p>
<h2>Offline Support</h2>
<p>As you know, much of Africa lacks reliable Internet access. Much of Africa lacks clean water, electricity, and other services much more basic than that. So to support Africans working to transform their countries, we need rock-solid offline tools. Salesforce.com has had offline support in Internet Explorer for years, and many African nonprofits are currently using that to successfully support their work.</p>
<p>Salesforce.com recently released <a href="http://developer.force.com/flashbuilder">Adobe Flashbuilder for Salesforce</a> a toolkit that includes easy to use offline support. I think we need to build some killer offline apps with this toolkit to show the way in this space. Classroom attendance, health clinic service tracking, micro-finance payment collection. We need to build these and share the source code.</p>
<h2>Deep Case Studies</h2>
<p>I want to work with a few nonprofits in Africa to go deep in their usage of Salesforce.com. I want to hear the stories of how this helps them achieve their goals, and I want to share those stories with the world. Knowing what&#8217;s possible is an important step in the path to impact and excellence. We need to prove it, show it, tell it.</p>
<p>I normally don&#8217;t share my goals publicly. I like to under promise and over deliver. That&#8217;s worked for me for years. But I can&#8217;t seem to contain this new fire I feel. So I&#8217;m laying out what I want to see happen and I&#8217;ll do what I can to bring it about.</p>
<p>If you feel a stirring when you read this, join me. What will we do? I don&#8217;t know. How will we do it? We&#8217;ll figure it out. But I need to act today. If you feel that need, drop me a line, and we&#8217;ll help Africa together.</p>
]]></content:encoded>
			<wfw:commentRss>http://gokubi.com/archives/inflection-point/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Using Javascript to validate an Apex form</title>
		<link>http://gokubi.com/archives/using-javascript-to-validate-an-apex-form</link>
		<comments>http://gokubi.com/archives/using-javascript-to-validate-an-apex-form#comments</comments>
		<pubDate>Mon, 16 Nov 2009 21:15:25 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[CRM]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://gokubi.com/?p=956</guid>
		<description><![CDATA[Recently I came into a project where an Apex form on a Sites page had to validate itself in Javascript before sending an email via a controller method. I hadn&#8217;t ever done this before, so after some digging and some help, I thought I&#8217;d share the solution.
First, here is the VisualForce form:

&#60;apex:form id=&#34;emailform&#34;  &#62;

&#60;input [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I came into a project where an Apex form on a Sites page had to validate itself in Javascript before sending an email via a controller method. I hadn&#8217;t ever done this before, so after some digging and some help, I thought I&#8217;d share the solution.</p>
<p>First, here is the VisualForce form:</p>
<pre class="brush: html">
&lt;apex:form id=&quot;emailform&quot;  &gt;

&lt;input type=&quot;hidden&quot; id=&quot;redirect&quot; name=&quot;redirect&quot; value=&quot;contactus&quot;&gt;
Your Email: &lt;apex:inputText value=&quot;{!youremail}&quot; id=&quot;youremail&quot; maxlength=&quot;80&quot; size=&quot;40&quot; /&gt;&lt;br/&gt;

Subject: &lt;apex:inputText value=&quot;{!subject}&quot; id=&quot;Subject&quot; maxlength=&quot;80&quot; size=&quot;40&quot; /&gt;&lt;br/&gt;

Message: &lt;apex:inputTextarea value=&quot;{!body}&quot; id=&quot;Body&quot; rows=&quot;6&quot; cols=&quot;40&quot;/&gt;&lt;br/&gt;
&lt;apex:commandButton value=&quot;Send&quot; id=&quot;sendButton&quot; onclick=&quot;validate3()&quot;/&gt;

	&lt;apex:actionFunction id=&quot;emailSendFunction&quot; name=&quot;sendEmail&quot; action=&quot;{!send}&quot;&gt;
		&lt;apex:param name=&quot;youremailparam&quot; assignTo=&quot;{!youremail}&quot; value=&quot;&quot;/&gt;
		&lt;apex:param name=&quot;subjectparam&quot; assignTo=&quot;{!subject}&quot; value=&quot;&quot;/&gt;
		&lt;apex:param name=&quot;topicparam&quot; assignTo=&quot;{!topic}&quot; value=&quot;&quot;/&gt;
		&lt;apex:param name=&quot;bodyparam&quot; assignTo=&quot;{!body}&quot; value=&quot;&quot;/&gt;
	&lt;/apex:actionFunction&gt;
&lt;/apex:form&gt;
</pre>
<p>Note that the form doesn&#8217;t have an action: we&#8217;re invoking code via the onclick action of the command button. When the button is clicked, we&#8217;re calling Validate() a Javascript function on the page that looks like this:</p>
<pre class="brush: javascript">
function validate() {
     var errorMessage = &quot;Please fix the following errors: \n\n&quot;;
     var errorFound = 0; 

     if (!isValidEmail(document.getElementById(&quot;about_contact:emailform:youremail&quot;).value)) { errorMessage += &quot;Enter a Valid Email Address\n&quot;; errorFound = 1; }
     if (document.getElementById(&quot;about_contact:emailform:Subject&quot;).value.length == 0) {errorMessage += &quot;Enter a Subject\n&quot;; errorFound = 1; }
     if (document.getElementById(&quot;about_contact:emailform:Body&quot;).value.length == 0) {errorMessage += &quot;Enter your Message\n&quot;; errorFound = 1; }    

     if (errorFound == 1) {
	alert(errorMessage);
     } else {
	sendEmail();
     }
}
</pre>
<p>It&#8217;s a simple validation scheme. Check a bunch of fields and if they don&#8217;t look right, add a message and pop it up to the user. If everything is successful, we call sendEmail().</p>
<p>SendEmail() is the tricky part. It&#8217;s actually an Apex controller method exposed as a Javascript function so that it can be called by Javascript. This is done via the ActionFunction tag in Visualforce. You can see it in the VisualForce form above, but I&#8217;ll reproduce it here:</p>
<pre class="brush: html">
	&lt;apex:actionFunction id=&quot;emailSendFunction&quot; name=&quot;sendEmail&quot; action=&quot;{!send}&quot;&gt;
		&lt;apex:param name=&quot;youremailparam&quot; assignTo=&quot;{!youremail}&quot; value=&quot;&quot;/&gt;
		&lt;apex:param name=&quot;subjectparam&quot; assignTo=&quot;{!subject}&quot; value=&quot;&quot;/&gt;
		&lt;apex:param name=&quot;topicparam&quot; assignTo=&quot;{!topic}&quot; value=&quot;&quot;/&gt;
		&lt;apex:param name=&quot;bodyparam&quot; assignTo=&quot;{!body}&quot; value=&quot;&quot;/&gt;
	&lt;/apex:actionFunction&gt;
</pre>
<p>The controller&#8217;s send method is exposed and 4 parameters are asked for. Each of these parameters are mapped to public variables in the controller, where they are then used by the send method.</p>
<pre class="brush: java">
public class sffSendEmail {

	public String youremail { get; set; }
	public String subject { get; set; }
	public String topic { get; set; }
	public String body { get; set; }
	public String redirect { get; set; }	// Value tells us where to redirect

	// Constructor
	public sffSendEmail() {
	}

	public PageReference send() {
	 // Define the email
	 Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();

	 String[] toAddresses = new String[] { &#039;destination@email.com&#039; };

	 // Sets the paramaters of the email
	 email.setSubject( subject );
	 email.setToAddresses( toAddresses );
	 email.setPlainTextBody( &#039;From: &#039; + youremail + &#039;\n\n\r&#039; + &#039;Subject: &#039; + subject + &#039;\n\n\r&#039; + &#039;Message: &#039; + body + &#039;\n\n\r&#039; );

	 // Sends the email
	 Messaging.SendEmailResult [] r = Messaging.sendEmail(new Messaging.SingleEmailMessage[] {email});

	 PageReference secondPage = Page.confirmation_page;

	 secondPage.setRedirect(true);
	 return secondPage;

	}
}
</pre>
<p>If you don&#8217;t use the param tags and explicitly map the form fields to the public variables, I found that the send method is invoked before the setters have run on your form, leaving you with null variables. Using the params gets the values into those variables for use.</p>
<p>Update: From the comments, Andrew Waite has a better way of constructing the validate() javaScript:</p>
<blockquote><p>
FYI, it’s a best practice to avoid the dependency on the generated DOM ID, i.e.: document.getElementById(”about_contact:emailform:youremail”. You’ve qualified every element in your path which is good but your code is still susceptible to being broken by a new layer in the hierarchy.<br />
&#8230;<br />
The better approach is to define your validation function to accept the DOM IDs as args and use $Component. For example, assume the validate function took one arg for the “youremail” field: function validate(emailid) {….}, and then your onclick would be something like: onclick=”validate({!$component.youremail});”.
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://gokubi.com/archives/using-javascript-to-validate-an-apex-form/feed</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Nonprofit Salesforce Users &#8211; you need to get to Dreamforce</title>
		<link>http://gokubi.com/archives/nonprofit-salesforce-users-you-need-to-get-to-dreamforce</link>
		<comments>http://gokubi.com/archives/nonprofit-salesforce-users-you-need-to-get-to-dreamforce#comments</comments>
		<pubDate>Fri, 30 Oct 2009 18:28:51 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[CRM]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://gokubi.com/?p=946</guid>
		<description><![CDATA[Metcalfe&#8217;s Law states that the value of a network is proportional to the square of the number of connected users. Network value isn&#8217;t additive&#8211;it&#8217;s geometric.
Right now we&#8217;re at 115% of the number of registrants from last year. Following Metcalfe, and if Dreamforce was tomorrow, that means it would be 128% move valuable this year than [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://en.wikipedia.org/wiki/Metcalfe's_law">Metcalfe&#8217;s Law</a> states that the value of a network is proportional to the square of the number of connected users. Network value isn&#8217;t additive&#8211;it&#8217;s geometric.</p>
<p>Right now we&#8217;re at 115% of the number of registrants from last year. Following Metcalfe, and if Dreamforce was tomorrow, that means it would be 128% move valuable this year than it was last year. You can&#8217;t argue with math. <img src='http://gokubi.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>But Dreamforce isn&#8217;t tomorrow&#8211;it starts November 17. If you come, you nonprofit user who hasn&#8217;t registered yet, you who has great ideas and insight to share with others, you who has so much to learn, the power of our network increases amazingly quickly.</p>
<p><strong>If we can get to double last year&#8217;s attendance, we will acheive 4 times the value of last year&#8217;s Dreamforce! It&#8217;s true&#8211;Metcalfe is right!</strong></p>
<p>This year will be my 4th Dreamforce conference. Every year has been much better than the previous. Every nonprofit organization that has taken the time and effort to use Salesforce.com to help manage their operations should find a way to send at least one staff member to the conference. The information, relationships, and experience will pay off many times the costs of traveling and registration.</p>
<p>If you&#8217;re at a Nonprofit using Salesforce.com, or thinking about using it, we currently have a $199 registration rate for you. To get the promotion code, email <a href="mailto:crmdonation@salesforce.com">crmdonation@salesforce.com</a>.</p>
<p>Come be a part of network power. See Metcalfe&#8217;s Law up close and personal! Join us in November!</p>
]]></content:encoded>
			<wfw:commentRss>http://gokubi.com/archives/nonprofit-salesforce-users-you-need-to-get-to-dreamforce/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>ONE/Northwest is hiring a CRM consultant</title>
		<link>http://gokubi.com/archives/onenorthwest-is-hiring-a-crm-consultant</link>
		<comments>http://gokubi.com/archives/onenorthwest-is-hiring-a-crm-consultant#comments</comments>
		<pubDate>Mon, 26 Oct 2009 15:08:13 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[CRM]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://gokubi.com/?p=939</guid>
		<description><![CDATA[Anyone who asks me has heard the story&#8211;ONE/Northwest was an absolutely fabulous job with amazing people. I loved my time there&#8211;the technical challenges, the freedom to lead, the opportunity to shape the strategy. I won&#8217;t ever stop talking about ONE/Northwest, and the folks I shared that time with will always have a place in my [...]]]></description>
			<content:encoded><![CDATA[<p>Anyone who asks me has heard the story&#8211;ONE/Northwest was an absolutely fabulous job with amazing people. I loved my time there&#8211;the technical challenges, the freedom to lead, the opportunity to shape the strategy. I won&#8217;t ever stop talking about ONE/Northwest, and the folks I shared that time with will always have a place in my heart.</p>
<p>So good news for you! <a href="http://www.onenw.org/about/jobs/CRM-Consultant">ONE/Northwest is hiring a CRM consultant</a>. You could deliver cutting-edge Salesforce solutions to groups that will change the world with your work. Check out the job description and see if you&#8217;re up for some of what I think is the most fulfilling work around! </p>
]]></content:encoded>
			<wfw:commentRss>http://gokubi.com/archives/onenorthwest-is-hiring-a-crm-consultant/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Force.com User Group starting in Seattle</title>
		<link>http://gokubi.com/archives/force-com-user-group-starting-in-seattle</link>
		<comments>http://gokubi.com/archives/force-com-user-group-starting-in-seattle#comments</comments>
		<pubDate>Tue, 22 Sep 2009 21:28:44 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[CRM]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://gokubi.com/?p=931</guid>
		<description><![CDATA[I just heard from Val that the Seattle Force.com Developer User group will kick off on October 1st. If you&#8217;re near Seattle and code in Apex and VisualForce, come join the group. I&#8217;m really excited about it.
Want to take a deeper dive into the technical capabilities of Salesforce? Would you like to meet other Force.com [...]]]></description>
			<content:encoded><![CDATA[<p>I just heard from Val that the Seattle Force.com Developer User group will kick off on October 1st. If you&#8217;re near Seattle and code in Apex and VisualForce, come join the group. I&#8217;m really excited about it.</p>
<blockquote><p>Want to take a deeper dive into the technical capabilities of Salesforce? Would you like to meet other Force.com developers in the Seattle area? Interested in learning about new/different tools that will help you create and develop better solutions? A new Salesforce user group will be starting up on Thursday Oct 1. Meetings will be held on the first Thursday of every month.</p>
<p>We will try to cover a different range of topics at these monthly meetings such as:</p>
<ul>
<li>Summary of new functionality in the upcoming release</li>
<li>Project spotlight where someone will demo their project and the technical details</li>
<li>Best Practices</li>
<li>3rd Party development and integration tools</li>
<li>Apex and VisualForce</li>
<li>Open session to discuss specific questions you may have regarding your current projects</li>
</ul>
<p>Time: 8-9am<br />
Date: Oct 1, 2009<br />
Location:</p>
<p>West Monroe Partners<br />
1215 4th Ave Suite 1010<br />
Seattle, WA 98161</p>
<p>Please contact Val Grasparil (<a href="mailto:vgrasparil@westmonroepartners.com">vgrasparil@westmonroepartners.com</a>) or Andrew Brown (<a href="mailto:abrown@westmonroepartners.com">abrown@westmonroepartners.com</a>) if you have any questions.</p>
<p>Since it is in the morning, coffee and snacks will be provided. Please RSVP if you are planning on attending so we can make sure to have enough food for everyone.</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://gokubi.com/archives/force-com-user-group-starting-in-seattle/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Apex Architecture</title>
		<link>http://gokubi.com/archives/apex-architecture</link>
		<comments>http://gokubi.com/archives/apex-architecture#comments</comments>
		<pubDate>Tue, 08 Sep 2009 16:55:32 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[CRM]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://gokubi.com/?p=918</guid>
		<description><![CDATA[My post on Friday spawned some great discussion, even over the Labor Day weekend. If you were off enjoying summer&#8217;s last gasp, go back and check it out. In this post, I want to follow up on that and try to take the Apex architecture discussion to the next level of depth.
As I&#8217;ve said many [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://gokubi.com/archives/two-interesting-ways-to-architect-apex-triggers">My post on Friday</a> spawned some great discussion, even over the Labor Day weekend. If you were off enjoying summer&#8217;s last gasp, go back and check it out. In this post, I want to follow up on that and try to take the Apex architecture discussion to the next level of depth.</p>
<p>As I&#8217;ve said many times on this blog, I&#8217;m not a computer scientist, so I&#8217;m backing into architecture and often the concepts from CS-101 are new to me. I know I&#8217;m not the only one, so I&#8217;d like to make explicit some of the assumptions that top-notch developers are making every day. I surely am not an expert, and love to have developers set me straight&#8211;life is about continuous learning.</p>
<p>I&#8217;m going to lay things out as I understand them&#8211;if you think I&#8217;m making poor assumptions, please comment and set me straight. Also know that one of the reasons I love coding is that it is a creative act. It&#8217;s an amazing combination of a highly analytical process and one of inspiration and experimentation. I bet most programmers love that aspect of the job, and so I don&#8217;t believe there is a right way to do things, and I hope this may help to unleash creativity, rather than be seen as laying out any kind of Apex dogma that must be followed for fear of wearing the scarlet &#8216;no software&#8217; mark on your breast.</p>
<h2>#1: How hard should you work to have your triggers be absolutely minimal?</h2>
<p>I&#8217;ve written a bunch of Apex code and also gotten to maintain Apex code written by others. I think writing software for maintainability should be one of the top goals of all coders. I think the most maintainable way to write Apex triggers is to have as little logic in them as possible. If you are trying to figure out how some code works, or doesn&#8217;t work, it&#8217;s a lot easier to know that the trigger can safely be ignored because it&#8217;s only job is to call the class methods that get things done.</p>
<p>But how hard should we try to do that? Should we make sure our trigger has no logic in it at all? If so, it could look something like this:</p>
<pre class="brush: java">
trigger MyTrigger on MyObject__c (before insert, before update, after insert, after update) {
    MyObjectClass triggerSet = new MyObjectClass(Trigger.new, Trigger.old, Trigger.isBefore, Trigger.Context);
    triggerSet.process();
}
</pre>
<p>This signature would only have to change if we decide to have this trigger fire in different contexts, like UNDELETE. Of course, it&#8217;s not possible now, because there is no Trigger.Context to pass the enum value of the DML context. But, if <a href="http://gokubi.com/archives/two-interesting-ways-to-architect-apex-triggers#comment-189233">Jon gets his way</a> and this enum value is created, we have minimized the trigger to 2 lines of code.</p>
<p>But I think there is an efficiency hit. We&#8217;re going to instantiate the MyObjectClass no matter what the trigger set includes. If we only want to process records when a certain value changes, wouldn&#8217;t it be more efficient to move some logic to the trigger, and only instantiate the object if some of the records in the trigger set need to be processed?</p>
<p>Or is it a negligible difference we shouldn&#8217;t worry about?</p>
<h2>#2: When should we use static methods vs. object-oriented design?</h2>
<p>The trigger above is object-oriented design where an object is instantiated and variables and methods exist for that instance of the object. But the trigger could be written this way too:</p>
<pre class="brush: java">
trigger MyTrigger on MyObject__c (before insert, before update, after insert, after update) {
    boolean success = MyObjectClass.invoke(Trigger.new, Trigger.old, Trigger.isBefore, Trigger.Context);
}
</pre>
<p>So which is better? That&#8217;s something I&#8217;ve never been clear on&#8211;George made some great comments on my previous post along these lines.</p>
<p>The static method approach seems to make sense when your methods are straight-forward and you aren&#8217;t trying to maintain context across a number of actions. I like static methods for &#8220;utility&#8221; type functions:</p>
<p>utilities.getRecordTypeName(Id recordTypeId);</p>
<p>utilities.submitMyObjectForApproval(List<MyObject__c> my Objects);</p>
<p>I personally like the object-oriented approach when invoking a trigger. I think it makes sense to instantiate the object that is going to handle the trigger set, and then kick that off with various methods based on the context and timing of the invocation. It seems to me that writing the code to collect all the data from the trigger is best written once, in the constructor. Here&#8217;s some pseudocode for a such a class:</p>
<pre class="brush: java">
public class MyObjectClass {
     public MyObjectClass()
     {
     }

     public boolean triggerIsBefore;

     public enum context {Insert, Update, Insert, Upsert}

     public context contextPassedFromTrigger;

     public List&lt;MyObject__c]]&gt; triggerOldSet = new List&lt;MyObject__c]]&gt;();

     public List&lt;MyObject__c]]&gt; triggerNewSet = new List&lt;MyObject__c]]&gt;();    

     public MyObjectClass(MyObject__c[] myObjects, MyObject__c[] myOldObjects, boolean isBefore, context triggerContext)
     {
          triggerIsBefore = isBefore;
          contextPassedFromTrigger = triggerContext;

          triggerOldSet = myOldObjects;
          triggerNewSet = myObjects;
     }

     public process()
     }
          // BEFORE INSERT
          if (contextPassedFromTrigger==context.Insert&amp;&amp;isBefore)
          {
               someBeforeInsertMethod()
          }

     {

}
</pre>
<p>The main difference between static and object-oriented functionality is that you can have multiple independent instances of an object, but not of a static variable. So, if you wanted to deal with 4 different opportunities at once, and maintain data or variables for each and then do some processing, object-oriented is probably the way to go.</p>
<p>Each trigger invocation is it&#8217;s own universe. scope-wise, so you don&#8217;t have to worry about static invocations conflicting across trigger invocations.</p>
<h2>#3: What should go in a static Utils class?</h2>
<p>I like object oriented design, and I always compliment that with static classes for &#8220;utility&#8221; type methods and variables. I think each module of functionality you write should have it&#8217;s own utility class that services the other classes you&#8217;ve got in that module. I gave the example of the getRecordTypeName() method. Also, all your references to Custom Labels and other strings can be placed in this Utils class, and then they can be accessed statically from your other methods.</p>
<h2>#4: What are the limits of class proliferation?</h2>
<p>This is a tough one. Let&#8217;s say I&#8217;ve got some complex functionality. It wouldn&#8217;t be at all out of the realm of possibility to have the following:</p>
<p>MyProcess.trigger &#8211; my trigger to handle DMLs<br />
MyProcessClass &#8211; my main class for handling the trigger<br />
MyProcessUtils &#8211; my utils class supporting all this functionality<br />
MyProcessException &#8211; a class to extend the exception class for this functionality<br />
MyProcessTest &#8211; tests supporting all this code<br />
Other classes for functions that should be instantiatable on their own<br />
VisualForce controllers for any necessary UI</p>
<p>With complex functionality it can get to be a lot of files. So how is this balanced with maintainability? Aren&#8217;t more files and more dependencies harder for a maintainer to track down?</p>
<p>It is true that the more classes you&#8217;ve got, the harder it will be for someone to find everything and get their head around it. Naming conventions are key to finding related functionality. Everything I write that is related to this process will be started with &#8216;MyProcess&#8217;. Things can get confusing where processes meet and overlap&#8211;there isn&#8217;t anything we can do about that other than document things well with process maps and other tools.</p>
<p>I think that while there may be a lot of classes in this architecture, and findability my suffer, changability can be enhanced. By <a href="http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming)">encapsulating</a> key functions in their own classes or in well-written methods in existing classes, changes can be more easily made. One thing I&#8217;ve learned about writing code is to &#8216;encapsulate that which is likely to change.&#8217; In the short-term that may seem like a lot of infrastructure for relatively simple code, but when it needs to change it may be a lot easier.</p>
<p>So my main takeaways from this foray into thinking about Apex architecture are:</p>
<ol>
<li>Move most of your logic out of Apex Triggers and into Apex classes. Don&#8217;t stress out if your Triggers have some logic in them, but the less the better in most cases</li>
<li>Decide where you fit on the spectrum between everything static and everything object oriented, and then be consistent. Maintainability will suffer if you&#8217;re changing up all the time for similar functions</li>
<li>Use a static utilities class, and be mindful about what goes in there</li>
<li>Don&#8217;t stress out about class proliferation as long as your doing it to encapsulate that which may change later, and aren&#8217;t forgetting about making things finadable</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://gokubi.com/archives/apex-architecture/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Two interesting ways to architect Apex triggers</title>
		<link>http://gokubi.com/archives/two-interesting-ways-to-architect-apex-triggers</link>
		<comments>http://gokubi.com/archives/two-interesting-ways-to-architect-apex-triggers#comments</comments>
		<pubDate>Fri, 04 Sep 2009 22:36:50 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[CRM]]></category>

		<guid isPermaLink="false">http://gokubi.com/?p=906</guid>
		<description><![CDATA[I&#8217;ve been writing Apex triggers for a while, and recently I ran across two ways to architect triggers that are different from how I used to do things. Both methods have one main benefit&#8211;they push all your logic to your classes, and allow the trigger to do just one job&#8211;invoke code on data change.
Here&#8217;s a [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been writing Apex triggers for a while, and recently I ran across two ways to architect triggers that are different from how I used to do things. Both methods have one main benefit&#8211;they push all your logic to your classes, and allow the trigger to do just one job&#8211;invoke code on data change.</p>
<p>Here&#8217;s a trigger architected the first way:</p>
<pre class="brush: java">
trigger MyTrigger on MyObject__c (before insert, before update, after insert, after update) {

    if(trigger.isBefore){
        if(trigger.isInsert){
            MyObjectInsertBefore myInsertBefore = new MyObjectInsertBefore(Trigger.new);
        }
        if(trigger.isUpdate){
            MyObjectUpdateBefore myUpdateBefore = new MyObjectUpdateBefore(Trigger.old,Trigger.new);
        }
    }

    if(trigger.isAfter){
        if(trigger.isInsert){
            MyObjectInsertAfter myInsertAfter = new MyObjectInsertAfter(Trigger.new);
        }
        if(Trigger.isUpdate){
        	MyObjectUpdateAfter myUpdateAfter = new MyObjectUpdateAfter(Trigger.old,Trigger.new);
        }
    }
}
</pre>
<p>As you can see from the trigger, all that we&#8217;re doing is invoking the correct class based on the starting criteria&#8211;are we an insert or an update, and are we before or after? We&#8217;ve got a separate class for each of the four cases.</p>
<p>Here&#8217;s what two of those classes might look like:</p>
<pre class="brush: java">
public class MyObjectInsertBefore {

	//create your variables and data structures

    //constructor
    public MyObjectInsertBefore(){

    }

    //constructor accepting a list of myObjects
    public MyObjectInsertBefore(MyObject__c[] myObjects){
        //call whatever methods you need to get the job done
        someMethod(myObjects);
        .
        .
        .
    }
}
</pre>
<pre class="brush: java">
public class MyObjectUpdateBefore {

	//create your variables and data structures

    //constructor
    public MyObjectUpdateBefore(){

    }

    //constructor accepting a list of myObjects
    public MyObjectUpdateBefore(MyObject__c[] myOldObjects,MyObject__c[] myNewObjects){
        //call whatever methods you need to get the job done
        someMethod(myOldObjects,myNewObjects);
        .
        .
        .
    }
}
</pre>
<p>Key to making this efficient is to have shared methods in a MyObjectUtil class, so that similar operations can be reused across your classes.</p>
<p>Here&#8217;s a trigger invoked the second way:</p>
<pre class="brush: java">
trigger MyTrigger on MyObject__c (before insert, before update, after insert, after update) {

	public enum triggerAction {beforeInsert, beforeUpdate, afterInsert, afterUpdate}

    if(Trigger.isInsert &amp;&amp; Trigger.isBefore){
        MyObjectClass process = new MyObjectClass(Trigger.new, Trigger.old, triggerAction.beforeInsert);
    }
    if( Trigger.isAfter &amp;&amp; Trigger.isInsert ){
        MyObjectClass process = new MyObjectClass(Trigger.new, Trigger.old, triggerAction.afterInsert);
    }
    if(Trigger.isUpdate &amp;&amp; Trigger.isBefore){
        MyObjectClass process = new MyObjectClass(Trigger.new, Trigger.old, triggerAction.beforeUpdate);
    }
    if( Trigger.isAfter &amp;&amp; Trigger.isUpdate ){
        MyObjectClass process = new MyObjectClass(Trigger.new, Trigger.old, triggerAction.afterUpdate);
    }
}
</pre>
<p>This trigger sends the old and new sets over to a class and passes the way that this was invoked via an enum value (look up enum in the Apex docs if you haven&#8217;t used them&#8211;I had to). There is only one class, and then the class sorts out what should happen based on the data:</p>
<pre class="brush: java">
public class MyObjectClass {

	public MyObjectClass()
	{
	}

	public enum triggeredAction {beforeInsert, beforeUpdate, afterInsert, afterUpdate}

	public MyObjectClass(MyObject__c[] myObjects, MyObject__c[] myOldObjects, triggeredAction ta)
	{	

		// BEFORE INSERT
		if (ta==triggeredAction.beforeInsert)
		{
			someBeforeInsertMethod()
		}

		// BEFORE UPDATE
		if (ta==triggeredAction.beforeUpdate)
		{
			someBeforeUpdateMethod();
		}

		// AFTER INSERT
		if (ta==triggeredAction.afterInsert)
		{
			someAfterInsertMethod()
		}

		// AFTER UPDATE
		if (ta==triggeredAction.afterUpdate)
		{
			someAfterUpdateMethod();
		}

	}
}
</pre>
<p>You can see that you&#8217;re basically accomplishing the same thing&#8211;getting the class to invoke the right methods based on the invocation, but that we&#8217;re doing it in two different ways. In the first example, we&#8217;ve got a proliferation of classes, and each class is very simple. In the second example, we&#8217;ve got one class that is more complex as it has to handle many types of invocation.</p>
<p>I ran across the second example in the spring and really liked it. Then I ran across the first example last month and now it&#8217;s my favorite. I&#8217;m going to try to write new triggers that way and see how they go.</p>
<p>Thanks to Matt and Mike for architecting your code in these really interesting ways! I hope you, like me, love seeing how other people do things&#8211;it can really improve the way you code so very quickly. </p>
]]></content:encoded>
			<wfw:commentRss>http://gokubi.com/archives/two-interesting-ways-to-architect-apex-triggers/feed</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>Using Sites to easily publish data out of Salesforce</title>
		<link>http://gokubi.com/archives/using-sites-to-easily-publish-data-out-of-salesforce</link>
		<comments>http://gokubi.com/archives/using-sites-to-easily-publish-data-out-of-salesforce#comments</comments>
		<pubDate>Wed, 24 Jun 2009 17:45:13 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[CRM]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://gokubi.com/?p=868</guid>
		<description><![CDATA[I want to show you a quick and easy way to take live data from Salesforce.com and post it on your website using Salesforce Sites. You can see lots of hard-core examples of how to use sites. Those are cool, absolutely no doubt. People are building amazing things.
There also are opportunities for very targeted uses [...]]]></description>
			<content:encoded><![CDATA[<p>I want to show you a quick and easy way to take live data from Salesforce.com and post it on your website using Salesforce Sites. You can see lots of <a href="http://developer.force.com/sitesgallery">hard-core examples</a> of how to use sites. Those are cool, absolutely no doubt. People are building amazing things.</p>
<p>There also are opportunities for very targeted uses of Sites. With these micro-sites, the investment-to-value ratio can be really high. Here&#8217;s an example of one such use case.</p>
<h3>The Use Case</h3>
<p>A nonprofit wants to have a page on it&#8217;s website acknowledging all sponsors who supported events in 2007. They want a simple list of organizations, leaving out any who have asked not to be thanked publicly.</p>
<h3>The Data</h3>
<p>Sponsorships are tracked as Opportunities connected to the relevant Account. Here&#8217;s the Opportunity related list from the relevant Account:</p>
<p><img src="http://gokubi.com/images/donors_opp.png" alt="screenshot" class="centered"/></p>
<p>I have created a rollup summary field on the Account to sum up all Opportunities from 2007:</p>
<p><img src="http://gokubi.com/images/donor_rollup.png" alt="screenshot" class="centered"/></p>
<p>And I&#8217;ve created a checkbox to flag Accounts that want to stay anonymous. You can see both fields on the account detail page:</p>
<p><img src="http://gokubi.com/images/donors_account-1.png" alt="screenshot" class="centered"/></p>
<h3>The Display</h3>
<p>I want to show a simple list of donors that gave in 2007 and aren&#8217;t anonymous. To do this, I need to create a VisualForce page with a simple Apex controller so I can grab the right data, and then display it correctly</p>
<p>Here&#8217;s the Apex controller where I&#8217;m grabbing the data that I want. You can see from my SOQL statement that I&#8217;m only getting Accounts where the rollup field is greater than zero and the anonymous field isn&#8217;t checked. I&#8217;ve named it donorListing:</p>
<pre class="brush: java">
public with sharing class donorListing {
	List&lt;Account&gt; accounts;
	public List&lt;Account&gt; getAccounts(){
		accounts = [select name from account WHERE X2007_Giving_Total__c &gt; 0 AND Anonymous_Sponsor__C = false ORDER BY Name];
		return accounts;
	}
}
</pre>
<p>Here&#8217;s the VF Page where I display the data. I point to the Apex I created via the controller attribute of the page. I also turn off the Header, so that I don&#8217;t see all the Salesforce navigation elements. Then I just list out the sponsors.</p>
<pre class="brush: html">
&lt;apex:page controller=&quot;donorListing&quot; showHeader=&quot;false&quot;&gt;
	&lt;apex:dataList value=&quot;{!accounts}&quot; var=&quot;account&quot; id=&quot;theList&quot;&gt;
		&lt;apex:outputText value=&quot;{!account.name}&quot;/&gt;
	&lt;/apex:dataList&gt;
&lt;/apex:page&gt;
</pre>
<p>And here is what the VF page looks like in my browser when I&#8217;m logged in to Salesforce.com:</p>
<p><img src="http://gokubi.com/images/donor_page.png" alt="screenshot" class="centered"/></p>
<p>OK, looks great. But I want it visible to people not logged into Salesforce. To do that, I need to create a Salesforce Site.</p>
<h3>The Site</h3>
<p>You can create a Salesforce site at Setup | Develop | Sites. Create a site, and give it a name. It will show you the URL for this site. That&#8217;s the URL people can hit from anywhere on the web to see your VisualForce pages.</p>
<p>You associate VisualForce pages with a Site on the Site detail page. You&#8217;ll see here my donorlist page is a part of this site:</p>
<p><img src="http://gokubi.com/images/donor_pages.png" alt="screenshot" class="centered"/></p>
<p>Next, I want to make this page visible to the public&#8211;I don&#8217;t need people to login to see it. That&#8217;s done by modifying the public access settings:</p>
<p><img src="http://gokubi.com/images/donor_site_detail.png" alt="screenshot" class="centered"/></p>
<p>Make sure your pages <del datetime="2009-06-24T19:08:11+00:00">and classes</del>(classes used by VisualForce pages are added automatically) are associated with the site:</p>
<p><img src="http://gokubi.com/images/donor_guest_access.png" alt="screenshot" class="centered"/></p>
<p>OK, now we&#8217;re ready to hit the page at it&#8217;s external location. For this example, the URL is:</p>
<p><a href="http://smsdev-developer-edition.na6.force.com/sms/donorlisting">http://smsdev-developer-edition.na6.force.com/sms/donorlisting</a></p>
<h3>The end product</h3>
<p>Now that we can see the page publicly, we can embed it anywhere on the web using something called IFRAME. It&#8217;s a part of the HTML that runs the web, and has been around for a long time. Here&#8217;s the code for embedding this page in my website:</p>
<pre class="brush: html">
&lt;iframe src=&quot;http://smsdev-developer-edition.na6.force.com/sms/donorlisting&quot; width=&quot;100%&quot; height=&quot;150&quot; frameborder=0&gt;
</pre>
<p>The nonprofit can now paste that IFRAME code into it&#8217;s website content management system. I&#8217;ve done just that in this post&#8211;you can see the sites page embedded right here:</p>
<p><iframe src="http://smsdev-developer-edition.na6.force.com/sms/donorlisting" width="100%" height="150" frameborder=0><br />
</iframe></p>
<p>When you hit this page, you&#8217;ll see the live data. If I get new sponsors or I flag sponsors as anonymous, they&#8217;ll appear or disappear accordingly. Just manage your data through your normal process and the public acknowledgement just happens.</p>
<p>Heck, you could even put workflow on the Account that automatically sends an email to the Account when they make this list. That email could contain a link to the acknowledgement page. That&#8217;s a pretty nice thank you experience for the sponsor, I think.</p>
<h2>The challenge</h2>
<p>This is a very simple example meant to get you thinking about what&#8217;s possible. What do you want to do with Sites? Come up with your own use cases and implement them in a developer org. As you can see, there isn&#8217;t much code involved to get it working. Show your boss what&#8217;s possible with an example. Tell them how long it took you to get data shared on your organization&#8217;s website. Modify the data in Salesforce.com and then hit refresh in the browser. Astound and amaze! And then build Sites into your business process for quick and easy publishing of your Salesforce.com data.</p>
]]></content:encoded>
			<wfw:commentRss>http://gokubi.com/archives/using-sites-to-easily-publish-data-out-of-salesforce/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Drip campaigns with Summer &#8216;09</title>
		<link>http://gokubi.com/archives/drip-campaigns-with-summer-09</link>
		<comments>http://gokubi.com/archives/drip-campaigns-with-summer-09#comments</comments>
		<pubDate>Wed, 17 Jun 2009 16:45:37 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[CRM]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://gokubi.com/?p=864</guid>
		<description><![CDATA[John Kucera is posting an awesome series about doing complex engagement work with Campaigns and the new enhancements in Summer &#8216;09. This is killer stuff John!
]]></description>
			<content:encoded><![CDATA[<p>John Kucera is posting an awesome series about doing <a href="http://blogs.salesforce.com/marketing/2009/06/automated-multiwave-campaigns-in-salesforce-marketing-summer-09-part-2.html">complex engagement work with Campaigns and the new enhancements in Summer &#8216;09</a>. This is killer stuff John!</p>
]]></content:encoded>
			<wfw:commentRss>http://gokubi.com/archives/drip-campaigns-with-summer-09/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Nonprofit Starter Pack is now an Open Source Project</title>
		<link>http://gokubi.com/archives/nonprofit-starter-pack-is-now-an-open-source-project</link>
		<comments>http://gokubi.com/archives/nonprofit-starter-pack-is-now-an-open-source-project#comments</comments>
		<pubDate>Mon, 15 Jun 2009 15:10:09 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[CRM]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://gokubi.com/?p=861</guid>
		<description><![CDATA[I just posted over on the Salesforce.com Nonprofit blog that we are releasing the Nonprofit Starter Pack as an open source project!
The post tells the full story and provides links to all the relevant resources: project site, issue tracker, code base, and documentation.
Come join us in this effort!
]]></description>
			<content:encoded><![CDATA[<p>I just posted over on the Salesforce.com Nonprofit blog that <a href="http://blogs.salesforce.com/nonprofit/2009/06/open-s.html">we are releasing the Nonprofit Starter Pack as an open source project</a>!</p>
<p>The post tells the full story and provides links to all the relevant resources: <a href="http://code.google.com/p/npsp/">project site</a>, <a href="http://code.google.com/p/npsp/issues/list">issue tracker</a>, <a href="http://code.google.com/p/npsp/source/browse/">code base</a>, and <a href="http://wiki.developerforce.com/index.php/Nonprofit_Starter_Pack">documentation</a>.</p>
<p>Come join us in this effort!</p>
]]></content:encoded>
			<wfw:commentRss>http://gokubi.com/archives/nonprofit-starter-pack-is-now-an-open-source-project/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
