# Friday, 03 October 2014
Started a new blog at www.dataminingcrm.com. Check it out!
Friday, 03 October 2014 12:03:52 (Pacific Daylight Time, UTC-07:00)
# Monday, 18 November 2013

Logalytics: Intelligent Audit Log (www.logalytics.io)
Our Dreamforce Mobile Hackathon entry is an intelligent activity stream of Salesforce events. Built on Salesforce1, Logalytics provides a unified interface giving people in Salesforce Operations roles the ability to monitor and manage many end-to-end workflows within a mobile user experience.

Why Logalytics?
Leading up to Facebook's IPO, a set of operational tools and processes were developed for SOX compliance and monitoring, and subsequently presented at Dreamforce 11. In the weeks and months prior to the Facebook IPO, our Salesforce environment and processes underwent several audits and reviews.

The Auditors questions around compliance in the cloud were confidently addressed, but there were still blind spots. There were incidents and human errors that should have gone detected much sooner. If we couldn't prevent every possible incident, surely we could monitor, alert, and respond much faster.

Trusting The Cloud
Logalytics is the mobile app plus service I wish we'd had at Facebook. Trusting the cloud requires keeping a close eye on changes, identity management, and access policies 24/7. While Salesforce provides a SOX "ready" environment, it is ultimately the responsibility of operations teams to maintain "compliance".

SOX, HIPAA, COBIT, PCI, Basel II, 8th Company Law Directive... some are more prescriptive than others, but fundamentally all these compliance frameworks share the same core set of IT governance principles that are applicable to either cloud or on-premise services.

Security
The Logalytics service continuously analyzes every Salesforce LoginHistory record and delivers suspect events directly into a Salesforce1 Visualforce activity feed:

  • Concurrent Logins: Logging in from 2 separate locations within a short time period.
  • Open Proxy Logins: Commonly referred to as "zombie" computers, these computers often have key logger and other viruses installed.
  • Repeated Failed Login Attempts.

Actionable Intelligence
Using the latest features in the Winter '14 Salesforce API (v29), Admins can instantly freeze any user flagged with suspicious login activity. Tasks and Cases can be created with one click for either personal follow-up or team remediation.

Change Management

The "View All" and "Modify All" profile permissions, while necessary for Admins, are generally disabled for all other users. These permissions are actively monitored with corresponding alerts raised when metadata changes.

Metadata changes on all standard and custom objects are also monitored and reported in the feed.

Notifications:

Salesforce1 supports both in-app and native push notifications. The push notifications only occur when a user is mentioned, so to ensure Admins received timely alerts, we used the Salesforce Chatter API to cc: mention all System Administrators when a red alert occurs.

Remediation
Once an alert is raised, the Salesforce Administrator or Developer is able to take action and resolve the issue. With Salesforce1, Tasks and Cases are only a swipe action away from the Logalytics feed. Some workflows can be managed end-to-end entirely from a phone.

Insights
For all the occasional incidents that may crop up, Salesforce Operations can be an extremely rewarding responsibility. Gaining deeper insights into how often users login, from where, with what apps, using which platform... these insights can now be gleaned with a quick glance at the Logalytics feed during the 150+ micro-moments per day we check our phones.

Salesforce Platform
Heroku is the glue that holds the Logalytics solution together. A REST API uses web dynos to publish the activity feed and serve event details. Background workers analyze production Salesforce environments.

The analysis workers use pretty much every Salesforce API: SOAP, Metadata, Apex, and Chatter.

The user interface is written entirely in HTML5 and hosted in Salesforce1 as a Visualforce mobile web tab. JQuery Mobile was initially used early in the hackathon, but we switched to Zepto for performance reasons.

Database.com is used for subscription and mobile user management. Logalytics provides an in-memory NoSQL datastore for capturing time-series analysis and trend data.


Monday, 18 November 2013 07:16:37 (Pacific Standard Time, UTC-08:00)
# Monday, 14 October 2013

Notes from presentation at the Silicon Valley Developer Users Group on Oct 15th, 2013

Monday, 14 October 2013 14:32:08 (Pacific Daylight Time, UTC-07:00)
# Friday, 06 September 2013

Not to be confused with "rapper" class.

The concept of a "wrapper class" occurs frequently in Force.com development. Object oriented design encourages the use of classes to encapsulate data and behaviors that may mutate the data, or interact with other classes.

The goals of an Apex wrapper class are:

  • Decouple data (records) from behaviors (methods)
  • Validate inputs
  • Minimize side effects
  • Enable unit testing
  • Handle exceptions

This article provides an example wrapper class template to address these goals and explores each aspect of the wrapper class individually.

Register for Dreamforce 13 and attend my session on "Leap: An Apex Development Framework" for training on how to use the Leap framework to generate wrapper classes, triggers, and more. Follow @codewithleap on Twitter for updates on Apex design patterns.

All Apex wrapper classes share a few common properties and methods. To avoid repeatedly cut-n-pasting the same common code into each wrapper class, a base class is created for all wrapper classes to inherit through the "extends" keyword.

public abstract class WrapperClassBase {
     public Id id;  
     public boolean success = true;
     public List<String> errors = new List<String>();
     public boolean hasErrors(){ return errors.size() > 0;}
     public void clearErrors() { success = true; errors.clear();}
}

Now, with a base class available, the simple wrapper class looks like the following:

public with sharing class Order extends WrapperClassBase {
     public Order__c record   = null;
     public static final String SFIELDS = 'Id, Name'; // ... add other fields here
     
     public Order(){}
     
     public Order withSObject(Order__c orderRecord){
          this.record = orderRecord;
          this.id = orderRecord.Id;
          return this;
     }
     
     public Order withId(ID recordId){
          id = recordId;
          String sFieldsToQuery = Order.SFIELDS;
          record = Database.query('SELECT ' + Order.SFIELDS + ' FROM Order__c WHERE Id=:id LIMIT 1');
          return this;
     }
     
     public Order validate(){         
          /*
          Validate fields here. Set this.success = false and populate this.errors.add('err message');
          */
          return this;
     }
     
     public Order doSomething(){
          return this;
     }
     
     private Map<ID,LineItem> m_lineItems = null;
     public Map<Id,LineItem> lineItems{
          get{
               if(m_lineItems == null){
                    m_lineItems = LineItem.fromRecords( this.lineItemRecords );
               }
               return m_lineItems;
          }
     }
     
     private List<OrderLineItem__c> m_lineItemRecords = null;
     public List<OrderLineItem__c> lineItemRecords{
          get{
               if(m_lineItemRecords == null){
                    m_lineItemRecords = Database.query('SELECT ' + LineItem.SFIELDS + ' FROM OrderLineItem__c WHERE Order__c=:id');
               }
               return m_lineItemRecords;
          }
     }
     
     public static Map<ID,Order> fromRecords(List<Order__c> records){
          Map<ID,Order> orders = new Map<ID,Order>();
          for(Order__c o : records){
               orders.put(o.Id, new Order().withSObject(o));
          }
          return orders;
     }
     
     public String toJSON(){
          Map<String, String> r = new Map<String, String>();
          List<String> fieldNames = Order.SFIELDS.split(',');
          for(String fName : fieldNames){
               r.put(fName, String.valueOf( this.record.get(fName) ));
          }
          return JSON.serialize(r);
     }
}

Inheritance

As of this writing, Apex does not allow inheriting the core SObject class (which would be ideal).

Record encapsulation uses the strongly typed Order__c record, rather than the abstractly typed SObject, in order to use the benefits of strongly typed objects in the Force IDE, such as auto-complete of the fields. Moving the record to the base class would require constantly casting SObject to the strong type.

Class Name

For custom objects, it's common to remove the namespace prefix and __c suffix from the wrapper class name. For standard objects, always prefix the class name with "SFDC", or some other naming convention, to avoid conflicts.

Wrapping Standard Objects

Creating wrapper classes with the same name as standard objects, although possible, is discouraged. Class names supersede standard object names, such that if the intent is to create a standard Account object, but a class named 'Account' already exists, the code will not compile because the compiler is trying to create an instance of the wrapper class and not the standard object.

To get around this, use a standard naming convention; SFDCAccount, SFDCContact, or SFDCLead; to differentiate the wrapper class names from their respective standard objects.

Construction

SObjects are constructed in 2 contexts:

  • withSObject(SObject record): The record has already been retrieved via a SOQL statement and the data just needs to be wrapped in a class container.
  • withId(ID recordId): The ID of a record is known, but has not yet been retrieved from the database.
The actual class constructor accepts no arguments. The builder pattern is used to construct the class and kick off a fluent chain of subsequent methods in a single line.

Once constructed, SObject fields are accessed directly through the public 'record' property, as in:

new Order().withID(someid).record.Custom_Field__c

This convention is chosen over creating getCustomField() and setCustomField() properties for brevity and to make use of code auto-complete features,. However, if mutability of the SObject record, or it's fields, are a concern then the public accessor can be modified to 'private' and corresponding get/set properties added.

SFIELDS

Each wrapper class exposes a static public string named SFIELDS for use in selecting all fields for a record. This is equivalent to writing "SELECT * FROM TABLE_NAME" in traditional SQL syntax.

The SFIELDS string can be periodically auto-generated from a Leap task to keep wrapper class field definitions in sync with the data model, or manually updated with just a subset of fields to be used by the wrapper class.

Builder Pattern

The real magic in the wrapper class template is it's ability to chain several methods together in a single line, commonly referred to as the Builder Pattern and discussed in a previous article, Developing Fluent Interfaces With Apex.

Using the Order__c wrapper class example above, the following is possible:

     Order o = new Order().withSObject(objectList.get(0)).doSomething();
     if(o.validate().hasErrors()){
          //handle exceptions
     }

The return types of builder methods must be the same as the wrapper class type. Each builder method returns 'this' to allow method chaining. Builder pattern is useful in the early stages of development when the exact method behaviors and system architecture is not entirely known (see 40-70 Rule to Technical Architecture) and allows a compositional flow to development, incrementally adding new features without significant refactoring effort.

Child Object Relationships

A wrapper class represents a single instance of a Salesforce record. Depending on how lookup relationships are defined, wrapper classes will usually be either a parent (master) or child (detail) of some other records, which also have wrapper classes defined.

The "fromRecords" utility method is provided to easily construct collections of child objects retrieved from SOQL queries. Collections of child wrapper classes are stored as Maps that support the quick lookup of child wrapper classes by their record ID.

Properties and Side Effects

The #1 cause of software entropy in Apex development is unwanted "side effects", which is the dependency on class variables that can be modified by other methods.

The wrapper class template encourages lazy initialization of properties to protect access to member variable. Lazy initialization also avoids repeated queries for the same records, which is a common cause for exceeding governor limits.

Java has not yet evolved to support class properties. But Apex does, and wrapper classes are an opportunity to use them whenever possible. For the sake of brevity, properties are preferred over methods, whenever possible. This Microsoft .NET article on choosing between properties and methods is very applicable to Apex.

For Developers doing a lot of client-side Javascript development in the UI, the use of server-side Apex properties closely approximates the associative array behavior of Javascript objects, and maintains a consistent coding style across code bases.

Unit Testing

Wrapper classes provide a clean interface for unit testing behaviors on objects. The Winter '14 release requires that unit tests be managed in a separate file from the wrapper class. Common convention is to always create a unit test file for each wrapper class with a suffix of 'Tests' in the class name.

Exception Handling

Without a clear exception handling strategy, it can be confusing for Developers to know how a class handles exceptions. Does it consistently bubble up, or catch all exceptions? There is no equivalent to the Java 'throws' keyword in Apex. To remedy this, the wrapper class template base provides a boolean 'success' flag that can be set by any method at any time.

When setting success=false, the exception handling code should also add to the List errors collection, giving an explanation of what went wrong in the transaction. It is the responsibility of calling objects/methods to check for success or hasErrors() after any transaction.

JSON Serialization

Wrapper classes can be serialized to JSON and returned to requesting clients for use in UI binding. The ToJSON() method is provided in the wrapper class template and can be customized to serialize the class.

Friday, 06 September 2013 10:46:42 (Pacific Daylight Time, UTC-07:00)
# Tuesday, 01 January 2013

Note: Apex can now be called from workflows as Invocable Methods using the Process Builder.

Here is a simple hack to call Apex classes from workflow rules.

Problem: Salesforce has a magnificently declarative environment for creating point-and-click applications and workflows, but one area that gets particularly gnarly is executing business rules in response to changes in state.

Given a problem like "When Opportunity stage equals 'Closed-Won', send the order to the back office system for processing", the Business Analyst has a good idea of "when" the business process should be executed. The Developer knows "how" the process should be executed.

The result is often the development of a trigger that includes both the "when" and "how" logic merged into a single class. The trigger ultimately ends up containing code to detect state changes; a task otherwise best left to workflow rule conditions.

Future enhancements to the business rules require the BA to submit a change request to the Developer, impairing the overall agility of the system.

(Some discussions of detecting record state in trigger can be found here, here, and here.)

The Solution: Calling Apex From Outbound Messages
Empower the System Administrator/BA to create workflow rules that call Apex classes in response to declarative conditions.

Create a workflow rule with an outbound message action that calls a message handler (hosted on Heroku), that in turn calls back to a Salesforce REST resource.

Components of the Outbound Message:

  1. The endpoint URL is hosted on Heroku. The outbound message handler receives the message and issues a callback to Salesforce using the path provided after the root URL.
  2. Pass the session ID to the endpoint (Note: the 'User to send as' must have permissions to call and invoke the Apex REST web service)
  3. Pass only the Id of object meeting the workflow condition. This gets passed back to the REST service as an "oid" parameter (object id).

Getting Started:

Download the Heroku outbound message handler from Github (link).

git clone https://github.com/cubiccompass/sfdc-om-workflow
Build the solution and deploy to Heroku.
mvn package
git init
git commit -am "Initial commit"
heroku apps:create omhandler
git push heroku master
Create a workflow rule with an outbound message action that calls the Heroku hosted endpoint.
Create a Salesforce REST resource for handling the callback.

To see the workflow in action, view the Heroku web service logs while updating records in Salesforce that trigger the workflow rule.
heroku logs -tail

Errata:

IWorkflowTask: In the real world, I'm evolving this design pattern to include an IWorkflowTask interface to clearly distinguish which business objects handle workflow actions. The execute() method takes a WorkflowContext object that includes more details from the outbound message.

Daisy Chaining Workflows: It's important that workflow tasks record or modify some state after executing a task in order to allow for triggering follow-up workflow actions. For example, an OrderProcessor workflow task might update an Order__c status field to "Processed". This allows System Administrators to create follow-up workflow rules/actions, such as sending out emails.

Security: Use HTTPS/SSL endpoints to ensure session information is not subject to man in the middle attacks.

Idempotence: Salesforce does not guarantee that each outbound message will be sent only once (although it's mostly consistent with 1:1 messaging). REST resources should be developed to handle the rare instance where a message might be received twice. In the use case above, the code should be designed to defend against submitting the same order twice; possibly by checking a 'Processed' flag on a record before submitting to a back-office system.

Governor Limits: Workflow tasks are called asynchronously, so there's a decent amount of processing and execution freedom using this pattern.

Tuesday, 01 January 2013 11:57:10 (Pacific Standard Time, UTC-08:00)
# Saturday, 15 December 2012

Technical Architects make many tough decisions on a daily basis, often with incomplete information. Colin Powell's 40-70 rule is helpful when facing such situations.

He says that every time you face a tough decision you should have no less than forty percent and no more than seventy percent of the information you need to make the decision. If you make a decision with less than forty percent of the information you need, then you're shooting from the hip and will make too many mistakes.

The second part of the decision making rule is what surprises many leaders. They often think they need more than seventy percent of the information before they can make a decision. But in reality, if you get more than seventy percent of the information you need to make the decision, then the opportunity to add value has usually passed, or the competition has beaten you to the punch. And with today's agile development and continuous integration (CI) methodologies, you can afford to iterate on an architecture with incomplete information.

A key element that supports Powell’s rule is the notion that intuition is what separates great Technical Architects from average ones. Intuition is what allows us to make tough decisions well, but many of us ignore our gut. We want certainty that we are making the right decision, but that's not possible. People who want certainty in their decisions end up missing opportunities, not leading.

Making decisions with only 40%-70% of the information requires responsibly communicating the technical architecture + how changes will be implemented as more information becomes available.

Architecture + Continuous Integration Process = Agility.

Architecture alone is not a sufficient solution and can leave a solution inflexible to change. "Release early and often" is the new mantra in cloud development.

The best way to manage risk as a TA with 40-70% of the information is to constantly ask yourself 2 questions:
1) What is the simplest possible solution to the current problem?
2) How will future changes be implemented?

Within the realm of Salesforce, a Technical Architecture conducive to CI is achieved primarily through 3 design patterns:
* Declarative configuration
* Custom Settings
* Hybrid apps / Web Tabs / Canvas

1) Declarative configuration. First and foremost, it's the obligation of a TA to maximize the point-and-click configuration of any solution. This is done by using as many out of box features as possible.
2) Custom settings: When coding is required, externalizing the behaviors and conditional branches to custom settings gives System Admins and Business Analysts the ability to fine tune a solution as more information becomes available. For example, rather than hardcoding a callout URL in a trigger, move the URL to a custom setting.
3) Hybrid / Web Tabs / Canvas: For ISVs and custom application development, an IFRAME wrapper to an app hosted on Heroku provides the greatest agility to pivot on a solution. Code changes can be pushed several times per day without having to go through the AppExchange package and review process. Matching the look and feel of Salesforce within a Hybrid or canvas app can provide the best of both worlds; a native Salesforce business application with code managed on a separate platform.

Saturday, 15 December 2012 13:44:55 (Pacific Standard Time, UTC-08:00)
# Wednesday, 28 November 2012

I've published an example of a self-documenting REST API to Github (source).

Why a self-documenting REST API?

A typical REST API sample is hosted at http://restdoc-sample.herokuapp.com/hello, using Heroku's embedded Tomcat Java example.

As a Developer, your initial questions may be:

  • "What does the 'hello' endpoint do?"
  • "Does the endpoint support GET, POST, PUT, DELETE?"
  • "What headers and message body payloads does this endpoint support?"

Fortunately, the RESTDoc project has already defined a specification for documenting REST APIs. The intent of RESTDocs is for each endpoint to support the OPTIONS method and return a structured RESTDoc for the particular API endpoint.

Getting back to the Heroku hosted sample, submitting a curl request for the 'hello' endpoint using the OPTIONS method returns the sample RESTDoc below.

curl -X OPTIONS http://restdoc-sample.herokuapp.com/hello

In addition to supporting the OPTIONS method, the github sample also supports appending '/describe' to any API endpoint to view RESTDocs in web browser. Example: http://restdoc-sample.herokuapp.com/hello/describe.

Standardizing on RESTDocs opens up a number of interesting possibilities. Since transitioning away from SOAP, the web development community has lost the ability to auto-generate object proxies for calling web services. Webhook and Enterprise Service Bus (ESB) platforms have lost the ability to auto-discover web service endpoints and their supported messages.

Self-describing REST APIs, using RESTDocs and the OPTIONS method, are a compelling solution for enabling the service oriented enterprise and integrating the cloud.

	{
	  "schemas" : {
	    "http://some.json/msg" : {
	      "type" : "inline",
	      "schema" : {
	        "type" : "object",
	        "properties" : {
	          "id" : {
	            "type" : "string"
	          },
	          "content" : {
	            "type" : "string"
	          }
	        }
	      }
	    }
	  },
	  // Headers can be described at the server level and/or per-method
	  "headers": {
	    "request": {
	      "Authorization": {
	        "description": "This server uses a custom authentication scheme. See http://myapi.com/docs/auth",
	        "required": true
	      }
	    },
	    "response": {
	      "X-RateLimit-Total": {
	        "description": "The number of API calls allowed per-hour"
	      },
	      "X-RateLimit-Remaining": {
	        "description": "Number of requests remaining until next refill"
	      },
	      "X-RateLimit-Reset": {
	        "description": "The time at which X-RateLimit-Remaining will be reset back to X-RateLimit-Total"
	      }
	    }
	  },
	  "resources": [
	    {
	      "id": "HelloMessage",
	      "description": "An example hello message",
	      "path": "/{locale}/{messageId}{?seasonal}", // representing query params with L3 URI templates
	      "params": { // URI parameters descriptions
	        "locale": {
	          "description": "A standard locale string, e.g. \"en_US.utf-8\"",
	          "validations": [ { "type": "match", "pattern": "[a-z]+(_[A-Z]+)?(\\\\.[a-z-]+)?" } ]
	        },
	        "messageId": {
	          "description": "A free-form message string",
	          "validations": [ { "type": "match", "pattern": "[a-z_]+" } ]
	        },
	        "seasonal": {
	          "description": "Whether the message is seasonal.",
	          "validations": [ { "type": "match", "pattern": "^(true|false|yes|no)$" } ]
	        }
	      },
	      "methods": {
	        "PUT": {
	          "description": "Update or create a message",
	          "statusCodes": { "201": "Created" },
	          "accepts": [   // Representations accepted by the method on this resource.
	            { "type": "text/plain" },
	            { "type": "application/json", "schema": "http://some.json/msg" }
	          ],
	          "headers": { // Request headers only, response headers are defined under 'response'
	            "X-User-Token": {
	              "description": "Used to identify the user creating the message"
	            }
	          },
	          "response": { // Response representations this resource/method provides
	            "types": [
	              { "type": "text/plain" },
	              { "type": "application/json", "schema": "http://some.json/msg" },
	            ],
	            "headers": {
	              "Location": {
	                "description": "The URL of the created message"
	              }
	            }
	          },
	          "examples": [
	            {
	              "path": "/en_US/greeting",
	              "body": "Hello, world!"
	            },
	            {
	              "path": "/en_US/greeting",
	              "headers": {"Content-Type": "application/json"},
	              "body": "{\"id\":\"greeting\",\"content\":\"Hello, world!\"}!"
	            }
	          ]
	        },
	        "GET": {
	          "description": "Retrieve a message",
	          "statusCodes": { 
	             "200": "Message retrieved successfully", 
	             "404": "Message not found"
	          }
	        }
	      }
	    },
	    {
	      // This resource has no human-readable documentation, but still provides some info on how to use it.
	      "id": "FallbackLocale",
	      "path": "/fallback/{locale}",
	      "params": {
	        "locale": { 
	          "validations": [ { "type": "match", "pattern": "[a-z]+(_[A-Z]+)?(\\\\.[a-z-]+)?" } ]
	        }
	      },
	      "methods": {
	        "GET": { "statusCodes": { "200": "OK" } },
	        "PUT": { "statusCodes": { "201": "Created" } }
	      }
	    }
	  ]
	}	
Wednesday, 28 November 2012 09:29:03 (Pacific Standard Time, UTC-08:00)
# Tuesday, 13 November 2012

Salesforce recently posted this tantalizing brainteaser question "When do you think Salesforce will reach 1B transactions per day?"

Analyzing the recent numbers from trust.salesforce.com reveals some interesting patterns and trends:

  • Peaks tend to occur most often on a Tuesday
  • Weekend traffic drops to about 1/3rd of weekday activity
  • The average growth between peaks is 0.52% per week
Extrapolating these numbers out reveals that Tuesday, December 18th, 2012 is the highest probability date to hit 1B transactions. But that date is pretty close to the holidays, so it's a tough call.

What is your prediction?

Tuesday, 13 November 2012 22:41:35 (Pacific Standard Time, UTC-08:00)
# Monday, 22 October 2012

I frequently use the FizzBuzz interview question when interviewing Salesforce developer candidates.

The original FizzBuzz interview question goes something like this:

Write a program that prints the numbers from 1 to 100. But for multiples of three print "Fizz" instead of the number and for the multiples of five print "Buzz". For numbers which are multiples of both three and five print "FizzBuzz".

The output from the first 15 numbers should look like this:

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz

It's a great question because the interviewer can evolve the requirements and take the discussion in many different directions.

A good interview is a lot like auditioning a drummer for a rock band. You want to start off with something easy, then "riff" on an idea to get a sense of the candidates listening skills and ability to create variations on a theme (aka refactoring).

Unfortunately, most interviews have the intimidating premise of pass/fail, so the key to an effective interview is in setting up the question so that the interview candidate understands it is okay to constantly change and revise their answers, and that the interview will be evolving around a central concept; which is FizzBuzz.

The questions below gradually get harder by design, and at some point the candidate may not have an answer. That's okay. As an interviewer, you need to know:

a) How does the candidate respond when asked to do something they don't understand?
b) If we hired this person, what is the correct onboarding and mentoring plan for this candidate to help them be successful?

I'll drop hints during the question setup, using buzzwords like "TDD" (test-driven development), "unit testing", and "object oriented design", hoping the candidate might ask clarifying questions before jumping into code, like "Oh, you want to do TDD. Should I write the unit test first?"

So, on to the code. The fundamental logic for FizzBuzz requires a basic understanding of the modulo operator; which, in all fairness, is not a particularly valuable thing to know on a daily basis, but is often the minimum bar for testing the meets "Computer Science or Related 4 Year Degree" requirement in many job descriptions, since it's universally taught in almost all academic curriculums.

After the first round, the basic logic for FizzBuzz should look something like this:

function doFizzBuzz(){
     for(integer i=1; i <= 100; i++){
          String output = '';
          if( i % 3 == 0 ){
               output += 'Fizz';
          }
          if( i % 5 == 0 ){
               output += 'Buzz';
          }
          if(output == ''){
               output = string.valueOf(i);
          }
          System.debug(output);
     }
}

Some things interviewers will be looking for:

  • Use and understanding of the Modulo operator
  • Efficiency. Is mod calculated twice for each value to meet the compound "FizzBuzz" requirement?
  • Using a 0 based loop index and printing numbers 0-99 instead of 1-100
  • Unclear coding blocks or control flow (confusing use of parentheses or indenting)

Even if the candidate misses one of these points, they can usually get over the hurdle quickly with a bit of coaching.

"So, let's evolve this function into an Apex class."

For experienced Salesforce Developers, you can start gauging familiarity with Apex syntax; but be flexible. More experienced Developers/Architects will probably think faster in pseudo code, and Java Developers (if you're gauging potential to become a Force.com Developer) will want to use their syntax.

Refactoring the basic logic above into an Apex class might look something like this:

public class FizzBuzz {
     public void run(){
          for(integer i=1; i <= 100; i++){
               if(math.mod(i, 3) == 0){
                    System.debug('Fizz');
               }
               if(math.mod(i, 5) == 0){
                    System.debug('Buzz');
               }
               else{
                    System.debug(i);
               }
          }
     }
}

"Okay. How would you test that? Let's write a unit test".

If the candidate is not familiar with Force.com Development, now might be a good opportunity to explain that 75% minimum test coverage is required to deploy code.

A basic unit test should look something like:

     public static testMethod void mainTests(){    
          FizzBuzz fb = new FizzBuzz();
          fb.run();
     }    

The test runner will report 100% unit test coverage by virtue of executing the entire run() method within a testMethod. But is this really aligned with the true spirit and principle of unit testing? Not really.

A more precise follow-up question might be: "How would you Assert the expected output of FizzBuzz?"

In it's current state, FizzBuzz is just emitting strings. Does the candidate attempt to parse and make assertions on the string output?

At this point, it's helpful to start thinking in terms of TDD, or Test Driven Development, and attempt to write a unit test before writing code. One possible solution is the Extract Method design pattern, creating methods for isFizz() and isBuzz(), then test to assert those methods are working correctly.

public class FizzBuzz {    

     private void run(){    
          for(integer i=1; i <= 100; i++){
               String output = '';              
               if( isFizz(i) ){
                    output += 'Fizz';
               }
               if( isBuzz(i) ){
                    output += 'Buzz';
               }
               if(output == ''){
                    output = string.valueOf(i);
               }
               System.debug(output);
          }
     }
   
     static final integer FIZZ_MULTIPLE = 3;
     private boolean isFizz(integer n){
          return ( math.mod(n, FIZZ_MULTIPLE) == 0);
     }

     static final integer BUZZ_MULTIPLE = 5;
     private boolean isBuzz(integer n){
          return ( math.mod(n, BUZZ_MULTIPLE) == 0);
     }

     public static testmethod void fizzTests(){
          FizzBuzz fb = new FizzBuzz();
          System.assertEquals(false, fb.isFizz(1));
          System.assertEquals(false, fb.isFizz(2));
          System.assertEquals(true,  fb.isFizz(3));
          System.assertEquals(false, fb.isFizz(4));
          System.assertEquals(false, fb.isFizz(5));
     }
    
     public static testmethod void buzzTests(){
          FizzBuzz fb = new FizzBuzz();
          System.assertEquals(false, fb.isBuzz(1));
          System.assertEquals(false, fb.isBuzz(2));
          System.assertEquals(false, fb.isBuzz(3));
          System.assertEquals(false, fb.isBuzz(4));
          System.assertEquals(true,  fb.isBuzz(5));
     }   

     public static testmethod void fizzBuzzTests(){
          FizzBuzz fb = new FizzBuzz();
          System.assertEquals(true, fb.isFizz(15));
          System.assertEquals(true, fb.isBuzz(15));
     }
}

This is a considerable improvement, but the test coverage is now only at 40%. The run() method is still leaving some technical debt behind to be refactored.

I may drop the candidate a hint about Model-View-Controller and ask how they might deconstruct this class into it's constituent parts.

There are no DML or objects to access, so effectively there is no Model.

But the run() method is currently overloaded with FizzBuzz logic (controller) and printing the output (view). We can further extract the logic into a List of strings to be rendered in any form by the run() method.

public class FizzBuzz { 

     private void run(){    
          for(String element : this.getFizzBuzzList()){
               system.debug(element);
          }
     }
   
     private List<string> getFizzBuzzList(){
          List<string> fizzBuzzList = new List<string>();
          for(integer i=1; i <= 100; i++){
               string listElement = '';

               if( isFizz(i) ){
                    listElement = 'Fizz';
               }
               if( isBuzz(i) ){
                    listElement += 'Buzz';
               }
               if(listElement == ''){
                    listElement = string.valueOf(i);
               }

               fizzBuzzList.add(listElement);
          }
          return fizzBuzzList;
     }
    
     static final integer FIZZ_MULTIPLE = 3;
     private boolean isFizz(integer n){
          return ( math.mod(n, FIZZ_MULTIPLE) == 0);
     }
    
     static final integer BUZZ_MULTIPLE = 5;
     private boolean isBuzz(integer n){
          return ( math.mod(n, BUZZ_MULTIPLE) == 0);
     }
    
     public static testmethod void fizzTests(){
          FizzBuzz fb = new FizzBuzz();
          System.assertEquals(false, fb.isFizz(1));
          System.assertEquals(true,  fb.isFizz(3));
          System.assertEquals(false, fb.isFizz(5));
     }
    
     public static testmethod void buzzTests(){
          FizzBuzz fb = new FizzBuzz();
          System.assertEquals(false, fb.isBuzz(1));
          System.assertEquals(false, fb.isBuzz(3));
          System.assertEquals(true,  fb.isBuzz(5));
     }
    
     public static testmethod void fizzBuzzTests(){
          FizzBuzz fb = new FizzBuzz();
          System.assertEquals(true, fb.isFizz(15));
          System.assertEquals(true, fb.isBuzz(15));
     }
    
     public static testmethod void fizzBuzzListTests(){
          FizzBuzz fb = new FizzBuzz();
          //0 based offsets.
          System.assertEquals(100, fb.getFizzBuzzList().size() );
          System.assertEquals('1', fb.getFizzBuzzList().get(0) );
          System.assertEquals('Fizz', fb.getFizzBuzzList().get(2) );
          System.assertEquals('4', fb.getFizzBuzzList().get(3) );
          System.assertEquals('Buzz', fb.getFizzBuzzList().get(4) );
          System.assertEquals('FizzBuzz', fb.getFizzBuzzList().get(14) );
          System.assertEquals('FizzBuzz', fb.getFizzBuzzList().get(29) );
     }
}

Test coverage is now at 90% after extracting the run() print logic into a unit testable method that returns a list. The last 10% can be easily covered by calling run() anywhere inside a testMethod.

If there's time remaining in the interview, a good enhancement is to add dynamic ranges. Instead of printing 1-100, modify the class to support any range of numbers. Basically, this is just testing the candidate's ability to manage class constructor arguments.

public class FizzBuzz {    
     private final integer floor;
     private final integer ceiling;    

     public FizzBuzz(){
          floor      = 1;
          ceiling = 100;
     }
    
     public FizzBuzz(integer input_floor, integer input_ceiling){
          floor = input_floor;
          ceiling = input_ceiling;
     }
    
     private void run(){    
          for(String element : this.getFizzBuzzList()){
               system.debug(element);
          }
     }
    
     private List<string> getFizzBuzzList(){
          List<string> fizzBuzzList = new List<string>();
          for(integer i=floor; i <= ceiling; i++){
               string listElement = '';
               if( isFizz(i) ){
                    listElement = 'Fizz';
               }
               if( isBuzz(i) ){
                    listElement += 'Buzz';
               }
               if(listElement == ''){
                    listElement = string.valueOf(i);
               }
               fizzBuzzList.add(listElement);
          }

          return fizzBuzzList;
     }

    
     static final integer FIZZ_MULTIPLE = 3;
     private boolean isFizz(integer n){
          return ( math.mod(n, FIZZ_MULTIPLE) == 0);
     }
     
     static final integer BUZZ_MULTIPLE = 5;
     private boolean isBuzz(integer n){
          return ( math.mod(n, BUZZ_MULTIPLE) == 0);
     }

    
     public static testmethod void fizzTests(){
          FizzBuzz fb = new FizzBuzz();
          System.assertEquals(false, fb.isFizz(1));         
          System.assertEquals(true,  fb.isFizz(3));
          System.assertEquals(false, fb.isFizz(5));
     }
    
     public static testmethod void buzzTests(){
          FizzBuzz fb = new FizzBuzz();
          System.assertEquals(false, fb.isBuzz(1));         
          System.assertEquals(false, fb.isBuzz(3));         
          System.assertEquals(true,  fb.isBuzz(5));
     }
    
     public static testmethod void fizzBuzzTests(){
          FizzBuzz fb = new FizzBuzz();
          System.assertEquals(true, fb.isFizz(15));
          System.assertEquals(true, fb.isBuzz(15));
     }
   
     public static testmethod void fizzBuzzListTests(){
          //Use a 0 based index range to make fetching/testing list offsets easier.
          FizzBuzz fb = new FizzBuzz(0, 100);
          System.assertEquals(101, fb.getFizzBuzzList().size() );
          System.assertEquals('1', fb.getFizzBuzzList().get(1) );
          System.assertEquals('2', fb.getFizzBuzzList().get(2) );
          System.assertEquals('Fizz', fb.getFizzBuzzList().get(3) );
          System.assertEquals('4', fb.getFizzBuzzList().get(4) );
          System.assertEquals('Buzz', fb.getFizzBuzzList().get(5) );
          System.assertEquals('FizzBuzz', fb.getFizzBuzzList().get(15) );
          System.assertEquals('FizzBuzz', fb.getFizzBuzzList().get(30) );
     }
}

I will usually follow-up this question with questions about boundary checking and programmatic validation rules.

"Should FizzBuzz be allowed to accept negative numbers?"

"Should the ceiling value always be greater than the floor?"

If yes to either of these, then how would the candidate implement validation rules and boundary checks? This very quickly gets into writing more methods and more unit tests, but mirrors the reality of day-to-day Force.com development.

Once variables get introduced at class scope, then this is a good opportunity to have discussions about side-effects and immutability.

"What happens 6 months later when another Developer comes along and tries to modify the ceiling or floor variables in new methods?"

"How can you prevent this from happening?"

"What are the benefits of initializing variables only once and declaring them 'final'?"

An experienced Developer will likely have a grasp of functional programming techniques and the long-term benefits of minimizing side-effects and keeping classes immutable.

And finally, these unit tests are all written inline. How would the candidate separate tests from production classes?

For more information about refactoring patterns, check out this list of patterns or read Martin Fowler's brilliant book Refactoring: Improving the Design of Existing Code.

Monday, 22 October 2012 16:53:22 (Pacific Daylight Time, UTC-07:00)