This is the first article in a three-part series inspired by something I read in Scalability Rules: 50 Principals For Scaling Web Sites by Martin Abbott and Michael Fisher:
Design for 20x capacity. Implement for 3x capacity. Deploy for ~1.5x capacity.
Fortunately, designing for scalability doesn't necessarily require us to change the fundamentals of how we develop software. But it does mean we need to expand our thinking beyond the design characteristics we'd expect to see in the individual software components themselves: a team of the best developers can follow all of the best practices they've spent years to master and still develop an application that doesn't scale. Even if you have an experienced team that designs a flexible robust architecture, there are still no guarantees with respect to how the application will scale.
Everyone plays a role
The responsibility doesn't lie solely within the engineering team. Whether you're a developer, a product manager or a member of the executive team, we all would rather be part of a successful software project than an unsuccessful one. Being responsible for a project that attracted 1,000,000 users instead of 50,000 is a problem all startups dream of. It's also a problem that quickly turns into a nightmare if each and every member of your organization isn't committed to unlimited growth.
It is absolutely critical to have all of the stakeholders agree on the priority of scalability:
Use design patterns appropriately
Unlike technology, design patterns are not concepts that are constantly evolving. There is and will always be a limited number of logical ways in which components can interact with each other. The operative word here is logical. You must be able to manage the physical relationships and dependencies outside the logical boundaries of the major components you use to construct your application. This is the best means of ensuring that we do not inadvertently introduced a tight coupling where none should exist.
Apply best engineering practices rigorously and consistently
Not only would it be impractical to provide a comprehensive list, but all best practice idioms do not necessarily apply to all software development projects. I've included the mantras I most often apply to my own designs, but it's up to you to determine the core set of design principles that best support your goals.
Apply the eight principles of Service Oriented Architecture
Service Oriented Architecture (SOA) addresses many of the fundamental principals that are necessary to developing a scalable application, but scalability itself is not SOA's primary focus. In fact, SOA is often achieved at the expense of performance and scalability and may introduce an even tighter coupling in the release process for dependent shared services. The key is to apply these principals intelligently, taking extra precautions to avoid unwarranted and unnecessary side effects that might impede scalability.
Quantify for maximum success and multiple your best guesses by a factor of x
One of the questions I'm sometimes asked by one of the developers I work with is how much load do we expect? My answer is usually something along the lines of show me your design and tell me why you think we need to worry about it. The fact is that it can be difficult to predict growth for a new innovative application. amazon.com's retail business is a perfect example.
I had the pleasure of listening to Jon Jenkins relay Amazon's early history at an AWS Summit a few months ago. Few people are aware of the fact that while Amazon was emerging as a successful online book store, they were running the site on three servers sitting in a closet. Shortly after what JJ referred to as a water event in 1988, they moved to a more reliable data center where they continued to grow both functionality and customers at a rapid pace.
Fast forward to 2005 when the Amazon engineers realized that their architecture would not support continued growth. If they neglected to address scalability, there would be no business. They spent the next six years migrating amazon.com to Amazon Web Services, turning off the last physical web server in November, 2010.
Design for the cloud
Of all the propositions discussed here, cloud computing is probably the biggest enabling factor. The great thing about cloud computing is that it really doesn't ask us to discard any of the good design habits we've already acquired. It simply encourages us to expand the scope of how we apply those principals.
Let's take a simple example: I need to develop an application that will read data from a database, apply a series of analytic operations and write the results to a database where it will be subsequently be consumed by a reporting application.
Identify the technical requirements
Defining the requirements for the project extends well beyond the scope of your customer's business needs. You also need to consider all of the factors that will impact your ability to deploy and support the application, as well as sustain growth without impacting performance.
Not only do I have to quantify the requirements for my new application, I need to have a complete understanding of the reporting application that's going to consume my data:
Identify proximity requirements
Once I have a complete understanding of how I might expect my application to be used, I can begin to make intelligent decisions about the proximity of my dependencies. If my new application expects to read a million rows, I probably want my application to live in close proximity to the database. If my reports are dynamically generated and presented to the user via a web interface, I can take advantage of the fact that users can visually consume a limited amount of data at one time -- I can tolerate a considerable distance between the web application and reporting data without sacrificing the perception of good performance.
Mapping proximity requirements will generally be an iterative process during which natural system boundaries will start to emerge. These boundaries will highlight the areas where we can take advantage of distributed deployment opportunities as well as the areas where we need to minimize if not eliminate proximity requirements altogether.
Use the AKF Scale Cube to measure the scalability of your design
A well-designed application will be able to scale equally well in any of three dimensions:
The X Axis represents our ability to scale horizontally, otherwise known as scaling out. Simply put, this is our ability to split our load across multiple instances. The ability to efficiently deploy an unlimited number of instances of my application means that I can always accommodate unexpected growth or load. In fact, the optimal solution would allow me to do any of the following with the least amount of time and effort:
The Y Axis represents the degree to which we've applied best practices and SOA. A system of smaller, more focused services almost always exhibit the characteristics usually associated with successful applications:
The Z Axis indicates how well we will be able to support big data. Even the simplest application can be subjected to huge volumes of data generated by external events outside our control. The degree to which we can distribute data and transactions will determine whether our design imposes undesirable limits on growth.
Next time, we'll take a deeper dive into how we apply these design principals to the implementation of scalable software.
About the author
Brenda Bell has been actively involved in software design and implementation for nearly thirty years. She is currently employed as a Software Architect at Awareness, Inc. and lives in Henniker, NH.