# 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, 29 October 2012 08:56:51 (Pacific Standard Time, UTC-08:00)
Some of my best code is written away from the keayobrd. Getting away from it helps you see the forest through the trees sometimes.My stumbles so far while working through CodeYear have been syntax and spelling the kind of things that I am saying Come on! Give me my points it's right!!! Then 5 minutes later I see it. Oh, capital L. Idiot. I always marvel at the fact I get paid to type. If they only knew.
Comments are closed.