-
Notifications
You must be signed in to change notification settings - Fork 434
Description
The problem
The VersionAttribute design pattern consists of
- incrementing the version with every change — to trip others so they don't overwrite your change
- conditioning on the version — to trip yourself so you don't overwrite others' change
There are two methods that can modify an existing model:
Model.saveModel.update
We've observed it to be a common pattern to change just a few fields and then call Model.save. In this case, a version condition is a good precaution to avoid overwriting more attributes than you meant to. Once users start seeing high % of conditional failures ("conflicts"), a more nuanced approach is called for, using Model.update. Often "last write wins" is good enough as long as you don't write unrelated attributes. Other times, a more nuanced condition can be used (e.g. update field X only if it had value Y before).
Unfortunately when we introduced VersionAttribute, we’ve made Model.update append a condition on the version attribute. This is probably counter-productive to what I described above.
The proposal
In PynamoDB 6.0, we can allow changing this behavior.
Options:
- Stop appending the condition in
Model.update. This risks silently breaking existing apps. - Make it optional and default to append. This drags the bad behavior as a default into green-field apps.
- Make it optional and default to not appending. This risks silently breaking existing apps.
- Ask user to decide, provide no default. 📌
I'm inclined towards option (4). Adding a parameter to Model.update is disruptive, and also risks adding a hidden crash, since not every Model.update call is necessarily exercised by tests. Instead, we can add a parameter to VersionAttribute, since it's executed at class load / module load, and likely prevent an app from starting up until its maintainer makes a conscious decision.
We should name it something like legacy_update_behavior: bool as to discourage setting it to True in green-field apps:
-version = VersionAttribute()
+version = VersionAttribute(legacy_update_behavior=False)In future versions we could switch to Option 1 by removing it.