What is a Service?
Lets understand the Service concept to better understand MicroServices.
Business serves customers by selling products (cars, electronic) and or providing services (cleaning, insurance). This intends to earn delightful customer experience and thereby earn profit to business.
In easier IT terms, technology business builds applications which provides variety of desired services/features to the customers.
Each of the the business functionality aka feature (aka service) can be considered as discrete a capability. E.g. Banking. Customer logs in, checks the balance, transfers money to , pays the bill, generates a tax statement.
Notice that each of these is a discrete function or service (meaning serves a purpose of the customer/business)
Each application/system has different user types and functionalities catered to those. E.g. In case of banking, there could be multiple divisions such as personal banking, corporate banking, lending & mortgages (home, auto), credit card, retail banking (term deposits etc.)
In this banking domain, each of the division (personal banking, credit card etc.) could be a sub domain.
Each of the sub domain has an offering for the customer for which they build a piece of software.
Same analogy can be applied for other domains.
There could be multiple user types of the system and those are majorly categorized as internal users (bank staff) and external users (Customers).
Business leverages technology as a means to serve better. It leveraged the technology and methodology available then and evolved to what it is today.
What does service comprise of?
To serve any functionality, there were primarily three pieces involved.
An interface for the user to provide instructions, commands or actions. Processing piece which acts on the actions provided by user. Thirdly a storage which keeps record on the user results.
Typically an application consisted of an user interface, a middle tier encompassing the core business logic and the persistence holding records/transactions for the longer duration.
To begin with, there was processing component and storage. This was facilitated with the minimalist user interface.
Firstly UI was a command line interface (CLI), then evolved to graphical user interface (GUI) and further evolved to a web browser. From mainframe era to desktop ages to client server applications
From processing logic perspective, the instructions were programmed in the same linked module, then came era of remote procedure call (i.e. calling other module deployed remotely) and the came SOAP Web Services followed by REST Web Services.
Anarchy within the software layers
Since there was no discipline established with respect to what piece of logic should reside where i.e. UI, middle tier and database; designers/developers were left with the choice to embed and implement the logic wherever they found it comfortable. They could fetch all data from storage through middle tier and write all core business logic, or code stored procedures close to database or have all control in middle tier. Meaning despite of this evolution, there was no balance and discipline established.
Going back to our business feature implementation across an enterprise..
Each domain, sub-domain (even features within the same sub-domain) created their own piece of software feature to fulfill their individual need. This resulted duplicate efforts, additional cost of building and maintaining applications.
Each business division created their own single gigantic software application structure to provide all necessary functionality to different users.
Each feature has a view, some business logic and storage coupled together. All such features were built into the same application bundle. Imagine many different teams within the organization working for different business unit and divisions/subdivisions started and continued building on the same application bundle for a long duration.
How Monolith & anti-patterns got built
Over a period of time such patterns where repeated across an enterprise.This led to building duplicate code/libraries/software pieces and hence duplicate efforts to do similar features. But majority of times, when people are pressed on time and are working towards delivering features defined with stringent deadlines, they lean towards putting additional code in the existing module/application. This tends to grow complexity. Release after release, loads of patches of code were added which made any application change very difficult.
Providing new features needed new (& mostly repetitive) code (was copy pasted) to be induced in an application. In a gigantic application structure with no modularity, finding out appropriate places to make code changes takes long time and very hard to make changes.This introduced rigidity and delay in delivering features.
Since the modules were tightly coded and built, a small change in one module could break the other module and its functionality .Breaking functionality makes software fragile and impact application users. Growing unstructured code is never easy to understand and hence maintain. Along with this manual testing made release cycles longer.
Dealing with increased usage
To deal with growing the user base and usage of software, provisioning on demand hardware and needed software was essential. Since a single dedicated and different operations group catered to all enterprise wide infrastructure needs, it was difficult to create a new or a temporary infrastructure. Also adding capacity to existing software (vertical scaling) was challenging and often time consuming. Reverting the releases was often painstaking process.
For example, in retail space, applications would have higher load on weekend compared to weekdays. The highest load on Thanksgiving or Christmas compared to rest of the year. In such situations over provisioning, procuring was a safe approach but that attracted heavy operational costs.
This overall situation led to creation monolith. This defeated the core objectives i.e. to provide features with a software which can be built and release quickly, with which be a reliable, available at all times to server, faster in performance, runs on needed cost, which can take care of dynamic load.
Birth of SOA
Learning from this era, gave birth to new architecture style called service oriented architecture.
In business terms, service is a peace of functionality which fulfills a need of the customers. Similarly in terms of software, Service is a piece of software which provides capabilities or functionalities to other piece of software. E.g. login service provides UI a capability to decide whether to let the user in the system or block access. Similarly service can provide functionality to other service. Order service provides details to Report service to generate monthly invoice report.
Service refers to a software functionality or a set of software functionalities with a purpose that different clients can reuse for different purposes. This simplified a world a lot since now in an enterprise there was a way to recognize business flows and or user flows and map them in the service oriented architecture pattern.
In this pattern, service logically represents a business activity with a specified outcome, it is self content and acts as a black box for the consumer. Beneath it, service may make use of different services but that aspect is abstract to the consumer.
In essence, enterprise would have many services (logically separated) talking to each other through a common message broker. This message broker holds the responsibility of managing communication from one service to other service. Message broker does it for all the services. Thus message broker becomes a single point of failure as well.
Challenges with SOA
SOA promotes application service re-usability, it focused on business functionality of reuse. SOA became popular and provided good relief to businesses and technocrats. However SOA services shared same message bus and same database. It also uses a common platform (application server) for all services deployed to it. It has common governance and protocol standards so all services need to abide it. While these aspects are good as those have evolved from past learning and have provided a good base to address challenges with respect to fragility, complexity, opacity, rigidity; on the other hand, SOA also has constraints and challenges. Few examples here.
Shared database. If specific application has a use case of a NOSql database instead of the established common SQL then its difficult to achieve. Secondly one shared database going down because of application A’s calls will impact all other dependent apps.
Message bus here is the backbone of the entire functioning and single point of failure. Also with many increased applications.
Common governance and protocol: E.g. services once establish to communicate in SOAP (heavy protocol to operate on) enforces this to be accepted in all services. It also impacts testing of all such services. Usage of different emerging and suitable technology for a specific service is challenging and difficult.
Although scaling was achieved, since all applications are deployed on the same application server, selective scaling (scale one among many applications) is not possible.
With this approach a systemic change requires changes in the monolith. So once you touch monolith… opening a Pandora’s box?
Overall it takes away some amount freedom and has opportunities to further improve. Also needs some traits to meet the desired need.
Lets take a look at how microservices solves for this further.