Tracking wrapper to preserve your codebase dependency free from 3rd-party vendors
TrackingEngine
Rationale
Ideally, we want to have our code completely dependency-free and preserve control over its entire functioning. In the real world, we know this is unrealistic since it would imply reinventing the wheel over and over.
TrackingEngine centralizes the tracking SDKs and exposes them via facades.
What’s the point?
Contracts expire, SDKs get deprecated and fees rises. These, just to mention a few, are valid reasons to change tracking vendors.
This is rather hard when our codebases are littered with direct SDKs implementations. TrackingEngine makes such processes painless by making their consumption behind a facade. This is why, whatever happens under the hood shall not concern our Tracking clients apps.
Installation
Xcode 13
- From the File menu, Add Packages….
- Enter package repository URL:
https://github.com/GeekingwithMauri/TrackingEngine
- Confirm the version and let Xcode resolve the package
Swift Package Manager
If you want to use TrackingEngine in any other project that uses SwiftPM, add the package as a dependency in Package.swift
:
dependencies: [
.package(
url: "https://github.com/GeekingwithMauri/TrackingEngine",
from: "0.1.0"
),
]
Example of usage
// A recommended place to put it is on the application(_:didFinishLaunchingWithOptions:)` due to some vendor's inner workings (such as Firebase init swizzling)
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
// This is done before any logging occurs.
TrackingEngineFacade.setup()
return true
}
// Tracking an event
TrackingEngineFacade.log(eventName: "view_appeared", parameters: ["type": "home"])
Good practices recommendations
“All problems in computer science can be solved by another level of indirection.” – David Wheeler
And the end of the day, this is also a 3rd party dependency so it’s recommended to limit its own spreading.
In order to prevent the spread of import TrackingEngine
and direct TrackingEngineFacade.log
all over the place, it’s highly advisable to centralize its usage within a thin wrapper as follows ??
import TrackingEngine
protocol TrackingLoggable {
/// Tracks user's events via the `TrackingEngineFacade`
/// - Parameters:
/// - eventName: event name to be tracked. I.e. _view_appeared_, _button_tapped_ and so forth
/// - parameters: The dictionary of event parameters. Passing `nil` indicates that the event has no parameters.
func track(eventName: String, parameters: [String: Any]?)
}
struct Tracker: TrackingLoggable {
func track(eventName: String, parameters: [String : Any]?) {
TrackingEngineFacade.log(eventName: eventName, parameters: parameters)
}
}
Testing
The above recommendation makes the library self contained. It also opens the door for testing, by simply replacing the real implementation with a TrackingLoggable
with a Spy.
Check out the example of how said testing could occur.
Current limitations
- For the time being, this only supports Firebase.
GoogleService-Info
must be included in the main project