Understanding the "Tell, Don't Ask" Principle Through Real-World Scenarios in C#
Admir Mujkic
Solution Architect | Engineering Leader | Driving Scalable, Innovative Software Solutions and Technical Leadership
In today's article, I will cover one particular programming concept which would allow you to tidy up code, making it more effective. The concept is "Tell. Don't Ask". To do that, we would illustratively demonstrate the concept through a metaphor in the world of banking which should make understanding easy for you. I'll break it down in simple terms, and we'll explore diagrams and C# code snippets to make it all come alive.
What is Tell, Don't Ask?
It's sort of like training a dog. Instead of checking if the dog is sitting and then you say fetch, it would just be telling the dog fetch. Then the dog knows if it can fetch or not. This way, you're not micromanaging the dog's actions. You're trusting it to do its job.
Scenario with Banking Business
Let's say you're developing a banking application. You have a BankAccount class that contains information like balance, account number, and so on.
Traditional Approach - Ask, then Tell
In this method, you ask the BankAccount for its balance and then decide whether to proceed with the withdrawal or not.
public class BankAccount
{
public decimal Balance { get; private set; }
public void Withdraw(decimal amount)
{
if (Balance >= amount)
{
Balance -= amount;
}
else
{
throw new Exception("Insufficient funds");
}
}
}
// Client code
BankAccount account = new BankAccount();
if (account.Balance >= 100)
{
account.Withdraw(100);
}
Modern Approach - Tell, Don't Ask
Here, you directly tell the BankAccount to handle the withdrawal. The account itself is responsible for checking if it has sufficient funds.
public class BankAccount
{
public decimal Balance { get; private set; }
public void Withdraw(decimal amount)
{
if (CanWithdraw(amount))
{
Balance -= amount;
}
else
{
throw new Exception("Insufficient funds");
}
}
private bool CanWithdraw(decimal amount)
{
return Balance >= amount;
}
}
// Client code
BankAccount account = new BankAccount();
account.Withdraw(100);
领英推荐
When should we consider the principle "Tell, Don't Ask"?
Encapsulation
When you follow the "Tell, Don't Ask" principle, fundamentally you're giving ownership of managing it's inner state to the object. This enhances encapsulation in the way you're not exposing the internals of the object. Instead, you are instructing the object to take care of its duties like a well-trained dog knowing when to sit, stay or fetch.
Readability
Code following the principle of "Tell, Don't Ask" usually is the one easy to read. Indeed, it reduces your cognitive load in order to understand what code will do next. You don't have to keep track of many conditions or states, you simply state what you want the object to do and it takes care of that on its own. It's like reading a well-written book the story flows naturally without having you jump back and forth between pages.
Maintainability
If the behavior is encapsulated into the object, any future changes made in that behavior will require changes to take place only at one location. This creates a codebase that can be maintained and fewer bugs occur. Imagine you have a car; if all the controls are in one place (the dashboard), it's easier to operate and fix. You do not have to go to different parts of the car to turn on the headlights, adjust the air condition or tune radio.
Reduced Complexity
By telling an object what to do, you localize the behavior and hence reduce the complexity. You don't have to write complex client code which has to handle various states and conditions. The object itself takes care of that making the overall system simpler.
For the end
The "Tell, Don't Ask" principle is handy as a guiding code rule that brings several benefits in the perspective of software development. It helps to have an exclusive way for enhancing the concept of encapsulation enabling objects to manage their own state as well as discouraging accessing internals. This thus results to a more readable and maintainable code, since you don't have to dig in the state of an object so as to understand its responsibility. Also, it invites the flexible code there is easy change and extension of the code in near future. Overall, adherence to "Tell, Don't Ask" can highly enhance your quality of code base.
Cheers! ??
Systems architect | Azure devops specialist | passion for development | loves .NET
1 年This is a problem, what occurs in a lot of systems, where is the business logic defined; in this principle the responsiblity is clearly devided. Nice post!
Driving Tech Innovation & Transforming Ideas into Market-ready Solutions | 15+ Years in Software Development
1 年Thanks for sharing!
Business Development Manager at Scimus | Helping businesses to go from Good to Great through automation
1 年Great analogy! Making the transition from 'asking' to 'telling' can really streamline any coding process. It's convenient to let an object manage its own state.