Atlas 2.1.0 Released with “Polymorphic Association” Support

I’m happy to announce that I released Atlas 2.1.0 late yesterday. (Atlas is a data mapper for your persistence model in PHP – not your domain model.)

In addition to some minor added informational and convenience functionality, the big addition in this release is support for many-to-one relationships by reference (aka “polymorphic association”). You can see the documentation for it here.

I.

Atlas uses SQL terms for relationships instead of OOP ones (e.g., “many-to-one” instead of “has one”). As such, the OOP term “polymorphic assocation” just wasn’t a good name for the feature.

However, some research revealed that PostgresANSI SQL has a constraint type named REFERENCES that supports the feature natively:

After trying out several alternative names, “many-to-one by reference” was a much better fit than “polymorphic association.”

II.

Because Atlas is for the persistence model, and not for the domain model, I had to wonder if this kind of behavior belongs in the database work at all. Should it happen in the domain instead?

After working through the problem, the answer turned out to be that it has to go in the database work. You simply don’t know which foreign tables to select from in the first place, without that information being represented in a relationship description. The reference column determines what the foreign table should be. If there are different values in the reference column, then you have to select from different tables to get the related rows. That can’t happen once you’re in the domain layer; it must happen in the persistence layer.

III.

Relationships-by-reference may not be a good data design choice if you are starting from scratch. See this 2009 presentation from Bill Karwin for some other alternatives:

https://www.slideshare.net/billkarwin/practical-object-oriented-models-in-sql/22

These each have different tradeoffs, and in one case require that your database system supports parent tables.

Of course, if you already have a database design that uses many-to-one relationships by reference, then you’re probably stuck with it. Atlas can now help you out in this situation.

UPDATE: This Reddit comment leads me to understand that I read the REFERENCES Postgres doc too hastily. In context of the linked mailing list message, I understood “refcolumn” to be on the native table, not the foreign one. So it’s a standard foreign key constraint, not a specialized/extended form provided by Postgres; I confess I find it easy to believe that Postgres often supports things that other databases do not.


You can read the Reddit commentary on this post here.

Perfection

The novice says: “Nothing can ever be perfect; anything I choose will be imperfect. Therefore, all choices are equally bad, so I may choose whatever I feel like.”

The master says: “Some things are less imperfect than others; I will make the least-imperfect choice that I can.”

Best Practices

Best practices evolve. Even though they change, they tend to change in the direction of “better”, not “worse”.


The novice thinks he is an individual.

The novice says: “Best practices are always changing; why bother adhering to something that I know will change? I am free to do what I feel like without referring to best practices.”

This is not freedom; it is license.

The master realizes he stands at the end of a long trail of experience and knowledge from others, that surpasses his own personal experience and knowledge.

The master says: “This is my current understanding; these are my expected circumstances; these are the known best practices; these are their tradeoffs. I will choose the best practice I can for the tradeoffs I am willing to endure.”

This is not slavery; it is clear thinking.

Considering Typehints As Communication

Typehints help communicate across time and space, to people who may never meet you or who might not be able to interrogate you about your code, so those people can understand how you expect the code to work.

Adding typehints is a succinct, more-complete form of communication than not-adding them. (It is rare, perhaps impossible, for all communication can be fully complete all the time.)

Further, you don’t know in advance which parts of the codebase are going to last for a long time, and which are going to be replaced in relatively short order. It’s probably better to to add the typehints when you know what they are, rather than to wait and see if you’ll “need” them later.

Typehints can be considered low-cost mistake-proofing against misunderstanding in an obvious place (i.e., where they are used), without having to look elsewhere (“just read the tests!” [groan]).