-
Notifications
You must be signed in to change notification settings - Fork 25
feat: Improve the performance of saving toggles to the StorageProvider #113
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
feat: Improve the performance of saving toggles to the StorageProvider #113
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍👍
Hi @lsj8706 . Thank you for your contribution. Our main Swift guy is Out of office until Tuesday March 4th, so you'll have to wait until then at the earliest for a proper reply here. |
I see what you are trying to do here. I'm wondering if there is a way to do this without requiring a major update. As we are changing the default behavior of the StorageProvider, everyone who currently has their own implementation would have to change it. Also, is |
Hello! Thank you for your thoughtful comments. |
@FredrikOseberg However, this change is intended to resolve existing performance issues, which I believe cannot be solved with the current interface alone. Current users are incurring the cost of n write operations when storing n Toggles in Storage, and this is a critical issue that must be addressed eventually. Although this will result in a major update, it seems better to resolve it during this opportunity when the scope of impact can be minimized as much as possible. |
With the provided DictionaryStorageProvider the current mode of operations should be fine, as the insert is entirely in memory and inserting into a dict is a O(1) operation. I can definitely see that this would be a problem for custom storage providers that are writing to disk, and I'd like to solve that problem. Do you have any benchmarks that can illustrate the performance gain on your provider with these changes? Generally, making a major release is more work for us, because we need to provide upgrade guides and documentation around the changes that led to the major update. It also puts some mental overhead on our users because they need to understand the changes and potentially make changes. Not saying I won't make a major release for this, but we try to be careful the number of majors that we do. Out of curiosity, would it be possible to do something like:
|
@FredrikOseberg public protocol StorageProvider {
func set(value: Toggle?, key: String)
func reset(keyedValues: [String: Toggle])
func value(key: String) -> Toggle?
func clear()
}
extension StorageProvider {
func reset(keyedValues: [String: Toggle]) {
for (key, value) in keyedValues {
set(value: value, key: key)
}
}
} By using Swift's protocol default implementation for the reset method, existing users won't need to implement the reset method separately. This addresses your concern since only those who need it can implement a custom reset method, while others can rely on the default implementation. |
Aiden Lee, thanks a lot for discussing this with me. I apologize for the time this has taken, but we have many SDKs and we try to make sure they are aligned as much as possible in how they work to reduce the cognitive load on users and ourselves. I've had a look at how our other SDKs handle this scenario in the StorageProviders and they all take the entire featureset and set it in the storageprovider in one go. I'm not sure why we opted for iterating over the features here, but it's clear that it's the wrong approach. I'm leaning towards doing a major update and changing the interface of the StorageProvider, but in that case I think we should just replace the set method entirely and have the set method do what you propose instead of adding a new method. It would keep the StorageProvider small and the interface more in line with other SDKs, and we'll remove this anti-pattern as a possibility. Here's an example of how it works in other SDKs:
I'd also love a test for this functionality if you have the time. What do you think? Could you make those changes to this PR? |
15bf176
to
4fcca3a
Compare
@FredrikOseberg I've checked the code from other SDKs that you attached, and I also think it's appropriate to change the implementation of the set method. Therefore, I've modified the implementation to store all Toggles at once in the set method. I've tested the modified implementation and confirmed that it passes without errors. 2d91e8d Additionally, I've added information about the injectability of the Poller to the README, as this information was missing. Please check and review. Thank you! |
4fcca3a
to
a3ae1f3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
About the changes
Currently, the Poller saves toggles to the StorageProvider individually through iteration, which consumes excessive resources. I Added
reset(keyedValues: [String : Toggle])
to StorageProvider interface. This improvement will optimize the process by implementing batch saving of the toggle array to Storage.Closes #112
Discussion points
In the current structure, when creating a StorageProvider that supports disk caching, read/write costs occur as many times as the number of toggles. This is because the toggle array is being iterated through and saved to Storage one by one. This PR is submitted to address this issue.