Despite best efforts, we will all at some point or another come across “stars-align” logic. It usually sits at the intersection of business logic and technical requirements (a smell of it’s own) and looks a little something like this:
if (model.SomeProperty.HasValue
&& model.OtherProperty > config.MinimumPermitted
&& user.HasPermission
&& (!model.RequiresFeatureX || featureX.IsEnabled))
{
// Preferred Behaviour
}
else
{
// Plan B
}
We’re already in a bad place here and the ideal solution is to refactor. We should never have reached this point, but code rot is a death by a thousand cuts and there’s only so much technical debt that can be factored into your workload.
In these cases, I find the lowest-risk, bare-minimum solution is turn complex conditions into a boolean function. This is fairly obvious advice but I rarely see it employed - likely because such a function already breaches the Single Responsibility Principle. So then why not use multiple functions? I find that following convention helps to distinguish between the two
ShouldWe()
- Makes a value judgement on what the business wants us to doCanWe()
- Do we have everything we need from a technical perspective
The example above now becomes:
if (ShouldDoPreferred() && CanDoPreferred())
{
// Preferred Behaviour
}
else
{
// Plan B
}
...
private bool ShouldDoPreferred()
{
return user.HasPermission
&& (!model.RequiresFeatureX || featureX.IsEnabled);
}
private bool CanDoPreferred()
{
return model.SomeProperty.HasValue
&& model.OtherProperty > config.MinimumPermitted
}