First time here? You are looking at the most recent posts. You may also want to check out older archives or the tag cloud. Please leave a comment, ask a question and consider subscribing to the latest posts via RSS. Thank you for visiting! (hide this)

Over the last few months I worked, on my spare time, on a new web development project: the site for the Web.NET Conference. It was a refreshing experience, going back working on custom development on ASP.NET MVC 4 and all the latest bits of technology.

That gave me quite a few ideas for posts, so over the next weeks I'm going to blog about some of the bits and pieces of code that I think are worth sharing with the community, like ActionResults, HtmlHelpers together with my first real-coding experiences with RavenDb.

As first post I’m not focusing on something about a technology, but I want to tell why you should never model a data field as Boolean, and instead start directly with an Enum.

How the problem started

I'm going to tell you what happened during the development of the registration and payment parts of the Web.NET Conference.

I needed to keep track of whether someone has paid or not, so I started modeling that field as a simple boolean value, HasPaid. I also wanted to show them a different message depending on whether they paid or not, to remind them they had to pay in order to get the meal they ordered. To achieve that I checked the value of the HasPaid field: after a while I realized that also people that didn't order a meal had the HasPaid to false, as indeed they didn't pay because they didn't have to.  
So in this confirmation screen I also checked whether the total of what they had to pay was different from 0. And it was still manageable.

After a while someone asked if they could pay at the registration desk as in their country PayPal was not operating: so I moved them manually to HasPaid=true and added in the note field that they will pay at the desk, so that their lunch and were taken into account.

Then again something else happened: someone that has already paid unregistered and left what he paid as donation for the conference. Now I needed to filter out their meals, their participation at the conference, but still keep their payment in the count of the donations received, unlike the ones that asked for a refund for which I need to filter out also the payment: this was becoming a nightmare to handle with the original HasPaid field.

On with the refactoring

One evening I sat down, and refactored the payment procedure and all reports to go from a simple boolean to an Enum with the following options:

  • Undefined
  • DidntPay (the original HasPaid=false)
  • NoNeedToPay (for those how didn't reserve a meal or gave no donation)
  • Paid (the original HasPaid=true)
  • PaysAtRegistration (for the guys who couldn't pay online)
  • Refunded (if someone cancels, and wants his money back)

And after the refactoring and making sure all reports and state transitions were using the new Enum, I also had to build a small script to convert all the data inside the RavenDb repository (and this is something interesting I’d probably write a blog post about).

Another example of the same problem

The same problem occurred with the registration status: it started with 2 booleans, IsRegistered and IsWaitlist, then expanded with HasCancelled and WasApprovedFromWaitList and all crazy combinations of boolean expressions to understand his real status, and then, in that very same refactoring session, it all became a more clear and easier with that Enum:

public enum RegistrationStatus
{
    Undefined,
    Confirmed,
    WaitingForPayment,
    Waitlist,
    Cancelled,
    Approved,
    ApprovalNotConfirmed
}

State Machine/Workflow

The benefit of this approach is that both registration and payment became two state machines, and it was much more easy to implement a very simple workflow with the possibility to set allowed and forbidden transition (for example, someone in waitlist couldn’t become “confirmed” without passing from the “approved” status), and action that needs to be done when a given state transition happens. Here is an example of what the transition rules look like: previously with the combination of booleans it was crazy, and very easy to make logical mistakes.

public static class RegistrationFlow
{
    public static void RegistrationStatusTransition(RegistrationStatus newStatus,
        Registration registration)
    {
        switch (newStatus)
        {
        ...
        case RegistrationStatus.WaitingForPayement:
            if(registration.RegistrationStatus!=RegistrationStatus.Undefined &&
            registration.RegistrationStatus!=RegistrationStatus.Approved)
                throw new ArgumentOutOfRangeException("newStatus",
                String.Format("{0} -> WaitingForPayement not allowed",
                registration.RegistrationStatus));
            if(registration.PaymentStatus==PaymentStatus.NoNeedToPay)
                registration.RegistrationStatus = RegistrationStatus.Confirmed;
            else
                registration.RegistrationStatus = RegistrationStatus.WaitingForPayement;
            break;
        case RegistrationStatus.Confirmed:
            if(registration.RegistrationStatus!=RegistrationStatus.Undefined &&
            registration.RegistrationStatus!=RegistrationStatus.WaitingForPayement &&
            registration.RegistrationStatus!=RegistrationStatus.Approved)
                throw new ArgumentOutOfRangeException("newStatus",
                String.Format("{0} -> Confirmed not allowed",
                registration.RegistrationStatus));

            registration.RegistrationStatus = RegistrationStatus.Confirmed;
            break;
        ...
        }
    }
}

Lesson Learned

When I tweeted about this while I was refactoring, someone told me: “Using a boolean is an antipattern”… well… now I experienced it myself.

From this experience, in the future, I’ll never use a Boolean field again, and always start with an Enum, especially with a Document database where migrating data is a bit more complex than with relational databases.

UPDATE: Given the comments received I’d like to clarify a bit my position. I’m not saying booleans are not to be used at all: booleans have value, just not when the the thing you are trying to model is a state and not just a real/physically boolean value.

posted on Monday, November 19, 2012 10:29 AM

Comments on this entry:

# re: Why you should never use a boolean field (use an Enum instead)

Left by Yves Reynhout at 11/19/2012 11:11 AM

Might I suggest you have a look at Stateless (http://code.google.com/p/stateless/) for writing internal statemachines.

# re: Why you should never use a boolean field (use an Enum instead)

Left by Simone at 11/19/2012 11:15 AM

Thank you, since it's a kind of pet app, I'll look into it the first time I have the chance.

# re: Why you should never use a boolean field (use an Enum instead)

Left by Jason Meckley at 11/19/2012 2:15 PM

I think the idea of "boolean is an antipattern" is dogmatic and a little short sited. I agree that state management is not ideal for a boolean value, but booleans have value.

Some would say that enums are an anti-pattern. Again, it all depends on the complexity of the functionality and how/where you want to encapsulate the logic.

# re: Why you should never use a boolean field (use an Enum instead)

Left by Jef Claes at 11/19/2012 2:46 PM

I think you're overgeneralizing. A boolean is the correct type for lots of scenarios. Here, you learned more about your domain along the way; it's okay to refactor and introduce an enum as you learn yes/no doesn't get the job done anymore.

# re: Why you should never use a boolean field (use an Enum instead)

Left by Simone at 11/19/2012 3:42 PM

I know over-generalization sucks, but recollecting all my previous projects, I found out that normally a boolean never gets the job done, unless you are modelling a digital phenomena that is only true/false.
When you model natural actions, and especially human, there is always a kind of uncertainty: this is why probably they came out with the nullable boolean too.
Just to be clear, I'm not saying boolean values are not to be used, ever. Just not when design a domain model. Of course they are great in viewmodels, or inside algorithms or logical statements.

# re: Why you should never use a boolean field (use an Enum instead)

Left by Mauricio Scheffer at 11/20/2012 6:37 AM

Or better yet, use an algebraic data type! (encoded as a closed class hierarchy)

# re: Why you should never use a boolean field (use an Enum instead)

Left by peterchen at 11/20/2012 7:37 AM

Oh. My. God. I could take that "Using a boolean is an antipattern" tongue in cheek, but I'm sadly certain it will be parroted over and over.

To put it bluntly to extremes: either you are in the agile camp and introduce the enum when needed, or you believe in design and might avoid the "boolean detour" in this place. Or you are somewhere inbetween and remember "the right type for the right job". ----

There is some redundancy to be expected, e.g. a "PayStatus=NeedsToPay" field vs. an AmountDue field. Nothing serious - OTOH we used to joke about the $0.00 check that won't go away...

# re: Why you should never use a boolean field (use an Enum instead)

Left by GregBrannon at 11/20/2012 12:34 PM

"Everything should be
as simple as it can be, but not simpler."

The original design was too simple because (I may unfairly assume) not enough time was spent defining and documenting the requirements before coding began. This experience doesn't mean that booleans are dead or useless. When the job is simple, booleans will still often be the right tool for the job and an enum may violate the KISS principle.

# re: Why you should never use a boolean field (use an Enum instead)

Left by sivanesan at 11/20/2012 2:12 PM

Thanks for d blog, very useful tutorial...

# re: Why you should never use a boolean field (use an Enum instead)

Left by Anthony Trudeau at 11/20/2012 2:43 PM

It's probably all been said, but the conclusion of your article is at fault. Whenever you use the word "always" or "never" you need to do some refactoring of the non-code sort. Boolean was certainly not the right fit in this instance. But the root problem was poor requirements gathering. It's easy to scapegoat some implementation choice, but if you do that you miss the opportunity to learn from your mistake. That puts you in the position to make yet another one in the future.

# re: Why you should never use a boolean field (use an Enum instead)

Left by Simone at 11/20/2012 4:18 PM

It's funny that everyone says that there was a faulty analysis or requirements gathering: no matter how much effort you put into gathering requirements, you'll always learn something new about your model and business while you are working on it, so some refactoring will always be required.
Problem is that refactoring from a boolean to an Enum is very very painful, especially when your object gets serialized as is without going through any mapping or conversion (NoSQL vs Relational DB).

# re: Why you should never use a boolean field (use an Enum instead)

Left by Vlad at 11/20/2012 4:41 PM

This is what happened: 1. You wanted a cap of coffee. 2. You got an empty Coca Cola can, filled it up with water from your neighbor's well, made fire on your back yard, and begun boiling that water in that can over that fire. But later, after 100 issues that you faced during that process, you realized that you've got a coffee machine in your kitchen.

Anthony is right - poor requirements gathering. This happens when you begin coding without thinking what exactly do you need to code. And please don't blame The Boolean. Look at your comment form. See the Remember Me? check box. First, you need to remove that question mark. Otherwise, I'd like to answer that question like this: "No, I don't remember you! I just want your form to remember ME the next time I come here." Second, try to justify the use of an enum to describe the state of that box. That's right. Long live The Boolean! :)

# re: Why you should never use a boolean field (use an Enum instead)

Left by Craig at 11/20/2012 4:56 PM

I'm afraid I have to agree with the people who are defending boolean. If every time I needed a boolean I started with an enum I'd have enums all over my system with two values, the equivalent of "true" and "false." ActiveState.Active and ActiveState.Inactive might as well be a boolean. If refactoring is that painful then maybe you're using the wrong tools. Personally I'm getting tired of the condescending "oh, that's an anti-pattern" that I keep hearing. If I need to pound a nail I'll use a hammer, I'm not going to use a skillsaw.

# re: Why you should never use a boolean field (use an Enum instead)

Left by Amon at 11/20/2012 5:57 PM

Great article title. I clicked on it just because it was outrageous. Won't stop using boolean values, but I've experience similar situations. The more boring title "Refactoring booleans to enums when modeling state machines" probably wouldn't have garnered much attention. Anyway, thanks!

# re: Why you should never use a boolean field (use an Enum instead)

Left by Jeff at 11/20/2012 6:49 PM

How did the enum ease your bussiness logic? You still are tracking has paid, approved and transaction status? Each value defined by the current status. You still only need 2 bools and an array that maps the value of the 2 booleens from what I see. Now who has the permission to set the "approved" which appears to be your issue your programming. Has a required step been done. This can be managed by populating a dropdown according who can do what.
You appear to be looking at your data as independant information pieces when it(the data) really isn't.... just my 2 cents.

# re: Why you should never use a boolean field (use an Enum instead)

Left by Erik Dietrich at 11/20/2012 8:24 PM

Simone, for what it's worth, I don't fault you for having new requirements come in -- go with what you know and make sure your code is designed well enough to adapt.

The issue I have here is that I think this goes the wrong direction from the spirit of "boolean is an anti-pattern." I imagine (though I can't speak for the person saying it, obviously), that they meant that boolean state flags as op-codes were an anti-pattern and, if that's the case, then an enum/switch paradigm is an exponential anti-pattern. Because what is an enum but a series of constant values with implied "is the thing equal to this one?" boolean conditions. That is, you traded one boolean state flag for six of them.

I would reconsider the object modeling and context for something like this. In other words, if I have something called "registrant" and it has a status flag of "isPaid", but that's not good enough because I also need "undefined" then I'm overreaching with this model. Isn't an "undefined registrant" just "not a registrant"? Why not have an object called "prospect" that becomes "registrant" when it registers. And why not have it become "reject registrant" if it's rejected? Using boolean state flags (and worse, enum state flags) you have a "registrant" that's a registrant and a bunch of other things too, depending on what's going on, which means that I have to query the thing and ask it questions to understand what it is. And *that* is the anti-pattern, IMHO.

# re: Why you should never use a boolean field (use an Enum instead)

Left by Andrei Rinea at 11/22/2012 1:16 AM

I agree to Simone. I can also add that booleans make less readable code. Compare :
<br/>
StartProcessing(true, false, true);

with

StartProcessing(Mode.Async, DependenciesBehavior.DoNotLoad, NotificationMode.OnExit);

# re: Why you should never use a boolean field (use an Enum instead)

Left by Simone at 11/22/2012 12:09 PM

@Jeff: of course here I'm just showing data, I couldn't put all the other components of the application in the blog post

# re: Why you should never use a boolean field (use an Enum instead)

Left by Visitor at 11/22/2012 4:39 PM

That's why they didn't define a boolean type in C.
If you only care about true vs. false, then your business logic will test for 0 vs. !0, but if you need to distinguish between different states, you'll use 0, 1, 2, ... So they were smart when they realized that an int will do the job. :)))

# re: Why you should never use a boolean field (use an Enum instead)

Left by Michael Lang at 11/25/2012 6:45 PM

@Andrei. Not a problem with booleans... just name your arguments.


StartProcessing(isAsync=true, loadDependencies= false, mode=NotificationMode.OnExit)


Only have an enum where there is more than two states. You can also pass in a parameters object.


StartProcessing(new ProcessingOptions(){IsAsync=false, LoadDependencies=false, NotificationMode=NotificationMode.OnExit});


Even worse than a bunch of boolean options to a method is having the same number of enum types defined with just two opposing values in each.

# re: Why you should never use a boolean field (use an Enum instead)

Left by Stephen Watkins at 11/26/2012 4:55 PM

Booleans are not the problem. Neglecting to think beforehand about what the code actually needs to do is the problem. Clearly you had more possibilities than "True" and "False" for the values you wanted to store.

In other words, don't use a hammer to change the channel on your television.

Comments have been closed on this topic.