Question

In my C# project, I have a domain class named 'User'. this class will contain user's id, firstname, last name, DoB, home address, phone, etc. And we also have a typical REST web api (i.e. api/users) to read/create/update/delete user. When we create a method (in class UsersController) to return a single user's details, we can make it return a type User (or UserDTO, UserVM or whatever class represents the details of the user) as below. So user details can be viewed / edited.

public class UsersController {
    .......
    public User GetById(int id) {....}
    .......
}

We also have another method to return a list user with some simplified information (id, name, phone number only). So that when we view the list of the users, we can find the most important information (i.e. name, phone number) about each user.

So we have to create a new class to represent this simplified user details. My question is what is the naming convention of the class for the list item (as XXXXX below shows)?

public List<XXXXXX> Get(...)

For now, my colleagues use the naming convention blow:

public class UsersController {
    .......
    public UserDTO GetById(int id) {....}
    public List<UserListDTO> Get(...) {...}
    .......
}

UserDTO --- for the details of a single user.

UserListDTO --- for a single user in a returned user list. But from my personal view, this class name is more like something to represent the whole list instead of a single item of that list.

I'd like to know what's your class naming convention in your project for this scenario.

--- Update ---

This scenario is pretty similar with Amazon's website. i.e. when you search 'mechanical keyboard' in Amazon.com, the searching result page shows the list of products with the most important details for each one (product name, product price, product image, rating, etc). But when you click one of the products, the page shows more details about that product (i.e. product specification details, etc). For the product details page, we can name the class as 'Product' or 'ProductDetail'. But what is the proper class name for each product in the product list page? 'SimplifiedButImportantProductDetail'?

--- Update 2 ---

Another similar example would be:

If a class named Question represents the information in this page - all the details of the question itself, and its answers, comments, etc, What is the class naming convention for the information highlighted below? 'QuestionSummary'?

enter image description here

Was it helpful?

Solution

The fact that you have the objects in a list is completely irrelevant. If you are sending a list of users somewhere then List<User> would be the most correct option, and you don't need to use a different class just because it's going in a List. The fact that the thing you're sending is different from a User is the reason that its name (might) be different, not because you're putting it in a list.

With that out of the way, my first recommendation is to just send the entire User objects (or UserDTO objects if you really need to) and let the caller ignore stuff it doesn't need. This doesn't always work, but nothing in the question indicates that it wouldn't. This simplifies your application in multiple ways, with "don't need to find new names for things" being one of them.

If you do actually need a different class then the new name should reflect that it's different from the original. It also should not include "List" in its name just because you're planning to put it in a List at some point; anything can go into a List. If you have a class specifically for containing a reduced set of User information, then the natural and concise name for it would be UserSummary. If you have a class specifically for displaying in a list of results when searching for users, that could be called UserSearchResult.

TL;DR You don't need to separate "User" from "User, but in a list"; you can make a list of users with List<User>. If you still need to make a second class, then the reason for the second class is not because of the List and you need to find the actual reason in order to name it.

OTHER TIPS

Naming is hard, but back up a little.

A List is a List. The type you give it is for an item in that list. ie. a single thing.

As for how to name that single thing.

  • It is a User (even cut down), so why not User, and therefor List<User>.
  • Alternately its a User's Phone Number, so how about UserPhoneNumber and List<UserPhoneNumber>
  • you can see it as a User's Contact, so how about UserContact and List<UserContact>.

Please try to avoid Polish naming. That is when you attach the function of something to its name. ie. DTO, command, factory. Just from context (and the type system) we already know what it is. Instead look at the purpose it is serving, what role it has, in the greater context. It is easier to understand UserPhoneNumber than UserDTO.

If you need a grouping construct pluralise the name. ie. UserPhoneNumbers. Leave how you internally store the group out of the name, its not important. If you must have two or more internal structures, find a more general statement about it such as: UserPhoneNumbers and UserPhoneNumberLookup to imply the difference between a sequential, and set/mapped structures.

I completely agree with Kain0_0 here, just call that type something like UserPhoneNumber for you want the name to describe what it contains, not its function within the code. Certainly do not use a name like UserListDTO for something that isn't a list but will be returned by a list. That will just cause huge confusion to anyone else reading the code as the name suggests its a list, not something that will appear in a list.

It's also worth addressing another point that you make:

So we have to create a new class to represent this simplified user details...

No, you really don't have to do this. You could alternatively create an interface, IUserPhoneNumber, which has the id, name and phone number properties and have User implement that.

Also, stop and think about why you are returning List<UserPhoneNumber>. Is the intention that that list can be modified by the callee? If all you anticipate happening is that the list is enumerated, then return a more appropriate type, eg IEnumerable<IUserPhoneNumber>. Remember, according to "Postel's law", your should be "conservative in what you send [from an API]". If they ask for a glass of water, don't ship them a lake and glass factory.

There are only two hard things in Computer Science: cache invalidation and naming things. (Phil Karlton)

As others have pointed out, your actual problem is not really related to having items in a List, but rather because you have a full 'User' object with many fields, but sometimes need to send a version of that object with a limited set of fields through a given method. No problem, just name the second class 'UserSummary'! Ahhh but now you need a User-type object with a different set of limited fields .... ahhh .... I guess 'UserSummary2'?

There is no easy answer for the above problem. Especially as you add new methods that need to give you a different sub-set of properties from 'User'. However, there is a new language feature of C# that might be able to give you a place to start: Named Tuples.

Consider the code below:

// Full User class
public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public DateTime DateOfBirth { get; set; }
    // More fields here.
}

// Get Full User for a given ID
public static User GetUserById(int id)
{
    // get from dbase, includes full User details
    return new User { Id = 3, Name = "Foo bar", Address = "100 Oak St", DateOfBirth = new DateTime(1980, 1, 1) }; 
}

// Get some sub-set of user props
public static IEnumerable<(int Id, string Name)> GetUserSummaries()
{
    // get from dbase, includes just the User properties that you need
    yield return (Id: 1, Name: "Steve Smith");
    yield return (Id: 2, Name: "Bharkat Tahbarat");
    yield return (Id: 3, Name: "Kelly Rodriguez");
}

You've got the full User class when needed, and each method that returns a collection of summary data can just define a return type of a Tuple that matches the props on the User for convenience. You can also add the returned Tuple a Type prop representing the type that it most closely matches, in this case typeof(User). I wouldn't do that unless really needed, but its an option.

Licensed under: CC-BY-SA with attribution
scroll top