DEV Community

Cover image for On the Occasional Misdiagnosis of "Not Invented Here Syndrome"

On the Occasional Misdiagnosis of "Not Invented Here Syndrome"

Ben Halpern on December 12, 2019

Not invented here syndrome (NIHS) is a slightly tongue-in-cheek name for the tendency of both individual developers and entire organizations to re...
Collapse
 
joerter profile image
John Oerter

Thanks for the article! I agree that this is a tough issue because so much of it depends on you and your organization's/project's specific circumstances.

I used to try and pull in as many third party dependencies as possible in order to accelerate development. Now, I tend to choose more foundational dependencies and avoid pulling in smaller libraries that bring in functionality I could easily do myself. I've found that it's easier to create something that is suited exactly for my purposes than it is to pull in and manage a dependency that was created for someone else's problems. It's always a trade off 😄

Collapse
 
scottshipp profile image
scottshipp • Edited

Joel Spolsky famously wrote a "Defense of Not-Invented-Here Syndrome."

In my career, I've more often seen bad cases of not-invented-here syndrome than I've seen cases like Spolsky mentions. After seventeen years, my personal philosophy about software engineering has developed into the idea that software engineers should do the most simple and obvious thing possible as much as possible, because I believe Donald Knuth's stance that code is actually human-to-human communication disguised as "instructions for a computer." This guideline overlaps with the idea of NIH syndrome in the sense that usually you want to reuse the abstractions people know already so that they can understand what your code does.

But it also doesn't rule out inventing your own something. In fact, it supports it in many cases where a domain-specific language makes the code clearer (and therefore "more simple and obvious") to others.

Collapse
 
ben profile image
Ben Halpern

Ironically, even though I linked to another Spolsky post, this article could be a re-invention of the same basic presence he was outlining.

However, in framing it in my own experiences and cultural context, the re-invention was justified 😄

I really like this quote from that post.

Pick your core business competencies and goals, and do those in house. If you’re a software company, writing excellent code is how you’re going to succeed. Go ahead and outsource the company cafeteria and the CD-ROM duplication. If you’re a pharmaceutical company, write software for drug research, but don’t write your own accounting package. If you’re a web accounting service, write your own accounting package, but don’t try to create your own magazine ads. If you have customers, never outsource customer service.

I think a good takeaway is definitely to know what types of software you should be inventing and don't invent the other kinds, and that is going to be incredibly context-dependent. I think that's probably the issue with these broad statements in general, they require contextual wisdom and framing.

That's why we hang around on sites like this, so we can noodle on the context.

Collapse
 
jacobherrington profile image
Jacob Herrington (he/him) • Edited

One benefit of rolling your own stuff (which I agree you should avoid regarding foundational pieces of the stack) is the opportunity to attack a problem from first principles. That allows you to challenge a lot of the assumptions that exist in external libraries in the same space, sometimes coming up with a much simpler bespoke solution.

The obvious danger is when you think you can simplify authentication, so you spin up your own insecure auth library! The same goes for a large number of generic tasks (like you mentioned: ORMs, web frameworks, servers, etc).

As long as there is some intentional thought or dialogue put into writing your own solution vs. pulling in a third-party dependency it's usually easy to determine the better path.

Collapse
 
lexlohr profile image
Alex Lohr

Only last week, one of our talented junior developers tried to convince me that utility libraries (in this case lodash or ramda) were worth including because they are tried and tested and have better code quality than anything you could write in a few minutes.

I raised three objections:

  1. Many of those libraries have a track record of having had many exploitable vulnerabilities and bad code quality. Just because something is widely used doesn't mean it is secure and has good code quality. Internet Explorer was the most used browser at one point in history and some of us still remember... though I digress.

  2. You often get a lot more than you think: let's take for example an isEmpty function - he actually brought it up in the discussion, which I am thankful about. In most cases you want to use it, you know exactly what type of value you are checking (if you are using TypeScript, you could even get it inferred if it is not already typed). In most cases, these are Objects, because in every other case, you wouldn't even consider isEmpty. There are a lot of checks for sets, maps, strings, etc., that you won't need for your use case.

  3. Using these helpers can save time, but that time is only wasted if used to think about a solution before understanding the underlying problem. Especially if you are less experienced, I challenge you to try this: before you import a helper to write an easy solution, try to understand the problem and how your helper would be solving it (e.g. by reading its sources). Then, only if implementing the solution yourself will take more than twice as long as an npm install, should you add the extra dependency. Even if you don't change your behavior, you will at least have learned how those helpers are doing it.

TL;DR: When using external dependencies is merely a replacement for thinking about the underlying problem, the diagnosis of NIHS does not apply.

Collapse
 
tobiobeck profile image
Tobi Obeck

Hi Ben, great article!

It is also fine to reinvent something just to learn how it works.
Following the slogan:

"What I cannot create, I do not understand"

Bundle size and tree-shakeability should also be considered when importing npm packages.

Could you elaborate on licence concerns when copy and pasting a part of the code from a library? What implications does this have?
Is it necessary to add a licence notice about the library in the project? If not done, is it a copyright infringement?
Does it differ when the copied code code is altered slightly?
I assume understanding the given code and coming up with an very similar solution would be legally fine.

Also a good article on that matter with the tendency to rely on proven solutions:
How to stand on the shoulders of giants by Quincy Larson

Collapse
 
peacefullatom profile image
Yuriy Markov

I'm always voting to use external solutions because such an approach saves a lot of time (usually 😀) and allows us to focus on achieving the goals.
A bright example is to use an external UI library instead of creating your own from scratch.

Collapse
 
kspeakman profile image
Kasey Speakman • Edited

Great article!

I think the key point you touched on is that the the core of your business should always be invented there. Otherwise, your business has no reason to exist over another constructed from the same commodity pieces.

I also find that I reinvent a few lower-level things simply because the big name options that exist out there have created too complex and/or too opinionated of an abstraction. For example, I wrote my own libraries for:

  • Event Storage in Postgres - 5 files 337 loc 2 complexity
    • SQL wrapper (SlimSql) - 9 files 300 loc 7 complexity
  • Validation - 4 files 171 loc 10 complexity
  • URI Routing (server side) - 7 files 667 loc 22 complexity

These numbers are from scc.

All of these projects started on the weekend at home out of frustration with the tools available to do the same job. I started working on it just to see if I could do better. The end result turned out useful enough that we use it at work.

Reinventing a wheel works well as an analogy because using a wheel is simple. You bolt it on and it works. If it breaks, you get another one off the shelf and bolt that on. It is the manufacturing of it that is more complicated. But it's already done for you. If wheels start needing significant investment to use correctly, they should be reinvented. Which is what I did with the libraries mentioned above.

Collapse
 
khrome83 profile image
Zane Milakovic

Great article. I would make the argument that for front end development, frameworks and libraries are typically safe to use from external sources. Provided the research was done to make sure it actually delivers and solve a need.

The best use case I have seen for avoiding external code is with components. When developers pull in a calendar widget, a expander, slider, etc it does solve a problem. But as I get older and focus more and more on accessibility and performance, I see these as bloating the client.

The really big cause is design and need. Many components are built for the masses to make things easier. Others are restrictive on patterns.

So what that causes us developers to do is either compromise the design, or choose larger components we can custom to our needs.

The other benefit for a front-end Dev to actually build it themselves, is they learn. So many boot camp devs have only copy and pasted from stack overflow or used libraries. Building it from scratch to meet your organizations needs, while focusing on a11y and performance, really educates.

Not everyone can afford to do this. But it’s a trade off we have made any chance we can, and it has paid off in spades with the development of our teams. But it does have to be thoughtful, and justified.

Collapse
 
codemouse92 profile image
Jason C. McDonald • Edited
Collapse
 
cheetah100 profile image
Peter Harrison

This raises the question of whether code is the best place for business logic. One of the things we have done as developers is feather our beds by raising barriers to certain tasks or roles, such as specifying business rules, data structures, user interfaces.

In many ways we retreated from tools like Delphi which made design more accessible. Developing basic business apps requires substantially more skill sets than they ever have. My own thesis is that we should write software that decouples from the domain as far as possible, just as databases have, and allow people without development skills to leverage technology to solve their own problems.

The spreadsheet is perhaps the best example of this approach, where managers can create their own solutions without knowing how to code. Most development tools follow the orthodoxy of domain binding, forcing you to statically link to data structures at design time.

We already accept the wisdom of domain decoupling when it comes to databases or email, or even TCP. With all of these the payloads are a separate concern. Obviously there is a domain, so I'm not suggesting that it does not exist, only that developers need to release their death grip over it and give it back to users.

Collapse
 
_morgan_adams_ profile image
morgana • Edited

I really appreciate the thoughts here. There's definitely a spectrum and it's not the same spectrum for every organization because each organization's needs are continually evolving and in different directions. For early iterations, NIHS is a good rule to follow as it helps with speed to market. That said, as a platform matures and grows I think forking or doing it yourself is perfectly reasonable as business logic often outgrows available abstractions.

Collapse
 
keithrbennett profile image
Keith Bennett

"These named patterns we identify with should always be the start of a conversation or debate, not the thing that ends the debate."

Very well said.

I've seen lots of programming "best practices" come and go. Many years ago it was "comment everything". Later on it was "comment nothing". Both are wrong.

As our experience grows, we realize that dogmatic oversimplifications like these are naive. They fail to take into account context and nuance. They may be correct in most cases, but when invoked as sacred truth their overuse is detrimental to a code base.

Another example is YAGNI (You Ain't Gonna Need It). I've been in discussions where, as you suggest, invoking it was like playing a trump card -- subsequent discussion was futile. YAGNI has an extreme beyond which it should not apply; if you wrote a left-pad method (speaking of left-pad methods) and so far you always needed to pad to a width of 16, would you write this?:

def left_pad_16(string)

No, of course not, you would parameterize the width:

def left_pad(string, width)

And yet the unquestioning application of YAGNI would dictate against that. It's a silly extreme, but it illustrates the point.

So, as you say, "not invented here syndrome" raises an important and useful question, but applying it unconditionally without considering the context and nuance is unhelpful.

Collapse
 
brookzerker profile image
Brooks Patton

My personal philosophy is to look at the business value. Does reinventing the wheel provide better value for our customers and is more important than what we could be doing otherwise?

I generally like to use external resources until they begin to cause problems. Only then do I think about investing something to replace them. This way I make sure not to invent the wrong thing at the wrong time.

Collapse
 
leob profile image
leob • Edited

Good point ... over-reliance on third party libs for pretty trivial pieces of functionality (application/ business logic, as opposed to "infrastructure") can easily lead to unnecessary "vendor lock-in". In these cases I'd also be inclined to just build a home-grown custom solution "at the app level".

Collapse
 
dwd profile image
Dave Cridland

I work for a critical messaging company.

If I were to suggest we should create our own database, this would be clearly NIH at its worst. We use databases, of course. We also use web servers, and all sorts. I wouldn't advocate trying to duplicate any of those.

If I were to suggest we should create our own messaging server, this makes a lot more sense - of course we could use another existing one, but our whole company is about messaging, so it makes sense that we should fully own our solution. We can, of course, survive on an existing server for some time, though.

If I were to suggest that we should use a pre-existing messaging client, though, that would be bizarre - we obviously need to write our own mobile apps. But we use existing libraries to do so - perhaps we'll start to commit back to those, and perhaps we might eventually choose to write our own.

So to me, the argument isn't about "high" or "low" level, it's about whether it makes sense to own a particular component given your mission. I think of this as a critical path through the stack, though I freely admit I'm mixing technical metaphor here.

Collapse
 
fagnerbrack profile image
Fagner Brack • Edited

There's an objective balance you can use:

As the value of the code is closer to the core of your business domain, it's more likely you'll want to write it yourself (if you have the skills) other than delegate to a third party.

If the code is closer to the core value of a technical domain outside of your core business domain, then it's more likely you'll want to use somebody else's code.

It's more of a risk management decision than an actual coding decision. It turns out many developers don't understand risk management in the context of the organisation or the project

Collapse
 
mortoray profile image
edA‑qa mort‑ora‑y