Configuration Based Components
What are “configuration based” components?
I don’t know if there is another name out there for this. Help me out if you know it.
The basic concept comes from a desire as a software architect to present a minimalist interface for a component. The reason is simple: smaller the interface the more likely it will not change, thus doing what an interface is supposed to do, give the hosting application resilience to component changes.
In classic Object-Oriented Programming (OOP) you have properties/attributes and methods all within a class. Configuration based components contends that parameters/attributes in general are a terrible idea.
So why are properties/attributes so bad? They represent things like state and expose the inner data of the class for the calling application to adjust. This tends to:
1) Bulk up the interface. This can be seen as a violation of interface segregation principle.
2) Make it harder to do multi-threading. This is well known problem with OOP.
3) Make unit testing more difficult. Basically variables, properties and attributes are so simple that they don’t really need unit tests. Or do they? More on this later. But this is the first clue. If it doesn’t need a unit test does it bring any real value? I would say no.
4) Developers tend to expose things because they are not sure if the user wants to adjust it. You know give them all the flexibility. But that is a cop-out. Your passing the buck to the user because you don’t understand the use-case. By doing that your taking on maintenance and future technical debt. Increasing the learning curve and cognitive load on the user. User defined parameters are just that, parameters of the function the user is eventually going to call. Our value as developers is to hide complexity through abstraction, that is a fundamental purpose of software.
Is this not just functional programming?
Yes it is. Done in the way modern C++ developers do it. Classes become containers for functions that do one thing (Single Responsibility Principle). They also provide for polymorphism. As containers of functionality they are the focus of dependency injection and primarily composition not inheritance.
So great I’m advocating for C++. Not really. I’m borrowing what I see as a clear strength in modern C++. Configuration based components goes beyond that. It assumes that objects need state and configuration (state that crosses instantiation). It purposes configuration/state needs to be injected at construction.
It is a simple pattern. The component takes a configuration string at construction. It takes that string and constructs a repository (repository pattern) that knows how to read the configuration and maintain it. This separates state and configuration, data, from functionality in the component class. The component class calls all state/configuration from the repository.
Why not just pass the repository? There is a tight coupling to data access from the component class. By using a configuration string, like a json string. You could pass a generic collection like a list or a dictionary of objects. I tend to do wrappers in python over my components that are in some other language. So I use a format like a string that easily crosses language inter-ops. The key is actual configuration becomes loosely coupled. This allows the component to maintain the loose coupling for configuration/state that the components interface provided.
But what about….
So what is the drawback? This pattern assumes that you will create a new instance of a component if the configuration changes. For example if the widget is blue you cannot just call an attribute to make it green. You must instantiate a new widget configured as green. Or you must call the value added function, something with a unit test, on the blue widget that turns it green while it is processing to show state. This enforces unit tests over state changes, which are often an issue if the component can somehow get into an invalid state. All state validity can be checked at one place, the construction.
That brings us to seeing the state. In general components are simple. If you want to see a state value you dump the entire current state of the object. Again you dump it as a configuration string, something like a json string. This again keeps the calling app loosely connected to the component.
As to objects that change back and forth and you don’t want to pay the cost of what instantiation may bring; you can always cache the object.
The other drawback is in tuning or finding the configuration. Developers often put properties and attributes in a class so they can figure out what the configuration should be. Then this baggage goes along for the production code ride and becomes technical debt right away.
The correct thing here is to recognize that the developer finding the configuration settings to use is the “developer use-case”. All components are born with two use-cases minimally. The first being the developers and the second being the use-case the application wants. To deal with the developers use case a light wrapper can be put around the component. That wrapper doesn’t ship or need to be unit tested, it is a simple developer tool.
Wait there is one more gem…
One huge benefit is the state (data) of the component is exposed as a dump separate from the functionality. Anyone that has tried to gather data from a system in an attempt to bring in a machine learning model as a new function or to replace an existing classic algorithm will instantly see the value in this approach. You are potentially dumping the labeled training data.
This pattern is a great pattern for hosting a potential ML model.
I’ve been using this pattern for a while now to create components that can be used in multiple frameworks on multiple OSes. It crosses multiple frameworks due to the loose coupling approach, which I borrowed from micro service architectures and just brought to the component level.
Let me know what you think. Thanks.