Thursday, June 28, 2012

Chatr.cc and the start of new experiments in higher ed

Today I close out a chapter of my life at Northeastern University.  Tomorrow I start a new chapter (and a new blog) at Granite State College.  The unifying factor?  Driving continuous improvement through the thoughtful application of technology.  And higher education.  And Salesforce CRM.

Speaking of Salesforce...  I hope that as companies begin adopting tools such as Chatter (and accessories like Chatr.cc), internal transparency translates into more engaged employees, customers and the public at large.  I'm thankful for all that I've learned at NU, professionally and academically, and I believe in the power of a social enterprise in both the Salesforce and the charitable senses of the term.

Thursday, May 3, 2012

FileMaker Pro Equivalent to SQL Query or View

Have you ever wondered how to create queries or views in FileMaker Pro on Mac?  I have, and it's one of those odd learning curves that come with being used to straight-forward but fairly technical SQL statements that are customary in Oracle, SQL Server, MySQL and even Access.  Searching for the word "join" returns no relevant results in the FileMaker Pro 9 Help files.

Well, for other SQL developers out there, I hope this tutorial will shed some light on how to join two tables and then create a query or a view: FileMaker Pro: Creating a "Query" or "View"

In summary, here are the key takeaways from the tutorial:
  • A SQL join is analogous to a layout in FileMaker Pro with relationships between tables.
  • A SQL query or view is analogous to using Find Mode in FileMaker Pro with a layout.
  • Simple filters can be applied in Find Mode using Symbols and the Omit checkbox.

Let me know what you think of the tutorial!  Personally, I was super excited to figure out how to import two lists from two different databases into FileMaker Pro in order to identify discrepancies between the two lists, like I would've done using Excel or Access.  Why would I use FileMaker Pro instead of Excel on Mac to do this?  Because Excel is unfortunately case-insensitive.

Thursday, April 26, 2012

Auto-filling City and State with Postcode Anywhere and Marketo

First, the "product": an HTML script block that can be added to Marketo as a snippet for looking up the City and State/Province based on a given Country and Zip/Postal Code! All one has to do to use it should be to edit and change the Postcode Anywhere license key.

The background for this is that our Marketing department went live with Marketo last week, and that was an awesome accomplishment which involved replacing all of our previous Web-to-Lead forms with Marketo landing pages. With that done, we set our eyes on a next step: making our forms more approachable by automatically filling in a lead's city and state/province if they give us the country and zip/postal code.

For the lookup service, we chose Postcode Anywhere originally because they were listed on the Salesforce AppExchange. But then we realized that the app was for internal use after a lead already went into Salesforce, and what we actually want is for the info to be filled in before a form is even submitted. Plus, we want our leads to go into Marketo first, not Salesforce.

Knowing that our marketers should not have to know JavaScript to use this functionality, it was obvious that any real solution would have to be able to be dragged and dropped on to a Marketo landing page with minimal configuration, if any at all.

Thankfully, it appears that there are standard address fields in Marketo with standard and consistent name and id attributes. Once I discovered this common characteristic across all forms that we had created, it was simple to customize the JavaScript code template that Postcode Anywhere publishes to work with Marketo.

This is a great example of two companies, Marketo and Postcode Anywhere, making user-friendly integration a viable and attractive option.

Monday, April 2, 2012

SObject Utility Class Template

Have you ever had to get the ID of a record type for a specific object? Or have you needed to hard-code a particular picklist value into a Visualforce controller/extension or other Apex class? I've had to do both on a fairly regular basis, and it soon became apparent that stress-related health problems may arise if I ever have to refactor my code, or if a user requests a change in picklist values.

To address this issue, it seems that setting up a global constant accessible to all Apex classes would be hugely valuable in making sure that picklist values and record types (and other items) are consistently referenced in Apex.

For example, if I'm trying to set the Status of a Contract to "Activated", I could write the code as follows:
myContract.Status = 'Activated';

This is great if it's the only place I ever deal with the Contract Status field. But what're the chances of that? Instead, how about writing the code as follows?
myContract.Status = ContractUtil.ACTIVATED_STATUS;

Now I don't need to worry about all the myriad places where I've hardcoded the status value. If I ever need to change the status, I can update the constant in ContractUtil or look for all references to ContractUtil.ACTIVATED_STATUS.

Here's the sample code for a generic SObject utility class:
/**
 * Utility class with supporting methods for
 * a Salesforce SObject.
 *
 * Examples of supporting methods include getting
 * a Record Type ID, getting an expected picklist
 * value for a particular field, and conversion
 * to/from other objects.
 */
public class GenericSObjectUtil {

    /**
     * The String value that
     * represents an activated status, which goes
     * into the Status field.
     */
    public static final String ACTIVATED_STATUS =
            'Activated';

    /**
     * The expected default Record Type Name
     * for all users.
     */
    public static final String DEFAULT_RECORD_TYPE_NAME =
            'This SObject';

    /**
     * The String value that
     * represents a draft status, which goes
     * into the Status field.
     */
    public static final String DRAFT_STATUS =
            'Draft';

    /**
     * The map of RecordTypeInfo
     * objects retrieved by describing the
     * SObject, keyed by the Record Type Name.
     * 
     * This is stored to make
     * getRecordTypeId method calls
     * more efficient.
     */
    private static final Map recordTypeInfosByName =
            Schema.SObjectType.Contract.getRecordTypeInfosByName();

    /**
     * Retrieve the Record Type ID based on a
     * given Record Type Name.  If no match is
     * found, then return null.
     *
     * @param  name The name of the Record Type
     * @return      The ID of the Record Type,
     *              if found; null otherwise.
     */
    public static Id getRecordTypeId(String name) {
        return recordTypeInfosByName.get(name).getRecordTypeId();
    }   // public static Id getRecordTypeId(String)
}   // public class GenericSObjectUtil

Note: I know the above code may be cut off a bit due to width limits in Blogger, but you should be able to copy and paste the code into a text editor to see the full structure if necessary.

What do you think? Feedback on this implementation or other solutions will be appreciated!

Wednesday, March 21, 2012

Installing PostgreSQL 9.1.3 on Mac OS X Lion

Unsatisfied and undaunted by the foreboding discussion on installation troubles ("PostgreSQL 9.1 Installer Fails on OS X Lion"), I decided to follow the official PostgreSQL instructions to install the software from source. All so that I could build Ruby on Rails apps to be deployed to Heroku.

Note: PostgreSQL 9.0.5 appeared to have been bundled with my Lion installation, as seen with pg_config before installing 9.1.3. But I wasn't sure how well it worked since Apple provides zero documentation on this bundled installation, and initdb was not located in a known path.

So, in short, here are the steps I followed to install PostgreSQL 9.1.3 on Mac OS X Lion 10.7.3 from the source code.

# Make sure you have the latest version of
# GNU Make for Mac OS X. This can be downloaded
# through Xcode 4.3 by installing the Command
# Line Tools.

# Download the source code from the PostgreSQL
# website, and start this procedure in the
# expanded directory containing the source files.

./configure
make
sudo make install

# At this point, assuming installation was
# successful, create a new user to serve as the
# unprivileged user that will own the server
# process.

# Open System Preferences to create a new user.
# New Account:  Standard
# Full Name:    PostgreSQL Agent
# Account name: postgres

cd /usr/local/pgsql/
sudo mkdir data
sudo chown postgres data
sudo mkdir log
sudo chown postgres log

# At this point, we're done with configuration
# and ready to start the server process.

sudo su - postgres

# The following commands will be run as the
# PostgreSQL Agent user.

cd /usr/local/pgsql/
bin/initdb -D data/
bin/postgres -D data/ >log/logfile 2>&1 &

# To verify that the server is working properly,
# let's create a test database and see whether
# we can connect using the interactive terminal.

bin/createdb test
bin/psql test

If all went well, you should see something like the screenshot below.


Finally, we can move on to the fun stuff!

AppleScript to Copy Message to Clipboard in Outlook 2011

I've created an AppleScript for Outlook 2011 that will copy some key information as plain text and throw it on the clipboard! I expect this to save me a good deal of time in the months to come.

Now that we're using ServiceNow to record our interactions, I'm finding myself having to copy and paste lots of info from emails into plain text fields on an incident or task in ServiceNow.

Specifically, for diligent tracking of communications, I've been recording the following info:
  • Subject
  • From
  • Sent
  • To
  • Cc
  • Body

The problem is that copying and pasting all that information into a template that I have to retype every time are all very time-consuming and mundane operations. This script allows me to get a well-formatted snip of the key information with a few simple clicks. Whew!

EDIT: March 22, 2012

Okay, I've discovered a simpler alternative: Reply to the email you want to copy and then copy what you want. The automatically composed reply will contain the same header information that this script copies.

Oh, well, I guess I'll just take this as a fun exercise in learning AppleScript.

Tuesday, March 20, 2012

Test Class Template for Apex Triggers

Having written a lot of test methods to validate trigger functionality, I've developed a general template for writing trigger-related test methods that hopefully encompasses all of the steps needed. I believe that there must be a generic template that can be applied to 99% of the trigger test cases out there, and I hope this is a good start in that direction.

@isTest
private class GenericTriggerTest {

    /**
     * Plain English description of what is being
     * tested and why.
     */
    public static testMethod insertSObjects() {

        // Stage the test data.

        // Set parameters and expectations.
        // Which records am I using?
        // What do I expect to change or see
        // at the end of the test?

        // Validate pre-conditions.
        // Impersonate another user
        // if appropriate.

        //System.runAs(null);
        System.assert(false, 'TODO');

        // Start the test.

        Test.startTest();

        // Execute test operations.

        // Stop the test.

        Test.stopTest();

        // Validate the results.

        System.assert(false, 'TODO');
    }   // static insertSObjects()

    /**
     * Plain English description of what is being
     * tested and why.
     */
    public static testMethod updateSObjects() {
        System.assert(false, 'TODO');
    }   // static updateSObjects()

    /**
     * Plain English description of what is being
     * tested and why.
     */
    public static testMethod deleteSObjects() {
        System.assert(false, 'TODO');
    }   // static deleteSObjects()
}   // private class GenericTriggerTest

Feedback on the template will be much appreciated.

Friday, March 2, 2012

Installing Ruby 1.9.2 on Mac OS X Lion 10.7.3

A few simple steps to get Ruby 1.9.2 up and running on Mac OS X Lion 10.7.3:
  1. Download Xcode from the App Store.
  2. Run Xcode and open the app's Preferences.
  3. Open the Downloads tab, then download and install Command Line Tools for Xcode.
  4. Download and expand Ruby 1.9.2 (stable) source from the official Ruby website.
  5. Launch the Terminal app.
  6. Change to the directory containing the expanded Ruby source code.
  7. $ ./configure
  8. $ make
  9. $ sudo make install

Then, to use the newly installed version of Ruby (instead of the pre-installed version that came with Lion):
$ export PATH=/usr/local/bin:$PATH

To summarize the results... Before installing Ruby 1.9.2:
$ irb -v
irb 0.9.5(05/04/13)
$ ruby --version
ruby 1.8.7 (2010-01-10 patchlevel 249) [universal-darwin11.0]

After installing Ruby 1.9.2:
$ ruby --version
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-darwin11.3.0]
$ irb -v
irb 0.9.6(09/06/30)

Thank you, Mike Clark, for pointing out that with Lion I now have to download Command Line Tools for Xcode in order to compile stuff.



Thank you, Ubuntu community, for giving instructions on how to compile programs from source code.

... And finally, with no further ado, I present: the rant behind this post!

Programming an application is supposed to be difficult and require significant thinking. Installing the compiler or interpreter or whatever package is necessary to run the code should be easy.

Maybe it's just me... but why in the world did it take me 2 hours and so much frustration to get Ruby setup on my Mac? Ruby's website says, "Compiling from Source is the standard way that software has been delivered for many, many years. This will be most familiar to the largest number of software developers." Thanks. For assuming incorrectly that I know how to "compile from source" and providing zero instructions for how to do that on my OS.

Monday, February 27, 2012

Select All Visible or Read-Only Checkboxes in Field-Level Security

It looks like I'm not the only one who has historically wanted a way to mark all Visible or Read-Only checkboxes on the Field-Level Security page in Salesforce.

Fortunately, while Salesforce (hopefully) works to make this a standard feature, administrators can use the following bookmarklets on this Salesforce Hacks page:
  • Mark all fields as visible
  • Mark all fields as read-only

Try it out with a profile in your org!

Friday, February 24, 2012

What (Infomation) Technology Really Does

In an explanation to a colleague today about what I do at work, I caught myself saying, "I'm here to make life easier for other departments." While I'm just as much a sucker for warm-and-fuzzy as the next guy, I realized I was telling a white lie that only sounds uplifting from the outside. It's not that I have no intention of helping my colleagues and teammates at the office; it's just that the nature of my job, of information technology really has nothing to do with "making life easier".

If you're thinking that I'm crazy and confused, let me ask you: Does having computers, email, word processing and spreadsheet software or any other piece of technology really make your life easier? The answer for me is simply "no". None of it makes my life easier; all of the above simply raise expectations for my output at the office. If I had to crunch numbers by hand, maybe 20 calculations a day would be considered amazing. But if I'm crunching numbers with Microsoft Excel, 200 calculations a day could get me fired.

So, this was a little depressing to me... Until I thought about the bigger picture. Increasing productivity is the only way for us to raise the standard of living and the quality of life for you, me and everyone else. But I won't bore you by waxing poetic about world peace, food for all, etc.

All I wanted to say are really two things.
  1. Information technology is here to increase productivity, not to make work cushier.
  2. My work as an IT professional is to improve my organization, my country, and... you get the idea.

Wednesday, January 25, 2012

Simple Method to Identify Blank Fields in Visualforce

I've often wondered why there is no ISBLANK() equivalent in Apex for developers to use when validating a Visualforce page. Maybe Salesforce always intended for developers to use the required attribute for the standard Visualforce components.

The problem with relying on field settings, Visualforce required attributes or object validation rules is that there is no consistent presentation of the error messages. For different sites, especially public ones, sometimes the validation errors need to be tailored specifically for the site.

To help this process along, I modularized the concept of ISBLANK() in the simple instance method below.
/**
 * Determine whether a given object is blank
 * or not, in the same manner as the ISBLANK()
 * Visualforce function.
 *
 * @param  o The object to examine
 * @return   Whether the object is blank
 */
public Boolean isBlank(Object o) {
    return o == null;
}   // public Boolean isBlank(Object o)

With this simple method (or variations thereof), developers can iterate through a List<Schema.SObjectField> of required fields and use controller.isBlank(Object) to validate the fields.
for (Schema.SObjectField field : requiredFields) {

    if (isBlank(application.get(field))) {
        addRequiredFieldError(field);
        isValid = false;
    }   // if (isBlank(application.get(field)))
    
}   // for each Schema.SObjectField in requiredFields

Monday, January 16, 2012

What is an enrollment product in higher education?

When it comes to enrollment management, I hypothesize that institutions in the education industry share many common administrative concerns as companies in other industries.
  1. What's our forecast for the next quarter or year?
  2. How much are we allocating to Marketing?
  3. What's our historical ROI on past campaigns? And what are we expecting for new Marketing campaigns this year?

But one big difference I see between education institutions and other companies is how the above questions are answered. While other companies usually answer Questions 1 and 3 above with dollar amounts, education institutions (from the enrollment perspective) answer with student headcount or with class enrollments.

This may seem like a trivial distinction, but how useful would it be for Apple to announce their forecasts using the numbers of iPhones, iPads and MacBooks it plans to sell in the next year? Or worse yet, what if Apple simply said it would sell 1,000,000 products this year? And how would Apple's Marketing department calculate ROI for its myriad campaigns if this was the case?

Back in the world of education, I think there is a mental roadblock which prevents us from recognizing what our products truly are. Culturally, we, the administrators, think highly of education (which we should). But perhaps we've become ignorant of the underlying business model for education, which in the simplest sense revolves around the sale of products to customers. Put another way, the business model revolves around the enrollment of students in classes.

Let's explore the potential similarities and see whether they are legitimate.
  • Student vs. Customer
  • Enrollment vs. Sale
  • Course vs. Product
  • Class vs. Lot
  • Seat in a class vs. Asset

We have recruiters, enrollment coaches and advisers who work with students to identify which courses to take to best meet their career aspirations and personal goals. Once the courses are identified, our staff help students to register for classes, thereby reserving their seats in the upcoming term. Once the add/drop period ends for a term, the enrollments are "closed" and invoices are sent to the students.

Other companies have salespeople working with customers to pick the most suitable products for each customer. Once customers decide to buy, they put in orders that are fulfilled in lots, resulting in assets (and associated invoices) delivered to each individual customer.

So, how different is an education institution from other companies? And if it's not that different, could adoption (or at least reconciliation) of real sales terminology be the way for an education institution to start answering the tough questions directly with real dollar amounts?

Note: I speak largely from my own experiences, and I recognize that there are other institutions which are already far along on the path of leveraging the concept of products in their CRM operations.

Friday, January 13, 2012

What is a program in higher education?

As system maintenance becomes more difficult, and as user dissatisfaction with reporting grows, I've been thinking a lot about one of the most controversial 4-word questions in higher education: "What is a program?"

I still remember some of the answers from when I first asked the question on Chatter last October.
  • "I would define a program as a sequence of college level courses (credit bearing) that lead a student to a certificate, degree, or diploma."
  • "I think specializations would be subcategories or tags within programs. I don't see Fast-Track degrees as separate programs. To me, that is similar to online vs. on-campus delivery. Same program, different delivery methods."
  • "I think what makes one program different from another is its required content. FT requires a certain and specific content (in a specific order even), so I would categorize it as a different program. However, online v on-ground wouldn't be a different program. Specializations have specific required content, so even though they don't end in different degrees, I would probably classify them as different programs."

Unfortunately, we never reached a conclusive answer. And the systems architect in me wanted a firm definition of a "program" in higher education so that I could help to design a system that best fit our business processes. Argh! "Frustrated" only begins to describe how I felt at the time.

But now, I have a different take on the question, with much less frustration.

For starters, let me back up and say something about our industry. I think the notion that higher education is somehow inherently different from all of the other industries out there has made me blind to the broader definition of the word "program". People in higher education can elevate and romanticize the industry to the point where colleagues will frown upon the application of business terminology (like "programs") to our operations. By removing the higher education context from the word, I feel like my grasp of "programs" has improved by leaps and bounds.

Let's jump back start with a program in higher education and see if we can discern any important characteristics.

All programs in higher education seem to have the following:
  • Eligibility criteria: Who is eligible to be considered for entry into the program? For example, to be eligible for a master's degree program, an individual should currently hold a bachelor's degree.
  • Entry procedure: If eligible, how does a person enter the program? Usually, a person enters a program by submitting an application for admission and then being accepted after a formal review of that application.
  • Curriculum: Once in the program, what courses is a student expected to take?
  • Services and perks: While in the program, what services or perks can a student expect to receive or have access to?
  • Maintaining program membership: What does a student have to do to remain in a program? For example, if a student does not complete a program within 7 years then that student is effectively out of the program and must apply again for re-entry.
  • Completion criteria: What does a student have to do to complete the program? Usually this involves passing all of the courses in a prescribed curriculum.
  • Reward for program completion: What does a student get for completing a program and graduating? In higher education, a graduate typically receives a combination of degree, major, minor, concentration and specialization from the institution to attest that the graduate now holds certain level of skill and knowledge within a field of expertise.

What's so special about this notion of a program is that this concept is not rigidly constrained by the generic, systematic definition (to which there are currently many exceptions) at our institution that programs are defined by distinct combinations of degree, major, and concentration.

And the real value of this discussion may be simply acknowledging that creating, changing, splitting, merging and retiring programs are more parts of an art than a science, which is how I imagine programs are treated in other industries like retail and fitness.

To give this concept a test drive: How may the different notions of a "program" play out in the following two scenarios?

Scenario 1: Doctoral program with specializations

Historically, we have had a doctoral program with specializations that was only ever tracked as a single program record in our student information system. However, Marketing would typically promote the handful of specializations as if they were separate programs on our website, because the target audiences were different enough and the rewards were different enough (in the eyes of our students).

In our CRM system (Salesforce), should the program records match 1-for-1 those in our student information system?

Scenario 2: Doctoral program with varying requirements

We also have a doctoral program that has slightly different curricula for students entering with a bachelor's degree compared to students entering with a master's degree. Historically and in the near future, the plan would still be to market this program as a single program on our website. But on the back end, the registrar's office created two separate programs in our student information system in order to better track our applicants and students.

Again, in our CRM system, should the program records match 1-for-1 those in our student information system?

Thursday, January 5, 2012

NO-SOFTWARE Salesforce Tutorial: Internal Web Service Callouts

Another developer recently talked about a situation where an Apex web service needed to be exposed to internal, authenticated users in order to work around a DML limitation.

The concept behind the workaround was very intriguing, and after playing around with some Apex code I came up with a tutorial that I hope others may find useful: NO-SOFTWARE Salesforce Tutorial: Internal Web Service Callouts

The key concepts demonstrated in the tutorial include:
  • Generating a WSDL from a global Apex class
  • Generating Apex from a WSDL created from a global Apex class
  • Using the UserInfo.getSessionId method to make callouts to internal web services as an authenticated user