Monday, October 24, 2011

Project HardBoil: Day 4.5

Succeess! Without registering the app with Google, HardBoil now works with any Google Account using the AuthSub library for Google Data.

Basically, a user can login, pick a spreadsheet and boil the spreadsheet into code right on the spot. With the right amount of documentation and UI cleanup, I think this could be available for beta testing soon...

Sunday, October 23, 2011

Project HardBoil: Day 4

What a milestone! 842 lines of Apex code generated to create test records for 8 different objects that have relationships between each other.

The back-end code definitely should be cleaned up and re-thought a little bit, but the concept is proved and now the only thing I need to make this available to the world for "beta testing" is to setup the Google authentication scheme.

I really wish that Google would simply make Spreadsheets accessible without having to login. Wouldn't that be so much easier?

Project HardBoil: Day 3

I've finally gotten my PHP code to start boiling Apex. Simply enough, the code it generated right now just looks like:

private class TestRecordSet {
    private Map<Id, Compensation_Rate__c> compensationRateMap;
    private Map<Id, Account> accountMap;
    private Map<Id, License_Certification__c> licenseCertificationMap;
    private Map<Id, Term__c> termMap;
    private Map<Id, Part_of_Term__c> partofTermMap;
    private Map<Id, Part_of_Term_Paydate__c> partofTermPaydateMap;
    private Map<Id, Course__c> courseMap;
    private Map<Id, Class__c> classMap;
}   // private class TestRecordSet

Every related SObject class used by HardBoiler will need to have methods that generate the appropriate code for the appropriate location. For example: SObject instances have a boilApexVariableCode method, a boilApexConstructorCode method and a boilApexGetterCode method.

Friday, October 21, 2011

Project HardBoil: Day 2

As I began writing my code today, I realized that there was a problem with the way I designed the related objects.

My improved scheme includes the following:
  • SObject
  • SObjectField
  • SObjectRecord
  • SObjectRecordFieldValue

I also took the easy way out with getting the spreadsheet to be read in the way I expected by duplicating the field name row and adding two more "column header rows" to represent the SOAPType and whether the field is a custom external ID or not.

Project HardBoil: Day 1

To make HardBoil work really, really well, in the ideal world, it would link to the Google spreadsheet for the data and then validate the spreadsheet and its contents against the developer's Salesforce org.

However, in the real world (and in the interest of actually using this code to meet an immediate need for my own, full-time employer), the ideal will take way too long with too much technical expertise that I just don't have at this time. Also, I don't want to waste time just yet with trying to figure out how to create a GUI that allows the user to login to Google and pick out the spreadsheet with the test data.

So, where does that leave me with a day of progress?

I've created code that begins to define the following classes:
  • HardBoiler
  • SObject
  • SObjectField
  • SObjectRecord

Forcing my way into my Google Account and hard-coding the authentication and spreadsheet selection, I was able to setup HardBoiler to be constructed with a parameter for the spreadsheet's Zend_Gdata_Spreadsheets_WorksheetFeed. This in theory allows HardBoiler to initialize with the right Salesforce records by iterating through each row in each worksheet.

Everything looked good until I got down to the field level for a specific record, where Google did something interesting that screwed up my original plans: Google treats my column header as the key in an array that represents a row of cells in the spreadsheet; but the key is the column-header in lower case with non-alphanumeric characters stripped out.

My original plan was to use the column header to hold the fields' API names, but now it looks like my immediate challenge will be to figure out a plan B for enabling the code to match cell values to fields.

Project HardBoil: Kickoff

So, I've decided to start a project called HardBoil, for lack of a wittier name. What's the goal of this project? To produce a web app that generates boilerplate code for Apex test classes. Specifically, it generates boilerplate code for Apex test classes to create test data to be used in individual unit tests.

What might that code look like? Take a look at the inner TestRecordSet class in this example test class. Some basic elements of the boilerplate code include...
  • List of test records.
  • Map of test records by ID.
  • Map of test records by record name.
  • Constructor that creates the test records and populates the maps.
  • Standard getter methods to get test records by index, ID or record name.

Concept

  1. Create a Google spreadsheet containing test records for different objects, with each object on a separate worksheet.
  2. Login to HardBoiled, point to the spreadsheet, and click a button to generate hundreds of reliable lines of code to setup records for staging best-in-class unit tests in Apex.

Why?

Well, after a few scrambles to fix broken Apex code in a production org, I realized that there is a lot of wisdom in the "Testing Best Practices" article in the Force.com Apex Code Developer's Guide, Version 23.0.

The trouble with implementing this wisdom consistently and repeatedly is that when you have to setup test records for a bazillion objects, the exercise becomes extremely tedious and painful... not to mention error-prone.

Imagine writing the same boilerplate code for 5 objects, with 3 records per object, with each record having 10 fields filled in. At a minimum, you're looking at writing 5 x 3 x 10 = 150 assignment statements. And then, what do you do about Lookup and Master-Detail relationships?

And you have to write this code all over again for every single test class you write? And how do users trust that you really understand what you're doing with the data?

Added Benefit

Who wants to create test data? Well, if your users really care about the system, then they would want to create the test data! This is a great collaborative exercise where admins, developers and users can all learn from each other by reconciling how the system was intended to be used and how the system is actually used.

Developers can setup the spreadsheets and then get functional users to fill in the test data! This frees up the developer's time to focus on the important part that only (s)he can do: actually writing the unit test methods.

Thursday, October 13, 2011

JavaScript Hack to Disable Fields for Internal WebCenter Users

In ApplyYourself, it may sometimes be desirable for some application fields to be editable by the applicant and then locked down for internal WebCenter users after the application is submitted. One example may be the term to which the applicant originally applied, before a decision or subsequent deferral occurs.

In order to accomplish this, the following JavaScript hack may be used.

<script type="text/javascript">
function isViewedInWebCenter() {
  return document.domain == "webcenter.applyyourself.com";
} // function isViewedInWebCenter()

if (isViewedInWebCenter()) {
  var inputElement =
      document.getElementById(inputElementId);
  inputElement.disabled = true;
} // if (isViewedInWebCenter())
</script>

Adding this bit of code to the bottom of a section's HTML should do the trick.

Best Practice for Automated Task Creation?

In retrospect, I think a best practice for automating task creation in Salesforce is to use workflow rules instead of Apex triggers. The primary reason is that the tasks are easier to manage and can be avoided during a mass update is the user leaves the "trigger workflow" checkbox unmarked in the import wizard.

Trimming Whitespace in XSLT

After some digging with Google and a hit on the W3C website, it appears that the String.trim() equivalent in XSLT is normalize-space().

"XQuery 1.0 and XPath 2.0 Functions and Operators (Second Edition)." W3C.

Thursday, October 6, 2011

What Programs and Products Mean in Higher Education

The word "program" is very interesting in its application to higher education. If you ask any higher education administrator or staff member whether his or her institution offers programs, 99% (if not 100%) of the time you'll get a quick and confident "yes". But dive a little deeper and start asking how programs fit into the scheme of CRM, especially within the Salesforce framework, and you may run into a lot of unanswered questions (depending on which institution you're at).

At the crux of the confusion: What exactly is a program?

Merriam-Webster provides one definition of the word "program" as "a plan or system under which action may be taken toward a goal"; Merriam-Webster also provides an alternative definition as simply "curriculum". Great, now what?

Translated into higher education lingo, a program may be defined as a curriculum of study under which a student may enroll in classes with the goal of earning a degree or certification. In the world of enrollment, a program boils down to just another tool to entice people to purchase the products sold by a school, college or university.

At this point, another question may arise: Aren't programs the same thing as products in higher education?

The answer is "no", unless someone can give a convincing argument to support a different position. Products in higher education are the courses offered by an institution. Some may argue that students buy degrees, not courses. "A student comes to us saying that he wants a Bachelor of Science degree with a major in Accounting; the student doesn't come to us saying that they just want to take ACCT 101 and ACCT 102." This argument sort of makes sense but misses the mark in describing the true business relationship between institution and student. In reality, students buy courses and get degrees when enough courses are purchased and completed at an established standard of achievement.

So, in short, courses are the products, not programs. Programs exist to get customers to buy more products, which in the case of higher education are courses.

Armed with these two answers to two high-level questions, the conversation can now move on to how to setup this business model in Salesforce for effective CRM.