It is relatively common to find (or write) a line of code like this
var thingy = new Thingy(_someDependency, false);
Reading this line a person can know this is initialising a Thingy
which takes a dependency on something… and something else is false.
I'm really lazy and easily distracted so I don't like to have to think about anything except the one task I'm trying to not get distracted from. Having to think about what it means that something is false provides an opportunity for me to get distracted.
Also, this means there is some information or some decision that has been taken by a previous developer that they have kept in their brain - all the person reading this line sees is the result of that. Each time somebody comes to this class they may have to invest time reminding themselves what the boolean parameter means.
Can it be better?
Well, C# (as well as other languages) allows named parameters so this Thingy
could be instantiated by using
var thingy = new Thingy(_someDependency, disableUnexpectedBehaviour: false);
Now when a person reads this line of code they know more about what is happening and that should support them in introducing correct code. Here they learn that there is a mode where this class can do something in an unexpected way. Since the named parameter makes the intent clearer a developer can make a decision about how to instantiate the class with a reasonable idea of what will happen.
However, the next time someone writes code that uses a Thingy
they don't have to use a named parameter so it is still possible to use the form which obscures intent.
Static Factory Method
It is possible to hide the constructor and provide static factory methods to create and return instances. Where there is more than one way to construct the object more than one factory method can be provided to clarify this difference.
These are my latest obsession - so I recommend taking the time to jump to the declaration of Thingy
and do something like this:
class Thingy
{
private readonly SomeDependency _someDependency;
private readonly bool _disableUnexpectedBehaviour
// make the constructor private - this isn't necessary
// but enforces the use of the static factory methods
private Thingy(SomeDependency someDependency, bool disableUnexpectedBehaviour)
{
_someDependency = someDependency;
_disableUnexpectedBehaviour = disableUnexpectedBehaviour;
}
//add static factory methods
public static Thingy WithExpectedBehaviour(SomeDependency someDependency)
{
return new Thingy(someDependency, true);
}
public static Thingy WithUnexpectedBehaviour(SomeDependency someDependency)
{
return new Thingy(someDependency, false);
}
//<snip/>
}
var thingy = Thingy.WithExpectedBehaviour(_someDependency);
var crazyThingy = Thingy.WithUnexpectedBehaviour(_someDependency);
Now you can't construct a Thingy
without using one of these methods. This means that your decision to use a Thingy
includes an explicit decision about what it means for it to be included in your code. Yay for clarity!