I’m going to share some of my thoughts about multi-layer application API design. These are simple design problems, but I think it is good to have some discussion about them. Please feel free to present your point of view on these design items – I am eager to hear both supporting and contrary opinions!
- On business logic layer, do we need to return any values from update APIs?
In a Java application that I was recently building, I had a message list page to display a message data table. On this message list page, user can select multiple messages and execute a “Delete” API from my business logic layer, like“deleteMessages(List<String> messageIdList)”.
The question is does my business logic layer API “deleteMessages” need to return deleted message count to presentation layer?
Before giving my answer, we have to think about another question, how do we define “successful operation”? If the user selected two messages to “delete”, but for some reason, only one message has been deleted, do we think this is a successful scenario? If we said yes, our business logic layer API definitely has to return deleted row count to the presentation layer, because we have to inform the user how many of the messages have been successfully deleted. If we said this is not a successful scenario, we have to check the updated row count in our business logic API, and throw an exception to rollback the transaction if the expected row count does not equal the real updated row count. In this case, we will have only two different scenarios, all of the expected messages have been deleted or throw an exception. So the updated row count will always equal the expected row count if the transaction succeed. So returning updated row count is not necessary.
But I still prefer to return updated row count, because it doesn’t cost anything. Even if we don’t want to return updated row count, we know the JDBC API (or other persistence framework APIs) still return the updated row count to us.
- On business logic layer, how to separate business logic from presentation logic?
I have to implement “delete” and “undelete” functionality for my message list; in the database, we are implementing soft delete using a “DELETED” flag in the “messages” table. I designed two different APIs for this, like “deleteMessage(String meesageId)” and “undeleteMessage(String messageId)”. The “delete” operation executes:UPDATE MESSAGES SET DELETED=’Y’ WHERE MESSAGE_ID=?
The “undelete” operation executes:
UPDATE MESSAGES SET DELETED=’N’ WHERE MESSAGE_ID=?
Do I need to merge those two different business logic layer API’s to one API like “updateMesssageDeleteFlag(String messageId, char yesOrNo)”?
My answer is no, because:
a) We don’t have a use case for “updateMessageDeleteFlag” method. If we don’t have use case controller, the business services in business logic layer should be the “use case controllers” and should be “transactional”. So in every use case, the presentation layer have to call only one corresponding business service API, otherwise, if we call two different service layer APIs in one use case, and one of the APIs succeed and the other one did not, then we will have conflict.
b) If we merged that two APIs, the presentation layer has to send ‘Y’ or ‘N’ to the business logic layer when we are going to do “delete” or “undelete”. This is wrong because setting the delete flag to ‘Y’ or ‘N’ is not presentation logic, so it should not be on the presentation layer. - On business logic layer, when we need to do Defensive Programming?
When I am going to create a message, I have to do some validation on the corresponding form values. After the presentation layer validation, do I need to do the validation again in business logic layer APIs? I think it depends on how “secure” our business service consumers are. If we only provide services for our own presentation layer, it is not necessary to do the validation again on the business logic layer, because those validations are already done on the presentation layer. But if there is any possibility of opening our business logic layer APIs to other application systems or subsystems as remote services, we have to do the validation again in our business services, because it is possible to receive invalid method parameters from an “unknown” consumer.