My team is debating how to transition a portion of our Rails application to allow "drafts". For simplicities sake, we can imagine a Post object where we want to allow a kind of draft mode.
Our real model contains, say, roughly 20 fields and 5 has_many relationships. There are some reasonably complex business rules (i.e., content can't be changed after a Post is delivered), and a state machine (Posts are pending, sending, then delivered).
class Post
string content
enum content_type
date deliver_on
enum delivery_state
has_many customer_group_segments
end
Two options being considered, but we are open to more. One is to duplicate all the existing tables (i.e., post_drafts
, customer_group_segment_drafts
, etc). The second is to include a kind of is_draft
field on the post.
The first option would separate all the data, but we'd need to consider sharing business logic between all models. And in the case of the draft, all of the validation rules would be optional until you tried to convert a Draft to a Post. And we'd also need to create a kind of transfer mechanism, etc...
The second option would remove all constraints from the underlying tables. We'd also need to make some kind of mode system, to ensure validation only kicks in where appropriate. And we'd also need to implement various checks to ensure, for example, that we don't try and deliver a draft.
There is a similar, but older question. I'm curious of there are any new opinions. Any ideas, observations, or working examples would be great!
-
I favor the latter approach, for several reasons.Robert Harvey– Robert Harvey2019年04月19日 20:52:29 +00:00Commented Apr 19, 2019 at 20:52
-
2In general, I dislike "staging tables" (they sort of break the "single source of truth" principle) and the complexity they bring to the table (which you have already alluded to), but sometimes you need to do it that way, for various reasons.Robert Harvey– Robert Harvey2019年04月19日 21:03:38 +00:00Commented Apr 19, 2019 at 21:03
-
1Could you link to the similar, older question? What makes you think things might have changed?jonrsharpe– jonrsharpe2019年04月19日 21:44:44 +00:00Commented Apr 19, 2019 at 21:44
-
4Wouldn't it make sense to see "draft" as an additional state in the delivery state machine? If it is somewhat orthogonal, for example if you can have draft in pending and sending states, you could have states pending_draft and sending_draft.Hans-Martin Mosner– Hans-Martin Mosner2019年04月20日 06:00:42 +00:00Commented Apr 20, 2019 at 6:00
-
1This sort of integrity worth having it modelled on the application side instead of the database. DB constraints should be balanced as well. Too many constraints make our designs more rigid too. If you need different reports or queries for one or another state, you can implement views too, instead of implementing new tables. I would start little and simple and move to dup structures only if whatever I do is proven not to be enough. @Christophe gave a good pattern to start with. If you need traceability between states, the memento pattern also helps.Laiv– Laiv2019年04月23日 14:03:11 +00:00Commented Apr 23, 2019 at 14:03
1 Answer 1
The simplest alternative would be the is_draft
property approach, since you would benefit of all the existing code, and a simpler maintenance, the day you would want to add new fields or behaviors to the record.
However, this implies that you would apply all your business rules also to draft records. And sometimes the purpose of the draft is to be more permissive than the final version (e.g. missing information). So, if your draft would not obey the same business rules and behave even slightly differently, you would need to add a lot of extra conditional clauses in a lot if places. This is what makes a separate clone of the class appealing. But the risk of painful redundant maintenance is real. So think twice before going that way.
Therefore, in the case where the simple is_draft
is not sufficient, instead of doubling the structures, I would suggest to consider the use of a draft state using the state design pattern.
Note: an is_draft
column in a database table is a simplified implementation of a draft state class using the single table inheritance approach
Explore related questions
See similar questions with these tags.