BrandGhost

Try THIS To Stop Enum Changes From Breaking Your C# Code

Continuing on our journey with Enums in C#, we turn our sights toward something different... Something slightly less conventional for supporting Enums in dotnet. What happens if you don't want to refactor your C# Enums out? What other tools do we have for our CSharp code? Have you subscribed to my weekly newsletter yet? A 5-minute read every weekend, right to your inbox, so you can start your weekend learning off strong: https://subscribe.devleader.ca Check out all of my courses: https://devl...
View Transcript
what the heck are you talking about why would you ever write a test like that I would argue that the right way to use enums are for values that aren't changing and I've mentioned before on my channel that if you have enum checks and comparisons scattered across your code base that as soon as you go to update that enum it's going to mean that all of those checks that you have probably have to get some attention but I get it I've seen many code bases where people are using enims that are having changing values over time it's really difficult to use an enum only for a set of values that aren't ever changing it really limits the usage for it so in a previous video which I'll link right up here and you can check that out I talked about different ways that you can go move away from using enums it's just one possibility that you could try out in this video I'm going to talk about an alternative to that so if you're using enums and the values might be changing how do you make sure that people are aware that that's going to have potentially a very big impact well it's a little bit unconventional but before I jump over to visual studio just a quick reminder to check that pin comment for a link to my newsletter let's go look at some code all right on my screen I have just a very simple enum called Dev leader enum I wasn't feeling very creative for names and we have three values that are inside of here Dev leader and then value three so if we were building a system and using this enum and this was supposed to be a set of values that are never intended to change for the lifetime of the application that we would be writing then I might say sure go use the enum and that's been the advice that I've been trying to promote on my channel however I do understand that there are situations where you can't plan for everything that might even be your intention that you don't want this to ever change but guess what at some point down the line maybe it's 2 3 years later you have value four that needs to be added to this enum what's supposed to happen even though you went in with best intentions to never have this change Oh no you're remembering what Nick said we can't possibly change the enum everything's going to break I'm exaggerating a little bit but you see what I mean this is supposed to be something that's not supposed to change and this is on a spectrum right so I keep saying not supposed to change don't do it if it's going to change but the reality is you can do whatever you want I'm just trying to indicate that there's going to be some maintenance cost to having that kind of thing scattered across your code and having to make an update like this you could have an enum that's changing very frequently and if it's only checked in one spot there's going to be very little maintenance so all of the information I'm trying to convey to you is based on historical code bases that I've seen where all of these enum checks are in many different spots and the enum that's being used isn't something that's going to be constant throughout the development time of that application so we've previously seen a way that we can try to move away from enum usage but instead of doing that if you want to use an enum because I think they're an awesome tool you get a string and an integer kind of combine into one thing it's really nice for expressing the intention of code I get it they're a handy thing to use if you want to make sure that you're protected something that you could do that seems a little bit weird is writing tests for it and I'm going to pause here cuz I know that some people are going to see the next part that I'm about to show you and go what the heck are you talking about why would you ever write a test like that and I'm going to explain why a lot of people talk about writing tests strictly from the perspective of we don't want to know about the implementation if you write a test that knows about the implementation it's going to break that means we can't refactor code the test is useless but I call bull crap on that I think that that's an awesome way to write tests and I encourage you to do it but I don't think that that's the only usage for tests in fact I think tests as a general statement are just tools that give us confidence that's it but what kind of confidence are you looking for a lot of the time people are framing this is I want to make sure I can have confidence in my refactoring I want to make sure I can make changes to something and the behavior of it from the outside's not going to break I get it that's a really common use case it's just not the only use case that you can write tests for so what I'm about to show you is a little bit weird it means that when you change the code your test is going to break but that's exactly what we want in this case because we don't want people to change the enum let's go have a look all right so I'm back in the code here and I'm going to start expanding this test class that I have on the screen and we're going to start with a test that checks if the enum names should not change and this was really cool because I typed this name out like this and copilot actually completed the rest of it so I'd love to take credit for this test but it's not even me so the point of this test it looks pretty obvious and it looks like it's really copying and pasting code it looks really brittle if you're understanding what this test is doing but we're going to take the three names for the enum values that we have and then we're going to call enum get names on the enum that we have which is going to give us back an array of strings so this array of strings should in theory match up with these three names so of course this is a string representation in an array of these three things right here it's a pretty obvious test it feels kind of silly but I do think that if you have something like this in place and you want to make sure that the names of your enum never change and the Order of your enum is not changed then this is a test that can really help with that now you might say well Nick people can go change the enom and the test at the same time what's preventing that and there's literally nothing preventing that but you could make the same argument about any test and any code change that people can go change both at the same time the point is it's one more opportunity where if someone was not aware that they should not be changing it then they're going to get caught here because whatever your continuous integration system is and I should have prefaced all of this hopefully you have something like that that's running your tests for you before you go to push to production at some point that this integration system would run this test and go oh wait these enum names are not the same or they're out of order so if we were to go run this test of course we would have it match because this is the same three names that we have up here here now if I take this one and I change it to Value 4 automatically if I wasn't aware that that's going to break or have repercussions in the code and you might say well Nick you can just refactor and rename across the code base you're totally right but in one of the earlier videos I made I talked about serialization if you wanted to serialize by name then you're not going to have a good time with a change like this and that might mean that you want to change the name of this test method to indicate that or maybe you want to leave a comment I know people are up in arms about comments when they're useful when they're not but again if you're trying to put a test like this in place to have preventative measures I think you could totally add a comment for context this is why we have this test this is what it's supposed to be protecting from so again it seems like a very brittle test because it is but that's the point if we want to have some protection against renaming reordering this kind of test really simple can give you some of that confidence it's one more stop in a pull request or a code review where someone can say it looks like you changed both of these spots and it's one more opportunity for the reviewer or the person that made the code to say hm I changed the test that says enum names should not change and I literally change the name maybe I should ask about this right it's not a perfect solution I don't think there's Perfect Solutions to anything but I think this is one more tool that you can leverage now I want to move on to another variation of this though and we're going to look at values should not change so again if we wanted to go back to the idea I'm going to scroll up a little bit but first have a look it just says 0 one and two for the array if we scroll back up here Dev is zero leader is one and value three is two that's a little bit confusing but 0 one2 now if we want to make sure that these don't change that would mean that if we were to add something else into here so if I were to put value four right that means that we're going to have 0 1 2 3 so we're going to have an array with four items in it up to index 3 and that means that if we go back down here this test would end up failing so we will get some protection against adding items or removing items which is great now if we don't care about renaming so let's go back to the example of serialization if your enum was always serializing based on the numeric type and you didn't care about the string value of it you might say I don't need the other test we already looked at I just want to make sure that we have this kind of coverage but I have a question for you I'm going to go back to this test and I'm going to ask you is this test sufficient coverage for making sure that the enum values don't change let's go have another look at it so to repeat the question does this test truly prevent enum values from not changing right we have an array of 012 if I scroll back up we know that the point of this test is to make sure based on the assertion that we we have the value 0 1 2 and hopefully you've had a minute to think about this but what happens if I do something like this right we still have the values 0 1 2 coming back however I've just reordered this enum and if that's going to make a big difference in your code maybe it doesn't in the code but maybe it does for your serialization because now value three is mapping to leader and leader is mapping to value3 that could cause some serious damage when you're trying to save and load data with some older sets data and your new code arguably this has very little impact within your code because all of the checks are going to be using the enum anyway however serialization or other scenarios could be very impacted by this and that's something that's not covered by this test here this is really just looking for 012 so what this means is that to get a little bit more verbose and the test is going to start to look pretty silly we can do something like check that everything that we have in the enum maps to the expected values let's have a look at that all right so here is an example of a test that seems pretty verbose but would give us that protection that we're looking for and again I know and I understand you're reading this saying you're literally mapping the entire enum this is way too cumbersome way too bloated and I get it but the point is that if you're trying to protect against that enum changing you can put things in code just like this to help so what this test will do is create a dictionary mapping the ENA name to to the value that it's supposed to have so that's the expected set of data and then we're going to map the enum to the dictionary that is the actual representation currently and then we can just check to see if they're equal so you can see that when I run this test I get this green check mark so I'm just WR clicking and running test they get that nice green check mark there and if you want to see what happens if I rename or do anything else in here what I can do is go put this back and mess it all up so we've done a rename here so if we go run this test once more I'll scroll back down run the test boom we get a red light so I want you to think about this as a tool that you can leverage you have the opportunity to introduce something like this if you're worried about people making changes and having big sweeping impacts across your code base do I recommend doing this all of the time no I think there's situations where it's very valuable and one thing that comes to mind for me is if you want to have other people have the opportunity to work in your code base you want to make sure that your codee's protected and they're protected from making mistakes one of the ways that you can help let people feel more comfortable in your code base is if you have tests that do things just like this you're protecting them from making mistakes that they wouldn't know about otherwise what's to stop anyone from making an enum change and if the code compiles and if they're running some scenarios that they're doing manually right if those all pass they might go great this is good to go someone doing a a code riew what's the likelihood they're going to catch every possible situation that they need to be looking for this it's going to be pretty low likely so having a test like this can be helpful it's just not a silver bullet now I also wanted to mention that I don't have experience yet with rosin analyzers I do think that this might be something that could be pretty cool with an analyzer you might be able to create a custom rule for it and say that if I have this enum declared you probably have to write something silly like one of these tests like the same type of logic to do the comparison but it could do an analysis on the enum well before you're trying to run it or run your tests and your integration Pipeline and be able to tell you with some syntax highlighting right on the spot hey you shouldn't change this I think that could be pretty awesome but again is it necessary all of the time absolutely not it's just one more tool that you can use if you find a good opportunity for it so thank you so much for watching I hope that you find some scenarios like this where might seem useful and I'll see you next time

Frequently Asked Questions

Why should I avoid using enums for values that might change?

I argue that enums should be used for values that aren't changing because when you have enum checks scattered across your codebase, any update to the enum can lead to a lot of maintenance work. If you intend for a value to change over time, it can complicate your code and lead to potential issues.

How can I ensure that changes to enums don't break my code?

One unconventional approach I suggest is to write tests that specifically check if the enum names or values change. This way, if someone tries to modify the enum, the tests will fail, alerting them to the potential impact of their changes.

Are there better alternatives to using enums in my code?

Yes, I've discussed various alternatives in previous videos. While enums can be useful, if you anticipate changes, consider using other structures that allow for more flexibility. However, if you choose to stick with enums, implementing tests can help mitigate risks associated with changes.

These FAQs were generated by AI from the video transcript.
An error has occurred. This application may no longer respond until reloaded. Reload