What is service-orientation?
This topic is important for software architects because… architects have a critical need for a practical and theoretical grounding in SOA and Microservices. Even if you do not work directly with REST services and web services, the principles are still critical for you.
Service-orientation is an evolution of object-orientation that is optimized for the construction of “distributed” systems. Services are the foundation of modern distributed systems.
Cobb Taxi. In this explanation, we will use “Cobb Taxi” as an example. Cobb Taxi provides cars for hire with many different drivers, a dispatcher to direct the drivers to customers, and a bookkeeper to ensure that customers are paying for the rides.
Microservices is a different topic. The term “Microservices” is both contemporary and relevant. Nonetheless, it is simply a refinement of first-generation service-oriented design. Therefore, we don’t need to discuss microservices specifics any further in this post.
Roadblocks to Developer Understanding
Service-orientation is often difficult for developers to understand for several reasons.
Theoretical explanations are typical. Service-orientation is often described from a theoretical perspective. Some examples are helpful.
Many developers don’t see the whole system. Many developers have created web services or RESTful services and thus understand the implementation technology very well. Some developers also understand the concepts around individual services. It is less common for developers to be involved in the design effort for an entire “system of services”. Consequently, their understand of the role of inventory and composition may be limited.
Services != Service-Orientation. It is actually easy to produce services over a network, but that does not mean that the overall design is service-oriented. Most developers understand that they could be using an object-oriented language, but not develop an object-oriented system. The analogy extends to service-orientation in that using service technology alone does not result in a service-oriented system.
Service-oriented vs. object-oriented. It can be easy to confuse object-oriented systems and service-oriented systems. Service-oriented design builds on the concepts of object-oriented design. In addition, both types of systems communicate through message passing. The differences in service-oriented design are mainly to accommodate the added capabilities and constraints presented by the networked environment. This is mainly via the “composition” and “inventory” concepts discussed below.
What is a “Distributed System”?
It is important to have a clear understanding of what distributed systems are because services form the basis of distributed systems.
As suggested by Figure #1, a distributed system runs multiple different programs on multiple computers working together to achieve a common goal. The computers communicate by passing messages among one another.
EXAMPLE: Amazon’s main online store. Amazon clearly has many different services working together. Some of these are for business partners, some financial, some inventory, etc. This is clearly a distributed system.
Not parallel processing. Parallel processing assumes work on the same task and typically on the same system, perhaps even sharing memory. Individual nodes of a distributed system may engage in parallel processing. EXAMPLE: Amazon can get product recommendations at the same time it gets a list of search results for a product you are searching for. That is parallel processing, but does not constitute a distributed system.
Not a server farm. A server farm assumes multiple instances of the same program running on multiple computers. This is an effective strategy for scalability and availability, but there are no differences among the components and no message passing. Distributed systems do, however, often have multiple instances of a particular node type to allow for availability and scalability. EXAMPLE: Amazon has thousands of computers servicing customers with the same storefront for scalability purposes, but that is not a distributed system.
Not client-server. In a client-server system, the client and server do pass messages between one another. The client and the server are not, however, part of the same system or achieving a common goal. Communications between two individual nodes of a distributed system may be considered “client-server” communications. EXAMPLE: If you go to Amazon’s web site on your phone, your phone is the client and Amazon provides the server, but that is not a distributed system.
KEY POINT: Distributed systems are characterized by multiple computers performing different tasks to achieve a common goal and communicate by message passing.
What is a “Service”?
An overloaded term. In software development, the word “service” can mean many different things. We are using the term only in the context of distributed systems.
Physical world services vs. virtual world services. People perform services, such as the drivers, dispatcher, and bookkeeper for Cobb Taxi. Services are very common – most workers are performing a service. We are just translating that concept from the physical world to the virtual world.
“Agnostic” logic. “Agnostic” logic is logic that has no knowledge of a particular task – the logic does not understand the context in which it is being used. By not knowing the context of the overall task, a set of logic can be repurposed for many different tasks in different contexts. Conversely, we can assess how agnostic a set of logic is by determining how easily it can be repurposed.
EXAMPLE: Agnostic Logic for Cobb Taxi. A driver for Cobb Taxi should just know about driving – the driver does not need to understand about taxi service companies and processes. Cobb Taxi has a driver service, a dispatcher service, and a bookkeeper service. Each of the services supports method calls related to that function. It would probably be easier to develop a single program called “CobbTaxi” that handles all functions for the business, but then it could not do driving or bookkeeping for other types of businesses.
KEY POINT: Service logic should be as agnostic as possible.
Concepts related to agnostic logic. This concept of agnosticism is sufficiently important that some additional reading is warranted. The “single responsibility principle” discussed at https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html and “separation of concerns” discussed at https://en.wikipedia.org/wiki/Separation_of_concerns
Published API with a public service contract. For logic to qualify as a service, it must be accessible via a “service contract” with a public Application Programming Interface (API). That is, there must be a well-defined way for an external program to interact with the service.
KEY POINT: Service = Agnostic logic + public service contract
Implementation of Services. Conceptually speaking, we don’t care what technology is used to implement a service. In practice, however, there are only two noteworthy types of implementations. These are:
(1) REST. RESTful services accessed via a uniform service contract, typically with JSON.
(2) Web Services. Services defined by a Web Service Description Language (WSDL) definition and one or more XML schema definitions.
EXAMPLE: Cobb Taxi’s Implementation Technology. Cobb Taxi publishes RESTful services deployed to HTTP web servers, all of which are deployed to a single server, but with different URLs.
What is a “System of Services”?
We have already covered distributed systems and services. It is important to keep in mind at this point that we may have a distributed system, it may have some services, and it may be based on agnostic logic, but still not be accurately described as a service-oriented system. That is, it may not be a coherent “system of services”.
Services are part of service-oriented systems. Services are the components, but must be able to support “composition” and “inventory” to be part of a service-oriented system.
Common architectural characteristics assumed. Conceptually, we just need to support composition and inventory to qualify a system as service-oriented, but such systems are typically assumed to have three common architectural characteristics. Most systems have services that have the same availability, reliability, and means of communication with one another.
KEY POINT: Service-oriented system = services + inventory + composition
We need to know which services are available within our system. There are technical means of maintaining a service inventory, but simple clerical means like maintaining a spreadsheet may be sufficient. The key point is that there is an actively maintained and communicated inventory.
Problems with inventory. In a small system with few stakeholders, the problem of inventory sounds simple, but as a system scales in size and complexity, the problem quickly limits the systems usefulness. These concerns include, but are not limited to:
(1) Versioning. Consider that each service may have different endpoints and different versions.
(2) Overlapping semantics. Consider that the purposes of some services may be overlapping.
(3) Unclear semantics. The syntax and semantics of a service may be unclear. This is particularly true as versions change.
(4) Awareness. Stakeholders that are looking to compose new functionality may not even be aware of the existence of services that can help them.
(5) Multiple environments. In IT development systems, we typically have different versions of the services in various environments such as development, quality assurance (QA), user acceptance (UA), and production.
Typically handled with administrative means. There have been technology-based means of solving the inventory problems as described at https://en.wikipedia.org/wiki/Web_Services_Discovery. When web services started coming into popularity in 2001, it was assumed that UDDI would be the main technology to address these problems – I wrote my Master’s thesis on the topic. In practice, however, the problem has generally been addressed with ad hoc documents, spreadsheets, and other non-structured communications.
“Governance” through proactive communications. As organizations become larger, there is generally an architectural “governance” function through “enterprise architects”. The general model of such governance includes proactive communications. Service inventories are among the key technical standards that are communicated through such governance.
EXAMPLE: Inventory for Cobb Taxi. Let’s assume that Cobb Taxi has development, QA, UA, and production environments. Cobb Taxi also has separate services for Driver, Dispatcher, and Bookkeeper. If we update one service every two weeks, we will be making a change to each of the four environments every two weeks. Although Cobb Taxi is a small organization, it is clear that there is a significant communication effort to ensure that everyone needs to know what they have to act on.
KEY POINT = You don’t need technical means to manage inventory, but you do need to manage it proactively.
As established earlier, we want to combine services into distributed logic that implements specific business functionality. This is called “composition”. We compose services from our service inventory into our applications. In Figure #2 above, we can see an application that calls one service that in turn calls other services.
EXAMPLE: Composition for Cobb Taxi. Let’s apply Figure #2 to Cobb Taxi. We can assume that the application, “CobbTaxi”, in blue is a web application that calls “RideService” at the top of the diagram. CobbTaxiService calls the Driver, Dispatcher, and Bookkeeper services at the bottom of the diagram. CobbTaxiService does not have to have “agnostic” logic because it is only intended to orchestrate the use of the other three services.