## Step 1: Define the symbolic variables
Let's define the symbolic variables for the problem:
- $x_1$ represents the number of caesar salads
- $x_2$ represents the number of house salads

## Step 2: Translate the objective function into symbolic notation
The profit per caesar salad is $5 and the profit per house salad is $8. Therefore, the objective function to maximize profit is:
\[ \text{Maximize:} \quad 5x_1 + 8x_2 \]

## 3: Translate the constraints into symbolic notation
1. There is only 2000 grams of lettuce available. The caesar salad contains 20 grams of lettuce and the house salad contains 30 grams of lettuce. Therefore, the lettuce constraint is:
\[ 20x_1 + 30x_2 \leq 2000 \]
2. The house salad is much more popular and at least three times the amount of house salads needs to be made than the caesar salads:
\[ x_2 \geq 3x_1 \]
3. A minimum of 8 caesar salads needs to be made:
\[ x_1 \geq 8 \]
4. Non-negativity constraints (number of salads cannot be negative):
\[ x_1 \geq 0, \quad x_2 \geq 0 \]
However, since $x_1 \geq 8$ is given, the $x_1 \geq 0$ is implicitly satisfied.

## 4: Create the symbolic representation
The symbolic representation of the problem is:
```json
{
'sym_variables': [('x1', 'caesar salads'), ('x2', 'house salads')],
'objective_function': '5*x1 + 8*x2',
'constraints': [
    '20*x1 + 30*x2 <= 2000',
    'x2 >= 3*x1',
    'x1 >= 8'
]
}
```

## 5: Write the Gurobi code
Now, let's write the Gurobi code in Python to solve this problem:
```python
import gurobi

def solve_salad_problem():
    # Create a new model
    model = gurobi.Model()

    # Define the variables
    x1 = model.addVar(lb=8, name="caesar_salads", vtype=gurobi.GRB.INTEGER)  # Minimum of 8 caesar salads
    x2 = model.addVar(name="house_salads", vtype=gurobi.GRB.INTEGER)

    # Objective function: Maximize 5*x1 + 8*x2
    model.setObjective(5*x1 + 8*x2, gurobi.GRB.MAXIMIZE)

    # Constraints
    model.addConstr(20*x1 + 30*x2 <= 2000, name="lettuce_constraint")
    model.addConstr(x2 >= 3*x1, name="popularity_constraint")

    # Optimize the model
    model.optimize()

    # Print the solution
    if model.status == gurobi.GRB.OPTIMAL:
        print(f"Optimal solution: Caesar salads = {x1.varValue}, House salads = {x2.varValue}")
    else:
        print("No optimal solution found")

solve_salad_problem()
```