danielwertheim

danielwertheim


notes from a passionate developer

Share


Sections


Tags


Disclaimer

This is a personal blog. The opinions expressed here represent my own and not those of my employer, nor current or previous. All content is published "as is", without warranty of any kind and I don't take any responsibility and can't be liable for any claims, damages or other liabilities that might be caused by the content.

Reply to - C# - Using implicit operator overloads to keep your API discoverable and open

Awesome! Got some nice feedback and questions on a previous post of mine, and got to think things over about some design decisions, getting the possibility to change the API before going live. Thanks! Now lets address some of the reoccurring questions.

First. Remember. The point is about making the API discoverable and open but at the same time encapsulated.

Do you cover this structure with tests?

Yes. Why? Well, in the actual case of the domain, it is about money transactions, hence one wrongly configured value will cause the consumer unwanted side effects which could lead to bad will.

Why not an enum?

An enum is static. It can not represent a dynamic custom value. Hence if the backend accepts a new option before the SDK is updated, enums fail.

Any possible future functionality to the “entity”, in the case of an enum, would need to be added as extension methods, which in this case is nothing I want.

Even though the underlying value is an int, working with enums introduces an explicit cast, which of course I can encapsulate, so this is not a big hindrance.

Why not a static class with constants (key-master)?

Key-master is probably a bad name. It has nothing to do with the movie “Ghostbusters”. More: I’m the master of all possible key-values. Otherwise, this construct suffers from the same issues as enums do. It’s static. Also, it can not be taken as an argument to a constructor and the BookingTypeId entity concept is taken away, hence functionality can not be added.

public static class BookingTypeIds {
    public const int Gold = 3;
    public const int Silver = 2;
    public const int Bronze = 1;
 }

Why construct items using factory methods and not fields or properties?

Regarding fields, I try to avoid fields when they are exposed outside the class. Why? If I need a property later on, it’s just a simple change, right? Yes. Same name and type but it still brakes backwards binary compatibility. Now, the chances in this case that someone should be fiddling with reflection against it should be very, very small, but even so, I would then go with properties.

The rest is a bit harder to explain which probably is a good sign of a bad choice from me and is also the one I might consider refactoring to. But, yes, properties can be used in a case like this, when no side effects or long running processes are involved. In this case, there clearly isn’t any long running processes involved. How about side effects? Well an argument exception can be thrown if the value is out of accepted range. You remember? The line: //...some simple validation logic....

private BookingTypeId (int value) {
    //...some simple validation logic...
    _value = value;
}

How-ever, in this case I’m in the control of the generation of the possible values: “Gold”, “Silver” & “Bronze”; so causing an exception to be thrown is something I can “look aside” from.

Then why not properties? Consistency? Exposing the constructor of BookingTypeId is not an option, because people will then miss the possible preconfigured values (which could be solved by letting it take an enum) and instead be using custom values that in 99.9% matches the pre-configured ones. So “Consistency” in this case would refer to the factory method “Custom”:

public static BookingTypeId Custom(int value) {
    return new BookingTypeId(value);
}

But shouldn’t this be named “Create” or something? Well, yes, probably. Just didn’t want: “CreateGold, CreateSilver, CreateBronze”; hence it became “Custom” to match this convention.

But yes, I agree, properties are probably a better way, BUT I (for now) would like to return the same value each time but different instances, and that is something I think a method expresses better, even though we are used to DateTime.Now.

Why implicit operator? Why not expose the inner value instead?

Because it’s geeky? Jokes aside. Yes, I agree that most people that come to the point to maintain the code probably need to scratch their head a bit, which is not a good thing. How-ever, in this case the actual entity is the value. Take DateTime. It represents an entity “DateTime”. Do you see a Value property on it? The idea is that BookingTypeId is more than an int. Currently, e.g. in the form of being as simple as argument range validation check. So with this in mind, that’s why it’s for now is not exposing the value.

Summary

Not much to say, except that in every design process we have different decisions to take and I’m grateful for all the feedback. Will probably lead to a bit of changes.

Cheers,

//Daniel

View Comments