Search icon
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Serverless Design Patterns and Best Practices
Serverless Design Patterns and Best Practices

Serverless Design Patterns and Best Practices: Build, secure, and deploy enterprise ready serverless applications with AWS to improve developer productivity

By Brian Zambrano
€28.99 €19.99
Book Apr 2018 260 pages 1st Edition
eBook
€28.99 €19.99
Print
€37.99
Subscription
€14.99 Monthly
eBook
€28.99 €19.99
Print
€37.99
Subscription
€14.99 Monthly

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Buy Now

Product Details


Publication date : Apr 12, 2018
Length 260 pages
Edition : 1st Edition
Language : English
ISBN-13 : 9781788620642
Concepts :
Table of content icon View table of contents Preview book icon Preview Book

Serverless Design Patterns and Best Practices

Chapter 1. Introduction

It's an exciting time to be in the software industry. Over the past few years, we've seen an evolution in architectural patterns, with a considerable movement away from large, monolithic applications toward microservices. As cloud computing has evolved, so too have the systems and services we software developers have at our disposal. One of the most revolutionary tools in this domain is lambda functions, or more accurately, Functions as a Service. A step beyond microservices, being able to run, manage, and deploy a single function as a different entity has pushed us into the realm of nanoservices.

Of course, this book focuses on design patterns for serverless computing. The best place to start then is: what are design patterns and what is serverless computing?

If you're just beginning your journey into the world of serverless systems and patterns, I encourage you to read other resources to get more details on these and related topics. Our upcoming discussion intends to set the stage for building systems with patterns, but it's not necessary to explain the foundations of serverless platforms or its concepts in excruciating detail.

In this chapter, I'll first define a few relevant terms and concepts before diving deeper into those topics. Then, I'll discuss when serverless architectures are or are not a good fit. Finally, I'll explain the various categories of serverless patterns that I'll present in this book. I presume that you, the reader, are somewhat familiar with these large topics, but absolute mastery is not required.

At the end of this chapter, you should be able to do the following:

  • Describe the term serverless in your own words
  • Know how design patterns relate to serverless architectures
  • Understand general classifications of serverless design patterns

What is serverless computing?


Let's start with the simpler of the two questions first—what is serverless computing? While there may be several ways to define serverless computing, or perhaps more accurately serverless architectures, most people can agree on a few key attributes. Serverless computing platforms share the following features:

  • No operating systems to configure or manage
  • Pay-per-invocation billing model
  • Ability to automatically scale with usage
  • Built-in availability and fault tolerance

While there are other attributes that come with serverless platforms, they all share these common traits. Additionally, there are other serverless systems that provide functionality other than general computing power. Examples of these are DynamoDB, Kinesis, and Simple Queue Service, all of which fall under the Amazon Web Services (AWS) umbrella. Even though these systems are not pay-per-invocation, they fall into the serverless category since the management of the underlying systems is delegated to the AWS team, scaling is a matter of changing a few settings, fault-tolerance is built-in, and high availability is handled automatically.

No servers to manage

Arguably, this is where the term serverless came from and is at the heart of this entire movement. If we look back not too long ago, we can see a time when operations teams had to purchase physical hardware, mount it in a data center, and configure it. All of this was required before engineers even had the chance of deploying their software.

Cloud computing, of course, revolutionized this process and turned it upside down, putting individual engineers in the driver's seat. With a few clicks or API calls, we could now get our very own virtual private server (VPS) in minutes rather than weeks or months. While this was and is incredibly enabling, most of the work of setting up systems remained. A short list of things to worry about includes the following:

  • Updating the operating system
  • Securing the operating system
  • Installing system packages
  • Dealing with dependency management

This list goes on and on. A point worth noting is that there may be hours and hours of configuration and management before we're in a position to deploy and test our software.

To ease the burden of system setup, configuration software such as Puppet, Chef, SaltStack, and Ansible arrived on the scene. Again, these were and are incredibly enabling. Once you have your recipes in place, configuring a new virtual host is, most importantly, repeatable and hopefully less error-prone than doing a manual setup. In systems that comprise hundreds or even thousands of virtual servers, some automation is a requirement rather than a mere convenience.

As lovely as these provisioning tools are, they do come with a significant cost of ownership and can be incredibly time-consuming to develop and maintain. Often, iterating on this infrastructure-as-code tooling requires making changes and then executing them. Starting up a new virtual host is orders of magnitude faster than setting up a physical server; however, we measure VPS boot time and provisioning time in minutes. Additionally, these are software systems in and of themselves that a dedicated team needs to learn, test, debug, and maintain. On top of this, you need to continually maintain and update provisioning tools and scripts in parallel with any changes to your operating systems. If you wanted to change the base operating system, it would be possible but not without significant investment and updates to your existing code.

When Lambda was launched by AWS in 2014, a new paradigm for computing and software management was born. In contrast to managing your virtual hosts, AWS Lambda provided developers the ability to deploy application code in a managed environment without needing to manage virtual hosts themselves. Of course, there are servers running somewhere that are operated by someone. However, the details of these servers are opaque to us as application developers. No longer do we need to worry about the operating system and its configuration directly. With AWS Lambda and other Functions as a Service (FaaS) platforms, we can now delegate the work of VPS management to the teams behind those platforms.

The most significant shift in thinking with FaaS platforms is that the unit of measure has shrunk from a virtual machine to a single function.

Pay-per-invocation billing model

Another significant change with the invention of serverless platforms is the pay-per-invocation model. Before this, billing models were typically per minute or hour. While this was the backbone of elastic computing, servers needed to stay up and running if they were used in any production environment.

Paying for a VPS only while it's running is a great model when developing since you can just start it at the beginning of the d``

ay and terminate it at the end of the day. However, when a system needs to be available all the time, the price you pay is nearly the same whether its CPU is at 100% usage or 0.0001% usage.

Serverless platforms, on the other hand, the bill only while the code is being executed. They are designed and shine for systems that are stateless and have a finite, relatively short duration. As such, billing is typically calculated based on a total invocation time. This model works exceptionally well for smaller systems that may get only a few calls or invocations per day. On many platforms, it's possible to run a production system that is always available completely for free. There is no such thing as idle time in the world of serverless.

Ability to automatically scale with usage

Gone are the days of needing to overprovision a system with more virtual hosts than you typically need. As invocations ramp up, the underlying system automatically scales up, providing you with a known number of concurrent invocations. Moving this limit higher is merely a matter of making a support request to Amazon, in the case of AWS Lambda. Before this, managing horizontal scalability was an exercise for the team designing the system. Never has horizontal scalability for computing resources been so easy.

Different cloud providers provide the ability to scale up or down (that is, be elastic) based on various parameters and metrics. Talk to DevOps folks or engineers who run systems with autoscaling and they will tell you it's not a trivial matter and is difficult to get right.

Built-in availability and fault tolerance

Servers, real or virtual, can and do fail. Since the hosts that run your code are now of little or no concern for you, it's a worry not worth having.

Just as the management of the operating system is handled for you, so too is the management of failing servers. You can be guaranteed that when your application code should be invoked, it will be.

Design patterns


With a good understanding of serverless computing behind us, let's turn our attention to design patterns.

If you've spent any amount of time working with software, you will have heard the term design pattern and may very well be familiar with them to some degree. Stepping back slightly, let's discuss what a design pattern is.

I will assert that if you ask 10 different developers to define the term design pattern, you will get 10 different answers. While we all may have our definition, and while those definitions may not be wrong, it's relatively simple to agree on the general spirit or idea of a software design pattern. Within the context of software engineering, design patterns are reusable solutions or code organization applied to a frequently occurring problem. For example, the Model-View-Controller pattern evolved to solve the problem of GUI applications. The Model-View-Controller pattern can be implemented in almost any language for nearly any GUI application.

Software design patterns evolved as a solution to help software authors be more efficient by applying well-known and proven templates to their application code. Likewise, architectural patterns provide the same benefits but at the level of the overall system design, rather than at the code level.

In this book, we won't be focusing on software design, but rather architectural design in serverless systems. In that vein, it's worth noting that the context of this book is serverless architectures and our patterns will manifest themselves as reusable solutions that you can use to organize your functions and other computing resources to solve various types of problem on your serverless platform of choice.

Of course, there is an infinite number of ways to organize your application code and hundreds of software and architectural patterns you can use. The primary focus here is the general organization or grouping of your functions, how they interact with one another, the roles and responsibilities of each function, and how they operate in isolation but work together to compose a larger and more complex system.

As serverless systems gain traction and become more and more popular, I would expect serverless patterns such as those we will discuss in this book to grow in both popularity and number.

When to use serverless


Many types of computing problem can be solved with a serverless design. Personally speaking, I have a hard time not using serverless systems nowadays due to the speed, flexibility, and adaptability they provide. The classes of problem that are suitable for serverless systems are extensive. Still, there is a sweet spot that is good to keep in mind when approaching new problems. Outside of the sweet spot, there are problems that are not a good fit.

The sweet spot

Since serverless systems work on the basis of a single function, they are well suited to problems that are, or can be broken down into, the following subsystems:

  • Stateless
  • Computationally small and predictable

Serverless functions are ephemeral; that is, they have a known lifetime. Computation that is itself stateless is the type of problem where FaaS platforms shine. Application state may exist, and functions may store that state using a database or some other kind of data store, but the functions themselves retain no state between invocations.

In terms of computing resources, serverless functions have an upper bound, both in memory and total duration. Your software should have an expected or predictable upper limit that is below that of your FaaS provider. At the time of writing, AWS Lambda functions have an upper bound of 1,536 MB for memory and 300 seconds in duration. Google Compute advertises an upper limit of 540 seconds. Regardless of the actual values, systems, where you can reliably play within these bounds, are good candidates for moving to serverless architecture.

A good, albeit trivial, an example of this would be a data transformation function—given some input data, transform it into a different data structure. It should be clear with such a simple example that no state needs to be or is carried between one invocation and the next. Of course, data comes in various sizes, but if your system is fed data of a predictable size, you should be able to process the data within a certain timeframe.

In contrast, long-running processes that share state are not good fits for serverless. The reason for this is that functions die at the end of their life, leaving any in-memory state to die with them. Imagine a long-running process such as an application server handling WebSocket connections.

WebSockets are, by definition, stateful and can be compared to a phone call—a client opens up a connection to a server that is kept open as long as the client would like. Scenarios such as this are not a good fit for serverless functions for the two following reasons:

  • State exists (i.e., state of a phone call is connected or disconnected)
  • The process is long-lived because the connection can remain open for hours or days

Whenever I approach a new problem and begin to consider serverless, I ask myself these two questions:

  • Is there any global state involved that needs to be kept track of within the application code?
  • Is the computation to be performed beyond the system limits of my serverless platform?

The good news is that, very often, the answer to these questions is no and I can move forward and build my application using a serverless architecture.

Classes of serverless pattern


In this book, we'll discuss four major classes of serverless design pattern:

  • Three-tier web application patterns
  • Extracttransformload (ETL) patterns
  • Big data patterns
  • Automation and deployment patterns

Three-tier web application patterns

Web applications with the traditional request/response cycle are a sweet spot for serverless systems. Because serverless functions are short-lived, they lend themselves well to problems that are themselves short-lived and stateless. We have seen stateful systems emerge and become popular, such as WebSockets; however, much of the web and web applications still run in the traditional stateless request/response cycle. In our first set of patterns, we'll build different versions of web application APIs.

While there are three different patterns to cover for web applications, they will all share a common basis, which is the three-tier model. Here, the tiers are made up of the following:

  • Content Delivery Network (CDN) for presentation code/static assets (HTML, JavaScript, CSS, and so on)
  • Database for persistence
  • Serverless functions for application logic

REST APIs should be a common and familiar tool for most web developers. In Chapter 2A Three-Tier Web Application Using REST, we'll build out a fully featured REST API with a serverless design. This API will have all of the methods you'd expect in a classic REST API—create, read, update, delete (CRUD).

While REST APIs are common and well understood, they do face some challenges. After starting with a serverless REST API, we'll walk through the process of designing the changes needed to make that same API work as a single GraphQL endpoint that provides the same functionality in Chapter 3A Three-Tier Web Application Pattern with GraphQL.

Finally, in Chapter 4Integrating Legacy APIs with the Proxy Pattern, we'll use a proxy pattern to show how it's possible to completely change an API  but use a legacy API backend. This design is especially interesting for those who would like to get started migrating an API to a serverless platform but have an existing API to maintain.

ETL patterns

ETL patterns is another area of computing that lends itself very well to serverless platforms. At a high level, ETL jobs comprise the following three steps:

  • Extracting data from one data source
  • Transforming that data appropriately
  • Loading the processed data into another data source

Often used in analytics and/or data warehousing, ETL jobs are hard to escape. Since this problem is again ephemeral and because users would probably like their ETL jobs to execute as quickly as possible, serverless systems are a great platform in this problem space. While serverless computation is typically short-lived, we will see how ETL processes can be designed to be long-running in order to work through large amounts of data.

In the fan-out pattern, discussed in Chapter 5Scaling Out with the Fan-Out Pattern, a single unit of work will be broken up into multiple smaller units of work and processed in parallel. This pattern may be used as a standalone system or as a subcomponent in a more extensive system. We'll build out an application using the fan-out pattern in isolation, but later discuss how it can work as a piece in a more extensive system.

Messaging patterns themselves can be an entire class of design pattern. In our context, we will show how to use this as a general pattern to process data asynchronously with a known or fixed amount of processing power. Chapter 6,Asynchronous Processing with the Messaging Pattern, will walk through a full example of this pattern and its variants in a serverless context.

Big data patterns

It may seem confusing that lambda can refer to both AWS Lambda functions as well as a pattern in and of itself. The lambda pattern was born from the need to analyze large amounts of data in real time. Before this, the big data movement, where large batch jobs would run to calculate and recalculate things, was in full swing. The problem faced by this movement was that these batch jobs, in order to get the latest results, would need to spend the majority of their computing resources recalculating metrics on data that hadn't changed.

The lambda pattern, which we will discuss in Chapter 7, Data Processing Using the Lambda Pattern, creates two parallel planes of computation, a batch layer, and a speed layer. The naming of these layers should give you an idea of what they're responsible for.

MapReduce is another well-known and tested paradigm that has been popular in the software world for some time now. Hadoop, arguably the most famous framework for MapReduce, helped to bring this pattern front and center after Google's original MapReduce paper in 2004.

As amazing as Hadoop is as a software system, there are substantial hurdles to overcome in running a production Hadoop cluster of your own. Due to this, systems such as Amazon's Elastic MapReduce (EMR) were developed, which provide on-demand Hadoop jobs to the developer. Still, authoring Hadoop jobs and managing the underlying computing resources can be non-trivial. We'll walk through writing your serverless MapReduce system in Chapter 8, The MapReduce Pattern.

Automation and deployment patterns

Many of us are used to logging onto a machine via ssh and grepping through log files to look for problems. Our worlds are now turned upside down since there are no longer any servers to SSH into. Fortunately, there are methods of handling errors and getting the information needed to debug and monitor your programs. 

In Chapter 9Deployment and CI/CD Patterns, we'll focus on error handling, as well as some of the dos and don'ts of serverless systems and what modern-day best practices look like in the serverless world. Many development practices change when building on top of a serverless platform and there are a lot of gotchas that, if you're unfamiliar with them, may surprise you. Chapter 9, Deployment and CI/CD Patterns, will walk through some of the biggest issues that may bite you if you're brand new to this ecosystem.

While some tooling and techniques may change, let's not forget a healthysoftware development life cycle consists of well-structured code, continuous integration (CI), continuous deployment (CD), and unit tests. Coupled with the myriad of hosted CI/CD platforms, running tests and deploying code automatically is quite painless and even fun. In Chapter 10Deployment and CI/CD Patterns will discuss various options and examples with hosted CI and CD platforms. I'm confident that you'll find the velocity at which you can ship code using serverless technologies exciting and enabling.

Serverless frameworks


With the advent of serverless platforms came the creation of multiple frameworks to help us manage our serverless applications. Just as Ruby on Rails, Spring, Django, Express, and other web frameworks aid in the creation and management of web applications, various serverless frameworks have sprung up that make the software development lifecycle easier for serverless applications.

An essential difference between web frameworks and serverless frameworks is that serverless frameworks often help with the management of application code on a serverless platform. In contrast, much of the help web frameworks provide revolves around web logic and tasks such as the following:

  • Producing HTML output via templating engines
  • Managing database records via Object Relational Mappers (ORMs)
  • Validating submitted form data
  • Dealing with the details of HTTP requests and responses

Not all applications that run on a serverless platform are HTTP-based. Therefore, serverless frameworks do not necessarily have application-specific functionality baked in but, instead, they have deployment and management functionality. Some frameworks do target web developers and aid in web-centric tasks; however, there are several other frameworks that do not and instead focus on managing arbitrary application code.

A few popular serverless frameworks worth noting are the following:

  • Apex
  • Serverless
  • ClaudiaJS
  • Kappa
  • SAM (Serverless Application Model from AWS)
  • Chalice (from AWS)
  • Zappa

Throughout this book, I'll be using a serverless framework to manage application code and the entire stack of resources that we will deploy during the examples. Serverless works with a variety of programming languages and various platforms, such as AWS, Azure, Google Compute Cloud, and IBM Open Whisk. We will build all of our examples using AWS, but the patterns discussed should apply to other cloud providers unless explicitly noted otherwise. Since serverless frameworks such as Zappa don't give us any web-specific functionality, we will be responsible for some of the lower-level web application details in Chapter 2A Three-Tier Web Application Using REST, and Chapter 3, A Three-Tier Web Application Pattern with GraphQL.

Summary


In this introduction, we covered the main points regarding serverless platforms and discussed the attributes that make a system serverless. We covered the main differences between building software on top of self-managed systems, either physical or virtual, compared to building software systems on a serverless platform. Additionally, readers should have a clearer perspective of when serverless architectures are a good fit and when they are not.

We also reviewed the main categories of design pattern that I will cover in this book and gained a high-level overview of each one. Finally, I covered the differences between web and serverless frameworks and gave some examples of the latter.

With the stage set, we can jump into our first pattern with a real-world example. By the end of Chapter 2A Three-Tier Web Application Using REST, we will have produced a complete three-tier web application using REST API, all with serverless technologies.

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Learn the details of popular software patterns and how they are applied to serverless applications
  • Understand key concepts and components in serverless designs
  • Walk away with a thorough understanding of architecting serverless applications

Description

Serverless applications handle many problems that developers face when running systems and servers. The serverless pay-per-invocation model can also result in drastic cost savings, contributing to its popularity. While it's simple to create a basic serverless application, it's critical to structure your software correctly to ensure it continues to succeed as it grows. Serverless Design Patterns and Best Practices presents patterns that can be adapted to run in a serverless environment. You will learn how to develop applications that are scalable, fault tolerant, and well-tested. The book begins with an introduction to the different design pattern categories available for serverless applications. You will learn thetrade-offs between GraphQL and REST and how they fare regarding overall application design in a serverless ecosystem. The book will also show you how to migrate an existing API to a serverless backend using AWS API Gateway. You will learn how to build event-driven applications using queuing and streaming systems, such as AWS Simple Queuing Service (SQS) and AWS Kinesis. Patterns for data-intensive serverless application are also explained, including the lambda architecture and MapReduce. This book will equip you with the knowledge and skills you need to develop scalable and resilient serverless applications confidently.

What you will learn

• Comprehend the popular design patterns currently being used with serverless architectures • Understand the various design options and corresponding implementations for serverless web application APIs • Learn multiple patterns for data-intensive serverless systems and pipelines, including MapReduce and Lambda Architecture • Learn how to leverage hosted databases, queues, streams, storage services, and notification services • Understand error handling and system monitoring in a serverless architecture a serverless architecture • Learn how to set up a serverless application for continuous integration, continuous delivery, and continuous deployment

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Buy Now

Product Details


Publication date : Apr 12, 2018
Length 260 pages
Edition : 1st Edition
Language : English
ISBN-13 : 9781788620642
Concepts :

Table of Contents

18 Chapters
Title Page Chevron down icon Chevron up icon
Copyright and Credits Chevron down icon Chevron up icon
Dedication Chevron down icon Chevron up icon
Packt Upsell Chevron down icon Chevron up icon
Contributors Chevron down icon Chevron up icon
Preface Chevron down icon Chevron up icon
Introduction Chevron down icon Chevron up icon
A Three-Tier Web Application Using REST Chevron down icon Chevron up icon
A Three-Tier Web Application Pattern with GraphQL Chevron down icon Chevron up icon
Integrating Legacy APIs with the Proxy Pattern Chevron down icon Chevron up icon
Scaling Out with the Fan-Out Pattern Chevron down icon Chevron up icon
Asynchronous Processing with the Messaging Pattern Chevron down icon Chevron up icon
Data Processing Using the Lambda Pattern Chevron down icon Chevron up icon
The MapReduce Pattern Chevron down icon Chevron up icon
Deployment and CI/CD Patterns Chevron down icon Chevron up icon
Error Handling and Best Practices Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon
Index Chevron down icon Chevron up icon

Customer reviews

Filter icon Filter
Top Reviews
Rating distribution
Empty star icon Empty star icon Empty star icon Empty star icon Empty star icon 0
(0 Ratings)
5 star 0%
4 star 0%
3 star 0%
2 star 0%
1 star 0%

Filter reviews by


No reviews found
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

How do I buy and download an eBook? Chevron down icon Chevron up icon

Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.

If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.

Please Note: Packt eBooks are non-returnable and non-refundable.

Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:

  • You may make copies of your eBook for your own use onto any machine
  • You may not pass copies of the eBook on to anyone else
How can I make a purchase on your website? Chevron down icon Chevron up icon

If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:

  1. Register on our website using your email address and the password.
  2. Search for the title by name or ISBN using the search option.
  3. Select the title you want to purchase.
  4. Choose the format you wish to purchase the title in; if you order the Print Book, you get a free eBook copy of the same title. 
  5. Proceed with the checkout process (payment to be made using Credit Card, Debit Cart, or PayPal)
Where can I access support around an eBook? Chevron down icon Chevron up icon
  • If you experience a problem with using or installing Adobe Reader, the contact Adobe directly.
  • To view the errata for the book, see www.packtpub.com/support and view the pages for the title you have.
  • To view your account details or to download a new copy of the book go to www.packtpub.com/account
  • To contact us directly if a problem is not resolved, use www.packtpub.com/contact-us
What eBook formats do Packt support? Chevron down icon Chevron up icon

Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.

You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.

What are the benefits of eBooks? Chevron down icon Chevron up icon
  • You can get the information you need immediately
  • You can easily take them with you on a laptop
  • You can download them an unlimited number of times
  • You can print them out
  • They are copy-paste enabled
  • They are searchable
  • There is no password protection
  • They are lower price than print
  • They save resources and space
What is an eBook? Chevron down icon Chevron up icon

Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.

When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.

For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.