Name Your Logic

The bare-minimum when refactoring is not viable

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 do
  • CanWe() - 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
}