Last active
March 12, 2020 19:55
-
-
Save oschmid/3ee4c21525ef9082390ba469c897d7cf to your computer and use it in GitHub Desktop.
To Do List Design Exercise
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public class Task { | |
| public Status status; | |
| public String description; | |
| public Optional<Integer> priority; | |
| public Visibility visibility; | |
| } | |
| public enum Status { | |
| TODO, IN_PROGRESS, UNDER_REVIEW, BLOCKED, DONE | |
| } | |
| public enum Visibility { | |
| PRIVATE, FRIENDS | |
| } | |
| public class ToDoList { | |
| private final UserId owner; | |
| private final List<Task> tasks; | |
| private final Set<UserId> friends; | |
| private final List<Change> history; | |
| // includes private as well as public | |
| public int getTotal(); | |
| // returns tasks visible to user | |
| public ImmutableList<Task> getTasks(UserId user); | |
| // rewinds change history and returns tasks visible to the user | |
| public ImmutableList<Task> getTasksSnapshot(Instant instant, UserId user); | |
| public void add(Task task, UserId user); | |
| public void update(Task oldTask, Task newTask, UserId user); | |
| public void delete(Task task, UserId user); | |
| } | |
| public interface Change { | |
| public Instant getTimestamp(); | |
| public ImmutableList<Task> undo(ImmutableList<Task> tasks); | |
| } | |
| public class Add implements Change; | |
| public class Update implements Change; | |
| public class Delete implements Change; | |
| // getTasks() can be filtered with: | |
| public Predicate<Task> onlyState(State state); | |
| // getTasks() can be sorted with: | |
| public Comparator<Task> byPriority(); | |
| public class UserId { | |
| private final UUID uuid; | |
| } | |
| public class User { | |
| public final UserId id; | |
| public String username; | |
| public final ToDoList todoList; | |
| } | |
| public class App { | |
| private final Map<UserId, User> users; | |
| private final Map<String, UserId> usernames; | |
| User login(String username, String password); | |
| User getUser(UserId userId); | |
| User getUser(String username); | |
| Integer getCountOfUsersWithTasksMatching(String description); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Initial Design
Pretty straight forward. I chose to use "TODO" instead of "not done" as names containing negation can be confusing. Tasks are immutable so instead of updating in place, changes (such as marking items as done) are made by replacement using
update(old, new).First round of feature requests
Added more values to the
Stateenum. One alternative I considered was to makeStatea class and allow custom states perToDoList. But this seemed like overkill. Also added optional priorities. The UI can filter and sort to-do items by callingToDoList.getTasks()and then using Java streams along with theonlyState()FilterandbyPriority()Comparatorto filter and sort tasks before displaying them.Second round of feature requests
Added a task
Visibilityand updated the methods ofToDoListto require theUserIDof the user making each change or viewing the list of tasks. Internally it'll compare thisUserIDto the owner and set of friends to determine what to show. Since we now have users, I added anAppclass to handle login and looking up theToDoListof a friend. Currently the user would have to know their friend'sUUIDto add them or look them up but adding usernames and a lookup by name is pretty straight forward.UUIDis preferable to just using aStringsince the user may want to change their username.Third round of feature requests
Counting the users with the same task descriptions is a strange (and insecure) feature but easy enough to add to
App. I forgot to add it but we can have a list of Users as our internal data structure. The spec says to count the tasks of all users so I'm assuming private tasks are counted too. Though this may change to include only our friends or only public tasks. If so,getCountOfUsersWithTasksMatching()may change and include aUserIdparam.Because of my decision to return an
ImmutableList<Task>rather than allow editing in place, adding change history is straight forward.add(),update(), anddelete()can add concrete implementations of theChangeinterface to the change history list andgetTasksSnapshot()can rewind that list until the desiredInstantin time. There's no way of retroactively adding history toToDoLists that already exist so the earliest snapshot will just be the list as it existed when the history feature was introduced.(Final cleanup)
I changed the name of
StatetoStatussince it fits better, added a missinggetTimestamp()method to theChangeinterface. And a map to store users and usernames inApp.