As a Roblox developer, it is difficult to understand Datastore budgeting, because the enumerators of Enum.DataStoreRequestType are obscure and do not map directly to the Datastore operations that are available. Moreover, budget consumption differs between the two available Datastore types. Developers need to look up on the wiki what kind of budget each Datastore request uses constantly for this reason, it is hard to memorize.
For example, if I want to check if GlobalDataStore::RemoveAsync is possible, I need to check if the SetIncrementAsync budget is higher than 0. They do not relate at all in terms of naming.
And when we switch to OrderedDataStore::RemoveAsync, I now suddenly need to check SetIncrementSortedAsync budget, instead of SetIncrementAsync.
For GlobalDataStore::UpdateAsync, I can simply check the UpdateAsync budget. However, for OrderedDataStore::UpdateAsync, this is not sufficient, as explained in this thread, you need to check for both GetAsync and SetIncrementSortedAsync budget to be both higher than 0.
In short: these enumerators are obfuscating in nature for no reason, and they also leak unnecessary implementation details that make them all too difficult to use. Budgeting checks should be abstracted more to make it as easy as possible for developers to write these checks by heart, to prevent mistakes due to misunderstanding how these DataStoreRequestType values map to the various Datastore operations, and to make them more backwards-compatible in case the budget consumption of a certain operation changes.
Even though I shouldn’t put solutions in feature requests as a developer, I would still like to describe a possible solution to explain what I mean and to show how it would improve the structuring and clarity of API calls that developers make in their code.
My suggestion is to deprecate the following API:
Enum
-DataStoreRequestType
-GetAsync
-GetSortedAsync
-SetIncrementAsync
-SetIncrementSortedAsync
-UpdateAsync
-OnUpdate
DataStoreService
-GetRequestBudgetForRequestType(DataStoreRequestType requestType)
And to add the following API:
Enum
+DataStoreMethod
+Get
+Increment
+Set
+Update
+Remove
+OnUpdate
+GetSorted
+AdvanceToNextPage
GlobalDataStore
+GetRequestBudgetForMethod(DataStoreMethod method)
OrderedDataStore
+GetRequestBudgetForMethod(DataStoreMethod method)
Note that the budget checking has shifted from DataStoreService to the GlobalDataStore/OrderedDataStore classes themselves, and we now have enumerators per operation rather than per arbitrarily defined budget types that have too much dependency on implementation details of internal code. This allows us to distinguish budget consumption between datastore types for the same operation, and to write clearer checks, as will be shown next.
Compare these listings of old vs proposed API:
Before:
GlobalDataStore::GetAsync
DataStoreService:GetRequestBudgetForRequestType(Enum.DataStoreRequestType.GetAsync) > 0
GlobalDataStore::IncrementAsync
DataStoreService:GetRequestBudgetForRequestType(Enum.DataStoreRequestType.SetIncrementAsync) > 0
GlobalDataStore::OnUpdate
DataStoreService:GetRequestBudgetForRequestType(Enum.DataStoreRequestType.OnUpdate) > 0
GlobalDataStore::RemoveAsync
DataStoreService:GetRequestBudgetForRequestType(Enum.DataStoreRequestType.SetIncrementAsync) > 0
GlobalDataStore::SetAsync
DataStoreService:GetRequestBudgetForRequestType(Enum.DataStoreRequestType.SetIncrementAsync) > 0
GlobalDataStore::UpdateAsync
DataStoreService:GetRequestBudgetForRequestType(Enum.DataStoreRequestType.UpdateAsync) > 0
OrderedDataStore::GetAsync
DataStoreService:GetRequestBudgetForRequestType(Enum.DataStoreRequestType.GetAsync) > 0
OrderedDataStore::IncrementAsync
DataStoreService:GetRequestBudgetForRequestType(Enum.DataStoreRequestType.SetIncrementSortedAsync) > 0
OrderedDataStore::OnUpdate
DataStoreService:GetRequestBudgetForRequestType(Enum.DataStoreRequestType.OnUpdate) > 0
OrderedDataStore::RemoveAsync
DataStoreService:GetRequestBudgetForRequestType(Enum.DataStoreRequestType.SetIncrementSortedAsync) > 0
OrderedDataStore::SetAsync
DataStoreService:GetRequestBudgetForRequestType(Enum.DataStoreRequestType.SetIncrementSortedAsync) > 0
OrderedDataStore::UpdateAsync
DataStoreService:GetRequestBudgetForRequestType(Enum.DataStoreRequestType.SetIncrementSortedAsync) > 0
and DataStoreService:GetRequestBudgetForRequestType(Enum.DataStoreRequestType.GetAsync) > 0
OrderedDataStore::GetSortedAsync
DataStoreService:GetRequestBudgetForRequestType(Enum.DataStoreRequestType.GetSortedAsync) > 0
MockDataStorePages::AdvanceToNextPageAsync
DataStoreService:GetRequestBudgetForRequestType(Enum.DataStoreRequestType.GetSortedAsync) > 0
Note:
- For most of these, the method name has nothing to do with the budget type.
- OrderedDataStore::UpdateAsync needs to check 2 budgets
- OrderedDataStore and GlobalDataStore writes use different budgets despite the operations named the same way.
After:
GlobalDataStore::GetAsync
GlobalDataStore:GetRequestBudgetForMethod(Enum.DataStoreMethod.Get) > 0
GlobalDataStore::IncrementAsync
GlobalDataStore:GetRequestBudgetForMethod(Enum.DataStoreMethod.Increment) > 0
GlobalDataStore::OnUpdate
GlobalDataStore:GetRequestBudgetForMethod(Enum.DataStoreMethod.OnUpdate) > 0
GlobalDataStore::RemoveAsync
GlobalDataStore:GetRequestBudgetForMethod(Enum.DataStoreMethod.Remove) > 0
GlobalDataStore::SetAsync
GlobalDataStore:GetRequestBudgetForMethod(Enum.DataStoreMethod.Set) > 0
GlobalDataStore::UpdateAsync
GlobalDataStore:GetRequestBudgetForMethod(Enum.DataStoreMethod.Update) > 0
OrderedDataStore::GetAsync
OrderedDataStore:GetRequestBudgetForMethod(Enum.DataStoreMethod.Get) > 0
OrderedDataStore::IncrementAsync
OrderedDataStore:GetRequestBudgetForMethod(Enum.DataStoreMethod.Increment) > 0
OrderedDataStore::OnUpdate
OrderedDataStore:GetRequestBudgetForMethod(Enum.DataStoreMethod.OnUpdate) > 0
OrderedDataStore::RemoveAsync
OrderedDataStore:GetRequestBudgetForMethod(Enum.DataStoreMethod.Remove) > 0
OrderedDataStore::SetAsync
OrderedDataStore:GetRequestBudgetForMethod(Enum.DataStoreMethod.Set) > 0
OrderedDataStore::UpdateAsync
OrderedDataStore:GetRequestBudgetForMethod(Enum.DataStoreMethod.Update) > 0
OrderedDataStore::GetSortedAsync
OrderedDataStore:GetRequestBudgetForMethod(Enum.DataStoreMethod.GetSorted) > 0
MockDataStorePages::AdvanceToNextPageAsync
OrderedDataStore:GetRequestBudgetForMethod(Enum.DataStoreMethod.AdvanceToNextPage) > 0
This is cleaner, does not leak implementation details, and is easy to remember and guess via Intellisense without needing to keep the Developer Hub / other kinds of documentation open on the side (PS: the information on the Developer Hub about budget consumption is actually wrong at the time of writing, even ).
If Roblox is able to improve budgeting API (i.e. self-descriptive enumerators and API), it would improve my development experience because budgeting checks would be easier to write, easier to remember, easier to understand, be backwards-compatible in case the internals of datastores change or new datastore methods are added, and cause less room for user error.