Nimble AMS, Salesforce and Nimble Life articles by team Nimble!

Lessons Learned

  • Written by Luke Freeland on December 27, 2013

Nimble AMS Implemementation Lessons Learned

As a Software Engineer on the Nimble AMS Product team, I'm constantly working on Nimble AMS features, enhancements, testing documentation, and other product areas. Every now and again, product engineers assist with client implementations. This helps us remain connected with how Nimble AMS is implemented and received by the customer. Earlier this year, I had the great pleasure of implementing Nimble AMS for one of our clients with my fellow Nimblers.

Here are some Lessons Learned and Re-affirmed from that experience.

Easily Customized

Associations have many things in common. They have members, hold conferences at various venues, sell merchandise, and conduct other business too. While many of these activities are similar, each association does them their own way. During implementation, Nimble AMS is customized to fulfill the association's way of doing things, which it does easily through administration and customization.

One common customization is pricing. While Nimble AMS provides many pricing options already without customizing, there are times when other pricing needs to be implemented. Our client required specific membership tiered pricing based on a member's Annual Revenue Level (ARL).

Here's a contrived membership tiered pricing example.

 

Annual Revenue Level (ARL) Member Price ($)
                      1 -   9,999.99  100.00
      10,000.00 - 99,999.99  100.00 + 1% of ARL
   100,000.00 - 999,999.99  100.00 + 2% of ARL
 ... Other Pricing Tiers ...  

 

To implement this, a new "Member Dues Price" formula field was added to the member record that looks at the member's Annual Revenue Level to calculate the member's dues price. Here's what the contrived formula would look like

 

If (Annual_Revenue_Level <       10,000,    100.00,
If (Annual_Revenue_Level <     100,000,    100.00 + (Annual_Revenue_Level * 0.01),
If (Annual_Revenue_Level <  1,000,000,    100.00 + (Annual_Revenue_Level * 0.02), ...

 

Now with this formula created, whenever the member's Annual Revenue Level is entered on the member's record, the membership price will be calculated and instantly shown. Next, the Nimble AMS order processor was augmented to use this "Member Dues Price" field to allow the correct membership price to be calculated when a member joins or renews their membership. In short order, our client's membership tiered pricing was implemented and ready to go.

Now, if the pricing changes, an administrator can simply change the "Member Dues Price" formula field and the changes will be reflected throughout the system without any coding changes and without requiring any engineers. Now that was easy!

Viewing Customers Using Nimble AMS Is Rewarding

During our client's go-live week, I had the great opportunity to be on-site with a few of my fellow Nimblers. While there, I met many great people and was able to observe how they used Nimble AMS. Here are some of my observations:

  • Nimble AMS greatly simplified and eased the amount of work staff had to do. This saved time and enhanced capabilities allows staff to focus more on their members and ultimately to provide even more benefits to them.
  • The staff were very enthusiastic to retire their old system and start using Nimble AMS. They even held a "Memorial" service for the old system and an after party. Don't believe me? Here are some photos. For more photos, check out ASCRS Nimble AMS Launch Photos, MSTA Nimble AMS Launch Photos, and LeadingAge Nimble AMS Launch Photos. 

Test Suite Executing Daily is Priceless

Automatically executing a Test Suite daily is priceless during development / implementation. Daily regression testing during development / implementation helps identify things that broke since yesterday.

For example, if Feature A was working yesterday and isn't today, it's easy to track down what changed and resolve the problem, especially when using Source Control. With the change(s) that caused the issue originating within the last 24 hours, the change(s) are fresh within the developer's mind so time isn't needed to remember or figure out how things work.

This ultimately leads to better quality software developed in less time.

Read More.

Apex WebService Callout Test Mini Framework

  • Written by Luke Freeland on November 27, 2013

Recently, the Nimble AMS feature I was developing in Salesforce required one or more web service callouts. Naturally, this code has to be tested. See the "Original Test Code" at the end if desired.

After building up the test suite, the TestWebServiceMockImpl became rather lengthy with many nested if elses. This is unfortunately necessary because only one mock class can be set per test method and some test methods invoke multiple web service callouts. Reviewing the code made me think… ewwww, this stinks with a nasty code smell…. How can this be improved? Answer: A mini framework.

Apex WebService Callout Test Mini Framework

The solution is to create a single mock class that delegates the mock request to one or more responder classes which create the response object for the given request. Let’s see some code.

We start by creating a Responder interface that is responsible for creating response objects for a given request.

public interface ITestWebServiceResponder {

   object createResponse(

       Object stub,

       Object request,

       String endpoint,

       String soapAction,

       String requestName,

       String responseNS,

       String responseName,

       String responseType);

}

The Executor class is the only class that implements WebServiceMock and is used throughout our test suite. It’s responsible for executing the responders to generate the appropriate response for any given web service callout.

global class TestWebServiceMockExecutor implements WebServiceMock {

   // Use simple lookup table to grab the responder indexed by request name

   Map<String, ITestWebServiceResponder> responders =

     new Map<String, ITestWebServiceResponder>{

           ‘Request_a’, TestWebServiceAResponder,

           ‘Request_b’, TestWebServiceBResponder,

           // other responders here

   };

   global TestWebServiceMockExecutor() { }

   // Use constructor dependency injection to allow callers to add additional

   // responders or replace existing ones.

   global TestWebServiceMockExecutor(

       Map<String, ITestWebServiceResponder> otherResponders){

       responders.putAll(otherResponders);

   }

   global void doInvoke(

       Object stub,

       Object request,

       Map<String, Object> response,

       String endpoint,

       String soapAction,

       String requestName,

       String responseNS,

       String responseName,

       String responseType) {

       // Grab the responder to use by request name.

       ITestWebServiceResponder responder = responders.get(requestName);

 

       // Responder creates the web service response.

       Object response_x = responder.createResponse(

            stub,

            request,

            endpoint,

            soapAction,

            requestName,

            responseNS,

            responseName,

            responseType

       );

 

       // Put the response in the response object

       response.put(‘response_x’, response_x);

}

 

// Responder class can be nested within the test class or be a separate class in the org.

@isTest

public class TestWebServiceAResponder implements ITestWebServiceResponder {

    public object createResponse(

            stub,

            request,

            endpoint,

            soapAction,

            requestName,

            responseNS,

            responseName,

            responseType){

 

         ResponseElement1 re1 = new ResponseElement1();

         re1.property1 = some_value;              

         return re1;

    }

}

 

Now, our test classes simply use the Executor class for the mock class and we’re all done.

@isTest

private class TestWebServiceCallout {

 

  static testmethod void webServiceCallout1Test(){

      Test.setMock(WebServiceMock.class, new TestWebServiceMockExecutor());

      // Test code that invokes webservice callout 1

  }

 

  static testmethod void webServiceCallout2Test(){

      Test.setMock(WebServiceMock.class, new TestWebServiceMockExecutor());

      // Test code that invokes webservice callout 1 and 2.

  }

}

 

Advantages

  • Executor class is easily extensible by creating additional responder classes and either adding them to the responders map or passing them in as needed when creating the Executor.

  • Executor class doesn’t have deep if else spaghetti code.

  • Responder classes developed independently allowing us to follow the Single Responsibility Principle.

 

Disadvantages

Please share if you find some. 

Happy Coding,

Luke

 

Original Test Code (Ewwww)

global class TestWebServiceMockImpl implements WebServiceMock {

   global void doInvoke(

       Object stub,

       Object request,

       Map<String, Object> response,

       String endpoint,

       String soapAction,

       String requestName,

       String responseNS,

       String responseName,

       String responseType) {

 

        if (requestName == ‘request_a’){

              ResponseElement1 re1 = new ResponseElement1();

              re1.property1 = some_value;

              

              response.put(‘response_x’, re1);

        }

        else if (requestName == ‘request_b’){

              ResonseElement2 re2 = new ResponseElement2();

              re2.property1 = some_value;

              re2.property2 = some_other_value;

 

              response.put(‘response_x’, re2);

        }

        // other responses handled.

   }

}

And my test class looked like:

@isTest

private class TestWebServiceCallout {

  static testmethod void webServiceCallout1Test(){

      Test.setMock(WebServiceMock.class, new TestWebServiceMockImpl());

      // Test code that invokes webservice callout 1

  }

  static testmethod void webServiceCallout2Test(){

      Test.setMock(WebServiceMock.class, new TestWebServiceMockImpl());

      // Test code that invokes webservice callout 1 and 2.

  }

}

Read More.

Apex Test Driven Development Bug Fixing

  • Written by Luke Freeland on November 27, 2013

Unfortunately, bugs exist in all software. However, Salesforce’s automated testing capabilities built into the platform allow Software Engineers to very easily reproduce the bug and confirm that it stays fixed.

Whenever a bug is reported, the first action taken is to reproduce the bug. Once the bug is reproduced, simply re-perform the same steps to confirm that a fix has squashed the bug. While troubleshooting the bug, I’d simply follow these reproduction steps manually every time until the bug was fixed.

With Salesforce’s testing capabilities, the bug is reproduced by writing one or more Apex tests. Now, with the click of a button, the tests will run, and if there’s a problem, the tests fail. Since the bug hasn’t been fixed yet, the tests are failing. Eventually, the bug is fixed and when the tests run again, they pass.

The biggest benefit of this approach is regression testing. These tests are run regularly to ensure that any software changes don’t re-introduce the bug. 

Contrived Bug Example

Let’s look at an Account trigger with a known bug in it. Can you spot the bug?

trigger AccountTrigger on Account (Before Update){

   for (Account account : Trigger.New){

          Account updatedAccount =

          [select id, name, Other_Fields_Here

               from Account

             where Id = :account];

          // do something with updated account

   }

}

Now, here’s a test class to ensure our trigger works as expected.

@isTest

private class TestAccountTrigger {

  static testmethod void updateTriggerTest(){

      Account a = DataFactoryAccount.insertAccount();

      a.Field_To_Update = updated_value;

      update a;

      // assert expected changes

  }

  // other test methods here

}

Bug Reported: When many accounts are updated simultaneously, a “Too Many SOQL Statements” error is shown. 

Right off the bat, trying to create a bunch of account records and then updating them manually through point-n-click is going to be impossible. As a result, the TestAccountTrigger is augmented with another test method to reproduce the error. 

    static testmethod void updateTriggerInBulkTest(){

         List<Account> accountsToUpdate = DataFactory.insertAccounts(500);

 

         for (Account accountToUpdate : accountsToUpdate){

              accountToUpdate.Field_To_Update = updated_value;

         }

        // With the current implementation, this is where

        // the Too Many Soql Queries error is thrown.

         update accountsToUpdate;

 

         // assert expected changes

    }

 

After a little troubleshooting, it becomes apparent that the issue is caused by each account being queried individually in the Account Trigger. Since Salesforce currently only allows 100 SOQL queries in a given Execution Context, updating more than 100 accounts causes the “Too Many Soql Queries” error to be thrown.

Luckily, the bug fix is straight-forward. The trigger becomes

trigger AccountTrigger on Account (Before Update){

  List<Account> updatedAccounts =

         [select id, name, Other_Fields_Here

               from Account

             where Id in :Trigger.New];

   for (Account updatedAccount : updatedAccounts){

          // do something with updated account

   }

}

 

Now the TestAccountTrigger test class is ran again and all the tests pass. The bug has been fixed and going forward the tests will automatically detect if there’s a problem.

Happy Coding & Testing,

Luke

Read More.

Apex Data Factory Design Pattern

  • Written by Luke Freeland on November 27, 2013

As the Salesforce ISV that develops Nimble AMS, we write many Apex tests to ensure Nimble AMS works as expected under a variety of conditions. As a Salesforce Testing best practice, these tests create all the data they require. Doing so allows the tests to run in any Salesforce org without having data created in the org.

This best practice led us to another best practice: The Apex Data Factory Design Pattern. 

Data Factories 

Data Factories are apex classes that are responsible for generating data. They primarily generate Salesforce records in various ways. By far, test classes use Data Factories the most to generate their data. However, they can be used in other contexts also. For example, they can be used to generate data within a Salesforce org. Another example is if you’re a Salesforce ISV  developing a product, your product could have these Data Factories that can then be used within any custom test classes to generate data without replicating the data creation logic.

Alright, enough theory. Let’s see a Data Factory that creates Accounts.

 

/*

  DataFactory used to generate Accounts. It’s global so that it can be used outside your managed package. The naming convention is “DataFactory{Object_Name}” so that the classes are grouped together allowing one to easily see what Data Factories there are in an org or within the Force.com IDE.

 */

global class DataFactoryAccount {

    // define default constants that can be accessible to assert against.

    global static final String DEFAULT_NAME = ‘ACME Inc.’;

 

    /* The “create” methods are used to instantiate the sobjects without inserting them. This is tremendously helpful when you need to create a particular record and then tweak it before it’s inserted from the calling code. */

    global static Account createAccount(){

          return createAccount(DEFAULT_NAME);

    }

 

    /* The create methods are commonly overloaded to allow different properties to be set. */

    global static Account createAccount(String name){

           return new Account(

               Name = name

           );

    }

 

    /* The “Insert” methods are used to create the sobjects and then insert them. They delegate       the creation to the create methods and then insert the records. Like the create methods, the insert methods are overloaded to allow different properties to be set as necessary. Another best practice is to bulk insert or bulk create data, but to keep the sample short, that’s omitted. */

    global static Account insertAccount(){

          Account accountToInsert = createAccount();

 

          insert accountToInsert;

          return accountToInsert;

    }

}

 

Now, let’s see how the DataFactoryAccount can be used.

 

@isTest

private class TestAccount {

 

     static testmethod void insertAccountTest(){

         Account company = DataFactoryAccount.insertAccount();

 

         Account anotherCompany  = DataFactoryAccount.insertAccount(‘Another Company’);

 

         // Test and assert with Accounts here.

     }

 

     static testmethod void veryBasicInsertAccountsLoadTest(){

         Integer numberToInsert = 5000;

 

         /* Useful to flush out poorly written triggers. For example, a trigger thatdoes SOQL or DML within loops.*/

         List<Account> manyAccounts = DataFactoryAccount.insertAccounts(numberToInsert);

     }

}

 

Benefits

  • Data creation is factored out of the test classes and contained within their own classes. This allows the logic to be used in a variety of ways.

  • Allows dependent data to be created more easily without necessarily caring about parent records. For example, if an opportunity record needs to be inserted, DataFactoryOpportunity.insertOpportunity can be called and it will automatically insert any other required records and then return the Opportunity record.

  • Reusability. Eliminates the need to copy paste data creation code across the test suite.

  • Reusable in client orgs. With global Data Factories in a managed package, any custom test classes needed for customizations can use them to generate their data without re-creating the same data creation logic.

If you have other uses cases, other ways to implement this, questions or other comments, please leave them below. We’d love to hear from you.

 

Happy Coding,

Luke

Read More.

It’s 9am - How Many Members Does Your Association Have? Geckoboard to the rescue.

  • Written by Sig VanDamme on November 22, 2013

How In Tune Are You To information On Your Association?  

Geckoboard For Associations

  • Do you know how many members you have?

  • How about the number of registrations for your next conference?

  • Do you know how many transactions your organization is processing every week?

  • How many unique visitors did you have to your website yesterday?

  • What are people searching for to arrive at your site?

  • Who on your staff has an upcoming birthday?

  • What is the uptime of your association's website?

If you have a good association management system and Google Analytics you could likely easily dive in and find this information.  But do you do that every day?  Does everybody (or anybody) else in your organization?

 

What if there was a large board in the breakroom  
that was constantly updated with key performance
indicators and timely
 information?

Meet Geckoboard Geckoboard Logo

Geckoboard is a great solution for this.   Geckoboard monitors your associations vital signs and presents them on a dashboard as it happens. It allows your team to focus on what’s important and react faster.

A Geckoboard status board is made up of widgets (and there are a boatload included). You can select and configure widgets to connect to 3rd party services and retrieve the data you want to display.   Get a nice web enabled TV and point it at a loop of dashboards and your staff will be in the know!

Real-time data from Nimble AMS served up fresh!

Geckoboard and Nimble AMS

NimbleUser has developed a number of widgets to enable associations to display information directly from Nimble AMS and Salesforce on a Geckoboard.  

Included in this initial set of widgets are:

  • Member Count Widget - quick and real-time display of how many members your association has.
    Geckoboard Association Member Count

  • Most Orders by Staff / Most Account Updates by Staff - shows which staff are the most active in Nimble AMS

    Geckoboard Updates By Association Staff

  • This week's revenue and transaction count - real-time display of revenue and transactions count.

    Geckoboard Association Revenue And Transaction Counts
  • Monthly Revenue - month by month graph showing revenue.

    Geckoboard Association Monthly Revenue

  • Member Composition Pie Chart - shows member type breakdown for you association.

    Geckoboard Membership Composition By Member Type

  • Staff Birthday Widget.  This widget reads the birthdays out of the user object and displays the next three staff birthdays. Salesforce stores the user's birthday on the user object.  This widget uses the Salesforce API to query an ordered list of birthdays and send the three upcoming birthdays to the Geckoboard to be displayed.


  • Chatter widget for staff kudos.  Use the hashtag #kudos in a post and it will be placed on the Geckoboard kudos widget.  This is a great way to enable recognition for a job well done.  This widget cycles through the last three #Kudos posts in your association's Chatter stream.



Easy Steps to Get Started Today

  1. Get a display that you can place in an area (break room, etc) to render the Geckoboard.  You will need either a smart TV with a built in web browser or connect a simple computer with a browser connected to the monitor.  At NimbleUser we opted for two Samsung  32" LED 5300 Series smart TV and they work really well.

  2. Obtain a Geckboard account at http://www.geckoboard.com/

  3. Configure and install the Nimble AMS components.  Email or call our customer success manager Julie Tracz at 585.454.8706 and we will give you the installation details or create a task order and implement for you.

Geckoboard Association Full Screen Reports And Anylitics

 

Read More.