Let\'s say I have a method DoTheThing() which requires the precondition-check Ca
ID: 644300 • Letter: L
Question
Let's say I have a method DoTheThing() which requires the precondition-check CanTheThingBeDone() to return true. The latter method is time consuming as it accesses the database.
I'm finding it hard to find a perfect way to perform the precondition check effectively (i.e. once) while maintaining both readability and API integrity. Observe these examples:
Example 1:
class System() {
public void DoTheThing() {
if (!CanTheThingBeDone()) throw new Exception(...);
// Do it
}
public bool CanTheThingBeDone() {
// Some time consuming code
}
}
class Consumer() {
public void SomeLargerOperation() {
try {
system.DoTheThing();
}
catch (Exception) {
// Error handling
}
}
}
Example 2:
class System() {
public void DoTheThing() {
// Do it
}
public bool CanTheThingBeDone() {
// Some time consuming code
}
}
class Consumer() {
public void SomeLargerOperation() {
if (system.CanTheThingBeDone()) {
system.DoIt();
}
}
}
Both approaches are ok, but both have drawbacks. In Example 1, I'm forcing the consumer to wrap the code in a try-catch for faulty states. These states can be user-triggered so some graceful handling is required. I'm unsure if try-catch for handling user-errors is a good approach.
In Example 2 I'm handing the responsibility of state-checking over to the consumer, opening up for non-descriptive runtime errors. In this example, CanTheThingBeDone() is checked, but when Jimmy enters the team 1 year from now to develop module 2, that might change.
Example 3:
class System() {
public bool DoTheThing() {
if (!CanTheThingBeDone()) return false;
// Do it
return true;
}
public bool CanTheThingBeDone() {
// Some time consuming code
}
}
class Consumer() {
public void SomeLargerOperation() {
if (!system.DoTheThing()) ProduceSomeErrorMessage();
}
}
Now in this example, I avoid try-catch for user errors and prevent the actual Do-code to be executed if invalid state, while ensuring the check-code is run only once. But I feel I'm breaking some naming/coding principle when the method is both performing check and modifying class state (I'm pretty sure it even has a name).
As a fourth example, I could envision a combination of #1 & #2 where both the consumer and DoTheThing calls CanTheThingBeDone, but then we're doing the work twice.
To sum up - I can't seem to find a best approach. Anyone have a better idea than mine, or suggestions on how to tweak one of these approaches for a better result?
Explanation / Answer
There is one rule I like: When in doubt, create an object. C# is an OOP language, not functional after all. So thinking in objects is much better than thinking in methods.
public abstract class ExpensiveOperation
{
bool wasTested = false;
bool canBeDone = false;
protected abstract bool Precondition();
protected abstract void DoExecute();
public bool CanExecute()
{
if (!wasTested)
{
canBeDone = Precondition();
wasTested = true;
}
return canBeDone;
}
public void Execute()
{
if (!CanExecute())
throw new Exception("Cannot execute");
DoExecute();
}
}
Then you just derive this for your custom operation with precondition. It has many good properties:
It encapsulates the operation with it's precondition
Ensures the precondition is called and operation cannot be executed if precondition fails
Ensures the precondition is called only once no matter what caller does.
Give caller option to check if it can be executed if necessary
You just supply the code for precondition and operation, no need to create more code
Ensures the caller cannot bypass this precondition logic
Related Questions
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.