Generic Code? Just Don't

Or should I say “Just Don’t Bother”?

A long time during my career writing generic code was the ultimate goal.
Invent the wheel only once right?
Sounds amazing!

The trouble is that if we look at how we do things these days, one can safely say that we
still haven’t figured out how to do this correctly yet…or do we?

This article uses a service with API and endpoints as the example, because services are a very common part of software development.
This article is absolutely also applicable to libraries, components and frameworks.

Situation…

So you are writing a generic service. Generic is good, you have heard! It is expected to get many clients in the future.
You need to disclose information from your domain. You have analysed your domain and know what de most important information is.
You have a good idea on how to do this and have created a nice API and are happy with the results.
You tell your first customer, who enabled you to write this service in the first place, how they must use your service.
The customer frowns and asks: “Why do I have to filter out this data? I didn’t ask for this data?”
You tell the customer that it is a generic service and build for the future. The customer frowns again, but complies as
you are both from the same company, and the customer knows they can do this filtering. The customer might even be happy,
because they finally got something they can work with.
They have to add a new database and configuration to their own client to keep track of the things they have to filter,
but the client is able to get the needed data.
Then new features need to be build. Your service grows and grows. New customers had questions for your domain you had not
anticipated.

To account for more and more specific scenario’s, the API also needs to change often.
All the Clients need to filter out data they do not need because they are calling a generic service (generic != specific),
and they get way more data than they need. Clients are unhappy and feature creep is happening at a large scale.
Now you have to think about how to work with multiple versions of your service in production and about a scenario on
how to force your customers to upgrade within a certain amount of time.
Soon there is nothing left of your initial beautiful API. At some point it becomes too difficult to work with, due to
all the configuration options and edge cases and because clients need to do too much themselves to get to the
information, like building their own filters and possibly security.

Then we build a new service to replace the old one because nobody wants to work with it anymore.
The new service is amazing. It doesn’t suffer from a bloated API. It works and performs awesome, and it does more or less the same
as the other service.
Time passes and now the same cycle of development as before is happening and before you know it you are in the same situation again.
It too becomes bloated and needs to be replaced with something new.
Customers need to change to new versions of the service, or a completely new service, more and more and are not happy.

So if this cycle is happening again and again, what are we doing wrong?

Generic much… too much?

Writing reusable code is a good thing and a good goal. Reusable code needs to be generic to some extent. It is a basic requirement.

An important question to ask though is at what level?

Writing a single, flexible, all encompassing, monolithic service applicable to a whole domain for a broad range of use
cases is extremely difficult.
It would mean you have to know just about every use case beforehand. Looking into the future is not one of the skills people have
at this time. So it is not only difficult it is next to impossible.

A generic service might also seem easy to make for the providing party, as they are exposing everything in their domain,
but what is your added value than above your database?
Making a service too generic will not make it more usable.

You might say that the more generic something is the less usable it becomes.

That is not all. Being too generic can actually hurt re-usability.
Most clients will have to do post processing to extract the actual data they need from a generic service.
This makes the client tightly coupled to the service as it needs more knowledge and filtering on the data of the generic service.
By being more tightly coupled it is less easy for the client to be moved or reused.
So you might say that making a generic service will make working with it more complicated for clients.
This can of course result in it not being used at all, which would defeat the purpose.

So if too generic is not the way to go… what then?

One thing…

How do we solve this problem? How to write reusable code? The solution lies in thinking smaller.
Write a service which does one thing and one thing well. At the time a service is build you probably have a customer
asking for specific information from your domain. That customer is at that time the only reason this service is actually build.
You might expect more customers, but you don’t know for sure, and you really don’t know what they might want.
Listen to this real and current customer. What does he/she want? specifically! Can I be of value to this customer? How?
Can I answer his/her question? Yes! Let’s do that then! Now you are writing a service with immediate and specific value to a customer.
You are not looking into the future for a possible need you don’t know about. You know what you are writing is needed.

On component level you can say you are having a single responsibility.

The first principle of the Agile Manifesto says:

Our highest priority is to satisfy the customer
through early and continuous delivery
of valuable software.

If you ‘are’ agile and not ‘do’ agile (there is a distinction!), you can be happy as you are delivering immediate value.
In fact, you will probably have to do way less than you had to do for that generic service. You have a conversation with
your customer and know what is asked. You can embrace change during the development and ask for frequent feedback.
The result is a small, well written service with clear API and responsibility. It is maintainable and trust is high that it does
what the customer wants.

Now a short while later a new customer comes along with a question for your domain. Does it match what your first service already provides?
If it does, you are done and if it does not you can have the same conversation again with the new customer. You might write a
new service for this specific value. Now you are not reusing code but team knowledge. You have experience in writing a service like this.
The service will be written faster but still for a specific customer and with a guaranteed value.

The original service did not need to change at all.
The new service is just as simple in design and use, but answers a new use case.

Time goes by and more services have a need to be written. Experience is now very high.

A Way of Working has been established.

You might even have invested in a template, which is a form of reuse many people do not think of.
You have a nice set of services, and you now also have more knowledge of you domain and what customers want.

You are looking back to a period of delivering actual value and only value and start to see patterns.

You might want to refactor services to these patterns. You probably do not even have to change the existing API’s.
You are learning from looking back and at valuable code, not at a possibly predicted might be, but never will be future needed code.

Let’s call these valuable services Micro Services… Get it 😄?

Conclusion

  • Talk with the customer you have and make him/her king!
  • Don’t make the customer conform, conform!
  • Focus your software! Do one thing and one thing well Single-responsibility principle.
  • You ain’t gonna need it YAGNI principle. Futures you just don’t know! Don’t predict and ass-u-me.
  • Keep it Simple Stupid! KISS principle. The simpeler your service is the easier to test and trust it.
  • Be Agile, don’t Do agile! Agile Manifesto / Agile Principles
  • Reuse can be done on many levels. Team Experience is one of them!
  • Refactor continuously and don’t be afraid to.