Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Newspaper metaphor support #2657

Closed
rkrisztian opened this issue Oct 17, 2022 · 14 comments
Closed

Newspaper metaphor support #2657

rkrisztian opened this issue Oct 17, 2022 · 14 comments

Comments

@rkrisztian
Copy link

rkrisztian commented Oct 17, 2022

The newspaper metaphor (introduced by Robert C. Martin in his book Clean Code) is a useful concept that puts the highest-level code to the top, so it's easy to figure out the high-level goals of a module or class. Because you start reading at the top, which is what we usually do anyway. But if it starts with the implementation details, it's much harder, and I usually ask myself: why is this function needed, where is it going to be used? It's a constant struggle for me.

Your style guide never mentions the newspaper metaphor, which is somewhat incompatible with your view that "functions should not be used before they are defined":

Functions

[7.1](https://github.com/airbnb/javascript#functions--declarations) Use named function expressions instead of function declarations. eslint: [func-style](https://eslint.org/docs/rules/func-style)

    Why? Function declarations are hoisted, which means that it’s easy - too easy - to reference the function before it is defined in the file. This harms readability and maintainability.

Even the ESLint rule description fails to talk about the newspaper metaphor:

https://eslint.org/docs/latest/rules/func-style

But, the biggest problem is not hoisting, IMO. It's the use of var. When we only use const or let, the newspaper metaphor can be used most of the time:

const main = function() {
  lowerLevelFunc();
}

const lowerLevelFunc = function() {
}

// This would normally be the first line...
main();

Not perfect, sadly. The language limits us here. But that doesn't mean we should introduce a style guide that makes the situation even worse.

(Off topic, but I pretty much agree with this comment: #794 (comment) , i.e., not giving functions 2 names. If people can't keep their browsers updated, then they will inherit the security vulnerabilities too.)

Also, I would consider the use of arrow functions almost everywhere (i.e. function expressions), for the reason that this cannot be overridden by callers, which reduces mental complexity or any defensive code to be written. But the world does not always agree:

https://davidwalsh.name/i-dont-hate-arrow-functions

(In short: a function that looks like a variable assignment is confusing and not easy to read.)

Then, is it really worth standardizing the way we declare functions? For callbacks, sure, I agree, but for higher scopes, the picture isn't clear. It's more like a language design problem for which a straightforward solution cannot be given currently.

@ljharb
Copy link
Collaborator

ljharb commented Oct 17, 2022

The "newspaper metaphor" is not a good way to make readable code in a world of modules - nothing mentions it because it's not a valuable concept. If something's not important to read first, move it to another module instead of relying on hoisting.

I strongly suggest reading https://qntm.org/clean, as well.

@ljharb ljharb closed this as not planned Won't fix, can't repro, duplicate, stale Oct 17, 2022
@rkrisztian
Copy link
Author

@ljharb , I can be convinced, but not like this. You can't just say it's not a valuable concept" without telling why. That's not an argument, that's just your decision to disregard what I think makes readable code. I've spent a lot of time on the Internet learning about this metaphor, and the biggest problem is that people simply don't talk enough about it. So where is your reasoning?

The only thing you said is move implementation details to another module, but why? I agree that sometimes that is a good idea. But sometimes it makes overly fine-grained architecture:

  • Encapsulation thrown out of the window.
  • Too many small modules (too extreme).

Modules don't differ from classes much, conceptually. They share a lot of similarities. Just like they share the concept of low coupling, high cohesion.

My biggest issue is when people go for the extremes: totally disregarding a book, even if it has some good points; or throwing away certain practices completely because they can be misused. Somehow they keep forgetting it's not the kitchen knife that's evil. It's the people who use it to kill with it. If you ban the knife, how will you chop your cooking ingredients? With a "golden hammer"?

I'm going to read the article you linked, but I searched for the "newspaper metaphor" in it, and once again, the problem is rather I could find nearly nothing about it. (That doesn't mean it's a bad thing, just seemingly not popular enough.)

In the meantime: yes, Clean Code has problems, I noticed. It has the kind of problems that new editions would fix...

@ljharb
Copy link
Collaborator

ljharb commented Oct 17, 2022

Encapsulation is not thrown out of the window at all - encapsulation happens at the package, file, and scope levels.

Modules differ from classes by an extreme amount, conceptually - classes are bags of mutable state, and modules are not used that way.

Do you have any other reference for this pattern?

@ljharb
Copy link
Collaborator

ljharb commented Oct 17, 2022

Separately, "too many small modules" is both not really possible - you can't have too many - but also not too extreme. It's the best way to architect a codebase.

@rkrisztian
Copy link
Author

This convo is futile to me if you don't explain yourself well enough. I think you know more than you are willing to tell. But I can't believe you unless you do. If you can share some guides about this topic, feel free to link.

  • How isn't it possible to have too many modules if your argument is about creating enough so that the newspaper metaphor gets irrelevant?
  • If I understood it right, too many isn't really a problem in your opinion. How come? I think it's just as hard to maintain as many small functions in a single module. I think it's natural to happen that in a module some functions are closely related to each other. How does breaking up such a module and using other ways of categorization like packaging solve this problem in a maintainable way?
  • Modules can contain classes. I hope this is not an OOP vs FP flame war. I use both paradigms, not only one or the other.

Please note: I'm still looking for the big picture: why you don't think the newspaper metaphor has relevance in JavaScript. I'm not here to get dragged onto the less important tiny details (at least not too much). I know I'm not perfect, I will make mistakes, I may already have. Feel free to point them out, but at the end of the day, I want to understand your justification of closing this issue.

@rkrisztian
Copy link
Author

I've read the article you linked and I was wrong: it does talk about the newspaper metaphor, but it has weak arguments:

Many source files, I would even say most source files, cannot be neatly hierarchised in this way.

There won't always be a perfect ordering, but that doesn't mean we can't get close to it. For the Java language, IntelliJ IDEA can reorder dependent methods, and you can pick between breadth first or depth first. Not saying we should necessarily use this, but to me that's better than nothing.

And even for the ones which can, an IDE lets us trivially jump from function call to function implementation and back, the same way that we browse websites.

True, but not helpful when we're reviewing a code change, like in a pull request. Even on GitHub, we're not there at the same level of convenience.

@ljharb
Copy link
Collaborator

ljharb commented Oct 17, 2022

I don't think that using "an obsolete medium for transmitting news and capturing human attention via that medium's constraints" is a particularly useful metaphor for any aspect of programming.

You organize files with directories, and this works just fine whether you have one or a million.

Modern IDEs, and github as well, you can jump between files just as easily as within a single file.

Modules can contain classes

Of course they can, but the advantage is that they don't have to.

for the reason that this cannot be overridden by callers, which reduces mental complexity or any defensive code to be written.

A much simpler fix is to avoid use of this itself :-)


The overarching justification for closing this issue is that this style guide - which you're free to not follow - won't be incorporating this concept, nor changing its position on the decades-old best practice of avoiding relying on hoisting. I'm happy to keep trying to convey understanding, but there's no need for the issue to be open when there's nothing actionable to be done.

@rkrisztian
Copy link
Author

I think your guide is one of the best out there, seems very thoroughly thought out, even given explanations not just rules, so I do plan to follow, I just couldn't get my head around this one problem. Thanks for the explanations you gave so far.

@rkrisztian
Copy link
Author

rkrisztian commented Oct 19, 2022

Alright, I'm back to asking questions.

The overarching justification for closing this issue is...

That was really painful to read. Not because of the "won't" part, but because I just find zero information in "there's nothing actionable to be done." And I tried to be extra careful with how I formalize my sentences, still managed to trip up. I of course look for deeper stuff than that.

There's a huge problem with JavaScript right now, which is, we don't know how to write functions in general. There's no consensus:

  • Write regular functions because they are the easiest to read?
  • Write function expressions because they avoid the hoisting problem?
  • Write named function expressions because of browser compatibility?
  • Write arrow functions because of no binding of this?

None of them are perfect, it's like choose your "bad". Everyone has different opinions, and it's confusing for the developer.

So far I learned from you that you got the ultimate solution, but then, they also come with problems:

  • You say classes are bad. => Angular will disagree. Angular users will have to use them anyway. And there will be lots of this. At least React doesn't seem to have this problem, because React users have a choice to go functional. And most often they do. Sure, but choosing Angular is not necessarily wrong.
  • You say people still use old browsers. => Angular disagrees. And might as well say, use polyfills then, simple. No need to suffer from legacy.
  • Who needs the newspaper metaphor, just write small modules, and have more directories. => I'm going to refer to two sources here:
      1. "Modular programming can get a bit messy if [...] you’re passing data or functions around between too many files." (source)
      1. "one horse-sized JavaScript duck is faster than a hundred duck-sized JavaScript horses" (source)

So yes, you can avoid having to deal with function ordering, but then you introduce other problems. That's my real issue. It's that we can easily overdo modular programming. Then the ordering of functions can still matter.

Calling the newspaper "an obsolete medium" doesn't help. You still read news sites, right? They still organize content into titles, intro paragraphs, etc. So the basic idea is still there. LISP is the oldest functional language. You can call it obsolete. But functional programming still isn't dead.

@ljharb
Copy link
Collaborator

ljharb commented Oct 19, 2022

we don't know how to write functions in general.

I don't agree with this take at all. There's no problem here, and there's some overall consensus, and the answer shouldn't be "write all functions the same way".

  • Regular function are necessary when they're receiver-sensitive, or when you want an explicit name for debugging purposes or recursion.
  • this guide requires function expressions, but function declarations with the no-use-before-define eslint rule also avoid relying on hoisting, it's just that using declarations without the lint rule risks relying on hoisting.
  • arrow functions are meant to be used for inline callbacks, in particular when they need to refer to the outer receiver (the this value).

As for old browsers, polyfills cover API - and this guide assumes you're using https://npmjs.com/airbnb-js-shims - but not syntax. As for Angular, the link you provided in no way "disagrees", it's just that they choose not to support older browsers. Their docs make no claim as to what people use.

As for arguments about small modules and many files vs larger modules and fewer files, they are legion, and it wouldn't be productive to just list articles at each other until one of us gives up.

So yes, you can avoid having to deal with function ordering, but then you introduce other problems. That's my real issue. It's that we can easily overdo modular programming. Then the ordering of functions can still matter.

While I don't agree at all that it's easy to overdo it, the critical thing to realize here is that it's a much easier mistake to unmake. If you somehow "overdo" modular programming, it's trivial to combine things and make it less modular - but it's MUCH harder to separate things later. In other words, always prefer the mistake that's easier to unmake, and it's much easier to consolidate than to separate.

No, I don't read news sites, and haven't for decades, and I don't think we need to get into a debate about the objective decline of the news industry. I'm mostly saying that labeling a metaphor "newspaper" is as applicable to modern developers as it would to label something with "answering machine" or "floppy disk" or "telegraph" - the age of the web has busted many myths about newspapers, especially the "fold" metaphor, and I think this one applies as well.

Regardless, the consensus of the entire industry seems to be that they don't care enough about this concept to discuss it, and while that doesn't prove it's a bad concept, it dramatically reduces the likelihood that it's a good one. This style guide's purpose is to document what Airbnb does - so if current Airbnb engineers decide to make a change and notify me, I will dutifully update the guide, but short of that, I will be continuing to keep it aligned with the company's intentions as I understood them when I left in 2019.

@rkrisztian
Copy link
Author

it dramatically reduces the likelihood that it's a good one.

Sure, but it's just a likelihood. As such, not tangible for me. => It does not help.

I still don't believe in writing so small modules that they unnecessitate the newspaper metaphor. This is why I was looking for Internet sources that support or undermine the importance of newspaper metaphor. Or I'd like to see an example project where they actually work.

And we don't have to call it "the newspaper metaphor", it can be called the way IntelliJ IDEA does it: "reorder dependent methods". But its naming is not the problem. The problem is that you think a newspaper is too obsolete to be used in a metaphor. => Details that don't help the main problem.

Why does it happen that an IDE thinks it's useful to reorder methods in Java? After all, the very same tool that is supposed to alleviate the need to have a specific method ordering, just happens to adds this feature. One reason I can think of is that we still have to know what a class does, and we still start reading from the top. And we don't want to waste our energy on useless things like figuring out what a private method is used for, even if we got the help of the IDE. I still consider it a workaround to a bigger issue: why make me guess at all? Navigation is not everything. Let alone we still got review tools that don't support it, or at least not to the desired degree (yes, GitHub also being one of them, check a Pull Request, and see if you can navigate, I did test it, it did not work).

I'm still convinceable, still open minded, but it's gonna take more. Since I could not get that here, I'm planning to end this conversation as unsolved.

@ljharb
Copy link
Collaborator

ljharb commented Oct 24, 2022

I wouldn’t take any examples from Java as something worth following :-)

It’s not the job of this guide, me, nor anyone on the internet to convince you. It “most people follow it” doesn’t have sufficient weight on its own, then i doubt anything would ever actually change your mind, given that all of this is subjective anyways. Good luck!

@rkrisztian
Copy link
Author

This is yet another problem in the world: basing reasons on subjectivity, or thinking that I do so. If you look at what I wrote so far, I tried to be as objective with my reasoning as possible. Yes, I know that readability is also very subjective, so it's really hard to address it in an objective way. But if we don't even try then what's the point of style guides? We do them because we look for a common style that is familiar to everyone and also makes us more efficient by causing the least problems while reading and maintaining code. Getting there is always difficult. So yes, by all means, I'm still convinceable. And I will stop suggesting the newspaper metaphor once I know it is really unnecessary.

At the same time I understand that you have no interest in this whole topic, and you made it clear. It's the wrong place for that. Therefore, I will stop here.

@ljharb
Copy link
Collaborator

ljharb commented Oct 24, 2022

The point of style guides is to enforce largely subjective rules in an opinionated fashion. If it were objective, no guide would be needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants