DEV Community

Cover image for Fake data that is not obviously fake
Ernesto Herrera Salinas
Ernesto Herrera Salinas

Posted on

Fake data that is not obviously fake

Back in the audit, I flagged a tension I had created for myself: I called seed and
demo data a co-equal job, then pointed the whole roadmap at composition, which
barely serves it. This post is where I start paying that off. It begins with an
ugly little object.

Here is what zero-config inference produces today, for a customer:

{
  FirstName: "Maria",
  LastName:  "Garcia",
  FullName:  "John Smith",          // unrelated to First/Last
  Email:     "k7zp@example.net",    // unrelated to the name
  Username:  "blue-tiger-441"       // unrelated again
}
Enter fullscreen mode Exit fullscreen mode

For a unit test, nobody cares. Any plausible string is fine. But for seed data in
a demo database, this looks broken. A human reads it in two seconds and knows it
is fake. And this is precisely the job composition cannot help with, because
composition is about structure (which definition builds a nested object), and this
is about correlation between flat scalar fields. Different problem, different
machinery.

The idea: a persona

The fix is an idea Bogus already has, called Person: a coherent bundle generated
once, where the fields agree because they all come from the same underlying
identity. Munchausen's version has to be deterministic and inferred rather than
hand-wired, but the core is the same. There is a hidden Person for the object,
and FirstName, Email, and FullName are facets of it, not independent
guesses.

The load-bearing fork: what is one identity?

The first real decision is the one that sets the mental model for everything after
it: in an object graph, which members share a single persona?

class Customer { string FirstName; string LastName; string Email; SalesRep Rep; }
class SalesRep { string Name; string Email; }
Enter fullscreen mode Exit fullscreen mode
A: object-scoped. Persona boundary equals object boundary.
   Customer.FirstName/LastName/Email -> Customer's persona (one identity)
   Rep.Name/Rep.Email                -> Rep's own persona  (a different identity)

B: role-scoped. Group by a member-name prefix, so two people flat on one object
   stay distinct (CustomerName vs SalesRepName).
Enter fullscreen mode Exit fullscreen mode

I chose object-scoped. It is predictable, it needs no name-parsing heuristics, and
the boundary is something the user can already see in their own type. A nested
object simply gets its own identity, which is almost always what you want.

Object-scoping has a known sharp edge. If someone flattens two people onto one
type, Order { CustomerName, SalesRepName }, object-scoping makes them the same
person. That is wrong, and I did not pretend otherwise. I deferred role grouping
as a later refinement and made the collapse diagnosable through Explain(), which
will happily report "four members bound to one Person" so you can see it.

The reason I was comfortable deferring it: object-scoping already beats AutoBogus
for the common case, a single identity per object, which is most of the win. The
flat-two-people shape is a denormalized DTO that no tool handles automatically
today. So the principled default ships now, and the differentiator can come later
without repainting the model.

Takeaway

Coherence is not "better random values." It is a shared source of truth that
several fields read from. And the first decision in any system like that is the
boundary question: what counts as one identity? Pick the boundary your users can
already see, and be honest about the case it gets wrong.

What's next

A persona is only useful if members actually attach to it, and the attaching has
to be trustworthy rather than magic. Next post: binding members to a persona
without magic, including how the engine decides a field is a person at all.

Top comments (0)