As discussed we will start work on restructuring the code in order to make the server optional and allow for different backends in the way the app starts.
Restructuring: Currently most models are aware of the server in order to leverage the fetch + url behaviour from Backbone giving us free Ajax and change propagation. However, we might have backends which are not HTTP based (local fs, dropbox) and to the best of my knowledge Backbone fetch doesn't handle anything else.
I'd propose uniformising the data handling under a common object which would expose all the required methods which return promises. We then subclass it as needed for custom backends.
To interact with it, I see 2 options given the current structure of the code:
We can forego the Backbone convention completely and make all data related calls systematically go through a singleton data store with custom methods. We can make the models unaware of how the data is fetched (the url, fetched combo implies http calls) and centralise all network calls.
Alternatively, keeping as much as the current code as possible, we override the fetch method on models to default to Backbone's when available (expose a url or mapUrl method for example), and use a specific method on the backend object otherwise.
I'd go with the former, as even if there would be more code to rewrite and test, everything would be explicit. We'd lose the reliance on Backbone for loading data (propagating changes would still happen in the models through Backbone set and changed) which I feel is more sane. The basic fetching logic is simple enough to centralise and the custom ones would have to be adapted either way.
In both cases the first step will be to pull out implicit references to the server and replace them by explicit calls to the backend (namely in asset, assetsource and landmarks which have custom behaviour, the rest of the models use standard fetch).
Startup phase: Handling various backends means we need to select one at some point. I'd make the app start in a blank state and ask user for which way they'd want it to work (local, server url, dropbox...), we delay the initialisation until we can instantiate a backend. To make it faster in some cases we can default to current behaviour if a server parameter is present in the url and store some data in local storage to automatically load the previously known backend after a hard reload.
As well, all backends will not be equal feature-wise. The idea would then be to advertise this in the backend (fetched or hard coded) and toggle functionality accordingly. We'll likely cross that bridge when implementing the various backends, but to accommodate I think the app startup should be in 2 phases: load a backend and then start the UI once we are aware of the backends' capabilities. We'd be able to check allowed behaviours in this phase rather than at runtime.
With this in mind, I'd stop making the server a Backbone model (doesn't carry state or propagate changes) but rather a simple object and a change in the backend would likely be equivalent to a restart of the app.
So to sum up, the plan is:
Abstract the server into a DataStore object (after we selected how we abstract it)
Make the server model an implementation
Update startup code to be app > server > app > rest instead of server > app > rest as it currently is
Implement a new context / backend, we can worry about tis one once the previous restructuring has been done
As discussed we will start work on restructuring the code in order to make the server optional and allow for different backends in the way the app starts.
Restructuring: Currently most models are aware of the server in order to leverage the
fetch
+url
behaviour from Backbone giving us free Ajax and change propagation. However, we might have backends which are not HTTP based (local fs, dropbox) and to the best of my knowledge Backbonefetch
doesn't handle anything else.I'd propose uniformising the data handling under a common object which would expose all the required methods which return promises. We then subclass it as needed for custom backends.
To interact with it, I see 2 options given the current structure of the code:
url
,fetched
combo implies http calls) and centralise all network calls.fetch
method on models to default to Backbone's when available (expose aurl
ormapUrl
method for example), and use a specific method on the backend object otherwise.I'd go with the former, as even if there would be more code to rewrite and test, everything would be explicit. We'd lose the reliance on Backbone for loading data (propagating changes would still happen in the models through Backbone
set
andchanged
) which I feel is more sane. The basic fetching logic is simple enough to centralise and the custom ones would have to be adapted either way.In both cases the first step will be to pull out implicit references to the server and replace them by explicit calls to the backend (namely in
asset
,assetsource
andlandmarks
which have custom behaviour, the rest of the models use standardfetch
).Startup phase: Handling various backends means we need to select one at some point. I'd make the app start in a blank state and ask user for which way they'd want it to work (local, server url, dropbox...), we delay the initialisation until we can instantiate a backend. To make it faster in some cases we can default to current behaviour if a
server
parameter is present in the url and store some data in local storage to automatically load the previously known backend after a hard reload.As well, all backends will not be equal feature-wise. The idea would then be to advertise this in the backend (fetched or hard coded) and toggle functionality accordingly. We'll likely cross that bridge when implementing the various backends, but to accommodate I think the app startup should be in 2 phases: load a backend and then start the UI once we are aware of the backends' capabilities. We'd be able to check allowed behaviours in this phase rather than at runtime.
With this in mind, I'd stop making the server a Backbone model (doesn't carry state or propagate changes) but rather a simple object and a change in the backend would likely be equivalent to a restart of the app.
So to sum up, the plan is:
DataStore
object (after we selected how we abstract it)app > server > app > rest
instead ofserver > app > rest
as it currently isWhat do you think so far @jabooth ?