跪拜 Guibai
← Back to the summary

Boolean Variable Names Are Questions Your Code Asks — Make Them Readable

0.png

The Problem

Suppose you just took over a project and then saw code like this:

public class OrderProcessor
{
    private bool open;
    private bool flag;
    private bool done;
    private bool status;
    
    public void Process(bool check)
    {
        if (open && flag)
        {
            flag = false;
            status = true;
        }
        
        if (done)
        {
            // What happens here?
        }
    }
}

Damn! Is this code easy to read?

If you think there's no problem, let me ask you a few questions:

Looking at the variable names alone, we simply cannot determine their intent.

Ambiguous Boolean variables are like landmines buried in the code. They usually seem fine, but when it's time to fix a bug or you have to troubleshoot code in the middle of the night, you realize you have no idea what they're trying to express.

Ambiguity easily leads to bugs.

During review, a reviewer seeing if (done) can only guess the developer's intent; a later maintainer seeing flag = false might also, because they didn't understand the original logic, casually invert the condition.

Look at if (!flag): is it turning a feature on, or turning a feature off? No one knows.

The reason Boolean variable names are important is that they are not just ordinary labels; they are more like a question. The code poses the question, and the Boolean value is responsible for answering true or false.

If the variable name itself cannot form a clear question, then whether the answer is "yes" or "no" has little meaning.

Four Tips

In the vast majority of common scenarios, we can start by considering the following four prefixes. They may not cover all Boolean naming, but they are enough to turn most variables into a clear, grammatically correct question.

1. is: Identity and State

When we want to describe what state an object is currently in, we can use is. It is usually followed by an adjective.

isAccess is not grammatically natural. If you want to express "has access permission," a more suitable name is hasAccess.

2. has: Possession, Containment, and Characteristics

When we want to express whether an object possesses some content, contains an element, or has a certain characteristic, we can use has. It is usually followed by a noun.

active describes a state, so isActive should be used here.

3. can: Ability and Permission

When we want to confirm whether an object has the ability or permission to perform an operation, we can use can.

The meaning of canAdmin is relatively vague. If you want to express the user's identity, you can use isAdmin; if you want to express whether the user can perform administrative operations, you can use canAdminister.

4. should: Intent and Decision

When a Boolean value represents a business rule, or whether the system should perform an operation next, you can use should.

It can distinguish "can we do it" from "should we do it."

shouldUser is not a complete question. Does it mean shouldCreateUser, or some other operation? You can't tell just by looking at the name.

Once these prefixes are mixed up, for example by writing isAccess or hasActive, the reader has to stop and mentally reorganize the sentence. This pause during code reading is often precisely where misunderstandings and bugs appear.

Prefix Scenario Role Example
is Identity / State Describes what or what state the object is in isActive, isEmpty
has Possession / Containment Describes whether the object has some content or characteristic hasChildren, hasAccess
can Ability / Permission Describes whether the object can perform an operation canEdit, canRetry
should Intent / Business Logic Describes whether an operation should be performed according to rules shouldCache, shouldRetry

Try to Avoid Negative Naming

1.png

There is another very practical piece of experience in Boolean naming: Try to use the positive form; do not write the negation directly into the variable name.

For example:

Why try to avoid this style? Because sooner or later, the code may need to check their opposite state.

if (!isDisabled)

Seeing this code, the brain needs to first understand "disabled," then negate it, and finally conclude "enabled." This is effectively a double negative.

In contrast, the following way is much more direct:

if (isEnabled)

The negative form might feel natural when defining the variable, and even be very useful in certain code flows — "I just want to check right now if it is disabled."

But for everyone reading the code later, it can bring extra cognitive cost.

Refactoring tools can sometimes make the problem worse and more obvious.

Suppose we invert an if condition, and the IDE conveniently changes isDisabled to isNotDisabled. The resulting name will only be harder to read.

However, this rule does not mean isDisabled can never be used.

If "disabled" itself is a well-defined state in the business domain, using it might be more accurate than awkwardly coining an antonym.

What should really be avoided is naming that frequently combines with !, forcing the reader to repeatedly compute double negatives.

A Common Exception

If the program needs to map an external API, or map an HTML attribute that defaults to a negative form, such as noValidate, then keeping the external name is usually reasonable.

Even so, try to confine this naming to the system boundary. In internal business logic, convert it to the positive form:

bool shouldValidate = !request.noValidate;

Don't Apply Property Naming Rules Directly to Method Parameters

The previous rules are mainly suitable for properties or variables describing state. But if a Boolean appears in a method parameter, just writing the name clearly is often not enough.

This is what is commonly called the Boolean Trap:

// Real code from an open-source library
schemaExport.Execute(false, true, false);

Without looking at the method definition, can you immediately tell what the second true actually controls? Obviously not.

You have to open the documentation or source code and reconfirm the meaning of each parameter.

When a method signature approaches Execute(bool, bool, bool), it usually means its API design is already problematic. The method call is reduced to a string of true and false, and the business meaning the parameters originally wanted to express has completely disappeared.

1. Split the Method

If a Boolean parameter causes the method to execute completely different behaviors, you can directly split it into two semantically clear methods.

// Not recommended
email.Send(message, true); // Is true "send immediately" or "high priority"?

// Recommended
email.SendImmediately(message);
email.SendQueued(message);

2. Use an Enum

If a Boolean represents different execution modes, you can use an Enum to name each mode.

// Not recommended
file.Write(data, true);

// Recommended
file.Write(data, WriteMode.Append);

3. Use a Configuration Object

If a method needs to receive multiple switches, you can collect them into a configuration object.

// Not recommended
export.Execute(false, true, false);

// Recommended
export.Execute(new ExportOptions { 
    Script = false, 
    Export = true, 
    JustDrop = false 
});

In this way, what each value controls is directly displayed at the call site, without needing to guess based on parameter position.

Several Common Anti-Patterns

If you are preparing to tidy up Boolean naming in a project, you can focus on the following types of problems during Code Review.

1. "Just pick a name" variables

Names like flag, done, check do not tell the reader: what state is the program actually recording?

2. Prefix and grammar mismatch

Incorrect use of prefixes destroys the semantics the variable is supposed to express.

3. Double negatives

When ! appears together with a variable name containing negative meanings like Not, No, it is usually worth re-examining.

4. Boolean variables wearing multiple hats

Some Boolean variables appear to represent a single result on the surface, but secretly mix multiple conditions behind the scenes.

For example:

It actually checks: the user exists, has filled in an email, and is currently in an active state.

In this case, rather than using the broad-meaning isValid, it's better to directly write out the real business meaning:

bool isReadyForBilling = user.Exists && user.HasEmail && user.IsActive;

5. Temporary flags that constantly change meaning

Another common pattern is reusing the same local Boolean variable repeatedly in different logic stages.

bool error = false;
if (!Save()) error = true;
if (!error && !SendEmail()) error = true;
return error;

Here, error is like a bucket used over and over: a save failure goes in, an email send failure goes in. As the flow continues to grow, its meaning only becomes more and more vague.

A more appropriate approach is to use a Result object, or to return early directly upon failure, rather than repeatedly recycling the same Boolean variable.

Summary

Naming is not just a code style issue; it also determines how much cost later people must pay to understand this code.

When you name a Boolean variable flag, you are only saving yourself a little time at the moment of writing the code.

When you name it isProcessed, you are taking care of the person who has to come back and fix a bug six months later.

Of course, that person is very likely the future you.