Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MOB-2959] Braze IAM for Newsletter NTP card #812

Merged
merged 19 commits into from
Nov 18, 2024

Conversation

lucaschifino
Copy link
Collaborator

@lucaschifino lucaschifino commented Nov 11, 2024

MOB-2959

Context

After spiking Braze IAM, we're setting up an experiment that uses it.

Approach

  • Refactor Braze integration and move it to Client
  • Add Braze IAM
  • Add Newsletter NTP card connected to an experiment
  • Link card and Braze IAM via a custom event
  • Track both the card and the IAM

Other

Before merging

Checklist

Copy link

github-actions bot commented Nov 11, 2024

PR Reviewer Guide 🔍

(Review updated until commit f84532a)

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Error Handling
The method initialize in BrazeService class catches errors but only prints them. Consider handling these errors more robustly or propagating them to allow for better error management and recovery.

Error Handling
The method requestAPNConsentIfNeeded catches errors but only logs them. It might be beneficial to handle these errors more explicitly to avoid silent failures and improve reliability.

Code Duplication
The methods brazeIAM and newsletterCardExperiment in Analytics.swift are very similar and could potentially be refactored to reduce code duplication.

Copy link

github-actions bot commented Nov 11, 2024

PR Code Suggestions ✨

Latest suggestions up to f84532a
Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Score
Possible bug
Add error handling for potential exceptions during Braze service initialization

Consider handling the scenario where BrazeService.shared.initialize might throw an
error that isn't caught, which could lead to unhandled exceptions during the app
initialization process.

Client/Ecosia/Braze/BrazeService.swift [195]

-await BrazeService.shared.initialize(notificationCenterDelegate: self)
+do {
+    try await BrazeService.shared.initialize(notificationCenterDelegate: self)
+} catch {
+    // Handle initialization error appropriately
+}
Suggestion importance[1-10]: 8

Why: Adding error handling for the initialization of Braze service is crucial to prevent the app from crashing due to unhandled exceptions, enhancing the robustness and reliability of the app initialization process.

8
Implement error handling for device token registration in Braze service

Ensure that the BrazeService.shared.registerDeviceToken method handles potential
failures or exceptions when registering the device token, as the current
implementation does not account for these scenarios.

Client/Ecosia/Braze/BrazeService.swift [405]

-BrazeService.shared.registerDeviceToken(deviceToken)
+do {
+    try BrazeService.shared.registerDeviceToken(deviceToken)
+} catch {
+    // Handle registration error appropriately
+}
Suggestion importance[1-10]: 7

Why: Implementing error handling for device token registration is important to ensure that potential failures are managed properly, which can prevent issues related to push notification functionality.

7
Enhance robustness of APN consent request handling in Braze service

Refactor the BrazeService.shared.requestAPNConsent method to handle the potential
throwing of exceptions more robustly, especially considering it's used in an async
context which might lead to unhandled promise rejections.

Client/Ecosia/Braze/BrazeService.swift [26]

-let granted = try await BrazeService.shared.requestAPNConsent(notificationCenterDelegate: delegate)
+let granted: Bool
+do {
+    granted = try await BrazeService.shared.requestAPNConsent(notificationCenterDelegate: delegate)
+} catch {
+    // Handle consent request error appropriately
+    granted = false
+}
Suggestion importance[1-10]: 7

Why: Enhancing error handling for the APN consent request is critical as it directly affects the app's ability to manage push notification permissions, which is a key functionality for user engagement.

7
Enhancement
Provide a default API key for Braze service to avoid potential issues with empty configuration

Add a fallback or default value for BrazeService.apiKey in case it is not found in
the environment variables, to prevent the app from using an empty or invalid API
key.

Client/Ecosia/Braze/BrazeService.swift [18]

-private static var apiKey = EnvironmentFetcher.valueFromMainBundleOrProcessInfo(forKey: "BRAZE_API_KEY") ?? ""
+private static var apiKey = EnvironmentFetcher.valueFromMainBundleOrProcessInfo(forKey: "BRAZE_API_KEY") ?? "default_api_key"
Suggestion importance[1-10]: 5

Why: Providing a default API key as a fallback is a good practice to ensure that the Braze service has a valid API key to operate, preventing potential runtime errors due to missing configuration. However, this should be handled with caution to avoid using inappropriate keys in production.

5

Previous suggestions

Suggestions up to commit 8059c7a
CategorySuggestion                                                                                                                                    Score
Possible bug
Add nil-check for notificationCenterDelegate to prevent potential delegate assignment errors

Consider handling the case where notificationCenterDelegate is nil before setting it
as the delegate to avoid potential runtime errors.

Client/Ecosia/Braze/BrazeService.swift [93]

-center.delegate = notificationCenterDelegate
+if let delegate = notificationCenterDelegate {
+    center.delegate = delegate
+}
Suggestion importance[1-10]: 7

Why: Adding a nil-check before setting the delegate can prevent runtime errors if notificationCenterDelegate is nil. This is a good defensive programming practice.

7
Enhancement
Implement error handling for asynchronous ID update in registerDeviceToken

Add error handling for the await self?.updateID(self?.userId) call within the
registerDeviceToken method to manage potential failures gracefully.

Client/Ecosia/Braze/BrazeService.swift [42-44]

 Task.detached(priority: .medium) { [weak self] in
-    await self?.updateID(self?.userId)
+    do {
+        try await self?.updateID(self?.userId)
+    } catch {
+        // Handle error, e.g., logging or retrying
+    }
 }
Suggestion importance[1-10]: 6

Why: Implementing error handling for the asynchronous ID update operation enhances robustness and reliability of the registerDeviceToken method.

6
Strengthen the validation of apiKey in the configuration setup

Validate the apiKey in getBrazeConfiguration method to ensure it meets expected
criteria (e.g., length, format) beyond just being non-empty.

Client/Ecosia/Braze/BrazeService.swift [136]

-guard !apiKey.isEmpty else { throw Error.invalidConfiguration }
+guard !apiKey.isEmpty, apiKey.count > 10 else { throw Error.invalidConfiguration }
Suggestion importance[1-10]: 4

Why: Strengthening the validation of apiKey is beneficial for ensuring the configuration's integrity, but the impact is moderate as it primarily adds a simple check for length.

4
Possible issue
Ensure thread safety for notificationAuthorizationStatus updates

Ensure that the notificationAuthorizationStatus is thread-safe if accessed from
multiple threads, possibly by using synchronization mechanisms or dispatch queues.

Client/Ecosia/Braze/BrazeService.swift [100]

-notificationAuthorizationStatus = currentStatus
+DispatchQueue.main.async {
+    self.notificationAuthorizationStatus = currentStatus
+}
Suggestion importance[1-10]: 5

Why: Ensuring thread safety for updating notificationAuthorizationStatus is important, but the provided solution assumes multi-thread access which might not be necessary if the code runs on a single thread.

5

@lucaschifino lucaschifino marked this pull request as ready for review November 13, 2024 17:54
Copy link

Persistent review updated to latest commit f84532a

@lucaschifino lucaschifino requested a review from a team November 13, 2024 17:55
Copy link
Member

@d4r1091 d4r1091 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great re-implementation 👌 .
Added some clarification points but nothing that strictly prevents this overall work from being merged 💪

Client/Application/AppDelegate.swift Show resolved Hide resolved
Client/Ecosia/Braze/BrazeService.swift Show resolved Hide resolved
@@ -13,44 +13,33 @@ protocol NTPConfigurableNudgeCardCellDelegate: AnyObject {

/// ViewModel for configuring a Nudge Card Cell.
class NTPConfigurableNudgeCardCellViewModel: HomepageViewModelProtocol {
var title: String {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the point here 👌 - I guess having them with the fatalError was an easier update considering the state of the class.
Wondering if we'd invest time and make it as protocol.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there might be complexities in adding one more protocol since the HomepageViewModelProtocol is already used. I like the idea that this is a superclass that can be extended and has the majority of the logic, just like you initially implemented. The main reason I changed to overriding methods is because those custom contents are then much more organised as part of the subclass file itself instead of somewhat hidden in the initialisation (which in turn happens on the already big HomepageViewModel).

What do you think? Do you see any specific advantages to using protocol here instead?

EcosiaTests/BrazeServiceTests.swift Show resolved Hide resolved
@lucaschifino lucaschifino mentioned this pull request Nov 15, 2024
10 tasks
@lucaschifino lucaschifino requested a review from d4r1091 November 15, 2024 16:07
d4r1091
d4r1091 previously approved these changes Nov 18, 2024
Copy link
Member

@d4r1091 d4r1091 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed with @lucaschifino that given all the challenges we had with the Braze integration and to make this work, we'd consider a further abstraction of the Braze implementation into another set of work.
Let's go 🚀

@lucaschifino
Copy link
Collaborator Author

@d4r1091 Found some issues with APN after the refactor when doing some last tests, had to add the notification options and update the status in one more place. Can you please take another look?

@lucaschifino lucaschifino requested a review from d4r1091 November 18, 2024 13:10
Copy link
Member

@d4r1091 d4r1091 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha 👍
👌

@lucaschifino lucaschifino merged commit 61c2242 into main Nov 18, 2024
3 checks passed
@lucaschifino lucaschifino deleted the ls-mob-2959-braze-ntp-card-newsletter branch November 18, 2024 13:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants