Skip to Content
Course content

129: Building a Console-Based Inventory Manager

Click on the "Edit" button in the top corner of the screen to edit your slide content.

When people first start building "manager" style applications, they usually fall into a specific trap: they think the List<T> is the manager. I've seen countless juniors write a program where the Main method just holds a List<Product> and performs all the logic—adding, removing, and updating—right there in the middle of the UI loop. They assume that as long as the data is stored in a list, they've "managed" the inventory.

Thinking a List<Product> is the Same as an Inventory Manager

Here is why that approach fails the moment your project grows. If your Main method handles the logic, you can't enforce rules. For example, what happens if a user tries to remove 10 items from a stock of 5? If you're just calling list[0].Quantity -= 10 in your main loop, you've just created -5 items out of thin air. Your data is now corrupt, and because the logic is scattered across your UI code, you have to hunt down every single place you modify quantity to fix the bug.

// The "Wrong" Way: Logic leaked into the UI
if (userChoice == "remove") {
    var product = products.Find(p => p.Id == id);
    product.Quantity -= amount; // Oops! No check for negative stock.
    Console.WriteLine("Removed!");
}

Building a Guardrail Around Your Data

The correct way is to treat your InventoryManager as a gatekeeper. The list should be private, hidden away where the rest of the program can't touch it. The only way to change the data is through specific methods that enforce your business rules. I call this "building a guardrail." If the InventoryManager says you can't have negative stock, then it is physically impossible for any other part of the app to create negative stock.

Let's look at how I'd actually structure this. We start with a simple Product record for data, then a manager class that handles the "how" of the inventory.

public record Product(int Id, string Name, int Quantity);

public class InventoryManager
{
    private readonly List<Product> _products = new();

    public void AddProduct(string name, int initialQuantity)
    {
        int id = _products.Count > 0 ? _products.Max(p => p.Id) + 1 : 1;
        _products.Add(new Product(id, name, initialQuantity));
    }

    public bool TryRemoveStock(int productId, int amount)
    {
        var product = _products.FirstOrDefault(p => p.Id == productId);
        if (product == null || product.Quantity < amount)
        {
            return false; // Rule enforced: No negative stock
        }

        // Since Product is a record (immutable), we replace it
        int index = _products.IndexOf(product);
        _products[index] = product with { Quantity = product.Quantity - amount };
        return true;
    }

    public IEnumerable<Product> GetAllProducts() => _products.AsReadOnly();
}

Keeping the Console Out of Your Business Logic

Another thing I want you to notice: there is not a single Console.WriteLine inside the InventoryManager. This is critical. Your manager should be "headless." It doesn't know it's being used in a console app; it could just as easily be powering a website or a mobile app. It returns bool values or objects, and it's the Program class's job to decide how to tell the user about it.

When you put the UI in the manager, you make the code impossible to unit test. You can't easily write a test that checks if TryRemoveStock works if the method is busy printing text to a screen. Keep the logic pure, and keep the Console calls in your main loop. It feels like more work upfront, but it's the only way to keep your sanity as the codebase expands.




📋 Practical Task

Implementing a Low-Stock Alert Filter

You have the base InventoryManager and Product logic from the lesson. Your task is to extend the InventoryManager class to support a "Low Stock Report."

  • Add a new method to InventoryManager called GetLowStockProducts.
  • This method should accept an integer parameter called threshold.
  • The method must return a collection of all products whose Quantity is strictly less than the provided threshold.
  • In your Main method, implement a console command that asks the user for a threshold value and then prints the name and current quantity of every product that falls below that limit.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.