I have an offline application and the data is 2-way synchronised between server and the app using pouchdb-couchdb. One requirement is both the server and the app must able to mutate the application data.

Now I have the problem to maintain large application logic on the server side, as there will be multiple version of the app (multiple application logic) running in production, but there's only 1 version of the server.


Offline Application:
v1.0: increase({ data: 1 }) => ({ data: 1 })
v2.0: increase({ data: { value: 0, percision: 2 }) => ({ data: { value: 1, precision: 2 } })

# only 1 version allowed, how to maintain?

To resolve this problem, there are 2 possible solutions:

  1. version my data, and the server will keep track all logic for each version, example
increase('1.0', { data: 0 }) => ({ data: 1 })
increase('2.0', { data: { value: 0, percision: 2 }) => ({ data: { value: 1, precision: 2 } })

The problem of this approach the server codebase will growth drastically (eg: 100+ function), and we still have two source of truth to maintain.

  1. store the business logic in the database. In the offline app, we store increase().prototype.toString() in db, let it sync with server. Whenever server need the function, it'll just perform eval(fn). Since only the app will able to mutate the function in the database, we only need to maintain 1 codebase

I personally prefer second approach but I not sure is there any pitfall on this approach. Or is there any better approach to this issue?

  • The first line in your first example looks like a typo, should be v1.0: increase({ data: 0 }) => ({ data: 1 }), I guess? And not percision, but precision?
    – Doc Brown
    Dec 6, 2019 at 8:52

1 Answer 1


If the data model of the server is extended, and there is a client app (which is able to mutate the data) which sticks to an older version and does not know about the server extensions, sooner or later you will come to the point where this will introduce the risk if data loss or inconsistencies, since the client may write back some data without the extended fields or the new data constraints.

A possible solution to this which is pretty safe is to make sure when an older client version connects to the server, it asks the server for the version number of the underlying data model or the API. When the server then returns a newer version number than the client will able to handle, the app switches into read-only mode and will forbid to synchronize any data until the client is updated to a newer version. When the client then is updated, it will run a defined migration process for its local data.

This works best when the installation of a client upgrade works almost automatically in the background, with no special user rights required, only a modest network connection.

Of course, there is also the possibility of providing different versions of the server API for different client versions. This may lead to a lot of functions on the server side, but not necessarily to "two sources of truth to maintain" - the outer side of those APIs should be freezed once they are published, and the "inner side" can be refactored to make functions "1.0", "2.0" and "3.0" of the API just delegate to some common function.

Both of these approaches can be combined, so you may shut down API "1.0" once "4.0" is released and force the clients of version 1.0 to update, but allow clients still to use version 2.0 and 3.0 in parallel to 4.0. This keeps down the number of API versions you have to maintain to a fixed number instead of letting it grow to infinity.

  • We unable to perform your solution in paragraph 2, our client must able to work with full function in offline mode, and some of the clients may be offline for 1 month+. Like you mention, most probably we'll refactor the core logic into the package, share it between server and client. But the backwards compatibility still an issue.
    – kingwei
    Dec 9, 2019 at 10:41
  • @KingWeiLo: being off-line for a long time is no reason not to apply this solution. As long as the application is off-line, it won't try to sync with the server, so no need to force the client to upgrade. But if the client wants to sync, the application has obviously to go online first, which reveals an opportunity to upgrade first before syncing.
    – Doc Brown
    Dec 9, 2019 at 12:12
  • ... of course, there should be some safety measures to prevent data loss in case the upgrade fails for some reason, so the user won't loose a month of unsynced work in case of a bug
    – Doc Brown
    Dec 9, 2019 at 22:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.