The post is part one of a blog series on the evolution of serverless security. The process of building applications has changed over time. Today, applications are designed to make use of multiple public clouds in addition to on-premises IT resources. They are also designed to use microservices, containers, and serverless. Each of these steps has been part of the evolution of application design, moving us towards applications that are inextricably interwoven with the infrastructure and workload automation software that controls the applications themselves.
At the dawn of the personal computer era, applications were designed to be used on a single computer. These applications were designed to process, manipulate, and store data all within a single application. These early “monolithic” applications were solid blocks of code; they weren’t broken up into modular components. That meant that code within the application was not easily reused.
Monolithic applications are hard to maintain. Every bug fix requires recompiling the entire application. Reusing code often means copying and pasting that code instead of building it into a separate library. As a result, buggy code can be replicated multiple times throughout the application, and not every instance of a given bug is always fixed.
Over time, monolithic applications started to be broken up. Frequently reused blocks of code were put into libraries. Specific features or functions were placed into separate modules which not only allowed for code reuse, but also meant that updates and fixes could be applied to individual modules without having to recompile the entire application.
Breaking applications into modules became especially popular as more and more functionality was added to applications and applications grew progressively larger and more complicated. Application components and modules usually contained a specific functionality, such as giving the application the ability to integrate with other applications or devices.
Eventually, as PC networking became popular, applications were broken up. Instead of having a single application for the processing, manipulation, and storage of data, these functions began to be placed on different computers. Storage might be relegated to a dedicated file server and/or database. Processing might be done by a dedicated server application, and data manipulation might be handled by a client application.
Communication between the different application components became important. Both standard TCP/IP communications and the concept of message queues drove the development of increasingly distributed applications, beginning with applications from the late ’80s and working up through today’s most bleeding edge cloud native applications.
Microservices are small services that combine to form a larger application. An important concept for the modern idea of microservices is their ability to scale independently. The rest of the definition depends on who you talk to, with some experts tying microservices to business processes and others viewing any independent application component as a potential microservices.
When the core code of an application is carved up into smaller applications, a number of terms can be used. If the resulting smaller applications are small enough, experts seem to agree that they constitute microservices. Larger application pieces can be called many things, but “components” is the most accurate term for them.
The basic idea of scaling components of an application independently proved to be important to successfully scaling applications to meet real-world needs. This resulted in the development of Service Oriented Architecture (SOA).
SOA was an attempt to break up monolithic applications into a collection of slightly less monolithic services. SOA didn’t really catch on for a number of reasons; one of the most important of these is that under the SOA approach, the resulting individual application components were still large and cumbersome.
In addition to being difficult to scale, large application components did not work well with the thin client approach to computing. Keeping the client-facing code small and lightweight – most web pages are good examples – became more important as the internet and smartphones grew in importance.
However, the core idea of breaking up applications was a good one, and it led to what we now call microservices. In any large application, there are probably components that crunch numbers and do analysis, other components that churn away on business logic, and there may be components that talk to other applications or even public cloud services.
In a traditional monolithic application, it would be hard to scale one component independently of the others. The best you could normally do would be to get the database to scale up or down as needed. Updating also became a problem. If you wanted to update just one small part of the application, you had to recompile and update the whole thing. Monolithic application development is slow.
Microservices allow for individual application components to be updated independently of one another. They also allow individual application components to be scaled independently of one another. Because microservices have defined interaction points with other microservices and/or the main application, microservices can also be developed independently of one another: their isolation reduces the impact of many types of bugs and code changes on the rest of the application.
A single application can consist of multiple components, some of which are easy to mentally separate and consider as their own service or microservices. There are underlying infrastructure components required to execute those services or microservices. There might be a client-facing web server. There is probably storage in some form, which might involve file storage, object storage, and/or a database.
The Nerdy Stuff
It is important to differentiate SOA from microservices when talking about development approaches. Most SOA approaches generally weren’t very “micro” in their attempts to split up monolithic applications into services. Java developers, for example, may be familiar with SOA technologies built into Java such as Enterprise JavaBeans (EJBs).
EJBs are basically Java-speak for self-contained services that can be stood up inside a lightweight container with just enough of an executing environment to communicate with neighboring services. While this may sound lightweight—and EJBs absolutely can be used for microservices—EJBs were usually used to stand up services large enough that the term “micro” just couldn’t reasonably apply.
A microservices can be envisioned using the Unix philosophy: do one thing, and do it well. Most modular application components in SOA applications could be better thought of as doing a largish cluster of related things while still being composed of a large amount of code with respectable system requirements.
Stay tuned for Part 2 which will focus on the introduction of containers and functions.