Best way to handle a public facing data rollback API?

I am attempting to take a swing at desiging my own datastore library mainly because I want to design one with built in rollbacking and compression. I know how I can do it via roblox versioning API but I want to know how to design the public facing API which I dont know how to do. E.G. If i have an optional DateTime object param where the user can pass in a data and it pulls the version closest to that data? Or if i should make it a one time event where the developer can call a .Rollback(DateTime) function that will kick players from there current game and rollback there data a single time? If you have any advice please let me know!

This post I wrote solves a very similar problem, it might be of interest to you : Migrating saved data to a new format - #4 by Noble_Draconian

You want a library to work in as many situations as possible (or at least all of the situations that you intend to support) otherwise it will not be used. So it’s usually a good idea to provide more control to the user of the library than less.

When designing an API, you need to know what use cases it should should support.

The question you are implicitly asking in the example you provided is: Should changing data version require players to be kicked? There is nothing technical that prevents either answer to that question. Instead it depends on two decisions from different parties:

  1. (You, the creator of library) Do you want to users of your library to have control over whether players get kicked or not when the data version is changed? For example, I may not be able to use your library because I wish to rollback data versions without a player being kicked but your library does not allow me to separate the act of kicking a player from rolling back their data.

  2. (The users of the library) Consider the trade-off of development work & technical complexity/fragility compared to player experience. Should the library users go to the effort of not kicking players when the players’ data is rolled back? (provided that the library gives them that option)

I am not very experienced with the specific scenario of rolling back player data as I have not done it much, so I cannot give you a good overview of the important use cases involved in this kind of system. I am sure there are other people on this forum more experienced than I am who can provide that.

But as for the topic of API design itself, in my opinion the actual details of the API (e.g. should you introduce a new function vs a new parameter to an existing function) do not matter that much provided the API supports the use cases and is fairly simple. In my experience the details vary by personal preference, coding standards, design patterns, etc.

It is also helpful to write your ideal usage code first so you have a good baseline of what the API could be. By “ideal”, I mean in the context of actually using the library (calling its functions, dealing with errors, manging state) not in the context of the use case (where you still want to be fully tethered to reality).

Examples of usage code for the kick/don't kick decisions

Both of these examples assume you (as the library creator) decided to give users of the library control over whether a player is kicked or not.

Library user decision 1 (Don’t kick):

-- When player joins the game
local PlayerData = LoadDataVersionCurrent(Player)

-- Rolling back player data
-- This function call affects both the DataStore AND the player's data in this current session.
local Success = LoadDataVersionNearestToDateTime(PlayerData, DateTime)
if Success then
   -- Reset the player's gameplay state that is affected by their data
else
   -- Whatever you do if the rollback fails. Maybe retry?
end

Library user decision 2 (Kick):

-- When player joins the game
local PlayerData = LoadDataVersionCurrent(Player)

-- Rolling back player data
-- This function call only affects the DataStore, NOT the player's data in this current session.
local Success = MakeDateTimeVersionCurrent(PlayerData, DateTimeToRollbackTo)
if Success then
   Player:Kick()
else
   -- Whatever you do if the rollback fails. Maybe retry?
end
2 Likes

Rollback sounds scary when you consider that players can lose their purchases.