When it comes to programming, there’s a lot of “rules” about refactoring. Ideas about “code smells”. Stuff you shouldn’t do. Stuff you should do.
Personally, I have not found many of these ideals to hold merit; or where they do, they aren’t really an absolute and the “buzzword” doesn’t always apply, but adherents will insist on using it everywhere. I say “adherents” because discussing things with people who follow these “best practices” often feels like talking to a religious person. Instead of reviewing, evaluating, designing, and writing software, people are referring to their doctrine bibles written by consultants, and sometimes even people who have no real experience in the industry beyond figuring out how to construct buzzword ideals to write books.
I’m sure I could write a book myself on them, however here I would like to discuss one specific “code smell”, “primitive obsession”. The general idea is to not use primitive types if another type makes more sense. I’ve seen the idea applied too judiciously by adherents; to the point of for example suggesting that instead of a string, a password should be a special type; or that a File Path should have it’s own special type.
The idea is that for example a signature like this:
public int Login(String username, String pass)
Should instead be:
public LoginResult Login(UserName username, Password pass)
There is merit here. Using an enum instead of an int for the result- or even using a class to represent the result of an operation where appropriate, absolutely makes sense. And, ceertain instances where additional features or capabilities for that typed information is completely sensible- A phone number, for example, can be validated, have the parts extracted and be formatted and so forth. However, I’m skeptical of examples like UserName or Password here, and think they are an obsession over removing primitive obsession, rather than something of useful merit. The result of somebody following doctrine, but not actually understanding it. Types that simply wrap a string merely provide the illusion of strong typing. A Username cannot be directly validated as a username; a password cannot be validated as a password.
There’s no special formatting or operations that you can do that are unique to a Username or a Password independent of the environment for which it is for. It just doesn’t make sense to me to construct a class for this purpose. Furthermore, I’m not even convinced it solves the issue it intends to anyway. In the example above, it would prevent client code calling the Login() method from calling it with a Password as the Username, or a Username as the Password. But that isn’t as helpful as it appears because there’s nothing preventing the creation of a UserName with a password or a Password with a username, due to the aforementioned lack of any useful validation logic which could verify the data (as, for instance, would be the case for a phone number)- The constructor for these special type variables, or any static class that constructs them, by necessity needs to be "Stringly typed" (as the zealots who treat programming books as a bible might say). To me this really removes a lot of the benefit; You are assuming that a Username is a Username no less than one would with a String variable named Username, so it’s unclear why there is some advantage to those sorts of situations. In fact Usernames and passwords are not even one of the samples discussed in books like "Refactoring: Improving the Design of Existing Code"- it uses examples like Phone Numbers, Currency, Coordinates, and Ranges- none of which are simply loose wrappers around a primitive type and have their own unique operations which make sense to encapsulate.
Like a lot of these sorts of “rules” that get reduced into short, catchy phrases, they end up being applied very judiciously by people who don’t really understand the underlying spirit of the rule- and instead interpret it as “if I do this, I’ll write good source code” which is of course not true.