The bill of materials design pattern is deceptively simple, yet incredibly powerful. This article will introduce an example, familiar to IT professionals, that you may not have thought fits the BOM pattern. It will also introduce concepts to show you how to make your BOM structures more flexible and much easier to manage.
A Short Recap of the BOM
A bill of materials has its roots in manufacturing. It is a list of the raw materials, sub-assemblies, intermediate assemblies, sub-components, parts, and the quantities of each needed to manufacture an end product.
In its simplest form, the classic BOM structure it looks like this:
However, the same kind of structure can be used for a multitude of different purposes, which range from something strictly hierarchical and tightly-coupled to something fairly flat and loosely-coupled. For more information on the BOM structure, see this article.
Schemas – an Everyday Example
Believe it or not, the class-attribute-type triplet and the table-column-type triplet follow the BOM pattern too. The physical data model below contains the core tables of a data dictionary.
|dd_attribute||A unique attribute, independent of any implementation.|
|dd_attr_instance||An instance of an attribute. The instance has two distinctive relationships:
1) The class it belongs to, which can be a logical or physical object. The instance is unique to this class.
2) The data type, which can be either a native type or another class type.
|dd_class||A class or object in the generic sense – the actual implementation being given by
A data dictionary, or metadata repository, is defined in the IBM Dictionary of Computing as a "centralized repository of information about data such as meaning, relationships to other data, origin, usage, and format".
Now consider the following XML Schema Definition (XSD) for a Java application:
It defines XSD complex types which have the attributes of either native XML types – e.g. string, NMTOKEN, anySimpleType – or other complex types.
To start populating the data dictionary for the above XSD, we first need to enter the XML native data types as classes:
We now have everything we need to start populating our data dictionary. In the example below, just enough is shown to fully define the ConnectionConfigType complex type.
|dd_attribute||of_class (via dd_attr_instance)||type_class (via dd_attr_instance)|
Note how the data type of the
ConnectionConfigType.Property attribute is another complex type,
PropertyType. In XML, complex types can be made up of other complex types. It’s not uncommon to find nested complex types in XML documents, especially in WSDL.
So what? you ask. Well, given that XML is hierarchic in structure and complex types can be reused, XML naturally follows the BOM pattern.
And this phenomenon is not limited to XML. Other schemas, like those for JSON and object-relational databases, follow the BOM pattern too.
Incorporating Flexibility in a BOM
In the classic product BOM structure, three finer-grained concepts are involved in modeling what happens in the real world. These are alternatives, variants, and revisions.
An alternative is a substitute for a particular item. For example, a car manufacturer may have different suppliers for certain items. Practically, this means the manufacturer can obtain equivalent fuel pumps from multiple sources. Usually, the customer isn’t given this option, but it gives the manufacturer flexibility.
We’ve used fuel pumps as items in the example table below, with Bosch and Lucas as the alternatives. Having a fuel pump alternative means that one and only one of the assemblies will be selected at the time of engine manufacture.
|V6 (Assembly)||Fuel Pump (Alternative)||1|
|Fuel Pump (Alternative)||Bosch Pump (Assembly)|
|Fuel Pump (Alternative)||Lucas Pump (Assembly)|
A variant is another type of item, but this time the customer makes the choice. A car buyer can choose different body styles – 3-door, 5-door, or an estate (station wagon or wagon). They can also select from two different types of engine – a V6 or a V8. In our example, the buyer must make a choice of one and only one of the assemblies below the variant.
|Parent||Child||Min Choice||Max Choice|
|Car (Assembly)||Body (Variant)||1||1|
|Body (Variant)||3 Door (Assembly)|
|Body (Variant)||5 Door (Assembly)|
|Body (Variant)||Estate (Assembly)|
|Car (Assembly)||Engine (Variant)||1||1|
|Engine (Variant)||V6 (Assembly)|
|Engine (Variant)||V8 (Assembly)|
In other domains, the number of choices is more varied. Take education as an example. To gain a particular qualification, a student has to complete a set number of groups. For each group, they can choose from several modules.
For example, suppose a student needs to complete two groups to get a diploma. They can choose two modules from a list of six to complete the first group. Then, they must choose three modules from five to complete the second group. (If this is a sector you’d like to see in more detail, a flexible design has been published by the UK’s Information Standard Board.)
Both of the above examples follow the simple pattern shown below. This pattern lends itself to structures that are fairly static. Variants and alternatives are inserted into the hierarchy to indicate that some sort of choice must be made from the items immediately below them.
Where things do tend to change over time, then the following pattern is more flexible and easier to maintain. On the downside, it’s a bit more unwieldy to traverse (or navigate).
By transforming the above logical model into a physical model, things start to look like this:
In this model, an item is either an indivisible part or an assembly. Parts and assemblies are organized into hierarchies. However, alternatives, variants and revisions have their own distinct relationships because they tend to change quite a bit over time. This minimizes hierarchy reorganization.
For example, car manufacturers continually develop their cars. It follows that part alternatives change over time, as do the variants made available to the customer. When a change occurs in an assembly, the assembly gets revised. A revision indicates the change history of the item. Consider this example:
The narrative for the above table goes like this: an item has at least one revision – its original version. The original version of the product is used to create the second version. The second was further developed to create version three, which didn’t work out. So the engineers revised the original version, creating version four. After extensive testing, this was also found to be less than ideal. So the engineers decided to take aspects of the second and third versions and create version five, the final product.
If you look at the preceding and subsequent keys, you will see why change history needs a many-to-many relationship between items and revisions. The same principle applies between items, alternatives, and variants.
A Final Word About the Bill of Materials Pattern
My hope is that this series of articles has helped you recognize the BOM pattern. When it appears in your projects, you’ll understand how best to model it in your specific domain.
Please note, though, that the strict bill of materials structure has pros and cons. Pro: hierarchies are reusable. Con: hierarchies are reusable. This may or may not be a bad thing in your case, but it’s certainly something to be aware of.
The good thing is that hierarchies don’t need to be set in stone. Using alternatives, variants, and revisions, you can model domains where options exist, where the historic position must be retained, and ultimately where the only constant is change.