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
The Codeborne Christmas beer brewing diaries
It was a sunny day in September. Quite warm for that time of year. We were sitting with my colleague Tiit on the roof terrace in the Codeborne office as we do every now and then. I ask him for advice on occasion - after all, what are the more experienced colleagues good for otherwise?
“Backing up” a good product owner
One of the key players in most successful agile projects is a product owner, at least in Codeborne’s practice. Our practice stretches for more than 15 years, during which we have successfully delivered over 100 projects.
Unleashing the power - How Creos partnered with Codeborne to change Luxembourg's energy sector
Creos Luxembourg involved Codeborne in its journey to modernize Luxembourg’s energy sector