Board Rotation Problem - Best Practices Problem: You are given a board containing lower-case letters and a word that you have to form. You can only take the letters from the front or the back, hence you have to rotate the board left or right. You have to use the greedy approach (choose which rotation lets you take the letter the fastest on each turn) and get a list of rotations necessary to get the word.

Example:

Initial Condition: Board: a g t c f  word: cat
Rotate Right -&gt; f a g t c
Take c -&gt; f a g t
Rotate Left -&gt; a g t f
Take a -&gt; g t f
etc


Code:

        public static List&lt;Move&gt; SolveLetterBoard(List&lt;char&gt; board, string word)
        {
            List&lt;Move&gt; result = new List&lt;Move&gt;();

            for (int i = 0; i &lt; word.Length; i++)
            {
                char curChar = word[i];

                int leftPosition = board.IndexOf(curChar);
                int rightPosition = board.LastIndexOf(curChar);

                int location = 0;
                int where = leftPosition;
                Direction howToSpin = Direction.Left;

                //Is it easier to spin to the right or to the left
                if (board.Count - rightPosition &lt;= leftPosition)
                {
                    where = board.Count - rightPosition - 1;
                    location = board.Count - 1;
                    howToSpin = Direction.Right;
                }

                Move curMove = new Move(howToSpin);
                for (int j = 0; j &lt; where; j++)
                {
                    result.Add(curMove);

                    //Spin the board
                    char temp = board[location];
                    board.RemoveAt(location);
                    board.Insert(board.Count - location, temp);                    
                }

                //Remove the letter
                curMove = new Move(howToSpin, curChar);
                board.RemoveAt(location);

                result.Add(curMove);
            }

            return result;
        }


The code works, but I was told by the interviewer that the code "Your final code showed some lack of best practices", without any elaboration.
Could someone please advise what I did wrong.
Overall I'd consider your approach to be "procedural" rather than object-oriented, which might have contributed to the feedback about "lack of best practices"

I agree with Shanif that it would be best to create a class with different methods and avoid static. 

Below is an example of the object-oriented approach. 

Under the principle of encapsulation I wondered, "Should the Board expose its inner workings of how it generates the moves?" I decided no, and kept the Board's "calculation" methods private. 

When I first posted this answer I knew that the various moves had enough in common to be candidates for inheritance. And, I got around to implementing it. Now the Move family of classes all derive from an abstract base class.

I also added the Solution class to capture the steps and help output them at the end.

Admittedly, this object model might be "overkill" for an app of this size. But, I was more interested in modeling the domain than in outputting the results as tersely as possible. 

Despite its verbosity in meeting the currently-modest requirements, this object model provides a foundation upon which the app could grow to any size.

Or, to put it another way... Object-oriented programming is useful for many things. Winning at code golf is not among them.

Here's the output:


And the code:  

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public class App_LetterBoard
{
    public void Run()
    {
        var board = new Board("agtcf");
        board.Solve("cat");
        board.OutputResult();

        Console.WriteLine();
        var board2 = new Board("agtcfqwerqweroqiweru");
        board2.Solve("cat");
        board2.OutputResult();
    }
}

public class Board
{
    private string initial; 
    private string target; 
    private string current; 
    private string result;
    private char next;

    public Solution Solution { get; private set; } = new Solution();

    public Board(string initial) =&gt; this.initial = initial;

    public void Solve(string target)
    {
        this.target = target;
        result = string.Empty;
        current = initial;            
        var index = 0;

        Solution.Add(new Start(initial));

        while (!result.Equals(target))
        {                
            next = target[index++];
            var distanceLeft = current.IndexOf(next);
            var distanceRight = current.Length - current.LastIndexOf(next) - 1;
            if (distanceLeft &lt;= distanceRight)
            {
                captureLeft(distanceLeft);
            }
            else
            {
                captureRight(distanceRight);
            };

            result = $"{result}{next}";
        }
    }

    public void OutputResult()
    {
        Console.WriteLine($"Find -&gt; {target}");
        Console.WriteLine(Solution.ToString());
    }

    private void captureRight(int distance)
    {
        for (var i = 0; i &lt; distance; i++)
        {
            var move = new RotateRight(current);
            Solution.Add(move);
            current = move.After;
        }

        var take = new TakeRight(current);
        Solution.Add(take);
        current = take.After;
    }

    private void captureLeft(int distance)
    {
        for (var i = 0; i &lt; distance; i++)
        {
            var move = new RotateLeft(current);
            Solution.Add(move);
            current = move.After;
        }

        var take = new TakeLeft(current);
        Solution.Add(take);
        current = take.After;
    }        
}

public class Solution
{
    public List&lt;Move&gt; Moves { get; private set; } = new List&lt;Move&gt;();

    public void Add(Move move) =&gt; Moves.Add(move);

    public override string ToString()
    {
        var sb = new StringBuilder();
        sb.AppendLine(string.Join("\n", Moves.Select(m =&gt; m.ToString())));
        return sb.ToString();
    }
}

public abstract class Move
{
    public abstract string Name { get; }

    public string Before { get; private set; }

    public string After =&gt; advance();

    public Move(string remaining) =&gt; Before = remaining;

    public override string ToString() =&gt; $"{Name} -&gt; {spread(After)}";

    protected abstract string advance();

    protected string removeLeft() =&gt; Before.Substring(1);

    protected string removeRight() =&gt; Before.Substring(0, Before.Length - 1);

    private string spread(string s) =&gt; string.Join(" ", s.ToArray());
}

public class Start : Move
{
    public override string Name =&gt; "Start";

    public Start(string current) : base(current) {}

    protected override string advance() =&gt; Before;
}

public class RotateLeft : Move
{
    public override string Name =&gt; "Rotate Left";

    public RotateLeft(string current) : base(current) { }

    protected override string advance() =&gt; $"{removeLeft()}{Before.First()}";
}

public class RotateRight : Move
{
    public override string Name =&gt; "Rotate Right";

    public RotateRight(string current) : base(current) { }

    protected override string advance() =&gt; $"{Before.Last()}{removeRight()}";
}

public abstract class Take : Move
{
    public override string Name =&gt; "Take";
    public Take(string current) : base(current) { }
}

public class TakeLeft : Take
{
    public TakeLeft(string current) : base(current) { }

    protected override string advance() =&gt; removeLeft();
}

public class TakeRight : Take
{
    public TakeRight(string current) : base(current) { }

    protected override string advance() =&gt; removeRight();
}