Skip to main content
added 4 characters in body
Source Link
Flater
  • 59.5k
  • 8
  • 112
  • 171

But I still agree with the orignal intention of the "no logical flow" rule

As a basic example of boolean usage where I do agree with you that it should not happen:

public void AddName(string name, bool alsoAddLowerCaseName)
{
    _myList.Add(name);

    if(alsoAddLowerCaseName)
        _myList.Add(name.ToLower());
}

It would be much better by letting the consumer call the Add method twice.

string name = "Robert";

AddName(name);
AddName(name.ToLower());

The consumer retains the same control (choosing whether to add the lower case name or not) but it does not require you to keep changing the method for new possibilities (e.g. upper case, reversed string, HTML encoded string, ...)

I believe that these cases are the core concern of your "no logical flow booleans" argument and I do agree with you there.

But I still agree with the orignal intention of the "no logical flow" rule

As a basic example of boolean usage where I do agree with you that it should not happen:

public void AddName(string name, bool alsoAddLowerCaseName)
{
    _myList.Add(name);

    if(alsoAddLowerCaseName)
        _myList.Add(name.ToLower());
}

It would be much better by letting the consumer call the Add method twice.

string name = "Robert";

AddName(name);
AddName(name.ToLower());

The consumer retains the same control (choosing whether to add the lower case name or not) but it does not require you to keep changing the method for new possibilities (e.g. upper case, reversed string, HTML encoded string, ...)

I believe that these cases are the core concern of your "no logical flow booleans" argument and I do agree with you there.

added 4 characters in body
Source Link
Flater
  • 59.5k
  • 8
  • 112
  • 171

Note that in this case, isReadonly again acts as a data-boolean as opposed to a logical-flow-boolean. It's the same underlying principle as the previous example. 

Whether you consider the boolean "passed" on is very arguable. While passing it to a submethod obviously counts as passing it on, does setting a property count too? I think this is highly subjective and liable to opinionated feedback.

Note that in this case, isReadonly again acts as a data-boolean as opposed to a logical-flow-boolean. It's the same underlying principle as the previous example. Whether you consider the boolean "passed" on is very arguable. While passing it to a submethod obviously counts as passing it on, does setting a property count too? I think this is highly subjective and liable to opinionated feedback.

Note that in this case, isReadonly again acts as a data-boolean as opposed to a logical-flow-boolean. It's the same underlying principle as the previous example. 

Whether you consider the boolean "passed" on is very arguable. While passing it to a submethod obviously counts as passing it on, does setting a property count too? I think this is highly subjective and liable to opinionated feedback.

added 1001 characters in body
Source Link
Flater
  • 59.5k
  • 8
  • 112
  • 171

Data vs logic

Booleans as data

LogicallyBy excluding booleans for logical flow, we haven't yetactually excluded booleans that function as data. 

For example, while you might expect an update method to look like this:

And this is a basic example of why boolean parameters do exist. Some data simply has an innate binary nature, and therefore it is best represented by a boolean.

Let's ignore the "dead people can't come back alive" argument and say that we allow for fixing bad data (we thought the person was dead but we were wrong). I picked living/dead because we can all agree that this is a binary value. Other options exist but I picked the one with the most commonly agreed upon consensus.

No passing allowed?

Booleans should never change logical flow?

HoweverI also find the "no logical flow repercussions from booleans" argument to be excessively broad and restrictive. Taken to heart, you're effectively suggesting that the if statement should have never existed.

I can also think of cases where the boolean causes logical flow variations yet still is relevant, e.g. if the backend uses separate componentsexternal services for handling living/deceased people.

Consider an application which connects to external services (onee.g. government registry: one for the living, one for the deaddeceased), where you do not want to expose to your user that different services are being used. "Unbooleaning" a method leads to something along the lines of

But this requires the consumer (i.e. the user of your backend service) to know that there is separate handling for living/deceased people, and this may be considered a leaking abstraction in certain scenarios.

It's perfectly reasonable for your application to specifically hide that fact that there are separate repositories. For example, maybe the living/deceased resource split happened after your application went live (it used to be the same resource) and you're trying to implement it without affecting your public API.

Another example

JustWhile I think there's no real reason to differentiate between methods with only a boolean parameter and methods with multiple parameters (one of which is a boolean), I'll humor you and give you an additional example of a function with only a boolean parameter:

Note that in this case, isReadonly again acts as a data-boolean as opposed to a logical-flow-boolean. It's the same underlying principle as the previous example. Whether you consider the boolean "passed" on is very arguable. While passing it to a submethod obviously counts as passing it on, does setting a property count too? I think this is highly subjective and liable to opinionated feedback.

Logically, we haven't yet excluded booleans that function as data. For example, while you might expect an update method to look like this:

And this is a basic example of why boolean parameters do exist. Some data simply has an innate binary nature, and therefore it is best represented by a boolean.

However, I can also think of cases where the boolean is relevant, e.g. if the backend uses separate components for living/deceased people.

Consider an application which connects to external services (one for the living, one for the dead), where you do not want to expose to your user that different services are being used. "Unbooleaning" a method leads to something along the lines of

But this requires the consumer (i.e. the user of your backend service) to know that there is separate handling for living/deceased people.

It's perfectly reasonable for your application to specifically hide that fact. For example, maybe the living/deceased resource split happened after your application went live (it used to be the same resource) and you're trying to implement it without affecting your public API.

Just to give you an additional example of a function with only a boolean parameter:

Note that in this case, isReadonly again acts as a data-boolean as opposed to a logical-flow-boolean. It's the same underlying principle as the previous example.

Data vs logic

Booleans as data

By excluding booleans for logical flow, we haven't actually excluded booleans that function as data. 

For example, while you might expect an update method to look like this:

And this is a basic example of why boolean parameters do exist. Some data simply has an innate binary nature, and therefore it is best represented by a boolean.

Let's ignore the "dead people can't come back alive" argument and say that we allow for fixing bad data (we thought the person was dead but we were wrong). I picked living/dead because we can all agree that this is a binary value. Other options exist but I picked the one with the most commonly agreed upon consensus.

No passing allowed?

Booleans should never change logical flow?

I also find the "no logical flow repercussions from booleans" argument to be excessively broad and restrictive. Taken to heart, you're effectively suggesting that the if statement should have never existed.

I can also think of cases where the boolean causes logical flow variations yet still is relevant, e.g. if the backend uses separate external services for handling living/deceased people.

Consider an application which connects to external services (e.g. government registry: one for the living, one for the deceased), where you do not want to expose to your user that different services are being used. "Unbooleaning" a method leads to something along the lines of

But this requires the consumer (i.e. the user of your backend service) to know that there is separate handling for living/deceased people, and this may be considered a leaking abstraction in certain scenarios.

It's perfectly reasonable for your application to specifically hide that fact that there are separate repositories. For example, maybe the living/deceased resource split happened after your application went live (it used to be the same resource) and you're trying to implement it without affecting your public API.

Another example

While I think there's no real reason to differentiate between methods with only a boolean parameter and methods with multiple parameters (one of which is a boolean), I'll humor you and give you an additional example of a function with only a boolean parameter:

Note that in this case, isReadonly again acts as a data-boolean as opposed to a logical-flow-boolean. It's the same underlying principle as the previous example. Whether you consider the boolean "passed" on is very arguable. While passing it to a submethod obviously counts as passing it on, does setting a property count too? I think this is highly subjective and liable to opinionated feedback.

Source Link
Flater
  • 59.5k
  • 8
  • 112
  • 171
Loading