Tuples in C# 7.x
During moths, I have been thinking about Tuples and their usages and advantages, I was planning to write a post weeks ago, but I was struggling to find good justifications about the usage of tuples and not repeat some of the same concepts already in internet.
The idea that started my initial thoughts about tuples was the advice of not using tuples on Public methods:
As we can read on the official documentation of C#, there isn’t an explanation about why not using Tuples on public methods, so I decided to explore the reason behind this suggestion.
One place where I did found very useful comment from other programmers was this Stackoverflow question “Is Using .NET 4.0 Tuples in my C# Code a Poor Design Decision?”
Reading the thread, the most common complain is related to the lack of names for the elements:
As we can read this lacking of strong naming of the type Tuple<,,,> makes the things difficult for the consumer, because it force us to go to the method and review the implementation, otherwise we would have to guess the right order of the tuple items, that makes sense why is not a good idea using tuples on public methods, because a third party user probably won’t have access to the source code. But if we put more attention to the comment on the Stackoverflow question, we can see that those comments are from 2010 or around, but we are now on 2019! It means now we have access to the brand new ValueTuple that came with C# 7.x.
So, with C# 7.x now we can do this:
Now we have strong typed names! So, it means that we don’t have any more those confuse ItemN variable names, which makes the code more readable for the consumer, so the consumer doesn’t need to know the internal implementation of the consumed method to know what Item4 means.
The second complaint that I found very interesting between those answers was this:
This is an interesting point, because, yes, the Tuples has a low level of reusability, that lead to repetition of code (Copy-Paste), a clear violation to the DRY principle. Under a normal day I would say that this is design flaw that makes the usage of Tuples not a good idea, and even worse on public methods. But today I have a different point of view, I agree that the over usage of Tuples can lead to repetition of code, but I don’t think that is a horrible idea, please hear me out.
The reason why I think some duplication of code that can be product of the usage of Tuples is not a terrible idea, is because even though it looks like an easy case of abstraction, let say under a single DTO, is the kind of trap that lead us to a non-productive wrong abstraction, and this kind of abstraction are very costly in terms of coupling and maintainability. This blog post of Sandy Metz explains very well why prefer duplication over The Wrong Abstraction
One of the nice things about the new Tuples, is how we can have anonymous containers of values that are not tight interlaced between each other. In this way, we have a more natural approach to make the data flow between methods, and only when we have enough number of duplication we can extract a good abstraction.
Let me exemplify this with a piece of code, let say that we have three classes, two of them are repositories and one is a service:
As we can see, we have an abstraction for Person, however the Person repository is returning Null for the Birthday, that sounds acceptable but is not ideal, because we have a wrong abstraction. Is like using shoes one number bigger, you can use it, but is not the best, to fix such mismatch we can create a PersonDTO that doesn’t contain the birthday field but then we will have to have another class, let say called PersonModel that contains the Birthday field, but now we have two container classes very similar between each other, that make the code more difficult/tedious to maintain.
What I have seen working with Line-Of-Business applications, is that usually we change the shape of our data slightly through a chain of methods, that lead us to take a decision eventually, the first option is to have several classes that are specific for each method or we can have a big chunky class that is trying to match most of the variations of the data, usually this latest one is the most common.
None of those are ideal, but fortunately we have Tuples, and those tuples makes our code cleaner and help us to have the right set of abstractions, without getting distracted with the slight variations that our data can have through all the layers of the system.
I didn’t find a strong reason why not to use the new ValueTuple type on public methods and I found why tuples promote an increase on code duplication, which if you have read the explanation above, is not a totally bad thing, of course nothing is perfect, so as a recommendation, I would suggest having these guide lines at time to work with tuples to avoid headaches:
- Three or less elements in a tuple is manageable, more than that makes the code more difficult to follow and maintain.
- Use always names for each tuple element, right now on C# 7.3 the tuple’s elements can be nameless, please add names otherwise the code readability will suffer.
- If you will be using a Tuple for a public method, think twice if the method is clear enough for the consumer, if you should go to the documentation to figure out what the method is doing, is a clear sign that something is wrong.
- If you are exposing an API that can be consume by other language, for example C# to TS, don’t use tuples, you don’t know if the other language will have a proper support of tuples.
- If your code will be used through reflection, don’t use tuples. Names on tuples are tracked by the compiler not the runtime, it means that if you use reflection you will have to access the data using the ItemN name convention for each element.