Skip to main content

TOMS - The Document as the Event: Building the Application Around One Coherent Planning Model

After several articles examining individual pieces of my C++ event-planning model, it is time to move to the object that brings almost everything together: the Document.

This is one of the most important architectural ideas in the application, and it is also one that has been in the back of my mind for many years.

I remember the way older Apple productivity software treated a document as more than a stream of text. You could work inside one document and place different kinds of content into it: text, tables, calculations, graphics, images and other elements. The document was the thing the user understood. The technical implementation of the individual elements was secondary.

Before writing this article I went back and researched that memory, and it turns out that I was remembering several related Apple ideas.

AppleWorks was probably the clearest historical example. It brought word processing, spreadsheets, databases, drawing, painting and presentations into one integrated application. Apple later described the ability to combine text, spreadsheets, images and movies in a single document. Early versions of iWork continued part of this philosophy: Pages and Keynote could contain spreadsheet-like tables, charts, photographs and other objects rather than forcing every kind of information into a separate application boundary.

There is also a deeper architectural idea underneath macOS itself: the document-based application.

That idea is surprisingly close to what I am reconstructing here.

The Document is not simply the file that gets saved. It is the in-memory representation of the user's complete piece of work.

The file is not the Document

This distinction is fundamental.

It is tempting to think of a document as a file:

event.plan
    │
    └── "the document"

Architecturally, however, that is backwards.

The file is a persistent representation of the Document.

While the application is running, the Document is a live network of objects and relationships in memory. Guests can be added. Groups can change. Tables can move. Seating can be rearranged. Images can be loaded. Floor plans can be edited. Relationships can be created and removed.

When the user saves, that living model is serialised into a persistent representation.

                    SAVE
Live Document  ─────────────────►  File
     ▲                              │
     │                              │
     └──────────── LOAD ────────────┘

This is very close to Apple's traditional definition of a document-based application: the document object manages the information currently in memory, while the file is how that information is stored outside the running application.

For this application, the Document is essentially the event

That leads to the way I now think about this particular Document.

From the user's perspective, the Document is effectively the event being planned.

It is not merely a container for a seating chart. It is the point at which the major domains of the application come together.

                    Event Document
                           │
       ┌───────────────────┼───────────────────┐
       │                   │                   │
       ▼                   ▼                   ▼
     People             Seating            Floor Plan
       │                   │                   │
   ┌───┴───┐          ┌────┴────┐        ┌────┴─────┐
   │       │          │         │        │          │
Guests   Groups     Tables    Seats    Layouts   Graphics
                                                / Images

The actual architecture is more detailed than this diagram, but conceptually this is the role of the Document.

It gives all those things a common context.

A Guest makes sense independently as a model object, but in the application that Guest belongs to a particular event. A Table is a graphical and seating object, but it exists on the floor plan of a particular event. A Group has members, but those members come from the event's Guest population.

The Document is the boundary that says: all of these things belong to this piece of work.

This is similar to the old AppleWorks idea

The historical comparison is useful because AppleWorks approached productivity from the user's perspective rather than from the internal type system.

A user might be writing a document but need a spreadsheet calculation inside it. That did not necessarily mean leaving the conceptual document behind and thinking in terms of a completely unrelated file.

The document remained the context.

My Event Document follows the same broad philosophy, although the domain is completely different.

Instead of this:

Text document
├── text
├── table
├── spreadsheet-like data
├── chart
└── image

I have:

Event Document
├── Guests
├── Groups
├── seating information
├── Tables and Seats
├── floor-plan objects
├── images
└── event-level configuration

The important similarity is not the content type. It is the architectural role of the Document as the coherent unit of user work.

The Document builds on the Seating model

One particularly interesting part of the reconstructed hierarchy is that the Document does not merely contain some unrelated seating helper.

The Document builds directly on the application's Seating abstraction.

This tells me something important about the original domain model: seating is not an optional external tool applied to a document. It is one of the fundamental capabilities of an event document.

Seating Model
     │
     │ provides fundamental
     │ seating behaviour
     ▼
Event Document
     │
     ├── adds people
     ├── adds groups
     ├── adds floor plans
     ├── adds assets
     └── coordinates the complete event

This also explains why seating operations appear throughout the application rather than being isolated inside one dialog.

The Document itself understands that the event has a seating state.

Guests belong to the Document context

The Guest class described earlier contains rich individual state: names, RSVP status, meal choices, contact information, custom values, Group membership and Table relationships.

But the Document provides the wider population in which those Guests exist.

The reconstructed call relationships show document-level operations for adding Guests, finding Guests belonging to Groups and resolving Guest references after data has been loaded.

This is exactly the kind of work I would expect from the central model.

Event Document
      │
      ├── Guest
      ├── Guest
      ├── Guest
      ├── Guest
      └── Guest

The Guest knows about itself.

The Document knows about the population.

That difference in scope is important.

Groups need the Document as coordinator

The Group article exposed a bidirectional relationship.

A Group knows which Guests belong to it, while a Guest can refer back to its Group.

Relationships like that need coordination.

If somebody moves from one Group to another, several pieces of the model may need to remain consistent:

Old Group
   │
   └── remove Guest

Guest
   │
   └── change Group reference

New Group
   │
   └── add Guest

The Document is the natural location for operations that span several domain objects because it has visibility of the complete event.

This does not mean every tiny operation should eventually remain inside one enormous Document class. But it does mean that cross-object invariants need a place where the complete model is visible.

The floor plan is part of the same Document

The Document also maintains the application's floor-plan context.

The current reconstruction includes a collection of floor-plan scenes associated with the Document.

That is important because a floor plan is not a detached illustration.

It is another representation of the same event.

Event Document
       │
       ├── people model
       │
       ├── seating model
       │
       └── floor-plan model
               │
               ├── tables
               ├── walls
               ├── shapes
               ├── text
               ├── images
               └── other visual objects

This is one of the strongest examples of why the Document metaphor works so well.

The Guest list and the floor plan may be presented through completely different screens, but they are not separate pieces of user work.

They are two views into the same event.

Images are Document resources too

The reconstructed Document also maintains image resources.

There is evidence of separate image collections used for event or room imagery and for Guest-related icons.

This is another parallel with old document-oriented productivity software.

An image inserted into a Pages or AppleWorks document was not conceptually a separate project. It became part of the document.

The same principle applies here.

A floor-plan background image, a room photograph or a Guest-specific visual asset exists because it contributes to this Event Document.

Event Document
       │
       ├── domain objects
       ├── seating
       ├── floor plans
       │
       └── resources
            ├── event / room images
            └── Guest images / icons

Keeping those resources associated with the Document also gives persistence code a clear answer to an important question:

What belongs to this event when it is saved?

Persistent identity becomes essential at this level

The Object Identifier discussed near the beginning of this series becomes particularly important once the Document contains many interconnected objects.

Inside memory, one object can hold a pointer or reference to another.

A saved file cannot rely on a memory address surviving until next week.

So relationships need persistent identities.

While running:

Guest ─────────────► Group object


When saved:

Guest ─────────────► Group identifier


When loaded again:

Group identifier
       │
       ▼
resolve reference
       │
       ▼
Guest ─────────────► Group object

This is why the Document has reference-resolution responsibilities during loading.

The file reconstructs objects first. The relationships between those objects then have to be re-established.

A document containing a graph of related objects is fundamentally more interesting than a file containing independent rows.

Saving means serialising an object graph

The current persistence path exports the complete plan to XML.

That is another area where the word Document becomes useful.

The XML is not the architecture itself. It is the serialised representation of the architecture.

                    Event Document
                          │
                          │ serialise
                          ▼
                         XML
                          │
                          │ parse
                          ▼
                    Event Document

The important engineering requirement is therefore not merely “write XML”.

It is:

preserve enough information to reconstruct the complete event model and all of its relevant relationships.

That includes identity, Guests, Groups, seating, floor-plan elements, images and the relationships connecting them.

A Document can have several views without becoming several documents

This is another area where Apple's document architecture provides a useful conceptual analogy.

A document is the model. A window or view is a way of looking at that model.

My application has the same requirement.

The user may look at:

  • a Guest list;
  • a Group-oriented view;
  • a table plan;
  • a floor plan;
  • an affinity-oriented view;
  • a dashboard or summary.

Those do not need to be separate Documents.

They are different projections of the same Document state.

                  Event Document
                        │
        ┌───────────────┼───────────────┐
        ▼               ▼               ▼
   Guest View      Seating View    Floor Plan View
        │               │               │
        └───────────────┼───────────────┘
                        │
                  same underlying
                       model

If a Guest's name changes in one view, another view should not need its own independent copy of that Guest.

Both should observe the same underlying event model.

Multiple views should describe one Document, not create multiple competing versions of the same event.

Modification state belongs naturally at Document level

A document-oriented application also needs to answer another apparently simple question:

Has anything changed since the user last saved?

This question cannot sensibly belong only to Guests, Tables or Floor Plans.

Changing any meaningful part of the event can make the Document dirty.

Guest changed ───────┐
Group changed ───────┤
Table moved ─────────┤
Seating changed ─────┼──► Document modified
Floor plan changed ──┤
Image changed ───────┘

The Document is therefore the natural unit for change tracking and save decisions.

Again, this mirrors the traditional desktop-document model: the application tells the user that the document has unsaved changes, not that twelve individual C++ objects have unsaved changes.

This is an aggregate boundary

In modern domain terminology, I would describe much of this as an aggregate boundary.

The Event Document establishes the scope inside which a large number of related objects form one coherent model.

I do not mean that the Document should eventually implement every operation itself.

That distinction matters.

Being the root of the model does not mean becoming a “God object”. Ownership of context and implementation of every behaviour are two different responsibilities.

A mature architecture can still delegate specialised work to dedicated components:

  • seating algorithms can live in seating services or solver objects;
  • XML persistence can live in import/export code;
  • graphics can remain inside scene and view classes;
  • Guest formatting can remain with Guest-related logic;
  • Group contact data can remain in its own value object.

The Document does not need to perform every calculation.

It needs to establish which model those calculations are operating on.

The danger of the central Document

The same architectural importance that makes the Document useful also makes it dangerous.

Central classes tend to attract code.

Whenever a developer needs access to Guests, Groups, Tables, images or seating, the Document is nearby. Over many years, convenience can turn the central model into a class that knows too much.

This is something I am paying particular attention to during reconstruction.

I want to preserve the Document as the coherent root of the event while identifying responsibilities that belong elsewhere.

Good:

Document
├── owns / coordinates model
├── exposes coherent operations
└── delegates specialised work


Dangerous:

Document
├── owns everything
├── draws everything
├── imports everything
├── exports everything
├── calculates everything
├── formats everything
└── knows every UI detail

The reconstruction is therefore not just an exercise in recovering functions. It is an opportunity to identify the architectural boundary that should remain and the accidental responsibilities that can later be moved.

Why I still like the Document metaphor

Modern software often talks about projects, workspaces, cloud resources, boards and databases.

There is nothing wrong with those concepts, but I still like the clarity of the traditional desktop Document.

The user creates something.

That thing opens.

They work on it.

They save it.

They can make another one without confusing the two.

Everything that belongs to the first stays with the first.

Everything that belongs to the second stays with the second.

For an event-planning application, that mental model is particularly natural.

Application
│
├── Event Document: Wedding
│   ├── Guests
│   ├── Groups
│   ├── Tables
│   ├── Seating
│   └── Floor Plan
│
└── Event Document: Conference Dinner
    ├── Guests
    ├── Groups
    ├── Tables
    ├── Seating
    └── Floor Plan

The application is not the event.

The Document is.

Putting the Document architecture together

At this point in the reconstruction, my conceptual view is becoming:

Event Document
│
├── event population
│   ├── Guests
│   │   └── individual contact information
│   │
│   └── Groups
│       └── shared contact information
│
├── seating model
│   ├── Tables
│   ├── Seats
│   ├── assignments
│   └── seating solutions
│
├── relationships
│   ├── Guest ↔ Group
│   ├── Guest ↔ Table
│   └── Guest ↔ Guest affinity
│
├── physical representation
│   ├── floor-plan scenes
│   ├── Tables
│   ├── walls
│   ├── shapes
│   ├── text
│   └── images
│
├── resources
│   ├── floor-plan / room images
│   └── Guest images or icons
│
├── document state
│   ├── object identities
│   ├── modification state
│   └── event-level settings
│
└── persistence boundary
    ├── load
    ├── resolve relationships
    └── save

Some of those responsibilities are implemented directly by the Document and some are delegated to collaborating objects. That distinction will become clearer as I continue reconstructing the remaining classes.

But the overall architectural role is already clear.

From individual classes to one coherent application model

The earlier articles in this series examined very small pieces: an Object Identifier, Guest Contact and Group Contact. Then came larger business objects such as Guest and Group.

The Document is where those earlier pieces begin to make sense as one system.

The Identifier allows relationships to survive persistence.

The Guest represents an individual attendee.

The Group gives several Guests shared context.

The contact objects separate personal and shared communication information.

The seating model relates people to physical places.

The floor-plan model gives those places spatial meaning.

And the Document says that all of these things belong to the same event.

The Document is the point where a collection of C++ objects becomes something the user recognises as a single piece of work: their event.

That is why I find the old Apple document model such a useful analogy.

The technology has changed enormously. The application domain is completely different. But the underlying idea remains elegant: create one coherent Document, allow different kinds of information to live inside it, and make that Document the unit the user opens, edits, saves and understands.

For this project, that is exactly the role I want the Event Document to play.

AI Assistance Disclosure: This article was developed from my original notes and personal professional experience with the assistance of generative AI. AI was used to help organise, expand and refine the text and clarify certain technical distinctions. The experience, opinions and conclusions remain my own. Identifying details have been omitted.

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...

ATA Drive Capacity Limitations

ATA interface versions up through ATA-5 suffered from a drive capacity limitation of about 137GB (billion bytes). Depending on the BIOS used, you can further reduce this limitation to 8.4GB, or even as low as 528MB (million bytes). This is due to limitations in both the BIOS and the ATA interface, which when combined create even further limitations. To understand these limits, you have to look at the BIOS (software) and ATA (hardware) interfaces together. NOTE In addition to the BIOS/ATA limitations discussed in this section, various operating system limitations exist. These are described later in this chapter. The limitations when dealing with ATA drives are those of the ATA interface as well as the BIOS interface used to talk to the drive. A summary of the limitations is shown in Table 7.12. Table 7.12. ATA/IDE Capacity Limitations for Various Sector Addressing Methods Sector Addressing Method Total Sectors Calculation Maximum Total Sectors Maximum Capacity (Byte...