-
Notifications
You must be signed in to change notification settings - Fork 16
Versioning How to modify code without breaking user scripts
When a script created in one of our supported UI is saved, all the BHoM components save information about themselves to they can initialise properly when the script is re-opened. That information is simply kept in a string format (more precisely Json format) and contains details such as the component/method name, it's argument types,...
If someone modifies a method definition in the code, it will become impossible to find that method based on outdated information. Unless, of course, we provide to the system a way to update that old json before using it to find the method.
The same logic applies for saved types (e.g. types of input/output of a component) and saved objects (e.g. objects stored in a database or file).
Alongside the dlls installed in AppData\Roaming\BHoM\Assemblies, you can find in the bin sub-folder a series of BHoMUpgrader exe programs. When a type/method/object fails to deserialise from its string representation (json), those upgrader are called to the rescue.
Every quarter, when we release a new beta installer, we also produce a new upgrader called BHoMUPgrader plus the version number (e.g. BHoMUpgrader32 for version 3.2). That upgrader contains all the changes to the code that occurred during the quarter.
When deserialisation fails in the BHoM, the most recent upgrader is called. If that upgrader contains all the information it needs to return a valid version of the object, it will return an updated version of the json string. There will, however, be cases where the json string is old enough that the current installer doesn't contain a record of the changes. There might even be cases where multiple changes on a method/class happened across multiple quarter. This means we will need to combine the information from multiple upgraders. If that is the case, the upgrader will first call the previous upgrader before trying to upgrade the json string again.

We will go in details how the upgrade information is stored inside an upgrader in the remaining section. There is however on aspect worth mentioning already. Once a quarter is finished, an upgrader is never modified again and simply redistributed alongside the others. During that quarter, the current upgrader is contently updated to reflect the new changes. For everyone working on the BHoM to have to modify the exact same files inside the Versioning_Toolkit would be inconvenient and a frequent source of clashes. For that reason, the information related to the upgraded of the current quarter are stored locally at the root of each project where the change occurred.

Notice that the file name ends with the version of teh BHoM it applies to.
The content of an empty Versioning_XX.json file is as follow:
{
"Namespace": {
"ToNew": {
},
"ToOld": {
}
},
"Type": {
"ToNew": {
},
"ToOld": {
}
},
"Property": {
"ToNew": {
},
"ToOld": {
}
}
}When the UI_PostBuild process that copies all the BHoM assemblies to the Roaming folder is ran (i.e. when BHoM_UI is compiled), the information from all the Versioning_XX.json files is collected and compiled in to a single json file copied to the roaming folder next to the BHoMUpgrader executable. It's content will look similar to the local json files with an extra section for the methods (more onto that later):
{
"Namespace": {
"ToNew": {
"BH.Engine.XML": "BH.Engine.External.XML",
"BH.oM.XML": "BH.oM.External.XML"
},
"ToOld": {
"BH.Engine.External.XML": "BH.Engine.XML",
"BH.oM.External.XML": "BH.oM.XML"
}
},
"Type": {
"ToNew": {
"BH.oM.XML.Settings.XMLSettings": "BH.oM.External.XML.Settings.GBXMLSettings",
"BH.oM.XML.Environment.DocumentBuilder": "BH.oM.External.XML.GBXML.GBXMLDocumentBuilder"
},
"ToOld": {
"BH.oM.External.XML.Settings.GBXMLSettings": "BH.oM.XML.Settings.XMLSettings",
"BH.oM.External.XML.GBXML.GBXMLDocumentBuilder": "BH.oM.XML.Environment.DocumentBuilder"
}
},
"Method": {
"ToNew": {
"BH.Adapter.XML.XMLAdapter(BH.oM.Adapter.FileSettings, BH.oM.XML.Settings.XMLSettings)": {
"_t": "System.Reflection.MethodBase",
"TypeName": "{ \"_t\" : \"System.Type\", \"Name\" : \"BH.Adapter.XML.XMLAdapter, XML_Adapter, Version=3.0.0.0, Culture=neutral, PublicKeyToken=null\" }",
"MethodName": ".ctor",
"Parameters": [
"{ \"_t\" : \"System.Type\", \"Name\" : \"BH.oM.Adapter.FileSettings\" }"
]
}
},
"ToOld": {
}
},
"Property": {
"ToNew": {
},
"ToOld": {
}
}
}Let's now go into detail how to record a change on the code for the various possible aspects that can be modified.
This applies to the case where an entire namespace is renamed. This means all the elements inside that namespace will now belong to a new namespace.
To record that change
-
Introduction to the BHoM:
What is the BHoM for?
Structure of the BHoM
Technical Philosophy of the BHoM -
Getting Started:
Installing the BHoM
Using the BHoM
Submitting an Issue
Getting started for developers -
Use GitHub & Visual Studio:
Using the SCRUM Board
Resolving an Issue
Avoiding Conflicts
Creating a new Repository
Using Visual Studio
Using Visual Studio Code -
Contribute:
The oM
The Engine
The Adapter
The Toolkit
The UI
The Tests -
Guidelines:
Unit convention
Geometry
BHoM_Engine Classes
The IImmutable Interface
Handling Exceptional Events
BHoM Structural Conventions
BHoM View Quality Conventions
Code Versioning
Wiki Style
Coding Style
Null Handling
Code Attributes
Creating Icons
Changelog
Releases and Versioning
Open Sourcing Procedure
Dataset guidelines -
Foundational Interfaces:
IElement Required Extension Methods -
Continuous Integration:
Introduction
Check-PR-Builds
Check-Core
Check-Installer -
Code Compliance:
Compliance -
Further Reading:
FAQ
Structural Adapters
Mongo_Toolkit
Socket_Toolkit