Friday, May 02, 2008

Unit Testing

Writing unit tests may be a bit of an acquired taste, but I don't think that the value of writing them can be overstated for any moderately complex software project.

Having a full suites of well-written unit tests gives developers the peace of mind to confidently refactor code that isn't their own, or to refactor code that they have written but are no longer happy with.

Writing unit tests before writing the actual code has an added benefit as well. It provides a developer with an extra opportunity to think about how clients of the code are going to use it. This in turn helps identify potential bugs much earlier in the development cycle.

Add it all up, and the end result is that the act of writing unit tests results in higher quality code. The popularity of NUnit helped Microsoft realize this, which is why Visual Studio 2005 Team System delivered integrated unit testing tools.

salesforce.com came to the same conclusion about the importance of unit testing and made it a fundamental component of Apex, their on demand programming language. Writing unit tests for Apex is a remarkably simple task, which is good, because Apex is the first programming language to require developers to write unit tests for their code - a minimum of 75% code coverage is required for all production Apex code. I anticipate that more languages will begin to follow suit, especially those designed to run in multi-tenant environments.

Having seen the value of unit testing personally and having seen the industry's acceptance of the value of unit testing, it's a bit surprising that more university computer science curriculums don't emphasize writing unit tests. Maybe it's because the teaching assistants like keeping their unit testing harnesses a secret...

Thursday, April 17, 2008

Summer '08

Wow! Lots of good stuff coming in the next release - Your Ideas in Summer '08.

These are the ones that I'm looking forward to the most:

  • Filter on Lookup - This should save a lot of people from having to write custom S-Controls to do the filtering.
  • In-line Editing for Views - This should solve a lot of requests for 'Excel-like' editing functionality. (I wonder if this will allow users to edit Related List values as well.)
  • Cross-Object Formula Fields - It will be great to be able to pull some data down from parent objects. (I wonder if this feature will work with Validation Rules as well.)
  • Many to Many Relationships - Custom Report Types solve this problem (see my post here) but it would be really cool if creating Many to Many relationships became even easier to do.
  • Asynchronous Apex - This should add a lot of flexibility, especially in conjunction with making web service callouts from Apex.

Some other solid new features:

Wednesday, April 16, 2008

Update Collision Detection

Have you ever wondered what happens when two people try to modify the same record in salesforce.com?

For example, what would happen in this scenario?

1. Sales Rep Bill Smith has a Contact, Jesse Cochran.



2. Sales Rep Bill learns that he needs to update Jesse's last name to Katsopolis.



3. At the same time, another Sales Rep, Roger Jones, learns that he needs to update the company that Jesse works for and that Jesse has a new title.



4. Sales Rep Bill saves his changes.



5. Sales Rep Roger tries to save his changes - and fails.



This is due to a feature called Update Collision Detection that was introduced in the Summer '07 release of salesforce. It's not a super glamorous bit of functionality, but it should let some folks sleep better at night knowing that it's there.

Also, if you're interested in why Jesse changed his last name from Cochran to Katsopolis, you'll want to check out his wikipedia entry: http://en.wikipedia.org/wiki/Jesse_Katsopolis.

Sunday, April 13, 2008

Innovator's Dilemma

I drank the Kool-Aid a long time ago - I'm convinced that Software as a service (SaaS) is the next phase in the computing revolution. A lot of established software vendors aren't so sure:


The future is a combination of local software and Internet services interacting with one another. Software makes services better and services make software better. And by bringing together the best of both worlds, we maximize choice, flexibility and capabilities for our customers. We describe this evolutionary path in our industry as Software + Services.

- http://msdn2.microsoft.com/en-us/architecture/aa699384.aspx



SAP has pioneered the “isolated-tenancy” model that combines the high availability and low risk of a single-tenancy approach with the efficiencies and deployment speed of a multi-tenancy architecture.

- http://www.sap.com/about/press/Press.epx?PressID=5618



Today's CRM deployment options include:
  • On-premises CRM
  • Privately managed on-demand CRM
  • Shared on-demand CRM
  • Hybrid CRM
- http://www.oracle.com/crmondemand/crm/deployment-options.html


These companies are trying to convince potential customers that SaaS is a feature, or an option, instead of the way of life that it clearly is. Microsoft, Oracle and SAP are caught in the classic innovator's dilemma - they can see the future clearly, but they can't invest fully in SaaS because doing so would cannibalize their packaged software revenue streams.

History has not been kind to established industry leaders when a disruptive innovation comes along - just ask Kodak.

Wednesday, April 09, 2008

salesforce.com cron

Time-based workflows in salesforce currently execute relative to a time. For example, you can use them to to schedule a task for the case owner to follow up with the customer two days after a
case is closed.

It's not currently possible to schedule time-based workflows to execute at a particular time every day - like a cron job would. For that, we'd need to add some secret sauce to time-based workflows.

The Apex trigger below will populate a custom DateTime field called Midnight_Local_Time__c with, you guessed it, midnight - local time for the running user. In conjunction with a time-based workflow, this trigger would allow you to do things like lock all 'Closed' Case records at midnight
trigger Case_PopulateMidnightLocalTime on Case (after update)
{
List cases = new List();
for(Case c : [SELECT CreatedDate FROM Case WHERE Id IN :Trigger.new AND IsClosed = true AND Midnight_Local_Time__c = null])
{
CaseTriggerHelper.SetMidnightTime(c, c.CreatedDate);

cases.add(c);
}

update cases;
}

public static void SetMidnightTime(Case c, DateTime dt)
{
// SFDC defaults 'Midnight' to the 'Time' for this call to newInstance();
DateTime midnightLocalTime = DateTime.newInstance(dt.year(), dt.month(), dt.day());
midnightLocalTime = midnightLocalTime.addDays(1).addMinutes(-1);
c.Midnight_Local_Time__c = midnightLocalTime;
}
If you use this, you'll want to keep in mind that there are limitations around time-based workflows and triggers though:
  • Time-based workflows aren't guaranteed to execute exactly on time, there could be a significant delay in their execution.

  • Unlimited Edition is limited to 20,000 time triggers per org

  • Enterprise Edition is limited to 10,000 time triggers per org
Linvio's CronKit appears to be a useful solution to this problem as well.

Wednesday, April 02, 2008

"No" - In So Many Words

Update January 26, 2014: Jared Spool conveys my thoughts much more clearly in his Beans and Noses post.

Update April 24, 2008: I've been revising this post regularly over the past month. I think that it expresses how I feel about saying "No" to a client, but I reserve the right to modify this post, and my opinion, in the future. Also, I do think that it can be appropriate to tell our clients "No" on occasion, but those scenarios are a topic for another day.

As an IT software engineer, and even as a newbie technology consultant, I didn't realize that my relationships with my clients required a relatively high degree of finesse. I had become accustomed to having very candid conversations with other technical people about what was technologically feasible for a given project. We regularly used the word "No" in these conversations. And we regularly used the word "No" when talking with the business about their requests. Looking back though leads me to believe that telling the business "No" probably hurt my teams' reputation - saying "No" to each other was probably counter-productive in some cases as well.

I've worked with clients whose project goals were to improve customer satisfaction, or to reduce operating expenses, or even to introduce new product lines. At the core, all of these project goals boil down to a desire to improve the business. Our job as technology experts is to provide the business with the tools that they need to accomplish their goals. And just in the way that a carpenter wouldn't like using a hammer that refused to pound nails, our business clients don't like technology experts that refuse to help improve the business by saying "No".

I have learned that it can be much more effective to be indirect and to guide the client to the conclusion that they don't really want to implement their request. Some of my favorite ways of doing this are:
  • "How important is this request compared to the others that we've identified?"
  • "Can you tell me more about why you want to do X?"
  • "That's a great idea, we can do that - have you considered how it will impact Y?"
  • "We can do that, but it will probably increase our timeline/cost." (optional: "Are you willing to accept that?")
  • "That makes a lot of sense, we can definitely do that, but we will probably have to cut out another feature." (optional: Which feature can we remove?")
Customers can request crazy, even impossible, things sometimes, but I've found that my relationships are much more productive if I can think of creative ways to get the customer to consider their request in a different light. The customer may not always be right, but that doesn't mean that we have to tell them that they're wrong.

Thursday, March 06, 2008

Speaking of Platforms...

My last post made me realize that I haven't already pointed out Marc Andreessen's excellent essay: The three kinds of platforms you meet on the internet.

And if the essay itself wasn't reward enough, check this out:

Get Your salesforce.com Org Under Version Control

Jeff Atwood, a software engineering hero to many, recently wrote about version control for databases.

His post spurred me to use the Force.com IDE to put my latest salesforce.com project under version control. It's dead simple to utilize a version control system for your entire salesforce application now: S-Controls, Apex code and salesforce schema included. (Here are the instructions for Subversion: Force.com Code Share)

If being able to define a database, build complex logic and create a sophisticated user interface wasn't enough to convince everyone that salesforce.com is a true development platform, the Force.com development environment just made it a little bit harder to deny.

And the whole platform is delivered as a service...

Saturday, February 23, 2008

V-shaped (Junction Object) Reports

Custom Report Types are incredibly powerful, but one feature that you might not know about, is the ability to "go back up" the object hierarchy.

Let's imagine that your business has a call center and that every once in a while one of your products breaks. When this happens, the affected customer will call your 1-800 number and ask for a replacement product. As a company, you're happy to oblige, but you want to run a report on Cases, Replacement Orders and Products to try and detect breakage patterns. With traditional salesforce reports, you'd be stuck, because the object relationship is V-shaped:



Using standard salesforce reports, you could easily run a report on Cases and Replacement Orders, but you wouldn't be able to "go back up" to get any Product fields beyond the name of the Product being replaced.

Allow me to introduce you to the little-known hero of our story, the "Add fields related via lookup" hyperlink for Custom Reports:




The "Add fields related via lookup" hyperlink will allow you to add fields from the Product table to your report on Cases and Replacement Orders.

And now you'll be able to save the company untold millions by detecting product breakage patterns - all thanks to one little hyperlink.

If you want to build a similar report in your salesforce org, you'll need to define a custom report type with one or more related objects:

Once you've defined your custom report, the next two steps are just a matter of clicking on the "Edit Layout" button and the "Add fields related via lookup" link. Happy Reporting!

Saturday, February 09, 2008

Favorite HTML/JavaScript Resources

Microsoft's HTML and DHTML Reference. It's saved me hundreds of times - and it's a lot more up to date than my 1998 version of HTML: The Definitive Guide.

DevGuru: JavaScript. Simple and straightforward JavaScript reference.

W3Schools JavaScript Tutorial. Easy to understand examples - that you can experiment with!