Building Mobile Apps at Scale 39 Engineering Challenges Gergely Orosz
Building Mobile Apps at Scale 39 Engineering Challenges Gergely Orosz
Building Mobile Apps at Scale 39 Engineering Challenges Gergely Orosz
Building Mobile Apps at Scale 39 Engineering Challenges Gergely Orosz
1. Building Mobile Apps at Scale 39 Engineering
Challenges Gergely Orosz download
https://textbookfull.com/product/building-mobile-apps-at-
scale-39-engineering-challenges-gergely-orosz/
Download more ebook from https://textbookfull.com
2. We believe these products will be a great fit for you. Click
the link to download now, or visit textbookfull.com
to discover even more!
Developing Inclusive Mobile Apps: Building Accessible
Apps for iOS and Android 1st Edition Rob Whitaker
https://textbookfull.com/product/developing-inclusive-mobile-
apps-building-accessible-apps-for-ios-and-android-1st-edition-
rob-whitaker/
Building Xamarin.Forms Mobile Apps Using XAML: Mobile
Cross-Platform XAML and Xamarin.Forms Fundamentals Dan
Hermes
https://textbookfull.com/product/building-xamarin-forms-mobile-
apps-using-xaml-mobile-cross-platform-xaml-and-xamarin-forms-
fundamentals-dan-hermes/
Analytics Engineering With SQL and dbt: Building
Meaningful Data Models at Scale 1st Edition Rui Pedro
Machado
https://textbookfull.com/product/analytics-engineering-with-sql-
and-dbt-building-meaningful-data-models-at-scale-1st-edition-rui-
pedro-machado/
Learning React Native Building Native Mobile Apps with
JavaScript 2nd Edition Bonnie Eisenman
https://textbookfull.com/product/learning-react-native-building-
native-mobile-apps-with-javascript-2nd-edition-bonnie-eisenman/
3. Beginning Power Apps: The Non-Developer's Guide to
Building Business Mobile Applications 2nd Edition Tim
Leung
https://textbookfull.com/product/beginning-power-apps-the-non-
developers-guide-to-building-business-mobile-applications-2nd-
edition-tim-leung/
Pro Java ME Apps Building Commercial Quality Java ME
Apps Iliescu Ovidiu
https://textbookfull.com/product/pro-java-me-apps-building-
commercial-quality-java-me-apps-iliescu-ovidiu/
Build Mobile Apps with Ionic 2 and Firebase: Hybrid
Mobile App Development 1st Edition Fu Cheng
https://textbookfull.com/product/build-mobile-apps-with-
ionic-2-and-firebase-hybrid-mobile-app-development-1st-edition-
fu-cheng/
Designing Platform Independent Mobile Apps and Services
1st Edition Rocky Heckman
https://textbookfull.com/product/designing-platform-independent-
mobile-apps-and-services-1st-edition-rocky-heckman/
Build Mobile Apps with Ionic 4 and Firebase: Hybrid
Mobile App Development [Lingua inglese] 2nd Edition Fu
Cheng
https://textbookfull.com/product/build-mobile-apps-with-
ionic-4-and-firebase-hybrid-mobile-app-development-lingua-
inglese-2nd-edition-fu-cheng/
6. Building Mobile Apps at Scale
Table of Contents
Introduction 5
Acknowledgements 6
About the Author 7
Sponsors 8
When Things are Simple 10
PART 1: Challenges Due to the Nature of Mobile Applications 11
1. State Management 12
2. Mistakes Are Hard to Revert 15
3. The Long Tail of Old App Versions 17
4. Deeplinks 18
5. Push and Background Notifications 19
6. App Crashes 21
7. Offline Support 25
8. Accessibility 28
9. CI/CD & The Build Train 30
10. Third-Party Libraries and SDKs 36
11. Device and OS Fragmentation 38
12. In-App Purchases 40
PART 2: Challenges Due to App Complexity 47
13. Navigation Architecture Within Large Apps 48
14. Application State & Event-Driven Changes 51
15. Localization 53
16. Modular Architecture & Dependency Injection 57
17. Automated Testing 58
3
7. Building Mobile Apps at Scale
18. Manual Testing 62
PART 3: Challenges Due to Large Engineering Teams 64
19. Planning and Decision Making 65
20. Architecting Ways to Avoid Stepping on Each Other’s Toes 67
21. Shared Architecture Across Several Apps 69
22. Tooling Maturity for Large Engineering Teams 71
23. Scaling Build & Merge Times 72
24. Mobile Platform Libraries and Teams 74
PART 4: Languages and Cross-Platform Approaches 80
25. Adopting New Languages and Frameworks 81
26. Kotlin Multiplatform and KMM 83
27. Cross-Platform Feature Development 87
28. Cross-Platform App Development versus Native 90
29. Web, PWA & Backend-Driven Mobile Apps 95
PART 5: Challenges Due to Stepping Up Your Game 98
30. Experimentation 99
31. Feature Flag Hell 102
32. Performance 105
33. Analytics, Monitoring and Alerting 111
34. Mobile On-Call 117
35. Advanced Code Quality Checks 119
36. Compliance, Privacy and Security 122
37. Client-Side Data Migrations 125
38. Forced Upgrading 126
39. App Size 129
Closing Thoughts 132
4
8. Building Mobile Apps at Scale
Introduction
I have noticed that while there is a lot of appreciation for backend and distributed systems challenges,
there is often less empathy for why mobile development is hard when done at scale. Building a backend
system that serves millions of customers means building highly available and scalable systems and operating
these reliably. But what about the mobile clients for the same systems?
Most engineers who have not built mobile apps assume the mobile app is a simple facade that requires less
engineering effort to build and operate. Having built both types of systems, I can say this is not the case.
There is plenty of depth in building large, native, mobile applications, but often little curiosity from people not
in this space. Product managers, business stakeholders, and even non-native mobile engineers rarely
understand why it "takes so long" to ship something on mobile.
This book collects challenges engineers face when building iOS and Android apps at scale. By scale, I
mean having numbers of users in the millions and being built by large engineering teams. These teams
launch features continuously and still ensure the app works reliably, and in a performant way.
This book is a summary of the current industry practices used by large, native mobile teams and points to
some of the common approaches to tackle them. Much of the experience conveyed in this book comes from
my time working at Uber on a complex and widely-used app. More than 30 other engineers working in
similarly complex environments have contributed their insights; engineers building apps at the likes of Twitter,
Amazon, Flipkart, Square, Capital One and many other companies.
I hope this book helps non-mobile engineers build empathy for the type of challenges and tradeoffs mobile
engineers face and be a conversation starter between backend, web, and mobile teams.
5
9. Building Mobile Apps at Scale
Acknowledgements
The book has been written with the significant input and reviews of more than 30 mobile engineers and
managers, many of them deep experts in their respective fields. Thank you very much to all of them. If you are
on Twitter, I suggest you follow them:
● Abhijith Krishnappa (Halodoc)
● Andrea Antonioni (Just Eat)
● Andreea Sicaru (Uber)
● Andy Boedo (RevenueCat, Elevate Labs)
● Ankush Gupta (Quizlet)
● Artem Chubaryan (Square)
● Barnabas Gema (Shapr3D)
● Barisere Jonathan (Sprinthubmobile)
● Corentin Kerisit (Zenly)
● Dan Kesack (DraftKings)
● Edu Caselles (Author: The Mobile Interview,
Funding Circle)
● Emmanuel Goossaert (Booking.com)
● Franz Busch (Sixt)
● Guillermo Orellana (Monzo, Skyscanner,
Badoo)
● Injy Zarif (Convoy, Microsoft)
● Jake Lee (Photobox)
● Jared Sheehan (Capital One)
● Javi Pulido (Plain Concepts)
● Jorge Coca (VG Ventures)
● Julian Harty (previously Google, eBay,
Badoo, Salesforce, Klarna, ServiceNow, and
others)
● Leland Takamine (perf.dev, Uber)
● Matija Grcic (EMG Consulting)
● Michael Bailey (GDE, American Express)
● Michael Sena (Tesla, Amazon)
● Nacho Lopez (Twitter, Facebook, Yahoo)
● Patrick Zearfoss (Capital One)
● Praveen Sanap (Carousell)
● Paul Razgaitis (Cameo, Braintree, Venmo)
● Robin van Dijke (Uber, Apple)
● Rui Peres (Sphere, Babylon Health)
● Sabyasachi Ruj (Flipkart, CloudMagic,
Webyog)
● Sathvik Parekodi
● Tuğkan Kibar
● Tuomas Artman (Linear, Uber)
● Wouter van den Broek
Thank you to Emmanuel Goossaert for writing most of Chapter 10: Third-Party Libraries and SDKs.
Special thanks to the editor of the book, Dominic Gover at Best English Copy for helping create a book that is
pleasant to read.
6
10. Building Mobile Apps at Scale
About the Author
Gergely has been building native mobile apps since 2010, starting on Windows
Phone, later on iOS, and Android. Starting from one-person apps, he worked
with small teams at Skyscanner, to hundreds of engineers working on the same
codebase at Uber.
At Uber, he worked on the Rider and Driver app rewrites, both projects involving
hundreds of mobile engineers. The apps he worked on had more than 100
million monthly users in more than 60 countries, with several features built for a
single country or region.
You can read books he has written, browse The Pragmatic Engineer Blog he
writes and connect with him on social media channels.
7
11. Building Mobile Apps at Scale
Sponsors
Publishing of this book has been sponsored by vendors providing world-class mobile engineering solutions.
Using vendor solutions over building your own is often the pragmatic approach: this allows you to focus on
providing business value over maintaining infrastructure.
Bitrise is CI/CD built for mobile - by mobile engineers. From pull request, to app store submission and
beyond, Bitrise automates, monitors and improves your app development workflows. Teams who use Bitrise
build better quality apps, deliver them faster, with developers who are happy.
Bitrise supports native Android or iOS, React Native, Flutter and other mobile builds. More than 100,000
developers and thousands of organizations trust Bitrise to increase productivity. Try Bitrise for free, today, and
build better apps, faster.
Bugsnag is an error monitoring and application stability management solution. Not all bugs are worth fixing,
and stability is the key to making data-driven decisions on whether to build software or to fix bugs.
Bugsnag is a daily stability dashboard for mobile engineers, product managers, release managers, and
observability teams to manage quality applications. We help drive code ownership, balance faster release
cycles, reduce technical debt, and improve user experience.
Processing over a billion crash reports a day, Bugsnag is used by over 6,000 of the world’s best small and
large engineering teams such as Airbnb, Slack, Square, Lyft, Shopify and Tinder. Get started for free today.
SonarSource builds world-class code quality and security tools used by more than 200,000 engineering
teams. Open-source and commercial code products that help you find and fix bugs, vulnerabilities and code
smells, so you deliver better mobile apps.
SonarCloud is the leading code static analysis and code security tool, integrating with GitHub, GitLab and
other providers. It integrates directly into your code review workflow, and helps assess your code health. Free
to use for open source projects - get started now.
SonarQube is the on-premise code quality and security tool supporting Swift, Kotlin, Objective C, Java, and 23
other languages. Detect code smells, common bugs, and security hotspots. Get started for free.
8
12. Building Mobile Apps at Scale
RevenueCat makes it easy to build and manage iOS and Android in-app purchases at scale. With a few lines
of code RevenueCat provides IAP infrastructure, customer analytics, data integrations, and gives you time
back from dealing with edge cases and updates across the platforms.
Created by developers, for developers, thousands of the world’s best apps use RevenueCat to power their
in-app purchases and subscriptions. Get started for free here.
Touchlab is trusted by mobile innovators to scale Kotlin Multiplatform Mobile (KMM). Touchlab accelerates
KMM adoption through product & SDK development, early adopter support, architectural &
production-readiness reviews and open-source projects.
Touchlab advises enterprises like Square and NBC on scaling KMM and partners with JetBrains to increase
KMM adoption. Looking to get started with KMM? Check out their Kotlin Multiplatform starter kit.
Perf.dev is an industry-leading mobile performance platform and enables a proactive workflow for managing
mobile performance.
The platform provides automated testing and root cause analysis to address performance issues before
releasing to end-users. Upgrade your mobile performance strategy.
Craft Docs is the modern writing app, native for MacOS, iPhone and iPad, built with Catalyst. Perfect from
note-taking to collaborating within a team. Most people who try Craft say the same: that this is the app they've
been looking for all this time. Try Craft for free.
Linear is the issue tracking tool you'll enjoy using - built for software teams who want to build high quality
products. Linear helps to streamline your team’s software projects, sprints and tasks. Integrated with Github,
Gitlab, Figma and Slack. On MacOS, Web and Mobile. Start using it for free.
9
13. Building Mobile Apps at Scale
When Things are Simple
Let's address the elephant in the room: the frequent assumption that client-side development is simple. The
assumption that the biggest complexity lies in making sure things look good on various mobile devices.
When the problem you are solving is simple, and the scope is small, it is easier to come up with simple
solutions. When you are building an app with limited functionality with a small team and very few users, your
mobile app should not be complicated. Your backend will likely be easy to understand. Your website will be a
no-brainer. You can use existing libraries, templates, and all sorts of shortcuts to put working solutions in
place.
Once you grow in size — customers, engineers, codebase and features — everything becomes more
complex, more bloated, and harder to understand and modify, including the mobile codebase. This is the part
we focus on in this book; when things become complex. When your app gets big, there are no silver bullets
that will magically solve all of your pain points, only tough tradeoffs to make.
This book begins at the point at which your app stops being simple.
10
14. Building Mobile Apps at Scale
PART 1: Challenges Due to the Nature of Mobile
Applications
People who have not done mobile development often assume that most challenges of native apps are similar
to those on the web.
This could not be further from reality.
Mobile engineering has close to a dozen unique challenges that exist neither on the web, nor on the
backend. Most of these relate to the binary distribution of mobile apps; the need to work in low connectivity
setups, and to incorporate unique capabilities like push notifications, deeplinks or in-app purchases.
In this part, we will go through the challenges that are new to people who have not worked in the mobile
domain, both for software engineers, but also for engineering managers, product managers and business
stakeholders.
This part is sponsored by Bitrise and Bugsnag.
Bitrise is a mobile-first CI/CD solution trusted by the world’s most efficient mobile teams. As your app and
team scales, builds will become harder and more time-consuming to manage - this is where we can help.
Bitrise works for any part of the process, all the way to integration tests, device test farm deployment and
distributing to testers. Builds support native iOS, Android, Flutter, React Native, Cordova, Ionic and all other
popular mobile frameworks.
Try Bitrise for free today, and build better apps, faster.
Bugsnag is an error monitoring and application stability management solution. Not all bugs are worth fixing,
and stability is the key to making data-driven decisions on whether to build software or to fix bugs.
Bugsnag is a daily stability dashboard for mobile engineers, product managers, release managers, and
observability teams to manage quality applications.
Processing over a billion crash reports a day, Bugsnag is used by over 6,000 of the world’s best small and
large engineering teams such as Airbnb, Slack, Square, Lyft, Shopify and Tinder. Get started for free today.
11
15. Building Mobile Apps at Scale
1. State Management
State management is the root of most headaches for native mobile development, similar to modern web and
backend development. The difference with mobile apps is how app lifecycle events and transitions are not a
cause for concern in the web and backend world. Examples of the app-level lifecycle transitions are the app
pausing and going to the background, then returning to the foreground or being suspended. The states are
similar, but not identical for iOS and Android.
Events driving state changes in mobile apps
Events drive state changes in most mobile apps. These events trigger in asynchronous ways such as
application state changes, network requests or user input. Most bugs and unexpected crashes are usually
caused by an unexpected or untested combination of events and the application's state becoming corrupted.
State becoming corrupted is a common problem area with apps where global or local states are manipulated
by multiple components unknown to each other. Teams that run into this issue start to isolate component and
application state as much as possible and tend to start using reactive state management sooner or later.
12
16. Building Mobile Apps at Scale
A common root reason for exotic bugs in complex apps: non-deterministic events put parts of the app in
invalid states
Reactive programming is a preferred method for dealing with a large and stateful app, in order to isolate
state changes. You keep state as immutable as possible, storing models as immutable objects that emit state
changes. This is the practice used at Uber, is the approach Airbnb takes, and is how N26 built their app.
Though the approach can be tedious in propagating state changes down a tree of components, the same
tediousness makes it difficult to make unintended state changes in unrelated components.
Applications sharing the same resources with all other apps, and the OS killing apps at short notice, are
two of the biggest differences between developing for mobile versus developing for other platforms, like
backend and the web. The OS monitors CPU, memory, and energy consumption. If the OS determines that
your app is taking up too many resources in the foreground or the background, then it can be killed with little
warning. It is the app developer's responsibility to react to application state changes, save state, and to
restore the app to where it was running. On iOS, this means handling app states and transitions between
them. On Android, you need to react to changes in the Activity lifecycle.
Global application state, such as permissions, Bluetooth and connectivity state, and others, brings an
interesting set of challenges. Whenever one of these global states changes, for example, the network
connectivity drops, then different parts of the app might need to react differently.
13
17. Building Mobile Apps at Scale
With global state, the challenge becomes deciding which component owns listening to these state changes.
At one end of the spectrum, application screens or components could listen to global state changes they care
about; resulting in lots of code duplication, but components handling all of the global state concerns. At the
other end, a component could listen to certain global state changes and forward these on to specific parts of
the application. This might result in less complex code, but now there is a tight coupling between the global
state handler and the components it knows.
App launch points like deeplinks or internal shortcut navigation points within the app also add complexity to
state management. With deeplinks, the application state might need to be set up after the deeplink is
activated. We will go into more detail in the Deeplinks chapter.
14
18. Building Mobile Apps at Scale
2. Mistakes Are Hard to Revert
Mobile apps are distributed as binaries. Once a user updates to a version with a client-side bug, they are
stuck with that bug until a new version is released and the user updates.
Multiple challenges come with this approach:
● Both Apple and Google are strict on allowing executable code to be sent to apps. Apple does not
allow executing code that changes functionality in their store guidelines and Google can flag
unrelated executable code as malware, as per their program policy. This means you cannot just
remotely update apps. However, pushing bug fixes that revert broken functionality should be within
both stores’ policies: for example, when using feature flags. At the same time, Apple does allow
executing non-native code like JavaScript, which is why solutions like Codepush are gaining
popularity. Codepush allows React Native or Cordova apps to deliver updates on the fly. At Uber, we
built a homegrown solution along the same lines, as several other companies have done.
● It takes from hours to days to release a new app version on the store. For iOS, manual reviews
happen for all apps, taking 24-48 hours to complete. Historically, every review had the possibility of
rejection. As of June 2020, Apple has changed guidelines, so bug fixes are no longer delayed over
guideline violations, except for legal issues. On Android, manual reviews do not always happen, but
when they do, they can take more than seven days.
● Users take days to update to the latest version after a new version is published to the app store. This
lag is true even for users with automated updates turned on.
● You can not assume that all users will get this updated version, ever. Some users might have
automated updates disabled. Even when they update, they might skip several versions.
Chuck Rossi, part of release engineering at Facebook, summarizes what it is like to release for mobile on a
Software Engineering Daily podcast episode:
“It was the most terrifying thing to take 10,000 diffs, package it into effectively a bullet, fire that
bullet at the horizon and that bullet, once it leaves the barrel, it's gone. I cannot get it back, and
it flies flat and true with no friction and no gravity till the heat death of the universe. It's gone. I
can't fix it.”
This means that all previous versions of your app need to be supported indefinitely and in theory, you
should do this. The only exception is if you put homegrown controls in place and build a force update
mechanism to limit the past versions to support. Android supports in-app updates in the Play Core library. iOS
does not have similar native support. We will cover more on this in the Forced Upgrading chapter.
15
19. Building Mobile Apps at Scale
Fixing a bug in a mobile app
Assuming you have an app with millions of users, what steps can you take to minimize bugs or regressions
from occurring in old versions?
● Do thorough testing at all levels. Automated testing, manual testing, and consider beta testing with
easy feedback loops. A common approach at many companies is to release the beta app to company
employees and beta users for it to "bake" for a week, collecting feedback on any issues.
● Have a feature flagging system in place, so you can revert bugs on the fly. Still, feature flags add
further pain points. We will discuss these points in the Feature Flag Hell chapter.
● Consider gradual rollouts, with monitoring to ensure things work as expected. We will cover this topic
in the Analytics, Monitoring and Alerting chapter.
● Force upgrading is a robust solution, but you will need to put one in place, and some customers might
churn as a result. We will go deeper on this in the Forced Upgrading chapter.
16
20. Building Mobile Apps at Scale
3. The Long Tail of Old App Versions
Old versions of the app will stay around for a long time, up to several years. This time frame is only shorter if
you are one of the few teams that put strict force app upgrade policies in place. Apps that have a rolling
window of force upgrades include Whatsapp and Messenger. Several others use force upgrades frequently,
like banking apps Monzo or American Express.
While most users will update to new app versions in a matter of days, there will be a long tail of users who are
several versions behind. Some users disable automatic updates on purpose, but many who do not update are
blocked because of old phones or OSes. At the same time, old app versions are unlikely to be regularly
tested by the mobile team because it is a lot of effort, with little payoff.
Even a non-breaking backend change can break an older version of the app - such as changing the content
of a specific response. A few practices you can do to avoid this breakage:
● Build sturdy network response handling and parsing, using dedicated tooling that solves these
problems. I prefer strongly typed, generated contracts between client and backend like Thrift,
GraphQL, or other solutions with code generation, over REST interfaces that you need to validate
manually, which is bound to break when someone forgets to update the parsing logic on mobile.
● Plan well in advance for breaking backend changes. Have an open communications channel with
the backend team. Have a way to test old app versions. Consider building new endpoints and not
retiring old ones until a forced upgrade moves all current app users off the old endpoint.
● Version your backend endpoints and create new versions to accommodate breaking changes. When
making breaking changes, you will usually create a new endpoint and mark the existing one as
deprecated. Note that in case of using GraphQL, this might not apply, as GraphQL takes a strong
stance against versioning.
● Proceed with caution when deprecating endpoints on the backend. Monitor the traffic, and have a
migration plan on how to channel requests, if needed.
● Track usage stats on an app version level. What percentage of users is lagging three or more
versions behind? Once you have this data, it is easier to decide how much effort to dedicate towards
ensuring the experience works well on older versions.
● Put client-side monitoring and alerting in place. These alerts might be channeled to a dedicated
mobile on-call, or just the normal on-call. We will dive more into this in the Analytics, Monitoring and
Alerting chapter.
● Consider doing upgrade testing, at least for major updates. Upgrade testing is expensive, hard to
automate, and there might be several permutations to try. Teams rarely do it because of this overhead.
17
21. Building Mobile Apps at Scale
4. Deeplinks
Deeplinking — providing a web or device link that opens a part of the app — becomes a surprisingly tricky
problem on mobile platforms. Both iOS and Android offer APIs to deal with this, but without any opinionated
native frameworks or recommended approaches. As Alberto De Bortoli puts it in the article iOS deeplinking at
scale:
“Deep linking is one of the most underestimated problems to solve on mobile.”
There are a few things that make deeplinking challenging:
● Backward compatibility: ensuring that existing deeplinks keep working in older versions of the app,
even after significant navigation or logic changes.
● State problems when deeplinking to a running app with existing state. Say you have an app open
and are on a detail page. You tap on a deeplink in your mail app that points to another detail page.
What should happen? Would the new detail page be added to the navigation stack, preserving your
current state? Or should the state be reset? The solution that results in the least amount of
non-deterministic behavior is to reset the app's state fully when receiving a deeplink. However, there
might be flows that you do not want to break, so plan carefully.
● iOS and Android deeplink implementation differences. Deeplink implementations are different for
iOS (universal links and URL schemes) and for Android (based on intents). There are third-party
deeplink providers that supply abstractions to work with a single interface, such as Firebase Dynamic
Links or Branch, among others.
● Lack of upfront planning. Deeplinks are often an afterthought once multiple versions of the app have
shipped. However, unlike on the web, where adding links / deeplinks is more straightforward,
retrofitting a deeplinking strategy can be a real engineering challenge. Deeplinks are connected to
state management and the navigation architecture.
The biggest challenge with deeplinks is how neither iOS nor Android provides an opinionated approach on
how to design and test deeplinks. As the number of deeplinks grows, the effort and complexity of keeping
these deeplinks working snowballs. You will have to plan well ahead in building a sensible and scalable
deeplink implementation.
18
22. Building Mobile Apps at Scale
5. Push and Background Notifications
App push notifications are a frequently used notification, communication, and marketing tool. The business
loves to use push notifications, and as a developer, you will be asked to support this method sooner or later.
However, push notifications bring a set of new challenges you need to tackle.
Setting up and operating push notifications is complex. Both for Android and iOS, your app needs to obtain
a token from a server (FCM on Android, APNS on iOS), then store this token on the backend. There are many
steps to take to get push notifications working; see this comprehensive tutorial for iOS and this for Android.
Sending push notifications has to happen from the backend. You need to work with the backend team on the
type of notifications they want to send and their triggers. Your backend counterparts will have to become
familiar with the mobile push notification infrastructure and capabilities to make the most out of this channel.
Using push notifications together with emails and text messages is a popular strategy for marketing activities.
In theory, such usage could go against iOS app guidelines. However, most of Apple’s apps, and many
third-party apps, use them as such. You will almost certainly not implement push notifications from scratch, but
instead use a third-party customer engagement service like Twilio, Airship, Braze, OneSignal, or similar.
Challenges with push notifications are numerous - on top of implementing them:
● A similar set of challenges as deeplinks, in terms of implementing what action the notification should
trigger. A push notification is a glorified deeplink: a message with an action that links into the app.
Thinking about backward compatibility, state problems, and planning ahead all apply to push
notifications as well.
● Users opting out of push notifications or not opting in. On iOS and Android, you have different ways,
and limits, for detecting when this is the case. As an interesting edge case, on iOS, if a user opts out of
push notifications, they can still be sent silent background notifications. Push notifications are usually
a "nice to have" for many applications, exactly because you cannot guarantee that each user will opt
into them, or that their device will be online to receive them.
● Push notification delivery is not guaranteed. Especially when sent in bulk, both Apple and Google
might throttle push notifications. The rules around this throttling is a black box. However, device
connectivity issues, as well as the OS restricting notifications for apps that have not recently been
active, might also result in people not seeing push notifications you send.
Testing push notifications is a challenge. You can, of course, test this manually. It is more of a workaround,
but you can test them on a simulator both on iOS, and on Android. However, for automated testing, you need
to write end-to-end UI tests, which are expensive to create and maintain. See this tutorial on how to do this for
iOS.
19
23. Building Mobile Apps at Scale
Background notifications are a special type of push message that is not visible for the user, but goes directly
to your app. These kinds of notifications are useful to sync backend updates to the client. These notifications
are called data messages on Android and background notifications on iOS. See an example for iOS usage.
The concept of background notifications is handy for real-time and multi-device scenarios. If your app is in
this area, you might decide to implement a cross-platform solution for iOS and Android, and instead of the
mobile app polling the server, the server sends data through background push notifications to the client.
When rewriting Uber's Rider app in 2016, a major shift in our approach was exactly this; moving from poll to
push, with an in-house push messaging service.
Background notifications can simplify the architecture and the business logic, but they introduce message
deliverability issues, message order problems, and you need to combine this approach with local data
caching for offline scenarios.
20
24. Building Mobile Apps at Scale
6. App Crashes
An app crashing is one of the most noticeable bugs in any mobile app, and often ones with high business
impact. Users might not complete a key flow, and they might grow frustrated and stop using the app (also
known as churning), or leave poor reviews.
Crashes are not a mobile-only concern. They are a major focus area on the backend, where monitoring
uncaught exceptions or 5XX status codes is common practice. On the web, due to its nature —
single-threaded execution within a sandbox — crashes are rarer than on mobile apps.
The first rule of crashes is you need to track when they happen and have sufficient debug information.
Once you track crashes, you want to report on what percentage of sessions end up crashing and reduce this
number as much as you can. At Uber, we tracked the crash rates from the early days, working continuously to
reduce the rate of crashed sessions.
You can choose to build your own implementation of crash reporting, or use an off-the-shelf solution. As of
2021, most teams choose one of the many crash reporting solutions, such as Crashlytics or Bugsnag, for
native apps.
Bugsnag is an error monitoring and application stability management solution. Not all bugs are worth fixing,
and stability is the key to making data-driven decisions on whether to build software or to fix bugs.
Recognized for best-in-class mobile support, their diagnostic data enables engineering teams to improve
application health and accelerate business growth. Bugsnag helps drive code ownership, balance faster
release cycles, reduce technical debt, and improve user experience.
Processing over a billion crash reports a day, Bugsnag is used by over 5,000 of the world’s best small and
large engineering teams such as Airbnb, Slack, Square, Lyft, Shopify and Tinder. Get started for free today.
On iOS, crash reports are generated on the device with every crash that you can use to map these logs to
your code. Apple provides ways for developers to collect crash logs from users who opted to share this
information via TestFlight or the App Store. This approach works well enough for smaller apps. On Android,
Google Play also lets developers view crash stack traces through Android Vitals in the Google Play Console.
As with Apple, only users who have opted in to send bug reports to developers will have these crashes
logged in this portal.
21
25. Building Mobile Apps at Scale
Third-party or custom-built crash reporting solutions offer a few advantages on top of what the App Store
and Google Play have to offer. The advantages are plenty, and most mid-sized and above apps go with either
a third-party, or build a solution with the below benefits:
● More diagnostic information. You often want to log additional information in your app about events
that might lead to a crash.
● Rich reporting. Third-party solutions usually offer grouping of reports and comparison of iOS and
Android crash rates.
● Monitoring and alerting capabilities. You can set up to get alerts when a new type of crash appears
or when certain crashes spike.
● Integrations with the rest of the development stack. You often want to connect new crashes with your
ticketing system or reference them in pull requests.
At Uber, we used third-party crash reporting from the early days. However, an in-house solution was built later.
A shortcoming of many third-party crash reporting solutions is how they only collect health information on
crashes and non-fatal errors, but not on app-not-responding (ANR) and memory problems. Organizations with
many apps might also find the reporting not rich enough and might want to build their own reporting, to
compare health statuses across many apps. Integrating better with in-house project management and coding
tools could also be a reason to go custom.
Reproducibility and debuggability of crashes are other pain points that impact mobile more than backend or
web teams. Especially in the Android world, users have a variety of devices that run a wide range of OS
versions with a variety of app versions. If a crash can be reproduced on a simulator or on any device, you
have no excuse not to fix the problem. But what if the crash only happens on specific devices?
22
26. Building Mobile Apps at Scale
Put a prioritization framework in place to define thresholds, above which you spend time investigating and
fixing crashes. This threshold will be different based on the nature of the crash, the customer lifetime value,
and other business considerations.
How do you prioritize fixing a crash? Is a smaller crash in a more frequently used part of the app more
important to fix than a larger crash in a less frequently used part?
You need to compare the cost of investigation and fixing, compared to the upside of the fix, and the
opportunity cost of an engineer spending time on something else, like building revenue-generating
functionality.
App stability is the metric you want to eventually measure in order to ensure that it does not regress. Your
app will never be truly crash-free, but if you can reduce crashes to a stability level that means less than one in
10,000 sessions are impacted, you are on the right track. Aim to calculate an app stability score based on
your total user sessions, and invest time in reducing crashes, until you meet your target.
Bugsnag have published metrics on what median app stability scores look like:
● 99.46% for apps built by 1-10 engineers
● 99.60% for apps built by 11-50 engineers
● 99.89% for apps built by 51-100 engineers
● 99.79% for apps built by 100+ engineers
If your app stability score is 99.99% or above, you are well ahead of your competition, and at what would be
considered world-class reliability.
23
27. Building Mobile Apps at Scale
Further reading:
● Error monitoring with Bugsnag and Splunk from Zynga
● Mobile crash reporting process from LinkedIn
● The mobile crash reporting pipeline from LinkedIn (video)
● CCSM: scalable statistical anomaly detection to resolve app crashes faster from Facebook
● The path to 99.99% crash-free on iOS from Turo Engineering
● Conquering our Android crash count from Strava Engineering
● Debugging native crashes in Android apps from ProAndroidDev
● Google Maps SDK crashes, impacting hundreds of apps from Google’s issue tracker
● SDKs should not crash apps - learnings from the Facebook outage from Bugsnag
● Why a small Facebook bug wreaked havoc on some of the most popular iOS apps from the Verge
● Application stability index from Bugsnag
24
28. Building Mobile Apps at Scale
7. Offline Support
Though offline support is becoming more of a feature with rich web applications, it has always been a core
use case with native mobile apps. People expect apps to stay usable, even when connectivity drops. They
certainly expect the state not to get lost when the signal drops or weakens.
Proper offline mode support adds a lot of complexity and unexpected edge cases to an app, such as:
● Reliably detecting when the phone is offline. The OS could report the user being online; however,
this might not be the case. When the phone connects to WiFi spots that use captive portals, no data
might be transmitted. For an edge case like this, the app might need to ping a couple of “always
online” domains to determine this.
● Detecting connection speed and latency and changing the app’s behaviour accordingly if it is
necessary. Streaming apps will optimize the stream to match the available bandwidth. Other apps
might warn users about poor connectivity that interferes with the app. Plan upfront on how you want
to handle these edge cases.
● Persisting local state when the device is offline, and synchronizing back when the connection
recovers. You need to account for race conditions when a user uses the app on multiple devices,
some online, some offline. You should take additional care with app updates that modify the locally
stored data, migrating the old data to the new format. We will cover this challenge in the Client-Side
Data Migrations chapter.
Decide which features should work offline and which ones should not. Many teams miss this simple step
that makes the planning of the offline functionality easier and avoids scope creep. I suggest starting with the
key parts of the application and expanding this scope slowly. Get real-world feedback that the "main" offline
mode works as expected. Can you leverage your approach in other parts of the app?
Decide how to handle offline edge cases. What do you want to do with extremely slow connections, where
the phone is still online, but the data connection is overly slow? A robust solution is to treat this as offline and
perhaps notify the user of this fact. What about timeouts? Will you retry?
25
29. Building Mobile Apps at Scale
Mobile devices going offline: An everyday scenario. How will you handle this?
Retries can be a tricky edge case. Say you have a connection that has not responded for some time — a soft
timeout — and you retry another request. You might see race conditions or data issues if the first request
returns, then the second request does too.
Synchronization of device and backend data is another common yet surprisingly challenging problem. This
problem gets multiplied with multiple devices. You need to choose a conflict resolution protocol that works
well enough for multiple parallel offline edits and is robust enough to handle connectivity dropping midway.
Retry strategies come with edge cases you need to think about. Before retrying, how can you be sure that
the network is not down? How do you handle users frantically retrying and possibly creating multiple parallel
requests? Will the app allow the same request to be made while the previous one has not completed? With a
switch to offline mode, how can the app tell when the network has reliably recovered? How can the app
differentiate between the backend service not responding or the network being slow? What about resource
efficiency; should you look into using HTTP conditional requests with retries utilizing ETags or if-match
headers?
With poor connectivity, the network request can sometimes time out. Sensible retry strategies or moving over
to offline mode could be helpful. Both solutions come with plenty of tradeoffs to think about.
Many of the above situations can be solved relatively simply when using reactive libraries to handle network
connections, such as RxSwift, Apple's Combine, RxJava or Kotlin Coroutines.
26
30. Building Mobile Apps at Scale
Requests that should not be retried come with a separate set of problems. For example, you might not want
to retry a payment request while it is in progress. But what if it comes back as failed? You might think it is safe
to retry. However, what if the request timed out, but the server made the payment? Then you will double
charge the user.
As a consumer of backend endpoints, you should push all retries on API endpoints to be safe, by having
these endpoints be idempotent. With idempotent endpoints, you have to obtain and send over idempotency
keys and keep track of an additional state. You also have to worry about edge cases such as the app crashing
and restarting and the idempotency key not being persisted. Implementing retries safely adds a lot of extra
work for teams. You have to work closely with the backend team to map the use cases to design for.
As with state management, the key to a maintainable offline mode and weak connection support is simplicity.
Use immutable states, straightforward sync strategies, and simple strategies to handle slow connections. Do
plenty of testing with the right tools such as the Network Link Conditioner for iOS or the networkSpeed
capability on Android emulators.
27
31. Building Mobile Apps at Scale
8. Accessibility
Accessibility is a big deal for popular applications, a few reasons:
1. If you have a large number of users, many of them will have various accessibility needs, finding it
difficult or impossible to interact with your app without adequate support.
2. If the app is not accessible, there is an inherent legal risk for the app's publisher; several accessibility
lawsuits targeting native mobile apps are already happening in the US.
Accessibility is not only a "nice" thing to do, your app quality increases as you make it more accessible. This
thought comes from Victoria Gonda, who has collected excellent iOS and Android accessibility resources.
Before you start, you need to confirm the level of depth you will go into implementing the WCAG 2.1 mobile
definitions. Ensuring the app is workable for sighted people over VoiceOver (iOS) / TalkBack (Android) and
making sure colors/key elements contrast enough, are typical baseline expectations. Depending on your
application type, you might need to consider hard of hearing people, or users with other accessibility needs.
Accessibility goes deeper than ensuring sighted people can use the app. Allowing accessibility preferences
to work with the app, such as supporting the user's font size of choice — via Dynamic Type support on iOS
and using scale-independent pixels as measurement on Android — are both practices you should follow. You
also need to take device fragmentation into account. For example, in the Android world, OnePlus phone is
known to have a different font size from the rest of the ecosystem.
Implementing accessibility from the start is a surprisingly low effort task on iOS and a sensible one for
Android. Both platforms have thought deeply about accessibility needs and make it relatively painless to add
accessibility features.
Retrofitting accessibility is where this problem can be time-consuming. Making accessibility part of the design
process is a better way to go about things, which is why it is a good idea to make accessibility part of your
planning/RFC process. Thinking about VoiceOver frames at a page level (iOS) and following accessibility best
practices from the start are good investments.
28
32. Building Mobile Apps at Scale
Testing accessibility is something that needs planning. There are a few levels of accessibility testing you
can and should add:
● Automate the parts of accessibility checks that can be automated, such as checking for accessibility
labels on-screen elements. On iOS, you can also have VoiceOver content displayed as text and
potentially automate these checks as well.
● Manually test accessibility features. Do this at least semi-regularly, as part of the release process.
● Recruit accessibility users in your beta program to get feedback directly from them. This is more
feasible for larger companies, but the payoff of having these users interact with the engineering team
can be a major win.
● Turn on accessibility features during development, where it is sensible to do so. This way, you can
inspect these working and get more empathy on how people who rely on these would use them.
29
34. and night to New York, so as to correspond with its business
hours. Many curious suppositions might be made about this polar
observatory with its “great night” and equally “great day.” It is
evident that to keep count of itself it would be compelled to note
dates and 24-hour days to keep in touch with us; so it would be
forced to adopt the local day of some place like New York. This
choice would be free, because a polar observatory would stand on
all the meridians of the earth at once.
We are now in a position to consider the next possible—and
even probable—improvement in our clocks and watches. To
minimize the next step it might be well to see what we can do
now. Clocks are often regulated by electric impulses over wires.
Electricians inform me that they can do this by wireless; but that
owing to the rapid attenuation of the impulses it cannot be done
commercially, over great distances. In the history of invention the
first step was to do something and then find a way of doing it
cheaply enough for general use. So far as I know, the watch in
the wearer's pocket has not yet been regulated by wireless; but I
am willing to risk the statement that the editor of Popular
Mechanics can name more than one electrician who can do this. A
watch to take these impulses might be larger than our present
watches, but it would not stay larger and would ultimately
become much smaller. You know what has happened since the
days of the big “onions” described in the third chapter. Fig. 34; so
get your electric watch and make it smaller at your leisure. We
have made many things commercially practicable, which looked
more revolutionary than this. Now throw out the mainspring,
wheels, pinions, etc., of our watches and reduce the machinery
part to little more than dial and hands and do the driving by
wireless, say, once every minute. I feel certain that I am
35. restraining the scientific imagination in saying that the man lives
among us who can do this. I repeat, that we now possess the
elementary knowledge—which if collated and applied—would
produce such a watch.
Now I have a big question to ask—the central note of
interrogation in this little scientific conversation with you,—does
the man live who can make the earth automatically record its
rotation? Do not be alarmed, for I am prepared to make a guess
as to this possibility. A direct mechanical record of the earth's
rotation seems hopeless, but let us see what can be done. You are
aware that some of the fixed stars have a distinct spectrum. It is
not unreasonable to suppose that an instrument could be made to
record the passage of such a star over the meridian. Ah, but you
say, there is no mechanical force in this. Do not hurry, for we have
long been acquainted with the fact that things which, apparently,
have no force can be made to liberate something which manifests
mechanical force. We could now start or stop the greatest steam
engine by a gleam of sunlight, and some day we might be able to
do as much by the lately discovered pressure of light. That is, we
can now liberate the greatest forces by the most infinitesimal, by
steps; the little force liberating one greater than itself, and that
one another still greater. A good example is the stopping of an
electric train, from a distance, by wireless. The standard clock in
Philadelphia, previously referred to, is a delicate instrument and
its most delicate part, having the least force, moves a little valve
every minute, and by several steps liberates the air pressure, 200
feet higher in the tower, to move the four sets of great hands. I
am not traveling beyond the record when I say that the invisible
actinic rays could be used to liberate a great force; therefore what
is there unreasonable in the supposition that the displacement of
36. the sodium line in the spectrum of a star might be made to record
the earth's rotation? So I say to the electrician—the optician—the
photographer—the chemist and the mechanic.—get together and
produce this watch. Permit me, with conventional and intentional
modesty, to name the new timepiece Chroncosmic. For pocket
use, it would be Cosmic watch. In the first chapter I allowed to
the year 2,000 for the production of this watch, but it is likely we
will not need to wait so long.
Having stated my proposal for universal time as fully as space
will permit and given my guess as to the coming cosmic watch, let
us in this closing paragraph indulge in a little mental exercise.
Suppose we copy the old time lecturer on astronomy and “allow
our minds to penetrate into space.” Blessed be his memory, he
was a doer of good. How impressive as he repeatedly dropped his
wooden pointer, and lo! It always moved straight to the floor; thus
triumphantly vindicating universal gravitation!!!
We can think of a time system which would discard months,
weeks and days. What is the meaning of the financial almanac in
which the days are numbered from 1 to 365 or 366? Simply a step
in the right direction, away from the months and weeks, so that
the distance between any two dates may be seen at a glance. We
would really be better without months and weeks. Now let us
consider the year of the seasons as a unit—long since proposed
by the astronomers—and divide it into 3,000 chrons. Clocks
regulated by star transits, as at present, would divide this
decimally, the fourth place being near enough to make the new
pendulums of convenient length. This would throw out months,
weeks and days, local time and the date line. Each of these
chrons would represent the same time in the year, permanently.
For example, 464.6731 would mark to a dixmilliemechron (a little
37. more than one second) the point reached in the year; while the
date does not, as I have shown in the first chapter. But you still
object that this is a great number of figures to use in fixing a
point in the year. Let us see what it takes to fix a point in the year
now, August 24th, 11-16-32 P. M., New York standard time. A
pretty long story, but it does not fix the point of the year even
then; for it would require the assistance of an astronomer to fix
such a point in any given year, say 1909. But 464.6731 would be
eternally right in absolute time of the seasons, and has only one
meaning, with no qualifications for any year whatever. I believe
the astronomers should use a method something like this. Ah, but
there is a difficulty in applying this to the affairs of daily life which
looks insurmountable. This is caused by the fact that the day and
year are incommeasurable. One of them cannot be exactly
expressed in terms of the other. They are like the diagonal and
side of a square. The day is now the unit and therefore the year
has an interminable fraction; conversely, if we make the year the
unit, then the day becomes an endless fraction. This brings us
face to face with the local day which we ignored in our scientific
year unit. We must regulate our labors, in this world, to day and
night and, with the year unit, the chrons would bear no fixed
relation to day and night, even for two days in succession. So the
year unit and absolute time must be left to the astronomers; but
the day unit and the uniform world day of universal time as
explained in connection with Fig. 46 I offer as a practical system.
I am satisfied that all attempts to measure the year and the day
by the same time yard stick must fail and keep us in our present
confusion. Therefore separate them once for all time. Brought
down to its lowest terms my final proposal is:—
1st. An equinoctial year unit for the astronomers, divided
somewhat as suggested, but no attempt to make the divisions
38. even approximate to days and hours. This would fix all
astronomical events, absolutely. A variation in the length of the
year would not disturb this system, since the year itself would be
the unit. In translating this astronomical, or year unit time, into
clock time, no difficulties would be added, as compared with our
present translation of sidereal time into clock time. Deal with the
year unit and day unit separately and convert them mutually when
necessary.
2nd. A universal mean time day of 24 hours, as now kept at
Greenwich, all human business being regulated by this time.
Dates and the date line as well as leap years all being retained as
at present.
3rd. Weight and spring clocks and watches to be superseded by
the cosmic clocks and watches regulated by wireless impulses
from central time stations, all impulses giving the same invariable
time for all places.
4th. Automatic recording of the earth's rotations to determine
this time.
To avoid any possibility of misunderstanding, I would advise
never counting a unit till it is completed. We do this correctly with
our hours, as we understand 24 o'clock to be the same as 0
o'clock. But we do not carry this out logically, for we say 24.30.
How can this be so, since there is nothing more than 24 o'clock?
It ought to be simply 30 minutes, or 0 hour 30 minutes. How can
there be any hour when a new day is only 30 minutes old? This
brings up the acrimonious controversy, of some years ago, as to
whether there was any “year one.” One side insisted that till one
year was completed there could only be months and days. The
other side argued that the “year one” commenced at 0 and that
the month and date showed how much of it had passed. Test
yourself,—is this the year 1909, of which only 8 months have
passed; or is it 1909 and 8 months more? Regarding the centuries
there appears to be no difference of opinion that 1900 is
39. completed, and that we are in the 20th century. But can you tell
whether we are 8 years and 8 months into the 20th century or 9
years and 8 months? It ought to be, logically 1909 years complete
and 8 months of the next year, which we must not count till it is
completed. Take a carpenter's rule, we say 1⁄4 in.—1⁄2 in.—3⁄4 in.,
but do not count an inch till we complete it. When the ancients
are quoted,—“about the middle of the third hour” there is no
mistake, because that means 21⁄2 hours since sunrise. If we said
the 1909th year that would be definite too, and mean some
distance into that year. Popular language states that Greenwich is
on the “first meridian”; strictly, it is on the zero meridian, or 0°.
These matters are largely academic and I do not look on them as
serious subjects of discussion; but they are good thought
producers. Bidding you good-bye, for the present, it might be
permissible to state that this conversational article on Time was
intended to be readable and somewhat instructive; but especially
to indicate the infinity of the subject, that thought and
investigation might be encouraged.
TRANSCRIBER'S NOTE:
Original spelling and grammar have mostly been
retained. However, on page 31, “clepsydral” was changed
to “clepsydra”.
Figures were moved from within paragraphs to between
paragraphs. In addition, some figures were originally
out of numerical sequence; they are now in sequence
(all but Fig. 46, which does need to be the last
illustration).
41. *** END OF THE PROJECT GUTENBERG EBOOK TIME AND ITS
MEASUREMENT ***
Updated editions will replace the previous one—the old editions
will be renamed.
Creating the works from print editions not protected by U.S.
copyright law means that no one owns a United States copyright
in these works, so the Foundation (and you!) can copy and
distribute it in the United States without permission and without
paying copyright royalties. Special rules, set forth in the General
Terms of Use part of this license, apply to copying and
distributing Project Gutenberg™ electronic works to protect the
PROJECT GUTENBERG™ concept and trademark. Project
Gutenberg is a registered trademark, and may not be used if you
charge for an eBook, except by following the terms of the
trademark license, including paying royalties for use of the
Project Gutenberg trademark. If you do not charge anything for
copies of this eBook, complying with the trademark license is
very easy. You may use this eBook for nearly any purpose such
as creation of derivative works, reports, performances and
research. Project Gutenberg eBooks may be modified and
printed and given away—you may do practically ANYTHING in
the United States with eBooks not protected by U.S. copyright
law. Redistribution is subject to the trademark license, especially
commercial redistribution.
START: FULL LICENSE
43. PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK
To protect the Project Gutenberg™ mission of promoting the free
distribution of electronic works, by using or distributing this work
(or any other work associated in any way with the phrase
“Project Gutenberg”), you agree to comply with all the terms of
the Full Project Gutenberg™ License available with this file or
online at www.gutenberg.org/license.
Section 1. General Terms of Use and
Redistributing Project Gutenberg™
electronic works
1.A. By reading or using any part of this Project Gutenberg™
electronic work, you indicate that you have read, understand,
agree to and accept all the terms of this license and intellectual
property (trademark/copyright) agreement. If you do not agree
to abide by all the terms of this agreement, you must cease
using and return or destroy all copies of Project Gutenberg™
electronic works in your possession. If you paid a fee for
obtaining a copy of or access to a Project Gutenberg™ electronic
work and you do not agree to be bound by the terms of this
agreement, you may obtain a refund from the person or entity to
whom you paid the fee as set forth in paragraph 1.E.8.
1.B. “Project Gutenberg” is a registered trademark. It may only
be used on or associated in any way with an electronic work by
people who agree to be bound by the terms of this agreement.
There are a few things that you can do with most Project
Gutenberg™ electronic works even without complying with the
full terms of this agreement. See paragraph 1.C below. There are
a lot of things you can do with Project Gutenberg™ electronic
works if you follow the terms of this agreement and help
preserve free future access to Project Gutenberg™ electronic
works. See paragraph 1.E below.
44. 1.C. The Project Gutenberg Literary Archive Foundation (“the
Foundation” or PGLAF), owns a compilation copyright in the
collection of Project Gutenberg™ electronic works. Nearly all the
individual works in the collection are in the public domain in the
United States. If an individual work is unprotected by copyright
law in the United States and you are located in the United
States, we do not claim a right to prevent you from copying,
distributing, performing, displaying or creating derivative works
based on the work as long as all references to Project Gutenberg
are removed. Of course, we hope that you will support the
Project Gutenberg™ mission of promoting free access to
electronic works by freely sharing Project Gutenberg™ works in
compliance with the terms of this agreement for keeping the
Project Gutenberg™ name associated with the work. You can
easily comply with the terms of this agreement by keeping this
work in the same format with its attached full Project
Gutenberg™ License when you share it without charge with
others.
1.D. The copyright laws of the place where you are located also
govern what you can do with this work. Copyright laws in most
countries are in a constant state of change. If you are outside
the United States, check the laws of your country in addition to
the terms of this agreement before downloading, copying,
displaying, performing, distributing or creating derivative works
based on this work or any other Project Gutenberg™ work. The
Foundation makes no representations concerning the copyright
status of any work in any country other than the United States.
1.E. Unless you have removed all references to Project
Gutenberg:
1.E.1. The following sentence, with active links to, or other
immediate access to, the full Project Gutenberg™ License must
appear prominently whenever any copy of a Project Gutenberg™
work (any work on which the phrase “Project Gutenberg”
45. appears, or with which the phrase “Project Gutenberg” is
associated) is accessed, displayed, performed, viewed, copied or
distributed:
This eBook is for the use of anyone anywhere in the United
States and most other parts of the world at no cost and with
almost no restrictions whatsoever. You may copy it, give it
away or re-use it under the terms of the Project Gutenberg
License included with this eBook or online at
www.gutenberg.org. If you are not located in the United
States, you will have to check the laws of the country where
you are located before using this eBook.
1.E.2. If an individual Project Gutenberg™ electronic work is
derived from texts not protected by U.S. copyright law (does not
contain a notice indicating that it is posted with permission of
the copyright holder), the work can be copied and distributed to
anyone in the United States without paying any fees or charges.
If you are redistributing or providing access to a work with the
phrase “Project Gutenberg” associated with or appearing on the
work, you must comply either with the requirements of
paragraphs 1.E.1 through 1.E.7 or obtain permission for the use
of the work and the Project Gutenberg™ trademark as set forth
in paragraphs 1.E.8 or 1.E.9.
1.E.3. If an individual Project Gutenberg™ electronic work is
posted with the permission of the copyright holder, your use and
distribution must comply with both paragraphs 1.E.1 through
1.E.7 and any additional terms imposed by the copyright holder.
Additional terms will be linked to the Project Gutenberg™
License for all works posted with the permission of the copyright
holder found at the beginning of this work.
1.E.4. Do not unlink or detach or remove the full Project
Gutenberg™ License terms from this work, or any files
containing a part of this work or any other work associated with
Project Gutenberg™.
46. 1.E.5. Do not copy, display, perform, distribute or redistribute
this electronic work, or any part of this electronic work, without
prominently displaying the sentence set forth in paragraph 1.E.1
with active links or immediate access to the full terms of the
Project Gutenberg™ License.
1.E.6. You may convert to and distribute this work in any binary,
compressed, marked up, nonproprietary or proprietary form,
including any word processing or hypertext form. However, if you
provide access to or distribute copies of a Project Gutenberg™
work in a format other than “Plain Vanilla ASCII” or other format
used in the official version posted on the official Project
Gutenberg™ website (www.gutenberg.org), you must, at no
additional cost, fee or expense to the user, provide a copy, a
means of exporting a copy, or a means of obtaining a copy upon
request, of the work in its original “Plain Vanilla ASCII” or other
form. Any alternate format must include the full Project
Gutenberg™ License as specified in paragraph 1.E.1.
1.E.7. Do not charge a fee for access to, viewing, displaying,
performing, copying or distributing any Project Gutenberg™
works unless you comply with paragraph 1.E.8 or 1.E.9.
1.E.8. You may charge a reasonable fee for copies of or
providing access to or distributing Project Gutenberg™ electronic
works provided that:
• You pay a royalty fee of 20% of the gross profits you derive from the
use of Project Gutenberg™ works calculated using the method you
already use to calculate your applicable taxes. The fee is owed to the
owner of the Project Gutenberg™ trademark, but he has agreed to
donate royalties under this paragraph to the Project Gutenberg
Literary Archive Foundation. Royalty payments must be paid within
60 days following each date on which you prepare (or are legally
required to prepare) your periodic tax returns. Royalty payments
should be clearly marked as such and sent to the Project Gutenberg
Literary Archive Foundation at the address specified in Section 4,
47. “Information about donations to the Project Gutenberg Literary
Archive Foundation.”
• You provide a full refund of any money paid by a user who notifies
you in writing (or by e-mail) within 30 days of receipt that s/he does
not agree to the terms of the full Project Gutenberg™ License. You
must require such a user to return or destroy all copies of the works
possessed in a physical medium and discontinue all use of and all
access to other copies of Project Gutenberg™ works.
• You provide, in accordance with paragraph 1.F.3, a full refund of any
money paid for a work or a replacement copy, if a defect in the
electronic work is discovered and reported to you within 90 days of
receipt of the work.
• You comply with all other terms of this agreement for free
distribution of Project Gutenberg™ works.
1.E.9. If you wish to charge a fee or distribute a Project
Gutenberg™ electronic work or group of works on different
terms than are set forth in this agreement, you must obtain
permission in writing from the Project Gutenberg Literary Archive
Foundation, the manager of the Project Gutenberg™ trademark.
Contact the Foundation as set forth in Section 3 below.
1.F.
1.F.1. Project Gutenberg volunteers and employees expend
considerable effort to identify, do copyright research on,
transcribe and proofread works not protected by U.S. copyright
law in creating the Project Gutenberg™ collection. Despite these
efforts, Project Gutenberg™ electronic works, and the medium
on which they may be stored, may contain “Defects,” such as,
but not limited to, incomplete, inaccurate or corrupt data,
transcription errors, a copyright or other intellectual property
infringement, a defective or damaged disk or other medium, a
48. computer virus, or computer codes that damage or cannot be
read by your equipment.
1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except
for the “Right of Replacement or Refund” described in paragraph
1.F.3, the Project Gutenberg Literary Archive Foundation, the
owner of the Project Gutenberg™ trademark, and any other
party distributing a Project Gutenberg™ electronic work under
this agreement, disclaim all liability to you for damages, costs
and expenses, including legal fees. YOU AGREE THAT YOU HAVE
NO REMEDIES FOR NEGLIGENCE, STRICT LIABILITY, BREACH
OF WARRANTY OR BREACH OF CONTRACT EXCEPT THOSE
PROVIDED IN PARAGRAPH 1.F.3. YOU AGREE THAT THE
FOUNDATION, THE TRADEMARK OWNER, AND ANY
DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE LIABLE
TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL,
PUNITIVE OR INCIDENTAL DAMAGES EVEN IF YOU GIVE
NOTICE OF THE POSSIBILITY OF SUCH DAMAGE.
1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you
discover a defect in this electronic work within 90 days of
receiving it, you can receive a refund of the money (if any) you
paid for it by sending a written explanation to the person you
received the work from. If you received the work on a physical
medium, you must return the medium with your written
explanation. The person or entity that provided you with the
defective work may elect to provide a replacement copy in lieu of
a refund. If you received the work electronically, the person or
entity providing it to you may choose to give you a second
opportunity to receive the work electronically in lieu of a refund.
If the second copy is also defective, you may demand a refund
in writing without further opportunities to fix the problem.
1.F.4. Except for the limited right of replacement or refund set
forth in paragraph 1.F.3, this work is provided to you ‘AS-IS’,
WITH NO OTHER WARRANTIES OF ANY KIND, EXPRESS OR
49. IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
MERCHANTABILITY OR FITNESS FOR ANY PURPOSE.
1.F.5. Some states do not allow disclaimers of certain implied
warranties or the exclusion or limitation of certain types of
damages. If any disclaimer or limitation set forth in this
agreement violates the law of the state applicable to this
agreement, the agreement shall be interpreted to make the
maximum disclaimer or limitation permitted by the applicable
state law. The invalidity or unenforceability of any provision of
this agreement shall not void the remaining provisions.
1.F.6. INDEMNITY - You agree to indemnify and hold the
Foundation, the trademark owner, any agent or employee of the
Foundation, anyone providing copies of Project Gutenberg™
electronic works in accordance with this agreement, and any
volunteers associated with the production, promotion and
distribution of Project Gutenberg™ electronic works, harmless
from all liability, costs and expenses, including legal fees, that
arise directly or indirectly from any of the following which you do
or cause to occur: (a) distribution of this or any Project
Gutenberg™ work, (b) alteration, modification, or additions or
deletions to any Project Gutenberg™ work, and (c) any Defect
you cause.
Section 2. Information about the Mission of
Project Gutenberg™
Project Gutenberg™ is synonymous with the free distribution of
electronic works in formats readable by the widest variety of
computers including obsolete, old, middle-aged and new
computers. It exists because of the efforts of hundreds of
volunteers and donations from people in all walks of life.
Volunteers and financial support to provide volunteers with the
assistance they need are critical to reaching Project
50. Gutenberg™’s goals and ensuring that the Project Gutenberg™
collection will remain freely available for generations to come. In
2001, the Project Gutenberg Literary Archive Foundation was
created to provide a secure and permanent future for Project
Gutenberg™ and future generations. To learn more about the
Project Gutenberg Literary Archive Foundation and how your
efforts and donations can help, see Sections 3 and 4 and the
Foundation information page at www.gutenberg.org.
Section 3. Information about the Project
Gutenberg Literary Archive Foundation
The Project Gutenberg Literary Archive Foundation is a non-
profit 501(c)(3) educational corporation organized under the
laws of the state of Mississippi and granted tax exempt status by
the Internal Revenue Service. The Foundation’s EIN or federal
tax identification number is 64-6221541. Contributions to the
Project Gutenberg Literary Archive Foundation are tax deductible
to the full extent permitted by U.S. federal laws and your state’s
laws.
The Foundation’s business office is located at 809 North 1500
West, Salt Lake City, UT 84116, (801) 596-1887. Email contact
links and up to date contact information can be found at the
Foundation’s website and official page at
www.gutenberg.org/contact
Section 4. Information about Donations to
the Project Gutenberg Literary Archive
Foundation
Project Gutenberg™ depends upon and cannot survive without
widespread public support and donations to carry out its mission
of increasing the number of public domain and licensed works
51. that can be freely distributed in machine-readable form
accessible by the widest array of equipment including outdated
equipment. Many small donations ($1 to $5,000) are particularly
important to maintaining tax exempt status with the IRS.
The Foundation is committed to complying with the laws
regulating charities and charitable donations in all 50 states of
the United States. Compliance requirements are not uniform and
it takes a considerable effort, much paperwork and many fees to
meet and keep up with these requirements. We do not solicit
donations in locations where we have not received written
confirmation of compliance. To SEND DONATIONS or determine
the status of compliance for any particular state visit
www.gutenberg.org/donate.
While we cannot and do not solicit contributions from states
where we have not met the solicitation requirements, we know
of no prohibition against accepting unsolicited donations from
donors in such states who approach us with offers to donate.
International donations are gratefully accepted, but we cannot
make any statements concerning tax treatment of donations
received from outside the United States. U.S. laws alone swamp
our small staff.
Please check the Project Gutenberg web pages for current
donation methods and addresses. Donations are accepted in a
number of other ways including checks, online payments and
credit card donations. To donate, please visit:
www.gutenberg.org/donate.
Section 5. General Information About
Project Gutenberg™ electronic works
Professor Michael S. Hart was the originator of the Project
Gutenberg™ concept of a library of electronic works that could
52. be freely shared with anyone. For forty years, he produced and
distributed Project Gutenberg™ eBooks with only a loose
network of volunteer support.
Project Gutenberg™ eBooks are often created from several
printed editions, all of which are confirmed as not protected by
copyright in the U.S. unless a copyright notice is included. Thus,
we do not necessarily keep eBooks in compliance with any
particular paper edition.
Most people start at our website which has the main PG search
facility: www.gutenberg.org.
This website includes information about Project Gutenberg™,
including how to make donations to the Project Gutenberg
Literary Archive Foundation, how to help produce our new
eBooks, and how to subscribe to our email newsletter to hear
about new eBooks.
53. Welcome to our website – the ideal destination for book lovers and
knowledge seekers. With a mission to inspire endlessly, we offer a
vast collection of books, ranging from classic literary works to
specialized publications, self-development books, and children's
literature. Each book is a new journey of discovery, expanding
knowledge and enriching the soul of the reade
Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.
Let us accompany you on the journey of exploring knowledge and
personal growth!
textbookfull.com