As of this writing the “Obamacare” web site remains fodder for late night comedians and armchair pundits. Much as been written about the debacle that is Healthcare.gov and the quotes are simultaneously damning and terrifying:
One specialist said that as many as five million lines of software code may need to be rewritten before the Web site runs properly – NY Times
The basic architecture of the site, built by federal contractors overseen by the Department of Health and Human Services, was flawed in design, poorly tested and ultimately not functional. – Time
The site’s front end… doesn’t look too bad, but it is not coping well with whatever scaling issues the back end (account storage, database lookups, etc.) is having. – Slate
The jury is still out on a number of issues, but what seems to be clear is the end-to-end system was never designed to perform even under the most moderate loads. The front-end processing may have been able to handle the expected traffic, but it takes a lot more than putting a load balancing router on the front-end to make an app scalable.
So, what does it take to make an app scalable – especially in the Cloud? A number of factors come into play, but the five most critical insights driving scalability are:
- Isolate Complexity
- Partition You App
- Replicate and Load Balance
- Dynamically Provision
- Instrument You Application
This post addresses isolating complexity. Subsequence posts will address the remaining four insights driving scalability.
1. Isolate Complexity
Simplicity is the goal of any well designed application, but “simple” often isn’t an option (like when you have to orchestrate multiple government agencies and private companies to offer health insurance). Complexity by itself isn’t a bad thing, but it must be isolated. Otherwise, required complexity in one area infects and corrupts an entire system – even those components that are relatively simple (like front-end page generation).
At Egen, we use a three-step process to isolate complexity: 1) Separate and Isolate; 2) Aggregate and Orchestrate; and 3) Coordinate and Collaborate.
Separate and Isolate
One of the fundamental principles of system design is separation of concerns (SoC). Essentially, SoC looks to segregate a system into distinct parts, such that each part addresses a distinct, non-overlapping element of the solution (a concern).
Within our iBlock Architecture, we separate concerns into logical assets and then isolate these assets through encapsulation. Assets are a powerful abstraction that bound distinct parts of the problem space. They represent the building blocks of a system.
Assets vary in scope and internal complexity, but this complexity is always isolated from other assets. Examples of assets include: legacy systems, third-party services, database platforms, shared resources, internal & external devices, message channels, and all or part of a Controller or Model layer.
Encapsulation “wraps” the asset into a software component that hides the internal implementation from other assets and provides a standard interface for its use. Essentially how an assets works (it’s state, low-level interactions, and how the asset is managed) is isolated from how it gets used.
An example of an encapsulated asset would be a Java Connector. The connector encapsulates an asset (e.g. a legacy system or device) into a Java object with a known interface. Other parts of an application would interact with that asset using this interface. Everything else is hidden within the implementation of that connector.
Aggregate and Orchestrate
Assets often encapsulate the API of the component they represent and then make this API available to other assets though their interface. Unfortunately, these APIs typically define low-level access points to the component and using the API to accomplish a task can be complicated. So even though the asset has isolated the component itself, the complexity of its usage has been distributed to the rest of the system.
To solve this problem, we take the additional step of aggregation and orchestration. Rather than exporting the API for a component, we aggregate the API into higher-order services that orchestrate the low-level API calls. It’s these higher-order services that define the interface for that asset. Using an asset is simplified (with a handful of services) and the complexity of the API is isolated within the asset.
Coordinate and Collaborate
In virtually every system there is functionality that relies on, or affects, many parts of the system and can not be isolated within an asset (e.g. security, memory management, status monitoring, transaction processing etc.). This type of inter-dependency is often referred to as a cross-cutting concern.
Without appropriate structuring, cross-cutting concerns can significantly add complexity through scattering (duplication of behavior) and tangling (hardwired inter-dependencies). To solve these problems, Egen identifies cross-cutting concerns as either a problem of coordination or one of collaboration, and then isolates the concern accordingly.
The essential purpose of coordination is to maintain order. In system design, this means assets are aligned to the same policies, follow the same rules, and behave in a consistent fashion. Examples of coordination are security, logging, memory management and status monitoring.
At Egen, isolation of coordination is achieve through aspects. Aspects are modular components which encapsulate the rules that are joined to assets (advice) and the structural components needed by other assets to implement the rules (inter-type declarations). Aspects are a powerful tool for isolating complexity. Too learn more, visit here.
Collaboration, on the other hand, is about assets working together to solve a problem. Examples of collaboration are transaction processing, persistence, and synchronization.
Isolating collaboration is simply a matter of encapsulating control and orchestration into a separate asset. But the techniques for using this asset to manage collaboration are varied. A few of the most common approaches are shown addressed below.
- Registration. The asset managing collaboration defines rules & structures for the collaboration and the assets which are part of the collaborative task implement these rules and structures and then register with the managing asset. An example of a registration approach to collaboration is a transaction manager. Registration is a good approach for separating highly complex collaborative behavior into a single asset, but it also inserts a high-level of usage complexity into a system (because assets involved in a collaborative task must adhere to specific rules and structures defined by the managing asset.
- Collaborative Service. The asset managing collaboration hides the collaborative details (including the assets used and how they coordinate) and then exports a service for the collaborative task. An example of a Collaborative Service is a data access service. Collaborative services are great for minimizing the usage complexity of collaborative tasks, but they are task-specific with limited flexibility.
- Rendezvous. With a rendezvous, assets involved in a Collaboration interact with the collaboration manager to synchronize behavior across assets. An examples of a rendezvous asset would be a queue manager. A rendezvous asset is perfect for synchronizing complex behaviors.
Scalability requires replication and replication requires isolation. You can not build a scalable, multi-component, end-to-end system without isolating complexity. It doesn’t matter if you are using clustering, OSGi bundles, or good-ol-fashioned router load balancing, unless you’ve isolated complexity – both internal and usage complexity – your system will breakdown under high loads (and sometime not so high).
Up Next: 5 Critical Insights for Scaling Apps in the Cloud – Part II (Partition Your App)