nbarbettini / little-aspnetcore-book

The Little ASP.NET Core Book, a friendly introduction to web programming and ASP.NET Core 2.0
http://littleasp.net/book
Creative Commons Attribution 4.0 International
702 stars 190 forks source link

Why don't we use the simplest type for method parameters in ITodoItemService? #43

Closed sadqiang closed 6 years ago

sadqiang commented 6 years ago

The current definition of ITodoItemService is as follows.

public interface ITodoItemService
{
    Task<IEnumerable<TodoItem>> GetIncompleteItemsAsync(ApplicationUser user);
    Task<bool> AddItemAsync(NewTodoItem newItem, ApplicationUser user);
    Task<bool> MarkDoneAsync(Guid id, ApplicationUser user);
}

As ITodoItemService is specifically intended to operate on

public class TodoItem
{
    public string OwnerId { get; set; }
    public Guid Id { get; set; }
    public bool IsDone { get; set; }
    public string Title { get; set; }
    public DateTimeOffset? DueAt { get; set; }
}

why don't we define ITodoItemService with the simplest types as follows?

public interface ITodoItemService
{
    Task<IEnumerable<TodoItem>> GetIncompleteItemsAsync(string ownerId);
    Task<bool> AddItemAsync(string title, string ownerId);
    Task<bool> MarkDoneAsync(Guid id, string ownerId);
}

The simplest types represent a type of TodoItem and/or types of properties defined in TodoItem class.

The advantage of my proposal above is that ITodoItemService depends only on TodoItem type and the built-in .NET types rather than ApplicationUser class or others.

nbarbettini commented 6 years ago

I like it. Definitely a lot simpler. 👍

nbarbettini commented 6 years ago

After thinking about this more, I don't want to show the simplest types. Here's my opinion:

There is a tradeoff here between using the simplest/primitive types in the interface, and reducing update churn later. Let's say that I later decide to make DueAt a required paramter of AddItemAsync. If it is a primitive parameter, I'd have to update the interface and also update any implementations of this interface (including tests/mocks). On the other hand, by using the class type, I have more flexibility down the road without requiring potentially breaking interface changes.

There definitely are counterarguments to this, and a lot of this comes down to personal preference (IMO). For this book, I'm going to show the more flexible style.