Developers have an obsession with maps or dictionaries. Adding a map to an entity makes it “extensible”, in as far as arbitrary keys and values can now be associated with the entity, or so they think.

Of course, rules are made to be broken, and there may be some cases where maps are useful, but in general I think they are a “model smell” — an indication that the modeling is incomplete, either in understanding or in implementation.

Here’s an example (using the new Map syntax that is being added to Concerto):

map Properties {
   o String key
   o String value  
}

concept Person {
   o String fullName
   o DateTime dob
   o Properties properties
}

So, far, so good… But what IS the Properties Map? It’s basically a semantic void, a dumping ground for unmodeled properties. The semantics of the keys and the values are pushed into the application and can no longer be introspected from the model. The model is not self-describing.

This is a big problem for downstream tools, because they can no longer provide meaningful tools support for the keys and values in the map. For example, we might have an instance of a Person(Dan) with a property key “pet” with value “Beau” and a Person(Steve) with a property key “pet” with the value “false”. 

What should we do if we create a report over all the instances of Person?

There’s also no way to localise map key names by associating them with a vocabulary, forcing the application to either use localised key names, or to display local neutral key names (codes).

Slightly, better, in as far as we can statically introspect the model to discover value keys:

enum KeyType {
   o ADRRESS_LINE_1
   o ADRRESS_LINE_2
   o ADRRESS_CITY
   o ADRRESS_ZIP
   o FAVORITE_COLOR 
}

map Properties {
   o KeyType key
   o String value  
}

concept Person {
   o String fullName
   o DateTime dob
   o Properties properties
}

But, still pretty unsatisfactory — we’ve lost the concept of an Address, and the type-system for addresses and colours has been reduced to String values.

A much better model, is:

concept Address {
   o String line1
   o String line2
   o String city 
   o String zip  
}

concept Person {
   o String fullName
   o DateTime dob
   o Address address
   o String favoriteColor
}

In summary, developers have a tendency to shy away from these strongly-typed models for two reasons:

  1. They don’t want to (or can’t) perform the semantic modeling of the concepts, preferring instead to make that “an exercise for the user”
  2. Or often, developers think that defining the model is a “design time” exercise. In fact, models are data structures just like any other, and can be created by tools at runtime. It’s not much harder to dynamically add a String property called “favoriteColor” to the Person concept, than it is to create a UI that allows someone to specify that a map key is “favoriteColor” and that the value is “RED”. Developers find it hard to break this “models are static, data is dynamic” habit because they have been conditioned by traditional class/struct development in static languages like Java, C#, Rust etc. that separate the definition of a data structure from the runtime usage of a data structure. Concerto data models can be manipulated as DATA and can be easily defined, or extended, at runtime.

Before using maps or dictionaries in your domain models I would strongly urge you to think again. Is this really what you are trying to model or are you waving a white-flag and deciding NOT to create a semantic model?