2

A developer is tasked with writing a service that will iterate through a number of records and send notifications for each one. The type of notification might be different per record, so you can imagine logic like this:

switch (record.DeliveryPreference)
{
    case "email": SendEmail(record); break;
    case "sms": SendSms(record); break;
}

The developer decides that some day there may be other delivery methods, so he wants to eliminate the case/switch and instead wants to be able to add additional delivery methods via configuration only:

<DeliveryMethod type="Company.Channels.Plugins.Sms.SmsClient, Company.Channels.Plugins.Sms.Library" />
<DeliveryMethod type="Company.Channels.Plugins.Email.EmailClient, Company.Channels.Plugins.Email.Library" />

...and then use type metadata (a.k.a. Reflection) to detect new delivery methods and automatically use them.

I consider this a problem-- informally named "uneven maintainability"-- because the ability to add a new DeliveryMethod via configuration is overengineered.

Why is it overengineered? Well, if the company is going to introduce a new delivery method, that is going to a big project. You'd have to get funding, source a provider, establish connectivity, open proxies and firewalls, and write the code base that uses the new connection. There is no way that is ever going to be something that is quick and easy. So here a developer has added all this complexity so he could save 30 minutes of coding from a 500-hour project, which seems of little benefit.

Meanwhile, the additional complexity could actually be harmful, for the usual reasons unnecessary complexity is harmful. But in particular one reason stands out to me. Instead of actually using the configuration as a place where developers can easily specify system parameters, it has become a document that must contain a series of magic strings in order for the system to even work. All the config files will always look the same, and if there is one letter out of place, the thing just blows up. From an information-theoretic perspective, you could say that the configuration file has increased its percentage of equivocation, meaning that the information content has gone down.

A different sort of analogy would visualize a bridge composed of planks where every other plank is rigid or flexible. The result is a bridge that is neither rigid nor flexible, but indeed weaker overall.

I could go on with examples and pros and cons and so forth, but that would be opinion-based and is not the point of this question. I am looking for terminology or engineering principles that deal with the notion of "useless flexibility" or uneven maintainability.

1

We're not in the head of the developer when he made it though :

  • He could just have thought that it would be worth it because that didn't take a lot of extra time to do
  • He could also need a way to disable SMS/Email sending when testing by providing a dummy implementation.

However, I see two different problems from your point of view : the external configuration, and how it was implemented.

Finally, when the developer thought about how he would do that, he may not have taken the time for a proper analysis, so he chose the most natural way for him to do it.

And how to name it ? Well that depends of the global state of the application.

If I only look and consider the hypothesis that I said before, I won't call this overengineering nor an inner Platform. The only thing that bugged me is the fact that he used reflection instead of using better tools for this kind of stuff.

As such, whatever we want to name it will depend on our view about it, and obviously that is only an opinion.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.