Skip to main content

TOMS - Building the Foundation First: Identity, Objects and the Base of the Event Model

In the previous article about my C++ event-planning project, I described the emerging object model at a fairly high level: guests, groups, tables, seats, floor-plan elements and the document that eventually brings those concepts together.

Before going further into those business objects, however, I want to move down one level.

The current reconstruction has reached the point where some of the application's foundational classes are becoming clear. These are not necessarily the classes that a user will ever know exist. They do not correspond directly to a screen or a feature. Instead, they provide common concepts on which much of the rest of the model can be built.

One of the most interesting of these is also one of the smallest: a dedicated Object Identifier.

Before an application can reliably connect guests, groups, tables, seats and graphical objects, it needs a stable way to answer a deceptively simple question: which exact object are we talking about?

Starting at the bottom of the model

At a simplified level, the emerging architecture has a common Event Object abstraction. More specialised domain objects can then build upon that foundation.

The graphical part of the model introduces another base abstraction for objects that have a physical representation on a floor plan. From there, specialised objects such as tables, walls, shapes, text elements, images and visual keys can add their own behaviour.

The important point is not the number of classes. It is the attempt to put common responsibilities in the correct place.

Object Identifier
       │
       │ identifies
       ▼
   Event Object
       │
       ├── Guest
       ├── Group
       │
       └── Graphical Object
              │
              ├── Table
              ├── Wall
              ├── Shape
              ├── Text
              ├── Image
              └── Visual Key

This is a conceptual diagram rather than a literal C++ inheritance diagram. In particular, the identifier is a value used by objects; it is not their base class.

That distinction matters. Inheritance describes what an object is. Composition describes what an object has. An event object can have an identifier without an identifier somehow becoming an event object.

Why an identifier deserves its own type

At first glance, an object identifier could simply be a string.

Technically, the recovered implementation does store the identifier as textual data. But the design wraps that value in its own small class rather than passing arbitrary strings around the application.

I think that distinction is worth preserving.

A normal string might mean a guest's surname, a table name, a note, an address, a filename or hundreds of other things. An Object Identifier has a much narrower semantic meaning: it represents the identity of an application object.

Giving that concept its own type creates a boundary around it. The class can control how identifiers are created, copied, compared, tested, converted to text and hashed without requiring every consumer of an identifier to understand its internal representation.

A dedicated identifier type turns identity from a string-formatting convention into part of the application's domain model.

What the Object Identifier actually contains

The recovered class is surprisingly compact.

Its persistent state consists of a single field, which I will simply call the identifier text. It is stored using Qt's string type.

That one field carries the textual representation of the identifier. Around it, the class provides the operations needed to treat that text as an identity rather than as arbitrary user-entered content.

Conceptually, the class looks like this:

Object Identifier
│
├── Identifier text
│
├── Create a new identifier
├── Construct from existing text
├── Copy an identifier
├── Compare identifiers
├── Test whether it is empty
├── Obtain its textual representation
└── Produce a hash value

This is a good example of a class whose importance is not proportional to its size.

There is very little state, but the abstraction can potentially be used throughout the object model.

Existing identities can be reconstructed

The class is not limited to generating new identities.

It can also be constructed from an existing textual identifier. The recovered implementation normalises the supplied value by removing surrounding whitespace. If meaningful text remains, that value becomes the identifier. If the supplied value is empty after normalisation, the class can generate a new identifier instead.

This behaviour is particularly relevant to persistence.

When an existing event is loaded, the application must be able to reconstruct the identity that an object already had. Generating a different identity every time an event is opened would defeat much of the purpose of persistent identifiers.

The same abstraction can therefore support two very different situations:

New object
    │
    └── generate identity

Loaded object
    │
    └── restore existing identity

That is a small design decision with significant consequences once objects begin referring to one another.

Identity is different from a name

This becomes clearer when considering a guest or a table.

A guest may have a name, but the name should not normally be the object's identity. Two guests can have exactly the same name. A guest's name can also be corrected without turning that person into a different object.

A table has the same problem. The user might rename “Table 4” to “Family Table”. The presentation has changed, but logically it is still the same table with the same relationships to seats and guests.

The identifier provides an independent identity that can remain stable while user-facing properties change.

A display name describes an object. An identifier distinguishes the object. Treating those as the same thing would make renaming, persistence and cross-references unnecessarily fragile.

The identifier is generated, not merely numbered

The recovered implementation also provides some insight into how new identifiers are produced.

They are not represented as a simple sequence such as 1, 2, 3 and 4. The generation algorithm constructs a textual identifier from multiple pieces of information. A time component is part of that process, represented in hexadecimal form and padded to a fixed width. The implementation also interacts with application-level user state as part of constructing a new value.

I am deliberately not reproducing the exact internal format here. The relevant architectural point is that the identifier is designed to contain substantially more distinguishing information than a small document-local integer.

Conceptually:

Time information ───────┐
                        │
Application/user state ─┼──► Identifier generation ──► Object identity
                        │
Additional sequencing ──┘

At this stage of the reconstruction, I am more interested in understanding the semantics and guarantees of this mechanism than blindly preserving every implementation detail. The format is part of the recovered behaviour; whether every detail belongs unchanged in the modern implementation is a separate engineering decision.

Comparison and hashing matter too

The class also supports direct comparison between identifiers and can calculate a hash value.

Those operations are exactly what I would expect from an identity value that may eventually be used heavily in collections and relationships.

Instead of repeatedly comparing several properties of two objects to decide whether they represent the same logical entity, code can compare their identities. Hash support also makes the identifier suitable for hash-based lookup structures where appropriate.

This starts to become valuable as the model grows:

Guest identity ─────────────┐
                            │
Group identity ─────────────┤
                            ├── relationships
Table identity ─────────────┤
                            │
Graphical-object identity ──┘

The diagram is conceptual: not every relationship in the application necessarily stores identifiers in precisely this manner. What matters is the role stable identity can play as objects become interconnected.

Then comes the common Event Object

Immediately above these small infrastructure concepts, the architecture introduces the common Event Object abstraction.

This is where the model starts to acquire meaning specific to the application. Guests and groups belong to this family, as do the objects that eventually participate in the graphical floor plan through a more specialised Graphical Object base.

The progression is therefore becoming clearer to me:

Identity
   │
   ▼
Common event behaviour
   │
   ├── People and groups
   │
   └── Graphical behaviour
          │
          └── Physical floor-plan objects

This is the part of object-oriented design I find more useful than simply drawing large UML diagrams.

The question is not “How many base classes can I create?” It is “Which responsibilities are genuinely common, and at what level do they become common?”

Identity is very low-level. It does not need to know whether it belongs to a guest or a wall. The common Event Object can then deal with behaviour shared by application objects. The Graphical Object can add concepts that only make sense for something that appears on the plan. Finally, concrete objects such as a table or wall can implement their specialised behaviour.

Recover first, modernise deliberately

There is another reason I am spending time documenting classes this small.

This project is not purely greenfield development. Part of the work is understanding an existing compiled application's behaviour, reconstructing its design and then deciding how that behaviour should be represented in modern C++ and Qt.

Those are three different activities.

First I need to establish what the original software actually did. Then I need to understand why the classes and relationships may have been designed that way. Only after that should I decide which parts deserve to survive unchanged and which should be modernised.

Reverse engineering tells me what existed. Architecture analysis tells me why it may have existed. Modernisation is the separate decision about what I want the new implementation to become.

The Object Identifier is a good example. I could replace it immediately with some standard identifier mechanism and move on. But doing that before understanding its generation, comparison, persistence and relationship semantics would throw away information that may become important elsewhere in the application.

So, for now, the objective is fidelity first and redesign second.

A small class, but an important foundation

The Object Identifier will never be one of the glamorous parts of an event-planning application.

No user will buy the software because its internal objects have well-defined identities.

But once guests belong to groups, guests occupy seats, seats belong to tables, tables appear on floor plans and all of those objects must survive saving and loading, identity stops being an implementation detail.

It becomes infrastructure.

That is why, at this stage, I am deliberately working from the bottom upwards. Before discussing sophisticated seating optimisation or polished graphical interfaces, I want to understand and reconstruct the small classes that make the rest of the model reliable.

Sometimes the most important architectural work begins with a class containing only one field.

AI Assistance Disclosure: This article is based on my original ideas, experience, analysis and conclusions. Artificial intelligence tools were subsequently used as editorial and research assistants to review grammar and wording, improve structure and presentation, organise some arguments into clearer logical sections, and help review references to legal, regulatory and technical concepts.

Where relevant, factual and regulatory references were checked against the sources cited in the article. AI assistance does not replace professional legal, regulatory, financial or technical advice, and the final selection, interpretation, opinions and conclusions presented here remain my own.

Comments

Popular posts from this blog

Movies - The Bubble (2022)

  Back to Evolution (2001) .

IT - Fixing Windows Error 1327: Account Restrictions Are Preventing This User from Signing In

Fixing Windows Error 1327: Account Restrictions Are Preventing This User from Signing In Introduction Error 1327, “Account restrictions are preventing this user from signing in,” is a perplexing and disruptive issue that occurs on some Windows 10 and Windows 11 machines. The message typically appears at login or while connecting to remote resources, like shared folders, network drives, or remote desktops. Table of Contents Symptoms of Error 1327 Common Causes Step-by-Step Troubleshooting Advanced Fixes Automation via PowerShell Prevention Tips Further Reading Symptoms of Error 1327 Users experiencing this error may encounter one or more of the following: Login screen fails after credentials are entered. Error message appears when accessing mapped drives or network resources. Remote Desktop Connection (RDP) is rejected with the 1327 message. Group Policy logon restrictions silently block access. Co...

IT - Troubleshooting Kodi DLNA Visibility Issues After Windows Updates: A Deep Dive Into Conflicts, Fixes, and Lessons Learned

Title: Troubleshooting Kodi DLNA Visibility Issues After Windows Updates: A Deep Dive Into Conflicts, Fixes, and Lessons Learned Subtitle: How I Diagnosed and Solved Intermittent Kodi Visibility Problems on a Samsung Smart TV After Windows OS Updates and Media Server Conflicts Introduction Home media streaming should be seamless, but anyone who has integrated Kodi into a smart home setup knows that stability isn't always guaranteed. Recently, I encountered a frustrating issue: Kodi, running perfectly on my Windows 10 Pro desktop, suddenly became invisible to my Samsung Smart TV via DLNA. The journey to resolve this seemingly simple visibility issue turned into a deep technical rabbit hole involving Windows Media Server, Universal Media Server, Jellyfin, NordVPN, and the very internals o... The System Setup Before diving into the problem, it's essential to understand my hardware and software setup: Operating System: Windows 10 Pro (build 2009) Media Server: Kodi (...