Discoverability vs. Compatibility: The Dilemma of Evolving the Access Object Model

Maintaining backward compatibility is a top priority for the Microsoft Access development team.

This means that when they make changes to the Access object model, they have to be very careful not to break existing code.  If they do, all .accde and .mde files created with previous versions of Access would need to be recompiled to work with the new version.  This would be a major headache for Access developers and users alike.

So how does the Access team add new features and extend the object model without breaking binary compatibility?

The "Stringly-Typed" Properties Workaround

One workaround the Access team uses is adding "stringly-typed" properties to the Access object's .Properties collection.

How to Use VBA to Set the ControlSource Property of an Access Image Control (and Other Deeply Hidden Object Properties)
Ever wonder why you can set some values in the form/report designer Property Sheet but not in VBA? You may just need this well-hidden workaround.

By using "stringly-typed" properties, the Access team can add new functionality without changing the underlying object model.  This preserves backward compatibility with existing .accde and .mde files. Developers can access these new properties using string literals, rather than strongly-typed object references.

However, this approach comes with its own set of trade-offs:

  • Reduced Compile-Time Safety
  • Reduced Discoverability

Let's explore each of these trade-offs in more detail.

Reduced Compile-Time Safety

When using "stringly-typed" properties, we lose the benefits of compile-time type checking.

If we misspell a property name or pass the wrong data type, we won't know until runtime.  This can lead to harder-to-detect bugs and slower development.  It's a significant downside of using "stringly-typed" properties.

Reduced Discoverability

"Stringly-typed" properties are harder to discover and understand than strongly-typed object model members.

They don't show up in IntelliSense, and their purpose and usage may not be clear from their names alone.  This can make it harder for developers to learn and use new Access features.  

Encapsulating "Stringly-Typed" Properties

So what can we as Access developers do to manage these trade-offs in our own projects?  

One strategy is to encapsulate "stringly-typed" properties behind strongly-typed wrapper classes or modules.  By creating our own abstractions on top of the "stringly-typed" properties, we can improve compile-time safety and discoverability for our own code.  We can also provide better documentation and examples for how to use these new features.

For example, let's say we want to create a strongly-typed version of the Image Control's ImageCtl.Properties("ControlSource") property. We could create a custom class module named ImageControlWrapper with the following code:

Option Explicit

Private m_ImageCtl As Access.Control

Public Property Get ControlSource() As String
    ControlSource = m_ImageCtl.Properties("ControlSource")
End Property

Public Property Let ControlSource(ByVal NewValue As String)
    m_ImageCtl.Properties("ControlSource") = NewValue
End Property

Public Property Set ImageControl(ByVal NewImageCtl As Access.Control)
    Set m_ImageCtl = NewImageCtl
End Property

Then, in our form code, we could use this ImageControlWrapper class like so:

Option Explicit

Private m_ImageWrapper As ImageControlWrapper

Private Sub Form_Load()
    Set m_ImageWrapper = New ImageControlWrapper
    Set m_ImageWrapper.ImageControl = Me.MyImageControl
End Sub

Private Sub SetImageControlSource()
    m_ImageWrapper.ControlSource = "SomeFieldName"
End Sub

This is a bit of a contrived example, but you get the idea.

By encapsulating the "stringly-typed" property access behind a strongly-typed wrapper class, we get the benefits of compile-time checking and improved discoverability via IntelliSense. We can also add our own error handling, validation, or default values in the wrapper class.

Final Thoughts

Ultimately, the Access team has to make difficult decisions about how to evolve the Access object model over time.  

By prioritizing backward compatibility, they ensure that existing Access applications continue to work with new versions of Access.  But this compatibility comes at the cost of reduced discoverability and reduced compile-time safety.  We can reintroduce discoverability and compile-time safety with wrapper classes, but that does create an additional maintenance burden onto us as developers.

The tension between adding new features and maintaining backward compatibility is yet another reminder that everything in life is a tradeoff.

Acknowledgements
  • Article title generated with the help of Claude-3-Opus
  • Article excerpt generated with the help of Claude-3-Opus
  • One or more code samples generated with the help of Claude-3-Opus
  • Initial draft generated with the help of Claude-3-Opus
  • Cover image generated by DALL-E-3