As with many terms in software, there's multiple common usages out there which are quite different in meaning. This page is what I would link to if the term were to come up in our conversation.
Definition in my words
A service object (an instance) represents either the whole application itself or some one service, resource, functionality "outside of the application". It's meant to represent things that have an equal or greater lifespan than the app itself. (3rd party network APIs, system clock, filesystem, etc.) Every time the app is instantiated, it's assumed that these services already exist and will continue to exist for the duration of the interaction.
Services are "immutable" only in a sense that they don't have any private state that changes as a result of interacting with the services. But they're not immutable in a sense that every interaction with them results in the same output every time.
Often times, a service object represents a whole other computer, fully outside of the computer that's running your app. If my app interacts with the some outside API/domain, like api.twitter.com, I would have a service class called Twitter and use an instance of it to interact with Twitter from my code.
The "App" service can then further be sub-divided into delegated-to sub-services, but that's much later in bigger apps. The important emphasis with services is the set of them which represent "outside" stuff. (clock, network APIs, repositories, etc.)
Sources/influences of the definition
-
Hexagonal Architecture by Alistair Cockburn obsesses over the idea of clearly separating your app from what's "outside of it" by imagining a series of stresses your application might (and is likely to) experience, relating to changes in technology or vendor selection. Your database may need to be sometimes substituted with a different brand. Maybe you're switching payment providers. All this stuff outside your app that may get completely switched, but not tweaked by you, is a "service" your app depends on.
-
In "Object Design Style Guide" ( a nice book on OOP in web applicaitons), Matthias Noback writes "Once they’ve been created, they can run forever, like little machines with specific tasks.". While not providing a direct definition, how "services" in that book are discussed is consistent with my interpretation of the term.
-
DDD book organises objects into 3 types: Values, Entities, and Services. The way "Services" are discussed there in Chapter 6 is consistent with the definitions collected here. A service represents behavior not attached to any "state" of the application
Typical Examples of Services in Software
-
Anything that your app accesses but it resides on some domain/computer/address that you cannot control at all. 3rd party APIs are the most common type of this
-
The system clock. They way I think about it is this - your programming language doesn't know "what time it is", but through it's standard library provides some way of accessing the "clock" that's outside of your "process".
-
Filesystem.
-
Logger
-
STDOUT/STDIN.
-
etc. (anything that you consider "outside" of your application)
Code examples:
Suppose we have a time tracking application. A user can clock in to work and clock out for a lunch break or end of day. The app then tallies up amount worked each day for billing and reporting purposes. To function well, with persistent storage between the times the application runs, it would need 2 services: a clock (to know what time it is), a repository (to store / record the in/out-from work transitions). An example in Ruby:
app = TimeTrackingApp.new( clock: Clock.new, # has a `.now` method repository: FileRepository.new, #has a read/write methods to read/write from disk )
In this example, a "clock" is a service because it is "outside" the application. Repository is a service because file system is "outside" the application. The TimeTrackingApp itself can be thought of as a "service" too.
Testing
If you can mock/fake/stub/etc. all the "services" that your app depends on, you can write phenomenal unit tests, since the only behaviour that's left is that of your "application", which you 100% control yourself.
Conflicting definitions out there
I've seen a few articles online that create a bunch of classes for something like a "Method Object" pattern, slap a single public method on it (often def call in Ruby) and call that a "RegistrationService", "LoginService", "PasswordResetService", etc. The number of services really explodes because essentially every route, job, etc. gets a Service. This is too much and it becomes difficult to tell what depends on what. Especially if these "services" depend on each other statically (as opposed to constructor injection).
Broader connection to object oriented programming.
I've always found it difficult to reconcile that in OOP, everything is an object. Twitter is an object, file system is an object, and so is the number 7 and character z. Clearly there's several super broad categories of what an object can "model". I think "services" are the easiest, most-bang-for-the-buck kind of object. Even in functional languages, there's a need to view something "outside" as a thing, an object with an interface. And after all, the earliest inspiration for OOP is the internet/Arpanet itself, wherein each object is literally a physical computer somewhere.
Let me know what you think.