On several occasions, I was faced with the following design issue that I don't know how to resolve. Imagine, for instance, an application which at some point receives a JSON object from an API. Before being able to use this object, the application should perform several transformations: for instance, one transformation may convert dates from one format to another, and another transformation may add extra data from cache (such as an entity describing a user, based on a sole user ID from the original object).
In order to be able to choose what transformations to apply at runtime, the transformations are defined in specific classes, such as DateFormatTransform
and ExtraDataFromCacheTransform
.
Basically, the code which performs the transformation would be like this:
foreach (var transform in this.GetRelevantTransforms())
{
entity = transform.Apply(entity);
}
this.GetRelevantTransforms
would return an instance of DateFormatTransform
, ExtraDataFromCacheTransform
and other classes. Each of those classes implement an interface containing the method:
SampleEntity Apply(SampleEntity x)
Later on, additional needs may arise, requiring to change the signature of Apply
. For example, one may need the transforms to be aware of the current user, because depending on the user, some transformations may be executed differently:
SampleEntity Apply(SampleEntity x, User currentUser)
The problem is that meanwhile, I can have a few dozen of transforms, and such basic change would require to walk through those dozens of files, changing both the interface (such as IDateFormatTransform
) and the class (such as DateFormatTransform
).
I suppose that having to change about fifty files just to add one simple argument is not a sign of a clean code base.
What are the alternatives?
Should I use a DTO, such as TransformArguments
, which would always be the only parameter of Apply
method? Or are there other techniques?
Or is my approach with a set of transformations flawed from the beginning, and if yes, how do I fix it?