Why it is bad to be opinionated
Tags: webdev, typescript
Published: 2023-06-02 07:28:27

As we all know, everybody always has an opinion, but that is not what this article is about. I want to talk about opinionatedness in relation to software engineering!

If you're a developer for a while, I'm sure you've heard someone (or yourself) dismiss an external library or framework, because it is "too opinionated", but what does it actually mean? And why is it so important for an external library to not be opinionated?

## Defining Opinionatedness
Opinionatedness is when something makes a choice for you, outside of the scope of that thing. Internet Explorer is a good example here. If you are a Windows user, up till a few years ago, you were forced to have Internet Explorer installed. I hope we can all agree at this point, that the choice for a web browser should by outside of the scope of an operating system (I'm looking at you MacOS/Safari).

## The Downsides of Opinionatedness
Let's look at a simple example:
```ts
function processResponse(res: { body: Record<string, unknown> }){
  return JSON.stringify(res.body)
}
```
At first glance there's nothing wrong with this function, but suppose that in the future, `JSON.stringify` turns out to be a very slow way to serialize your object? Or other serializers offer additional features that you want? You now have to change the `JSON.stringify` call inside the function. In this example that is not a big problem, but you can imagine in bigger applications, where the usage of a particular solution may be spread across several different files and functions, it can become quite problematic to make such changes.

## Preventing Opinionatedness
Looking back at the previous example of the `processResponse` function, we can make it unopinionated and future proof by making a few simple changes:
```ts
// Allow for passing in a custom serializer
function processResponse(res: { body: Record<string, unknown> }, options?: { serializer?: (Record<string, unknown>) => string }){
  const { serializer = JSON.stringify } = options || {}
  return serializer(res.body)
}
```
Now, I'm not suggesting that every function you write, should include an options object to customize every aspect (dependency injection). This is merely one example of how you can make your code less opinionated and more future proof, by making it open for extension (remember the open/closed principle?).

Another good way to make your code less opinionated and more future proof, is by using the middleware pattern, like ExpressJS does for example:
```ts
const app = express()
app.use((req, res, next) => {
  // Any request/response handling middleware goes here
  // Even ones that havent been invented yet
  console.log('Time:', Date.now())
  next()
})
```
## Possible Advantages of Opinionatedness
Sometimes the choice for an opinionated technology may have actual benefits, aslong as you are aware of the risks. A good example at the moment is NextJS. This is a React framework, with batteries included. It makes some choices for you, that may or may not be out of scope. For example, it has a very particular way of doing routing. However, because of the way they do routing, it is very easy to implement things that are generally very hard, like Server Side Rendering (SSR), Static Site Generation (SSG) and Incremental Static Regeneration (ISR). So, ***When something has very clear benefits, it may be worth it, even though it might limit you in the future.***

So, I hope the next time you have an opinion, you will remember this article and take some time to think about the long term implications of your choices! The developers who come after you, will appreciate the effort. :wink:

Some additional tips:
- Allow configuration and customization
- Use dependency injection
- Document limitations and trade-offs of solutions
- Prioritize simplicity and modularity
- Support extensions and plugins