Services, in principle, are meant to be consumed by some other part of the system, or even by an external system. It is required to keep in mind that the service may not, and most likely will not, be able to determine where and when it is used. This is why this type of development needs to be particularly robust and reliable, as various areas of the system may depend on its correct functioning.
When designing the services, aside from their scenario-specific implementation needs, there are several things that should be considered in order to minimize upgrade and maintenance costs:
- Keep services singular-task oriented: Even if the service is supposed to perform many actions on the system, one entry point should perform one consistent end-to-end task (for example, creating a business object, or deleting one). Avoid mixing multiple tasks in a single service call.
- Avoid direct database manipulation in services: Delegate all logic to the business logic layer.
- Expect, but check: Do not assume that all the required data is provided by the caller, and always verify its consistency.
- Provide consistent and explanatory responses, especially when errors occur, so the caller can react accordingly.
- Keep the service well documented, so it is clear from the consumer's perspective what to expect when calling a particular part of it.
- If possible, keep the service's interface unchanged: Even small changes to the interface will require adjustments in the consumer's implementation. Utilize optional parameters to keep backward compatibility.