Nodebestpractices: New best practice: avoid backward relative path

Created on 25 Nov 2017  ·  7Comments  ·  Source: goldbergyoni/nodebestpractices

I'm suggesting a new best practice under the code style practices: Avoid backward relative path

Context: it's common to see developers referring code in far-away folders - require('../../othercomponents/file.js')

Problem: encapsulation code smell + maintainability issue

What do you think?

Hot Discussion new best practice stale

Most helpful comment

Good point, I don't think that there is an agreed best practice for the technique, rather it should just be avoided:

  1. Redesign - if the project was correctly partitioned to components, there's no reason for any file to approach files in other components. One solution is to consider a redesign
  2. Share utilities as NPM package - if the referred file is a common utility that many needs, consider defining it as NPM package (can be even local module without using a repository)

Does it make sense?

All 7 comments

Well the question there would be how to solve this issue. Maybe enabling relative path resolve from the project root, for example not writing require('../../somecomponent/component.js') but instead writing require('somecomponent/component.js'), might help.

Good point, I don't think that there is an agreed best practice for the technique, rather it should just be avoided:

  1. Redesign - if the project was correctly partitioned to components, there's no reason for any file to approach files in other components. One solution is to consider a redesign
  2. Share utilities as NPM package - if the referred file is a common utility that many needs, consider defining it as NPM package (can be even local module without using a repository)

Does it make sense?

Let's say I've got a folder called models and there's a lot of them, so I partition that folder into models/User for user-related models and models/Product for product-related models. There are, of course, relationships between the two, so I'd have to require('../User/Cart') to get at it from the Product model. If I don't have relative requires setup, and many projects don't, this creates a pretty terrible situation where I'm moving files closer together so I can require them while adhering to an ill-advised best practice.

You can't tell people it's best practice to break up a large application into a bunch of NPM packages.

You can't tell people that they have to refactor within modules to not have backwards relative paths.

A better best practice might be "setup relative requires" that encourages you to avoid any require that starts with a directory symbol (., .., /). But even then, there's not really much fungible benefit to having require('foo/bar') over require('../../foo/bar') other than somewhat less visual noise, and there's not really a well accepted best practice for relative requires, is there?

I guess splitting up the application into node/npm modules might be the best way to avoid the backwards relative paths, really. But apart from that I do think that require('foo/bar') would look better than require('../../foo/bar') personally, simply because it's cleaner. There are ways to set up these relative requires from a root directory but this involves a somewhat hacked-together logic. I think the best situation might be either split the application into components that don't need the relative imports, split the application into (npm) modules, or accept the relative imports with directory separators.

@EdwardDrapkin it's not about the visual noise rather what it reveals.

I would split into two cases:

  1. Dependencies within a business module - if you have a business module/component that must create multiple models folders in different locations, there are great chances that this module is too big, have too many inner dependencies and will get too complex. A simple enough module should not have more than a few models and definitely not more than 1 models folder. If product module and user module are mixed together and not interact via a single interface (class service or HTTP API), you're likely to end up with some unpelasant level of spaghetti as your application grows.
  1. Dependency on common utility (e.g. logger) - in this specific case, the difference between './logger' and ../../utils/logger' is mostly aesthetic, not critical and still I would argue that: (A) it's a bit more maintainable not to use backward require rather adopt some relative require technique (simlinks, etc) (B) wrapping as NPM module is the most flexible and standard way of exposing a generic utility. Anyway, this is not the important scenario rather bullet 1

Would love to hear your thoughts

Hello there! 👋
This issue has gone silent. Eerily silent. ⏳
We currently close issues after 100 days of inactivity. It has been 90 days since the last update here.
If needed, you can keep it open by replying here.
Thanks for being a part of the Node.js Best Practices community! 💚

Just sharing all the possible ways to avoid backward relative require: https://gist.github.com/branneman/8048520

Was this page helpful?
0 / 5 - 0 ratings

Related issues

halfzebra picture halfzebra  ·  4Comments

Luifr picture Luifr  ·  5Comments

0x80 picture 0x80  ·  6Comments

goldbergyoni picture goldbergyoni  ·  3Comments

heyfirst picture heyfirst  ·  6Comments