Keep API simple
I want to share a success story of designing a simple API, when the problem seemed to be complex at first glance.
Recently we got a task. We had to log every action that user does on the web. In other words, we would need a simple class (API) which could be easily used from almost all the controllers in our web. Additionally, we should log different parameters depending on action.We also have got a draft solution for this task from unknown developers. We are not going to look inside logging; we are interested in how easy is to use logging (it’s API). Below you can see a typical controller code for logging user action:
private void logUserAction(User user) throws Exception {
UserActionModel model = new UserActionModel();
model.setAction("Buy a ticket");
List<String> values = new ArrayList<String>();
values.add("PersonCode");
values.add("UserName");
values.add("ContactInformation.EmailAddress");
values.add("ContactInformation.Language");
model.setParams(LogUtil.getParamsWithFieldNames(user, values));
LogUtil.log(model);
}
Probably you guess how LogUtil.getParamsWithFieldNames works. Given a “user” object and list of Strings, it calls corresponding getters: user.getPersonCode(), user.getUserName() etc.
It’s it nice?
Look what a mature, multi-purpose solution! It doesn’t depend on concrete class - it could be User, Client, Customer or whatever else. You can pass any object and list of field names, and this universal LogUtil can log all these fields. Yeah, that’s a smart API!
But
But you know what? You just don’t need this smartness.Stop for a while and think: couldn’t it done easier? Of course it could!Why do you need reflection? Why loose compile-time check of getter names? Why bother with handling reflection (checked) exceptions? Dude, just use getters!
Finally
The final solution didn’t use reflection and was not smart - it was simple.The following is the typical controller code for logging user action:
Action action = new Action("Buy a ticket")
.add("PersonCode", user.getPersonCode())
.add("PersonName", user.getPersonName())
.add("EmailAddress", user.getContactInformation().getEmailAddress())
.add("Language", user.getContactInformation().getLanguage());
LogUtil.log(action);
As simple as possible.
Archived comments
Ivo 2011-10-19T12:24:13.531Z
Why would you implement this programmatically anyway? IMHO this is a clear case for aspect usage …
Our recent stories
Transforming the workflow for financial reporting
From Word documents to a unified platform: Tackling workflow inefficiencies
Not only a Java house - what has changed?
In the past four years, the technological landscape at Codeborne has evolved significantly.
From prototype to platform: Revolutionising learning at kood/Jõhvi
How prototyping, collaboration, and innovation transformed a unique coding school’s educational system