On the subject of Third Normal Form (3NF), best practice and making one’s life a tad easier.
Ever since my CS classes of late high school, 3NF has been drilled into me. Of course, it makes a lot of sense for optimising databases and all in all its not, in my opinion, that difficult to implement given some forethought a careful consideration.
However, when working with non-technical people, and even technical people who are not familiar DB design ideas, it often appears to me that the easier approach is to deviate from 3NF.
As an example, let’s look at the following Django models.
class Treatment(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
case = models.ForeignKey(Case, related_name="treatments", on_delete=models.CASCADE)
text = models.CharField(max_length=512)
heading = models.CharField(max_length=512)
class Choice(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
uuid = models.UUIDField(unique=True, default=uuid.uuid4)
treatment = models.ForeignKey(Treatment, related_name="choices", on_delete=models.CASCADE)
points = models.IntegerField(null=False, blank=False)
text = models.CharField(max_length=512)
is_correct = models.BooleanField(blank=False, null=False, default=False)
def __str__(self):
return f"{self.text}"
The Treatment object contains data which can be displayed which is pertinent to all of its choices. For example, one might have.
Birds
When treating birds who have forgotten to fly, what is the recommended treatment?
- A good nights sleep
- Mandatory base jumping
- Flight simulator lessons
The heading comes from the Treatment
Object, as does the text. The options come from the Choice
model.
I have several applications which have the same structure. I can normalise the model by creating say, a model called DescriptiveText
which contains heading
and a text
attributes and have all models which use this feature to relate to DescriptiveText
by way of a FK.
The challenge for some of my colleagues is they struggle to use the Django Admin and understand why we have such a design. When working with the API with standard model serializers, we’ll always have to create the DescriptiveText
followed by the object in question. For me this is no biggy, but I will get some complaints.
I can of course dive into Django and create heavily customised endpoints or nested serializers. Customisation runs the risk of added complexity and nested serializers are just a pain when they’re not read-only, in my opinion.
So, what do you think? What would you do here? Ditch 3NF and just create the five or so models with text
and heading
attributes, or would you go the 3NF route?
The CS part of me says 3NF, use Inline admin and provide guidance and documentation of the use of the API. The part of me who can’t be bothered to deal with all the questions, feedback and pushback just says, sod it, let’s take the path of less resistance.
Having said all of this, I could be not seeing the wood for the trees or even be missing some key knowledge. Happy to be informed on both accounts.
As always, thank you for your thoughts.
C