Whiteboarding in interviews

NYC viewpoint from Ellis Island.
NYC viewpoint from Ellis Island.

A long time ago, I was asked to perform a programming function (FizzBuzz) on a whiteboard during an interview with T-SQL. I was able to get the theory behind it, but I am pretty poor at memorizing syntax. I’d rather spend my time studying concepts, theory, and technology. Indexes and cursors are two great examples. I don’t think it really matters if you don’t memorize how to write those by hand, it’s more valuable to understand how they work instead.

It takes about 30 seconds to google the syntax for a command but it can take hours of reading to understand how the command truly works. This is why I’m not a proponent of whiteboarding problems unless the person can have access to the internet for simple lookups. The goal behind the whiteboarding should be to see the thinking process of the individual and how they work through problems, not to “stump the chump”.

Likewise, I think it’s fine to have the interviewee read code or to give them word problems and ask for their interpretation. Points on syntax shouldn’t be accounted for unless you are a shop that just needs code monkeys to churn out basic code all day.

Let’s use the FizzBuzz example to explain how whiteboarding should go in an interview.

Write in the programming language that you want, a program that displays on screen the numbers from 1 to 100, replacing the multiples of 3 by the word “Fizz” and, in turn, the multiples of 5 by the word “Buzz”. For the numbers that, in time, are multiples of 3 and 5, use the word “FizzBuzz”.

FizzBuzz

One method to solve this is by creating a loop that increments and divides the value by 3 and 5 to test for a whole quotient number. Whole numbers are printed, while numbers that have a decimal are caught in the divide by 3, 5, or 3 and 5 filter. The key concepts here are order of operations, problem-solving, understanding of basic T-SQL, and basic math skills.

We start with dividing the value by both 3 and 5 because the CASE WHEN command evaluates the values sequentially and stops evaluating the condition as soon as it is met. Dividing by 3 and 5 will have commonalities with dividing by just 3 or 5, this is why we start by dividing with both. Afterward, we divide the remaining values by either 3 or 5. The order for which of those we divide by after testing both conditions is not relevant since there will be no commonalities. Through elimination, we know that all remaining numbers not divisible by 3 and 5, 3, or 5, are fine to print. So we print the value at the end of the CASE WHEN statement.

Here is a loop example of solving FizzBuzz:

DECLARE @Value DECIMAL(25, 2);

SET @Value = 1;

WHILE(@Value) <= 100

    BEGIN

        IF
        (
            SELECT 
                   CHARINDEX('.', (CAST(@Value AS FLOAT)/5))
        ) = 0
        AND
        (
            SELECT 
                   CHARINDEX('.', (CAST(@Value AS FLOAT)/3))
        ) = 0

            BEGIN

                PRINT 'FizzBuzz';
            END;
            ELSE
            BEGIN

                IF
                (
                    SELECT 
                           CHARINDEX('.', (CAST(@Value AS FLOAT)/3))
                ) = 0

                    BEGIN

                        PRINT 'Fizz';
                    END;
                    ELSE
                    BEGIN

                        IF
                        (
                            SELECT 
                                   CHARINDEX('.', (CAST(@Value AS FLOAT)/5))
                        ) = 0

                            BEGIN

                                PRINT 'Buzz';
                            END;
                            ELSE
                            BEGIN

                                PRINT CAST(@Value AS SMALLINT);
                            END;
                    END;
            END;

        SET @Value = @Value + 1;
    END;

This isn't a very efficient approach however, let's find another way to speed this up:

DECLARE @FizzBuzz TABLE([ID] DECIMAL(25, 2));

DECLARE @Increment SMALLINT;

SET @Increment = 1;

WHILE(@Increment) <= 100

    BEGIN

        INSERT INTO @FizzBuzz
        (
               [ID]
        )
        VALUES (@Increment);

        SET @Increment = @Increment + 1;
    END;

SELECT 
       CASE
           WHEN(CHARINDEX('.', (CAST([ID] AS FLOAT)/5))) = 0
               AND (CHARINDEX('.', (CAST([ID] AS FLOAT)/3))) = 0
           THEN 'FizzBuzz'
           WHEN(CHARINDEX('.', (CAST([ID] AS FLOAT)/3))) = 0
           THEN 'Fizz'
           WHEN(CHARINDEX('.', (CAST([ID] AS FLOAT)/5))) = 0
           THEN 'Buzz'
           ELSE CAST(CAST([ID] AS SMALLINT) AS VARCHAR(10))
       END AS [ID]
FROM @FizzBuzz;

The difference here is that I'm mostly using SET logic. The while loop is row by agonizing row (RBAR), but the SELECT clause is based on SET theory. It reads the entire table and applies the logic to a single transaction rather than doing this transaction 100 times altogether for the 100 rows.

We could speed this up more if we had some tables (even system tables would work) to create a cartesian join to populate the table variable up to 100. There are also many more methods of solving this problem, which is what I would want to capture from the interviewee. I don't care if they have to use books online to set up their WHILE loop. I care that they can come up with various ways to solve the problem and know where to go to enhance the solution. I also care about if they are able to explain their solution and why it works. The ability to teach what you know illustrates how well you know that subject better than showing me you can memorize syntax.

Leave a Reply

Your email address will not be published. Required fields are marked *