7. Data Source Interfaces
Status
Accepted
Date
2022-11-1
Context
Data sources can meet the needs of multiple use-cases, but all data sources
should not be expected to meet all needs. Currently, the JsonDataSource
throws
a NotImplementedException
for forecast-related methods required by the
ICarbonAwareDataSource
interface. As functionality expands in this way it
becomes harder maintain data sources and it prevents programmatic understanding
of which methods are actually available to the user.
For example, if someone wanted to expand functionality to include access to
power generation sources (coal, hydro, solar, etc.), such a change breaks
existing data sources and likely forces them into a similar workaround of
raising exceptions to meet the new interface. Users may similarly start to see a
power-consumption
command in the CLI that throws errors for the data source
they are using.
Decision
The project will strive toward the interface segregation principle of SOLID design by using separate interfaces for unique roles that a data source may serve. This is often signalled by a different model/schema being returned by the methods.
A single data sources can implement multiple interfaces.
Consequences
Current Implementation
Interfaces
To align with this decision, the ICarbonIntensityDataSource
interface would be
broken into two interfaces:
IEmissionsDataSource
– for data sources of measured emissions dataIForecastDataSource
– for data sources of forecasted emissions data
Aggregators
There is also no need for these data sources to have a shared aggregator as none of the existing aggregator functions leverage both types of data together. Thus, there should be two corresponding aggregators:
EmissionsAggregator
ForecastAggregator
Each aggregator should have its own parameters class, however the appropriate
way to split up the existing CarbonAwareParameters
class is less
straight-forward due to the large amount of shared code. How to split up this
class should be the subject of its own ADR, and it should continue to be shared
by both aggregators until an agreed upon design has been reached.
Configuration
Each data source type should be independently configurable. So an example config of
{
"carbonAwareVars": {
"carbonIntensityDataSource": "WattTime"
// ...
}
// ...
}
becomes the following with no user-facing changes since WattTime implements both interfaces:
{
"carbonAwareVars": {
"emissionsDataSource": "WattTime",
"forecastDataSource": "WattTime"
// ...
}
// ...
}
But it now becomes possible to configure different sources for each type.
{
"carbonAwareVars": {
"emissionsDataSource": "JSON",
"forecastDataSource": "WattTime"
// ...
}
// ...
}
Other Config Considerations When no data source is specified... Use a default data source following the null object pattern to provide empty, but strongly-typed responses.
When the data source type is not implemented by the specified data source... Throw an exception, alerting the operator to improper configuration.
Future Implications
New Aggregators A hypothetical feature which returned the differences between
forecasted emissions and measured emissions would implement a
ForecastEmissionsAggregator
to get the data from both sources and do the
calculations.
New Interfaces A hypothetical feature which exposed power generation data
would create an IPowerGenerationDataSource
which any data source with access
to such data could implement.
It would be configured by operators the same way as existing data source types,
by looking up the matching name of the interface (without the leading "I") in
the carbonAwareVars
section of the config.
{
"carbonAwareVars": {
"emissionsDataSource": "JSON",
"forecastDataSource": "WattTime",
"powerGenerationDataSource": "MyNewDataSourceName"
// ...
}
// ...
}
Features would be exposed to consumers via a PowerGenerationAggregator
or some
joint aggregator that merges data with another source, depending on the
use-case.
Green Impact
Neutral