Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ Local device storage options:

| Option | Pros | Cons |
| :--- | :--- | :--- |
| **Key-Value Storage** (UserDefaults/SharedPreferences/Property List/MMKV) | <ul><li>**Easy to use built-in API:** Simple APIs for storing and retrieving data.</li><li>**Fast for simple operations:** Efficient for small amounts of data.</li><li>**Low overhead:** Minimal memory footprint.</li></ul> | <ul><li>**Insecure:** Data is stored in plain text (use `EncryptedSharedPreferences` on Android, third-party wrappers or `Keychain` on iOS for sensitive data).</li><li>**Not for large data:** Performance degrades significantly with large datasets.</li><li>**No schema or querying:** Limited querying capabilities. No data integrity constraints.</li><li>**No data migration:** Difficult to manage schema changes.</li><li>**Poor performance for complex operations:** Inefficient for complex data structures or operations.</li><li>**Not ACID compliant:** No guarantee of atomicity, consistency, isolation, or durability.</li></ul> |
| **Key-Value Storage** (UserDefaults/SharedPreferences/Property List/MMKV) | <ul><li>**Easy to use built-in API:** Simple APIs for storing and retrieving data.</li><li>**Fast for simple operations:** Efficient for small amounts of data.</li><li>**Low overhead:** Minimal memory footprint.</li></ul> | <ul><li>**Insecure:** Data is stored in plain text (use Keystore for encryption key management on Android, third-party wrappers or `Keychain` on iOS for sensitive data).</li><li>**Not for large data:** Performance degrades significantly with large datasets.</li><li>**No schema or querying:** Limited querying capabilities. No data integrity constraints.</li><li>**No data migration:** Difficult to manage schema changes.</li><li>**Poor performance for complex operations:** Inefficient for complex data structures or operations.</li><li>**Not ACID compliant:** No guarantee of atomicity, consistency, isolation, or durability.</li></ul> |
| **Database/ORM** (SQLite/Room/Core Data/Realm/ObjectBox) | <ul><li>**Object-relational mapping (ORM):** Simplifies data access and manipulation using object-oriented paradigms.</li><li>**Schema and querying:** Supports structured data with defined schemas and powerful querying capabilities using SQL or ORM-specific query languages.</li><li>**Data migration:** Provides mechanisms for managing schema changes and data migration.</li><li>**ACID properties:** Guarantees atomicity, consistency, isolation, and durability.</li><li>**Efficient for complex operations:** Optimized for complex data structures and operations.</li></ul> | <ul><li>**More complex setup:** Requires defining schemas, setting up database connections, and managing ORM configurations.</li><li>**Potentially Insecure:** (use SQLCipher or other encryption libraries, properly configured)</li><li>**Bigger memory footprint:** Database files can consume significant storage space.</li><li>**Performance overhead:** ORM can introduce performance overhead compared to raw SQL queries.</li><li>**Steeper learning curve:** Requires familiarity with SQL or ORM concepts.</li></ul> |
| **Custom/Binary** (DataStore/NSCoding/Codable/Protocol Buffers) | <ul><li>**Highly customizable:** Allows fine-grained control over data serialization and storage.</li><li>**Performant:** Can be optimized for specific data structures and operations.</li><li>**Potentially smaller footprint:** If you carefully control serialization and avoid ORM overhead.</li></ul> | <ul><li>**No schema/migration:** Requires manual management of schema changes and data migration.</li><li>**Lots of manual effort:** Requires writing custom serialization and deserialization code.</li><li>**Increased complexity:** Requires a deep understanding of data structures and serialization techniques.</li><li>**Error-prone:** Serialization and deserialization code can be complex and prone to errors.</li><li>**Harder to debug:** Binary formats are difficult to inspect and debug without specialized tools.</li></ul> |
| **On-Device Secure Storage** (Keystore/Key Chain/Android Biometrics) | <ul><li>**Secure:** Provides hardware-backed or OS-level encryption for sensitive data. Protects against unauthorized access and data breaches.</li><li>**Integrates with device security:** Leverages device-level security features such as biometrics and PIN/password authentication.</li></ul> | <ul><li>**Not optimized for general storage:** Designed for storing small amounts of sensitive data such as encryption keys and user credentials.</li><li>**Encryption/decryption overhead:** Can introduce performance overhead for encryption and decryption operations.</li><li>**No schema/migration:** Limited querying capabilities. Difficult to manage schema changes.</li><li>**Complex API:** Can be complex to use correctly.</li><li>**Limited storage:** Has restrictions on the amount of storage space available.</li><li>**User Dependency:** Reliant on the user configuring a lockscreen.</li></ul> |
Expand All @@ -324,7 +324,7 @@ Local device storage options:

### Best Practices
- Store as little sensitive data as possible.
- Use encrypted storage for sensitive data (e.g., `EncryptedSharedPreferences`, `Keychain`, or SQLCipher).
- Use encrypted storage for sensitive data (e.g., Keystore for encryption key management on Android, `Keychain`, or SQLCipher).
- Prevent uncontrolled storage growth. Implement cache cleanup policies and manage file sizes.
- Use appropriate storage locations based on data privacy requirements (internal vs. external storage).
- Consider data backup and restore strategies for user-generated data.
Expand Down Expand Up @@ -433,7 +433,7 @@ Privacy and security should be a central consideration throughout the entire dev
- Assume on-device storage is not secure, even when using KeyStore/KeyChain functionality. Implement encryption to protect sensitive data.
- Encrypt all sensitive data at rest using strong encryption algorithms.
- Store encryption keys securely in the KeyStore/KeyChain or a hardware security module (HSM).
- Use secure data storage APIs such as EncryptedSharedPreferences on Android and the Keychain on iOS.
- Use secure data storage APIs such as Keystore for encryption key management on Android and the Keychain on iOS.
- Implement proper access controls to restrict access to sensitive data.
- Assume backend storage is also not secure.
- Use end-to-end encryption to protect data in transit and at rest. Implement server-side encryption to protect data stored in the backend.
Expand Down
2 changes: 1 addition & 1 deletion exercises/file-downloader-library.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ Prepare for questions that modify the original design.
> **Candidate**: "It's easier to access a file on the disk than from the database. We can partially read BLOBs and provide the content as a stream but it might not be sufficient in the general case."

> **Interviewer**: "How would you handle downloading sensitive information?"
> **Candidate**: "We might introduce an "encrypted" File Store implementation and encrypt a fully-received file in post-processing. Consider using platform-specific encryption APIs (e.g., `CryptoKit` on iOS, `Jetpack Security` on Android). Not sure if we can do it on the fly - don't have much experience working with encryption libraries."
> **Candidate**: "We might introduce an "encrypted" File Store implementation and encrypt a fully-received file in post-processing. Consider using platform-specific encryption APIs (e.g., `CryptoKit` on iOS, Keystore for encryption key management on Android). Not sure if we can do it on the fly - don't have much experience working with encryption libraries."

> **Interviewer**: "How would you change your design to support download requests of different priorities? For example, user-critical, UI-critical, UI-non-critical, low-priority?"
> **Candidate**: "The first option: update Download Dispatcher to use a priority queue; the second option: configure on the File Downloader instance level and maintain different instances based on the priority (would also require synchronization between instances). The priority information could be included in a Download Request."
Expand Down
2 changes: 1 addition & 1 deletion topics/caching-deep-dive.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Leverage standard headers to let the server control caching behavior.

## 6. Security Considerations
- **Sensitive Data:** Never cache PII (Personally Identifiable Information), auth tokens, or payment details in plain text on disk.
- **Encryption:** Use `EncryptedSharedPreferences` / `Jetpack Security` (Android) or `Keychain` / `File Protection` (iOS).
- **Encryption:** On Android, prefer `Keystore` for encryption key management. On iOS, use `Keychain` / `File Protection`.
- **Snapshots:** Be aware that the OS might take snapshots of the UI (which includes cached data) for the app switcher. Mask sensitive fields.

## 7. Common Pitfalls
Expand Down