The protocol of the service is the collection of data objects that are used in the interface. Those are publicly exposed data carriers, also known as DTOs or VOs (- Data Transfer Objects (They are sometimes also called VOs - Value Objects or BOs - Business Objects for that matter. Both these terms are somewhat missleading and that's why we don't use them in this case).
The implementation is the heart of the service. It implements the service interface, provides caching, enforce enforces business rules, provides business layer validation etc.
Many of the services do store some data over a longer period of time. To perform this task they need a persistence service. Against the classic layered model, where the business service relies on a previously defined persistence service and a global data model we let the business service to define its requirements to the Each business service defines its requirements for its own persistence. This also means that there is no such thing as a central data model in our application. Instead each service has it's own private data-model, which no one else is allowed to access directly.
This is different to other architectures, that have a single, combined persistence layer.
In some case cases you will use a database to store a thing or two. In this case we recommend to have a DAO to encapsulate SQL - or whatever language your DB speaks. From our experience it is best to have a DAO Class for each VO Class. This will automatically prevent you from using JOINs, and JOINs are the death of performance (and you don't want to be dead, do you? )
From time to time your internal services will rely on an external component to perform it its task or a set of components of the same type. For example it is advisable to use an email solution provider for sending emails to customers or sms gateway providers for sending sms-es. And if your portal supports payment you will have a connection to one or multiple payment providers at some place.
The service is not responsible for:
- distribution (this is a framework task).
- transforming a java object into persistent state.
- reading objects state states from a persistent state.
- performing queries (if they can't be performed by the business service).
- managing DAOs (if any present).
- managing FS resources (valid for fs-based persistence services).
The connector is responsible for transformation of internal application data and operations into vendor's language and back. It's also responsible for managing the connection to the vendor and for protection against misbehaving vendor vendors (for example by installing queues which decouple vendor's processing from system processesprocessing).
We sure already mentioned it, but it doesn't hurt to mention it again:
Services are exposing their interfaces to remote clients. Even if the service itself usually has no explicit knowledge of its distribution or the fact, that it is distributed, it is useful to know as a developer that my the service will be accessed remote and that services that one accesses are remote too and code accordingly.
ano-tecture doesn't recognize a need for joins. In the last 10 years we had not a single use case that wasn't solvable without a JOIN. If we find such a UseCase in the future, we will revisit this policy. In the meantime we prefer to 'join' on the application layer by combining information from several services into a higher level model.
Lets proceed to an example UserService.
This page contains example UserServiceSource.