Archive for September, 2007

Apex, what it is and how it improves Salesforce.com

Sunday, September 30th, 2007

A little over a year ago, Salesforce.com announced the Apex development language. There has been tons written about Apex. My goal here is to present what I think are the most salient points about Apex, why it’s a big deal, and how it will make things better for my Salesforce.com users. I’m not a killer programmer or industry analyst, so this article will focus on my strengths and look at what new angles Apex will give me for solving my customers’ business problems.

What is it?

Apex is a language to write procedural code that runs on the Salesforce servers. It’s like writing stored procedures–you can access and manipulate data quickly–it’s on the server and it’s compiled.

This was a big move forward for Salesforce. Until Apex, procedural code had to be written in your language of choice and it used the web API for access to data. While this worked, accessing lots of data was very slow as all the database access had to traverse the Internet with the added overhead of SOAP encapsulation. Apex happens on the server, so there is no travel time for the data.

It’s magic, right?

Turns out it’s not magic. It’s really not all that innovative in what it does. Client server setups have had this kind of functionality for decades, it seems. But in the context of the multi-tennant architecture of Salesforce, it is really innovative. With Apex, you now can get the best parts of client server along with the best parts of on-demand. I can write my own code but not kill my server. Pretty cool.

Language details

The language itself is syntactically appealing to me. It’s very terse, and had a number of conventions that make sense in the context of Salesforce, but might not make sense elsewhere. For example, there is a data type for Salesforce record Ids. Another example is a simple for loop structure for looping through a database query result. In comparison to working with their AJAX toolkit, I’ve found Apex to be quick and light, with little wasted code.

Another big positive of the Apex language is the Eclipse IDE plugin. The plugin for the popular Java development environment connects you directly to your Apex code on the Salesforce servers, and makes running unit tests a breeze. The developers I’ve shown the Eclipse plugin to have been jealous of features like automatically identifying the percentage of you code covered by your tests and listing which lines of code aren’t being covered at all. It has made my entry into test-driven development pretty smooth.

How does Apex stack up against other analogous languages? I have no idea, and I’ll leave that to experts in that arena.

Invoking Apex

You can invoke Apex code in 2 ways: via triggers and through web-service calls. Triggers are code blocks that are run on changes to the data in your database. By using triggers you can run your arbitrary code every time a new Opportunity is inserted, for example. Having code run automatically based on data events is really powerful, and can do a lot for the user experience. You can easily automate User tasks that would have to be done by hand, making the application experience much nicer.

Exposing your code via a web service makes it callable from the Salesforce UI. Apex has no facility for creating UI (newly announced VisualForce takes care of that), so exposing it as a web service makes that available to S-Controls, which can have UI. The User can click a button and fire your Apex code, replacing the need for complex S-Controls, and getting all the benefits mentioned earlier.

So, Apex is faster than S-Controls, with simpler syntax. It can be called from buttons and data triggers. But what does that mean for user experience, which is the real test in a CRM application?

Application benefits of Apex

The first benefit I saw to Apex when it was announced was the ability to use triggers to eliminate steps the User had to take. Here’s a real-world example.

In the nonprofit world we care about households. We have donors and other supporters, and we often know other members of their family. If we send them separate thank you letters, or (even worse) appeals for money, they might be offended. In most cases, we want to send one mailing to each household, naming the members of the household in the letter.

In Salesforce, we model this as a simple custom object that can have multiple Contacts associated with it. Then, we can use this object when we want to send mailings. But to get Households in the system is a bit of a drag for the user. A User would have to create a Contact, then create a Household and relate them together. Households have addresses, but so do contacts, so the User would have to make address changes in two places. Lastly, if a new person was added to the Household, their name would have to be added to the name of the household, so that the letters mailed would identify all known members.

Before Apex, we tackled these problems with S-Controls. We created an S-Control for creating Contacts that would automatically create a Household after the Contact save. The address fields would be synced at this time, but we had no way of keeping these automatically in sync later. We also got the name of the Household right, but the User was responsible for managing the data in the future.

With Apex we’ve been able to improve this situation. I’ve created a couple triggers:

  • When a Contact is created without a Household, a new Household is automatically created, the address is saved to the Contact and the Household, and it is named correctly.
  • When a Contact is added to or removed from a Household, the Household is renamed and the name is pushed to every Contact in the Household
  • If a Household or a Contact address changes, the change flows through to everyone in the Household

What this means is that all Householding activities are now fully automated. The User never need care about Households, they will just be there to be used when needed. As you can imagine, this is a big win and pretty exciting.

The second benefit to Apex is the ability to denormalize data in interesting ways. We’ve created triggers that do rollup calculations on related data and save it up to the Contact or Account. Apex can do complex calculations across much related data, so it’s more flexible and powerful than Rollup Summary Fields. But why is this valuable?

In Salesforce when you want to analyze data you build reports. Generally these reports look at one set of data–Contacts or Opportunities or Campaign Memberships. But often the questions that creative users come up with take multiple sets of data into account, or look at multiple pieces of data in the same set. Some examples of questions you can’t currently ask Salesforce are:

  • Who gave at least two donations in the last 5 years?
  • Who gave a donation and attended 3 events?
  • Are we converting our Members to Event attendees, or the other way around?

Apex lets us put strategic pieces of data on the Contact record. Then when we do a Campaign membership report, we can look at this other data at the same time. These native reports can fuel dashboards that are a level of analytics we don’t have right now. And because they are native, we can use the reports to create prospect lists and funnel those directly into Campaigns.

A third area where Apex can help immensely is with integrations. The plumbing of integration is pretty straightforward, but what is complex is supporting all the weird business cases that Users might have. Let’s look at our Household example above. Many integrations with Salesforce create Contact records at some point in the flow. Event registration, online donation processing, even the Outlook integration has a Create Contact form. But with Householding, these integrations won’t work, or will create incomplete data. A Contact with no Household is a problem, so we can’t use these kinds of external integratons.

But if Apex triggers fire whenever a Contact is created and take care of the Householding with no intervention, all of the sudden all these integrations work fine. The integrators don’t need to know about Householding or any other crazy processes–they just create a Contact and leave it up to me to write the correct triggers. This is really exciting for people writing integrations, I can assure you. We’re going to be offloading some of our Plone integration code that supports weird use cases to Apex triggers. Very happily, I might add.

Apex can also make callouts to external web services, making just about anything possible. I haven’t played with this yet but can’t wait to do things like geocoding, address certification, and who knows what else.

Nothing’s perfect

While I’ve been very positive so far, there are some limitations to Apex as it’s currently released. First is that triggers don’t cover all actions that could happen in the data. There are a number of junction tables that don’t listen for events. The two biggest for me are Opportunity Contact Role and Campaign Member. These are tables that connect Contacts to Opportunities and Campaigns, respectively. Because there are no triggers on those tables. I could change the donor on a gift, but wouldn’t be able to update the giving total to that Contact record. I also can’t recalculate the events a person has attended when we mark them as having attended an event. I think these are pretty significant holes in the Apex infrastructure that hopefully will be fixed soon. With them unfixed, users can take actions that will make the data unreliable. We hope to minimize these cases, but there is only so much we can do.

One way around gaps like the two I listed above is to use triggers as best we can and then run a nightly batch to clean up any changes that slipped through. But Apex as it’s currently released doesn’t let us schedule the execution of blocks of code in a cron-like fashion. I think that functionality will come.

The third limitation has to do with one of Salesforce’s greatest strengths–it’s multi-tenant architecture. When Salesforce decided to let crazy people like me run code on their servers, they had to protect themselves and their other customers from my bad code. So, they built a bunch of controls to make sure I couldn’t hog resources. Part of this control system is a set of governors that limit the kinds of operations you can do. A trigger can only have 20 SOQL statements in it, for example. If a trigger is fired by a change to one record, only 100 other records can be updated. Arrays can only have up to 1000 members. The list goes on.

So, the Apex cron job that would crawl through 20,000 opportunities nightly wouldn’t work in the current governor regime. A decent portion of the utility of Apex will hinge on how quickly these governors are lifted. It’s a tough problem to solve, and one that has direct cost implications for them, so we’ll see if they budge in the next 6 months.

Conclusion and next steps

I’m very bullish about Apex. It fills a need that has been wanting for a while. And it appears to fill it very nicely. There are some limitations in the current release, but still the benefit to user experience, analytics and integration are enormous, and the language and tools are very nice. We’re undergoing a process to rewrite as much of our custom code base from S-Controls to Apex. Initial experiments have been highly successful, and I’ve been very impressed by everything I’ve seen. Add to that the ability to adequately test the code we’re writing for the first time and I am incredibly happy with the direction we’re going.

As we convert our codebase and add new functionality, I will report back on our status and share code snippets and do some screencasts of interesting developments. I can’t wait to really get going on the Apex path–I feel like it’s going to change the way we do Salesforce, taking our systems to a level we’ve only been dreaming about.

The bar has been raised

Thursday, September 27th, 2007

Apex Tests

With a couple much-appreciated pointers from MikeD, today I took my past dabbling in Apex code and refactored it as Classes and Methods called by Triggers. It’s a better way to organize the code, and makes it more maintainable.

Then, I started building tests. Andrew, Jon, and David do all their Python programming in a test-driven fashion, so I understand how it works. But I’ve never done it. This afternoon I got built out tests to cover the Apex code I wrote automating the Householding process.

I now have tests that cover just shy of 100% of the lines of code I’ve written to automate Householding. That means that by clicking a button in Eclipse I can evaluate 5 triggers and 400 lines of heavily conditional code in about 5 seconds.

If I want to verify that the Household name actually changes when I add a Contact to that Household, I don’t have to go to the UI at all. I run my tests and it shows me what is happening. Without ever writing any data. In 5 seconds. I’m floored.

While I was writing the tests, the Apex plug in for Eclipse was kind enough to show me the lines of code I hadn’t covered yet. Amazing how helpful that was. Thanks Dave!

I sure have a lot to learn now that the bar has been raised, because I’m really just a script kiddie. But the learning I’ve done today has already paid off. Tests are the gift that keeps on giving!

Two of my ideas coming in Winter ‘08

Thursday, September 27th, 2007

Two of my ideas on ideas.salesforce.com have been flagged as coming in Winter ‘08:

Reporting on Inactive Campaigns and Make Salesforce.com work in Safari for Windows.

Salesforce.com announced they are overhauling Campaigns, so the first one isn’t much of a surprise. I’m really excited to see Safari support up there. I wrote earlier about how fast it is when using Saleforce, but there are just too many things that don’t work right. Can’t wait to see full support.

There’s another cool idea that just made the list–watch lists. Living in a feed-filled world, I love this idea!

ONE/Northwest hiring a CRM Consultant

Tuesday, September 25th, 2007

I can’t tell you how excited I am that we’re hiring a full-time CRM consultant up here at ONE/Northwest. The job description is over on the ONE/Northwest site. It’s a full-time, Seattle-based position working directly with environmental groups.

Can I say enough about ONE/Northwest and the team we have assembled here? I don’t think so. It is truly the best job I’ve ever had. Add that I get to work with the great people in the Salesforce.com/nonprofit world, and it’s tough to beat.

We’re planning on doing some amazing things in 2008 around Salesforce.com and the northwest environmental sector. If you’re interested, send an email to jobs@onenw.org with your resume and cover letter, and I’ll tell you all about it.

Race Report: Black Diamond Half Ironman

Sunday, September 23rd, 2007

Saturday I did my first half Ironman and it was quite an experience.

transition

It was a nice morning, and it wasn’t raining. It was a damp Northwest 50 degrees, so it felt pretty cold. I did an Olympic distance race on this course in June and it was cold and raining, so dry was a vast improvement.

I was wearing a tri-specific wetsuit for the first time, so I didn’t know what to expect. When the gun went off, I bobbed to the surface like a cork. The suit kept me in perfect swimming form the whole time–thanks Blue Seventy!

The swim went really well. I felt good and navigated fairly well. I found myself thinking about things other than not drowning, which was good. The field was smaller than the tris I did earlier in the year, so I wasn’t bumping into people after the first quarter mile.

lake

I came out of the water feeling great after 0:35:40–faster than I had expected. At the bike, I decided to dress warm as I had had two experiences this season with very cold bike rides and I did not care to repeat. I wore my neoprene biking jacket and lobster gloves. That was the best decision I made all day. I was gloriously comfortable for the entire ride.

The ride was really a blast. My bike is a speed machine, and there is nothing like freshly paved rural roads and surrounding competitors to make you go fast. The first 28 mile loop went well. I felt great, and was smiling thinking just how much further I had to go. I kept telling myself to take it easy on the second loop, and I did. My second half of the bike was definitely slower than the first. I have no idea by how much–I came in with a total bike time of 2:52:00, an average speed of 19.5 mph.

On the bike I drank Nuun and ate Shot Blocks. I ate on a schedule and tried to drink all the time. My stomach started to feel a little weird so I stopped eating with about 45 minutes left on the bike. I ate some more on the run, and generally my nutrition was pretty good, I think, for my first real effort at it.

I got to the run and pretty quickly realized I was in for quite a challenge. I’ve only ever run 13 miles once–I had more training planned but had some injuries in August that kept me off the roads. I expected the first mile or so to be a slog after having been on the bike for 3 hours. I started to feel better and my first couple miles were at a 9 minute pace. I walked at every water station, taking a minute or so to rest and drink. They had 4 stations on the course, and I damn well visited them all.

At 5 miles there was a false flat that took it out of me. It was about a mile long and made me feel like I was dragging a spare tire on a rope. I think this was the first time I walked out of fatigue. I ran some more, then walked some more, and them came to the 6 mile mark where they had inserted a very large hill. I walked to the top, and ran down then continued to run back down the false flat I had trudged up before. At the 7 mile mark, I first felt an overwhelming desire to stop running and take a nap by the side of the road. At one point I was running with my eyes closed, or I should say shuffling.

It wasn’t really pain, just this heavy feeling that I could barely resist. I’ve never experienced it before. I mean, every run I do I wish I could stop running, but this was qualitatively different, like irresistible sleep. So I walked some more, then ran a bit, then walked some more.

The course was out-and-back, meaning that there was a constant stream of runners on the other side of the street running in the other direction. Lots of waving and words of support was going on–that was nice. As I was dealing with my inner struggle to keep running, and being surprised at just how hard it was, I had the realization that everyone else was somewhere in their own struggle. Whether they looked great or were struggling, we all were pushing ourselves just for the sake of doing it. It was a voluntary test were had all decided to put ourselves through, for our own reasons. And we were all in the midst of it, supporting each other, and counting out the steps and the minutes with some goal in mind.

I didn’t think too much about it at the time, as I had other things to deal with, but since the race I’ve been thinking about it more. I was in the midst of really intense personal struggle on a vast scale. Amazing.

At 8 miles, I felt some pain in my right foot where I had injured it in August. The pain wasn’t intense, so I walked a bit and then ran. I was dull, so I decided not to abandon and keep going.

The 11 mile mark was pretty close to the park entrance, and I did the math and knew there was some sort of loop in the course that I didn’t know about, but my mind was trying to convince me that we were going directly to the finish line and that somehow that would miraculously add up to 13.1 miles. But no, they brought us to within 300 feet of the finish, where you could hear them calling out the finishers, and then sent us off on a mile and a half loop around the lake. Cruel!

Only a mile left, but I couldn’t run. I ended up walking probably half of that last mile. I just had nothing left. I started running as I recognized how close I was to the finish. I crossed over to the announcer saying, “Steve Andersen of Seattle, 70.3 miles…Finished!” 2:17:00 for the run, or 10 min pace. My total time was 5:57:00–I had guessed I could do it in 6 hours.

I was so glad to be done I didn’t really get excited. Relief was the primary feeling, followed by hunger. I ate a ton immediately and discovered that it was really hard to get up from the picnic bench–my legs didn’t really work. The person serving food asked me if I was OK.

Unfortunately the desire to nap continued on the drive home–next year I’ll get a ride or at least a triple latte before I get on the road!

I’ve been asked, will I do another one? Maybe, but with more training. If I had to answer today, I’d say I’ll focus on Olympic distance because of my limited training hours, what with work and kids and all. But I’m so glad to have done it. It was a struggle with myself for the last couple hours, and it was so nice to cross the finish line.

A special thanks to my wife and family who put up with all the hours of training. I couldn’t have done it without your support!

70.3

Saturday, September 22nd, 2007

I think that was the hardest thing I’ve ever done–70.3 miles. The hardest part was fighting off the incredibly powerful urge to stop running and curl up for a nap by the side of the road. I almost couldn’t resist it. But I finished!

I’ll write a longer post later, when I’m less completely spent, but a couple key thoughts:

  • How the hell do people do full Ironman races? Seriously.
  • Blue Seventy wetsuits make you go really, really fast
  • I found I can come up with possible solutions to a Plone/Salesforce/Paypal integration problem we’re up against, all while swimming in a pack of triathletes. Geek.
  • Triathlon bikes are some of the coolest machines I know. They are speed demons and so efficient. What a blast to ride one.
  • Don’t drive yourself home from your next half Ironman–it’s hard to stay awake.

Now to bed.

1/2 Ironman tomorrow

Friday, September 21st, 2007

By this time tomorrow I hope to have completed my first half Ironman triathlon. This has been the goal of my training since early May, so I’m pretty excited that it’s finally here.

It will consist of:

  1. 1.2 mile swim - not very painful
  2. 56 mile bike - fairly painful
  3. 13.1 mile run - I suspect this will be very painful!

My training was right on track until August, when I got derailed by a series of events. A bike crash, a tooth extraction, a sprained foot, and finally tonsillitis. So I’ve basically had a 6 week taper. Before that I put in 13 miles in the pool, 253 miles running, and 892 miles on the bike.

I think I’ll be OK, but the biggest concern is that foot pain will show up at some point in the run. I did 3 miles on the treadmill today and didn’t feel a thing, but we’ll see what tomorrow brings.

It’s going to be a bit cold at race-time, and it might be raining. So think warm thoughts and wish me luck!

Dreamforce 2007 Wrap Up

Thursday, September 20th, 2007

I’m bleary eyed as I write this wrap up of the Salesforce user Conference. I had a great time seeing lots of old friends and meeting a bunch of great new folks. Here were my top 15 moments:

  1. INXS, baybee!
  2. Going to the Nonprofit Salesforce.com party. Four words: stretch limo, Tiburon, and Marga-greet-as.
  3. Demoing the fun work Matthew and I did with Apex, and what Andrew and Jesse have built with Plone integration, and getting great response.
  4. Having Simon Fell ask me what my number one feature request was…and giving him 4!
  5. Staying up late with Evan Callahan–it was like geek summer camp…
  6. Being one of 3 folks to win a Developer Hero award from Adam Gross. Thanks Adam!
  7. Getting interviewed by Peter Coffee on the Expo floor
  8. Hearing great news on direction of the platform–big doings in the next 12 months
  9. Having 75 separate conversations about how we all have way too much work to do
  10. Getting nominated for an Appy award and losing to a much more deserving nonprofit–congrats Family Service Agency of San Francisco! And continued good luck with your implementation!
  11. Demoing for Sonny Cloward the heavy customizations we’ve done to manage our consulting program in Salesforce.com
  12. Getting to thank Glenn at CRMFusion and Andrew at Clicktools for giving us access to their awesome products. Mark from Apextremes was so busy telling people about Conga, I didn’t get a chance to thank him!
  13. Seeing Chris Pokrana continue to cash in on that photo shoot from 2005–he was on-screen 3 times in the keynote
  14. Meeting tons of great people–let’s stay in touch.
  15. Actually using twitter in a helpful way…I didn’t think it was possible

Thanks again to the Salesforce.com Foundation who got us all there, and showed us a great time. Now, off to dig myself out of a big pile of email!

Giving history matrix report on Contact via private Appexchange

Thursday, September 20th, 2007

At Dreamforce yesterday I showed how easy it is to add someone else’s components to your Salesforce.com instance by using private Appexchange packages. The example was an inline display of a matrix report showing the giving history of a Contact.

To install the giving matrix reports, follow the steps outlined in this video.

And here’s a link to the private Appexchange listing

Enjoy!

i-Dialogue, web integration with Salesforce

Saturday, September 15th, 2007

Mike Leach and I were co-presenters last year at Dreamforce. In the session, I talked about our work with Plone integration, and Mike talked about his I-Dialogue platform, which is a CMS/portal system with Salesforce.com integration built in.

Mike just posted about a new feature for Nonprofits using his CMS–easily publish your supporter list on your website. The list of supporters is driven from Opportunities in Salesforce, obviating the need for double entry to put supporter names on your website.

Nice looking, Mike!