loading...
Cover image for It's wrong to treat "Draft" mode as a state on the way to "Final"

It's wrong to treat "Draft" mode as a state on the way to "Final"

hagailuger profile image Hagai Luger ・1 min read

When we build a system that needs to have a draft mode (for example an order we would like to complete later), It might be tempting to save the draft in the same model and save it in the same table/collection/whatever as a real order, with a bit/enum that shows that it's a draft.

The problem with this attitude is that it makes as create the model/table with less mandatory fields, less constraints, etc...

The solution is to refer to a draft as a totaly different kind of object, and act accordingly regarding where to save it and how to handle it.

I think I'll call it: DFRS
Draft/Final Responsibilty Segregation
(What's now? Can I make millions lecturing about it?)

What do you think?
Am I just reinventing the wheel here?

Discussion

pic
Editor guide
 

You're not reinventing the wheel, you have a road with a weird surface and you're trying to figure out what rolls on it. There isn't a "one size fits all" solution: your case where a complete entity record is constrained in ways that incomplete records are not is common but not universal. In other systems, there might be well-known default values; or the entity's life cycle could simply hinge on how the values in a few always-defined fields mutate.

Separating storage is only one way to tackle your particular problem. You could, for example, break down your entity into a core with identical constraints at every stage of its life cycle, add subsidiary data to dependent ("specialization") tables as they come in, and use check constraints and triggers to enforce integrity. It's probably not worth the effort unless you have to do some pretty complicated stuff at multiple points in that life cycle, but it's an option -- and sometimes you do have the need for it!

 

Thanks for the detailed response!
I'll look at the option you proposed here.

 

Don't look too hard -- it probably isn't worth the effort if you only have a couple of states and don't want to do too much assembly of completed entities! I was just using it as an example to show that there are multiple ways to approach the problem, and choosing the best one is extremely situational.

 

What if you had multiple final versions of the same document? Or multiple draft versions? Venturing into the territory of source control systems.

Each auto-save is a commit, each hard-save and publish action acting like a commit+squash.

Idk, just thinking out loud.

 

As someone who just created a mass messaging app, I wish I had separated them in the architecture. It was my first attempt at this kind of app. Definitely lessons learned.

 

Thanks!
Can you elaborate more on what you did at the end?

 

In it's current state, they both sit in the same table, along with templates too. Only an enum differentiates them. The product still has time to change but it's so late in the project it may remain that way forever.

Ultimately I don't think having them all in one table is so bad it needs to be changed, but if I went back in time I probably would split finalized from all others.

As the project was filled in, I found myself writing more and more exception logic for final. That's a code smell for sure. Because it's not split in the data layer, it has to be done in business logic.

Consider though that doing anything has considerations. And perhaps if it was separated, there would be other issues. The code would certainly have repetition. Storing them all in one table is very DRY, if nothing else.

 

depending on specifics, you might want to consider composition/table inheritance.

 

You should read the Pragmatic Programmer.

stackoverflow.com/questions/404733...

 

Thanks
Can you please explain?
It seems like the link talks about development phases while I'm talking about an "object" that one of his "states" is draft

 

Ah! Sorry, I misread what you meant then. Apologies.