kukudas
kukudas

Reputation: 4934

Clean API Design

Which would be the better way to design an API:

Example A:
public class UserService {
  public void addUser(final User user);
  public void addUserToIndex(final User user, final int index);
  public User lookUpUser(final User user);
  public User getUserByIndex(final int index );
  public void removeUser(final User user);
  public List<User> getAllUsers();
}

Example B:
public class UserService {
  public void add(final User user);
  public void add(final User user, final int index);
  public User lookUp(final User user);
  public User get(final int index);
  public void remove(final User user);
  public List<User> getAll();
}

Obviously this code will not run - it should just show the problem. I like the second approach more. The method name might be a little bit generic but the context (className, parameter, return Type) makes it pretty clear. One problem which the second approach might have is, what happens if I would need another get method with the same Type. For example, if I want to get a User by their age. Thanks in advance for any help.

kuku

Upvotes: 5

Views: 1876

Answers (4)

Varun Achar
Varun Achar

Reputation: 15129

First approach seems cleaner. Gives more information up front. People reading code will instantly know the meaning of the code, which is important while debugging or maintaining someone else's code.

Here are 2 examples that are close to what you're doing from 2 of the best designed frameworks:

JDK7

package java.security.acl

public interface Group extends Principal
{

   public boolean addMember(Principal user);
   public boolean removeMember(Principal user);
   public boolean isMember(Principal member);
   public Enumeration<? extends Principal> members();
}

Spring:

public interface GroupManager {

   List<String> findAllGroups();
   List<String> findUsersInGroup(String groupName);
   void createGroup(String groupName, List<GrantedAuthority> authorities);
   void deleteGroup(String groupName);
   void renameGroup(String oldName, String newName);
   void addUserToGroup(String username, String group);
   void removeUserFromGroup(String username, String groupName);
   List<GrantedAuthority> findGroupAuthorities(String groupName);
   void addGroupAuthority(String groupName, GrantedAuthority authority);
   void removeGroupAuthority(String groupName, GrantedAuthority authority);
}

As you can see from these interfaces, if I was reading the code, it'd be instantly possible to tell what the code is doing without having to go back and look at the type of the object.

I vote for your Example A. It just makes everybody's lives simpler.

Upvotes: 1

ChssPly76
ChssPly76

Reputation: 100821

There are two main questions, which you need to answer to make your choice much easier:

  1. Are you absolutely 100% sure that you will never have this service deal with more than one entity?

    In other words, can there be a scenario where UserService will have additional methods such as getRoles()? If the answer is yes, you're definitely going with option A.

  2. If you're definitely going to have one entity per service, do you even need a per-service interface or would you rather use a common generic one?

    So, instead of your option B you can have something like

    public class Service<T> {
        public void add(final T entity);
        public void add(final T entity, final int index);
        public T lookUp(final T entity);
        public T get(final int index);
        public void remove(final T entity);
        public List<T> getAll();
    }
    

    Concrete services that need more specific functionality can then extend this generic service.

Upvotes: 3

Nishant
Nishant

Reputation: 55886

Your problem is 'getting verbose' vs 'getting confused'. As getting verbose makes client to code by guessing the functionality by looking at the method name. However, I prefer the second version, since method signature (and return type) makes it clear what it does. With IDE support and proper comment/document, the 2nd version is more terse and equally handy.

There is no other way to interpret UserService#add(User) will do anything other than adding user; same goes for other methods. The code looks small and it's less typing.

Upvotes: 1

MadProgrammer
MadProgrammer

Reputation: 347332

Given modern IDEs these days, I agree with Tomasz, that's a rather subjective question.

You have to consider what the code might end up looking like (and possible extenstions to the API).

a.add(b); // :P this would make no sense at all
a.addUser(b) // is at least more descriptive

There is an argument for for and against verbose method names. Personally with the abilities of modern IDEs, I'd say the argument against is slowly losing weight.

Personally, I prefer example A, it's much clearer the intention of what each method is doing

Upvotes: 2

Related Questions