Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Microservices with Clojure
Microservices with Clojure

Microservices with Clojure: Develop event-driven, scalable, and reactive microservices with real-time monitoring

eBook
$27.98 $39.99
Paperback
$48.99
Subscription
Free Trial
Renews at $19.99p/m

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
OR
Modal Close icon
Payment Processing...
tick Completed

Billing Address

Table of content icon View table of contents Preview book icon Preview Book

Microservices with Clojure

Monolithic Versus Microservices

"The old order changeth yielding place to new"

- Alfred Tennyson

A well-designed monolithic architecture has been the key to many successful software applications. However, microservices-based applications are gaining popularity in the age of the internet due to their inherent property of being autonomous and flexible, their ability to scale independently, and their shorter release cycles. In this chapter, you will:

  • Learn about the basics of monolithic and microservices architectures
  • Understand the monolithic-first approach and when to start using microservices
  • Learn how to migrate an existing monolithic application to microservices
  • Compare and contrast the release cycle and deployment methodology of monolithic and microservices-based applications

Dawn of application architecture

Ever since Ada Lovelace (https://en.wikipedia.org/wiki/Ada_Lovelace) wrote the first algorithm for Analytical Engine (https://en.wikipedia.org/wiki/Analytical_Engine) in the 19th century and Alan Turing (https://en.wikipedia.org/wiki/Alan_Turing) formalized the concepts of algorithm and computation via the Turing machine (https://en.wikipedia.org/wiki/Turing_machine), software has gone through multiple phases in its evolution, both in terms of how it is designed and how it is made available to its end users. The earlier software was designed to run on a single machine in a single environment, and was delivered to its end users as an isolated standalone entity. In the early 1990s, as the focus shifted to application software, the industry started exploring various software architecture methodologies to meet the demands of changing requirements and underlying environments. One of the software architectures that was widely adopted was multitier architecture, which clearly separated the functions of data management, business logic, and presentation. When these layers were packaged together in a single application, using a single technology stack, running as a single program, it was called a monolithic architecture, still in use today.

With the advent of the internet, software started getting offered as a service over the web. With this change in deployment and usage, it started becoming hard to upgrade and add features to software that adopted a monolithic architecture. Technology started changing rapidly and so did programming languages, databases, and underlying hardware. Companies that were able to disintegrate their monolithic applications into loosely-coupled services that could talk to each other were able to offer better services, better integration points, and better performance to their users. They were not only able to upgrade to the latest technology and hardware, but also able to offer new features and services faster to their users. The idea of disintegrating a monolithic application into loosely-coupled services that can be developed, deployed, and scaled independently and can talk to other services over a lightweight protocol, was called microservices-based architecture (https://en.wikipedia.org/wiki/Microservices).

Companies such as Netflix, Amazon, and so on have all adopted a microservices-based architecture. If you look at Google Trends in the preceding screenshot, you can see that the popularity of microservices is rising day by day, but this doesn't mean that monolithic applications are obsolete. There are applications that are still suited for monolithic architecture. Microservices have their advantages, but at the same time they are hard to deploy, scale, and monitor. In this chapter, we will look at both monolithic and microservices-based architectures. We will discuss when to use what and also talk about when and how to migrate from a monolithic to a microservices-based architecture.

Monolithic architecture

Monolithic architecture is an all-in-one methodology that encapsulates all the required services as a single deployable artifact. It works on a single technology stack and is deployed and scaled as a single unit. Since there is only one technology stack to master, it is easy to deploy, scale, and set up a monitoring infrastructure for monolithic applications. Each team member works on one or more components of the system and follows the design principle of Separation of Concerns (SoC) (https://en.wikipedia.org/wiki/Separation_of_concerns). Such applications are also easier to refactor, debug, and test in a single standalone development environment.

Applications based on monolithic architecture may consist of one or more deployable artifacts that are all deployed at the same time. Such a monolithic architecture is often referred to as a Distributed Monolith.

For example, a very common monolithic application is a word processing application; Microsoft Word is installed via a single deployable artifact and is entirely built on Microsoft .NET Framework (https://www.microsoft.com/net/). There are various components within word processing application, such as templates, import/export, spell-checker, and so on, that work together to help create a document and export it the format of choice.

Monolithic architecture applies not only to standalone applications, but also to client-server based applications that are provided as a service over the web. Such client-server based applications have a clearly defined multitier architecture that provides the relevant services to its end users via a user interface.

The user interface talks to application endpoints that can be programmed using well-defined interfaces.

A typical client-server application may adopt a three-tier architecture to separate the presentation, business logic, and persistence layer from each other, as shown in the preceding diagram. Components of each layer talk strictly to the components of the layer below them. For example, the components of the presentation layer may never talk to the persistence layer directly. If they need access to data, the request will be routed via the business logic layer that will not only move the data between the persistence layer and the presentation layer, but also do the required processing to serve the request. Adopting such a component-based layered architecture also helps in isolating the effect of change to only the components of dependent layers instead of the entire application. For example, changes to the components of the business logic layer may require a change in the dependent components of the presentation layer but components of the persistence layer may remain intact.

Even though a monolithic application is built on SoC, it is still a single application on a single technology stack that provides all required services to its users. Any change to such an application requires to be compatible with all the encapsulated services and underlying technology stack. In addition to that, it is not possible to scale each service independently. Any scaling requirement is met by deploying multiple instances of the entire system as a single unit. A team working on such a monolithic application scales over time and has to adapt to newer technologies as a whole, which is often challenging due to the rapidly changing technology landscape. If they do not change with the technology, the entire software becomes obsolete over time and is discarded due to incompatibility with newer software and hardware, or a shortage of talent.

Microservices

Microservices are a functional approach well applied to software. It tries to decompose the entire application functionally into a set of services that can be deployed and scaled independently. Each service does only one job and does it well. It has its own database, decides its own schema, and provides access to datasets and services through well-defined application programming interfaces that are better known as APIs, often paired with a user interface. APIs follow a set communication protocols, but services are free to choose their own technology stack and can be deployed on hardware of choice.

In a microservice environment, as shown in the preceding diagram, there are no layers like in monoliths; instead, each service is organized around a bounded context (https://en.wikipedia.org/wiki/Domain-driven_design#Bounded_context) that adds a business capability to the application as a whole. New capabilities in such an application are added as new services that are deployed and scaled independently. Each user request in a microservices-based application may call one or more internal microservice to retrieve data, process it, and generate the required response, as shown in the following diagram. Such software evolves faster and has low technology debt. They do not get married to a particular technology stack and can adopt a new technology faster:

Data management

In a microservices-based application, databases are isolated for each business capability and are managed by only one service at a time. Any request that needs access to the data managed by another service strictly uses the APIs provided by the service managing the database. This makes it possible to not only use the best database technology available to manage the business capability, but also to isolate the technology debt to the service managing it. However, it is recommended for the calling service to cache responses over time to avoid tight coupling with the target service and reduce the network overhead of each API call.

For example, a service managing user interests might use a graph database (https://en.wikipedia.org/wiki/Graph_database) to build a network of users, whereas a service managing user transactions might use a relational database (https://en.wikipedia.org/wiki/Relational_database) due to its inherent ACID (https://en.wikipedia.org/wiki/ACID) properties that are suitable for transactions. The dependent service only needs to know the APIs to connect to the service for data and not the technology of the underlying database.

This is contrary to a monolithic layered architecture, where databases are organized by business capability, which may be accessed by one or more persistence modules based on the request. If the underlying database is using a different technology, then each of the modules accessing the databases have to comply with the same technology, thus inheriting the complexity of each database technology that it has access to.

Database isolation should be done at the database level and not at the database technology level. Avoid deploying multiple instances of the same relational database or graph database as much as possible. Instead, try to scale them on demand and use the isolation capability of these systems to maintain separate databases within them for each service.

The concept of microservices is very similar to a well-known architecture called service-oriented architecture (SOA) (https://en.wikipedia.org/wiki/Service-oriented_architecture). In microservices, the focus is on identifying the right bounded context and keeping the microservices as lightweight as possible. Instead of using a complex message-oriented middleware (https://en.wikipedia.org/wiki/Message-oriented_middleware) such as ESB (https://en.wikipedia.org/wiki/Enterprise_service_bus), a simple mode of communication is used that is often just HTTP.

"Architectural Style [of Microservices] is referred to as fine-grained SOA, perhaps service orientation done right"

- Martin Fowler on microservices

When to use what

The monolithic layered architecture is one of the most common architectures in use across the software industry. Monolithic architectures are well suited for transaction-oriented enterprise applications that have well-defined features, change less often, and have complex business models. For such applications, transactions and consistency are of prime importance. They require a database technology with built-in support for ACID properties to store transactions. On the other hand, microservices are suited better for Software-as-a-Service, internet-scale applications that are feature-first applications with each feature focused on a single business capability. Such applications change rapidly and are scaled partially per business capability on demand. Transactions and consistency in such applications are hard to achieve due to multiple services, as compared to monoliths that are implemented as single applications.

It is recommended to start with a well designed, modular monolithic application irrespective of the domain complexity or transactional nature. Generally, all applications start as a monolithic application that can be deployed faster as a single artifact and later split into microservices when the application's complexity begins to outweigh the productivity of the team.

The productivity of the team may start decreasing when changes to the monolithic application start affecting more than one component, as shown in the preceding diagram. These changes may be a result of a new feature being added to the application, a database technology upgrade, or the refactoring of existing components. Any changes made to the application must keep the entire team in-sync, especially the deployment team, if there are any changes required in the deployment processes. Communicating such changes in a large team often results in a coordination nightmare, multiple change requests, and in-turn, reduces the overall productivity of the team working on the application.

Productivity also depends on the initial choices made with respect to the technology stack and its flexibility of implementation. For example, if a new feature requires a library that is readily available with a different technology stack or a programming language, it becomes challenging to adopt as it does not conform to the existing technology stack of the application components. In such cases, the team ends up implementing the same feature set for the current technology stack from scratch, and that in turn reduces productivity and further adds to the technology debt.

Before starting with microservices, first set up best design principles among team members. Next, try to evaluate the existing monolith with regard to components and their interaction. If refactoring can help reduce the dependency between the components, do that first instead of disintegrating your application into microservices.

Monolithic applications to microservices

Most applications start as a monolith. Amazon (http://highscalability.com/amazon-architecture) started with a monolithic Perl (https://en.wikipedia.org/wiki/Perl) /C++ (https://en.wikipedia.org/wiki/C%2B%2B) application, and Twitter (http://highscalability.com/blog/2013/7/8/the-architecture-twitter-uses-to-deal-with-150m-active-users.html) started with a monolithic Rails (https://en.wikipedia.org/wiki/Ruby_on_Rails) application. Both organizations have not only gone through more than three generations of software architectural changes, but have also transformed their organizational structures over time. Today, all of them are running on microservices with teams organized around services that are developed, deployed, scaled, and monitored by the same team independently. They have mastered continuous integration and continuous delivery pipelines with automated deployment, scaling, and monitoring of services for real-time feedback to the team.

Identifying candidates for microservices

The top-most challenge in migrating from a monolithic application to microservices is to identify the right candidates for microservices. A well structured and modularized monolithic application already has well-defined boundaries (bounded contexts) that can help disintegrate the application into microservices. For example, the User, Orders, and Interest modules already have well-defined boundaries and are good candidates to create microservices for. If the application does not have well-defined boundaries, the first step is to refactor the existing application to create such bounded contexts for microservices. Each bounded context must be tied to a business capability for which a service can be created.

Another approach in identifying the right candidates for microservices is to look at the data access patterns and associated business logic. If the same database is being updated by multiple components of a monolithic application, then it makes sense to create a service for the primary component with associated business logic that manages the database and makes it accessible to other services via APIs. This process can be repeated until databases and the associated business logic are managed by one and only one service that has a small set of responsibilities, modeled around a business capability.

For example, a monolithic application consisting of User, Interest, and Orders components can be migrated into microservices by picking one component at a time and creating a microservice with an isolated database, as shown in the preceding diagram. To start with, first pick the one with the least dependency, the User module, and create the User Service service around it. All other components can now talk to this new User Service for User Management, including authentication, authorization, and getting user profiles. Next, pick the Orders module based on the least dependency logic, and create a service around it. Finally, pick the Interest module as it is dependent on both the User and Orders modules. Since we have the databases isolated, we can also swap out the database for Interest with maybe a graph database that is efficient to store and retrieve user interests due to its inherent capability of storing relationships as a graph.

In addition to organizing your microservices around business capabilities and database access patterns, look for common areas, such as authentication, authorization, and notification, that can be perfected once as a service and can be leveraged by one or more microservices later.

Release cycle and the deployment process

Once a monolithic application is disintegrated into microservices, the next step is to deploy them into production. Monolithic application are mostly deployed as a single artifact (JARs, WARs, EXEs, and more) that are released after extensive testing by the quality assurance (QA) team. Typically, developers work on various components of the application and release versions for the QA team to pick and validate against the specification, as shown under the Org Structure of monolithic architecture in the following diagram. Each iteration may involve the addition or removal of features and bug fixes. The release goes through multiple developers (dev) and QA team iterations until the QA team flags off the release as stable. Once the QA team flags off the release, the released artifact is handed over to the IT ops team to deploy it in production. If there are any issues in production, the IT ops team asks the dev team to fix them. Once the issues are fixed, the dev team tags a new release for QA that again goes through the same dev-QA iterations before being marked as stable and eventually handed over to IT/ops. Due to this process, any release for a monolithic applications may easily take up to a month, often three months.

On the other hand, for microservices, teams are organized into groups that fully own a service. The team is responsible for not only developing the service, but also for putting together automated test cases that can test the entire service against each change submitted for the service. Since the service is to be tested in isolation for its features, it is faster to run entire test suites for the service for each change submitted by the developers. Additionally, the team itself creates deployable binaries often packaged into containers (https://en.wikipedia.org/wiki/Linux_containers), such as Docker (https://en.wikipedia.org/wiki/Docker_(software)), that are published to a central repository from where they can be automatically deployed into production by some well-known tools, such as Kubernetes (https://en.wikipedia.org/wiki/Kubernetes). The entire development to production timeline is cut short to days, often hours, as the entire deployment process is automated. We will learn more about deploying microservices in production and how to use these deployment tools in Part-4, the last part of this book.

There is a reason why a lot of microservice projects fail and only a few succeed. Migrating from a monolithic architecture to microservices must not only focus on identifying the bounded contexts, but also the organizational structure and deployment methodologies. Teams must be organized around services and not projects. Each team must own the service right from development to production. Since each team owns the responsibility for testing, validation, and deployment, the entire process should be automated and the organization must master it. Development and deployment cycles must be short with immediate feedback via fine-grained monitoring of the deployed microservices.

Automation is key for any successful microservices project. Testing, deployment, and monitoring must be automated before moving microservices to production. 

Summary

In this chapter, we learned about monolithic and microservices architectures and why microservices are becoming popular in the industry, especially with web-scale applications. We learned about the importance of database isolation with microservices and how to migrate a monolithic application to microservices by observing the database access pattern. We also discussed the importance of the monolith-first approach and when to move towards microservices. We concluded with a comparison of monolithic and microservices architectures with regard to the release cycle and deployment process.

The next chapter of this book will talk about microservice architecture in detail; we will learn more about domain-driven design and how to identify the right set of microservices. In Chapter 3, Microservices for Helping Hands Application, the last chapter of Part-1, we will pick a real-life use case for microservices and discuss how to design it using the principles of microservice architecture.

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • Relevance of the microservice architecture and benefits of Clojure's functional and simple features to implement it.
  • Learn best practices and common principles to avoid common pitfalls while developing microservices.
  • Learn how to use Pedestal to build your next microservices, secure them using JWT, and monitor them using the ELK stack

Description

The microservice architecture is sweeping the world as the de facto pattern with which to design and build scalable, easy-tomaintain web applications. This book will teach you common patterns and practices, and will show you how to apply these using the Clojure programming language. This book will teach you the fundamental concepts of architectural design and RESTful communication, and show you patterns that provide manageable code that is supportable in development and at scale in production. We will provide you with examples of how to put these concepts and patterns into practice with Clojure. This book will explain and illustrate, with practical examples, how teams of all sizes can start solving problems with microservices. You will learn the importance of writing code that is asynchronous and non-blocking and how Pedestal helps us do this. Later, the book explains how to build Reactive microservices in Clojure that adhere to the principles underlying the Reactive Manifesto. We finish off by showing you various ways to monitor, test, and secure your microservices. By the end, you will be fully capable of setting up, modifying, and deploying a microservice with Clojure and Pedestal.

Who is this book for?

You should have a working knowledge of programming in Clojure. However, no knowledge of RESTful architecture, microservices, or web services is expected. If you are looking to apply techniques to your own projects, taking your first steps into microservice architecture, this book is for you.

What you will learn

  • Explore the pros and cons of monolithic and microservice architectures
  • Use Clojure to effectively build a reallife application using Microservices
  • Gain practical knowledge of the Clojure Pedestal framework and how to use it to build Microservices
  • Explore various persistence patterns and learn how to use Apache Kafka to build event-driven microservice architectures
  • Secure your Microservices using JWT
  • Monitor Microservices at scale using the ELK stack
  • Deploy Microservices at scale using container orchestration platforms such as Kubernetes

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Jan 25, 2018
Length: 336 pages
Edition : 1st
Language : English
ISBN-13 : 9781788626316
Languages :
Concepts :

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
OR
Modal Close icon
Payment Processing...
tick Completed

Billing Address

Product Details

Publication date : Jan 25, 2018
Length: 336 pages
Edition : 1st
Language : English
ISBN-13 : 9781788626316
Languages :
Concepts :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total $ 183.97
Clojure: High Performance JVM Programming
$79.99
Clojure Programming Cookbook
$54.99
Microservices with Clojure
$48.99
Total $ 183.97 Stars icon

Table of Contents

12 Chapters
Monolithic Versus Microservices Chevron down icon Chevron up icon
Microservices Architecture Chevron down icon Chevron up icon
Microservices for Helping Hands Application Chevron down icon Chevron up icon
Development Environment Chevron down icon Chevron up icon
REST APIs for Microservices Chevron down icon Chevron up icon
Introduction to Pedestal Chevron down icon Chevron up icon
Achieving Immutability with Datomic Chevron down icon Chevron up icon
Building Microservices for Helping Hands Chevron down icon Chevron up icon
Configuring Microservices Chevron down icon Chevron up icon
Event-Driven Patterns for Microservices Chevron down icon Chevron up icon
Deploying and Monitoring Secured Microservices Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon

Customer reviews

Rating distribution
Full star icon Full star icon Full star icon Full star icon Half star icon 4.5
(2 Ratings)
5 star 50%
4 star 50%
3 star 0%
2 star 0%
1 star 0%
Felipe Caetano Silva May 16, 2020
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Com relação ao Produto em si, achei o acabamento do livro um pouco a desejar. O Conteúdo é o que eu esperava interessante, um bom introdutório aos microserviços e a clojure.
Amazon Verified review Amazon
Amazon Customer Sep 03, 2020
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
Microservices with Clojure is really great for learning to put together more serious applications and especially for going into depth on using Pedestal for web services.
Amazon Verified review Amazon
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.