0

I'm working on a web application that stores identifiers, such as usernames and email addresses in a "normalized" form and a "non-normalized" forms, for a variety of reasons. For example, an username 'John_Smith' would be normalized to 'johnsmith'.

However, some of the user interfaces need to work with the normalized representation, the others don't need to do so. Continuing with the same example, a visit to the page /user/John_Smith, /user/johnsmith or /user/jOhnsMith should return the same information, so normalization would be necessary. On the other hand, an API endpoint (e.g. /api/update/?user=John_Smith&value=20) wouldn't need to do that.

Thus, in the codebase, there are some functions that normalize usernames, and others that dont:

class UserManager {
  getUserInfo(username) {
    normalized_username = normalize(username)
    // do stuff with the normalized value
    return info
  }

  updateValue(username, amount) {
    // do stuff, without normalization
    return info
  }

  // ...
}

This seems very inconsistent, is there a better way?

The only better way I could think of is to require that the callers normalize the function arguments before passing them, and have all the functions work solely on such normalized inputs. (It would kill the API-strictness though, however, that is not an important requirement.)

(I'm aware of the real problem; it is the fact that Entity classes do not exist in the codebase. Had they been there, it would be simply a matter of Users.find('username', input_user) or Users.find('normalized_username', normalize(input_user)). However, writing a database-to-class mapper is not really possible at this point of time.)

  • 1
    Normally this problem is solved by using unique identifiers instead of names. It also solves other problems like people changing their names. What prevents you from doing that? – Robert Harvey Dec 31 '16 at 18:36
2

I would recommend wrapper classes around the strings, so you have NormalizedName and NonNormalizedName classes wrapping a string. This way you avoid mixing them up, and the function signatures will clearly signal what version they expect.

I would also recommend to exclusively use the NormalizedName in the business logic.

  • I cannot agree strongly enough with your last sentence given that you need to normalize at all. Having 2 valid-but-slightly-different ways of accessing data is a short path to insanity. Personally I'm in the don't-normalize camp, but then I've been hacking UN*X systems since 1980 and we've always thought that "FOO' was different from "foo". – Peter Rowell Jan 1 '17 at 23:41
0

When I have something that could be represented in multiple forms, I generally keep one settable property, and expose another property for the different format (usually I do this in terms for names, such as CommonName, FormalName, etc):

class User
{
    public string UserName { get;set;}
    public string NormalizedName {
        get {
            return normalize(Username);
        }
    }   
}

then use it like so:

var user = new User(username)
// do stuff with user.Username (non-normalized, as-is)
// do stuff with user.NormalizedName

With that said, Robert's mention of using an ID is spot on.

  • This doesn't preserve proper strong typing- the NormalizedName has invariants but you can trivially break them. It should be wrapped in a class. – DeadMG Jan 1 '17 at 15:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.