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

Fix duplication of available bin commands (#1991) #2019

Merged
merged 5 commits into from
Nov 25, 2016
Merged

Fix duplication of available bin commands (#1991) #2019

merged 5 commits into from
Nov 25, 2016

Conversation

DenisGorbachev
Copy link
Contributor

Summary

This PR solves #1991.

Test plan

I've modified __tests__/commands/run.js to reflect the fixed behavior.

Also, I ran all test suites:

Test Suites: 1 skipped, 36 passed, 36 of 37 total
Tests:       18 skipped, 279 passed, 297 total
Snapshots:   50 passed, 50 total
Time:        28.826s
Ran all test suites.

Copy link
Contributor

@hpurmann hpurmann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd rather de-duplicate the bin folder paths of the available registries beforehand. This keeps the concerns better separated than doing this inside a for-loop. You could even move this into a small, well-named function then :)

@DenisGorbachev
Copy link
Contributor Author

I'd love to - however, there's no duplication of the paths inside each registry, so this check has to be done in a for-loop anyway. Or maybe I misunderstand the suggestion?

@hpurmann
Copy link
Contributor

Let me phrase it differently: I'd do a small loop to construct an array of paths which could be de-duplicated with something like uniq before running the actual loop. This would be one way to solve it in a slightly more functional programming approach (which I think yarn is using way too few).

@DenisGorbachev
Copy link
Contributor Author

Like this? a968fd0

@hpurmann
Copy link
Contributor

Yeah, I think this is better. You have to be careful though: lodash is not part of yarns dependencies (so it currently only works coincidentally). I'd add the package lodash.uniq separately to yarn.

I think moving the

for (const registry of Object.keys(registries)) {
...
}

loop into a well-named function which takes registries and gives back unique binFolders makes it a bit easier to reason about. I'm not the only one though, other opinions might differ 😉

@torifat
Copy link
Member

torifat commented Nov 24, 2016

@hpurmann I think previous approach was simple & clean.

@DenisGorbachev
Copy link
Contributor Author

@hpurmann @torifat how about applying the YAGNI principle and accepting the first approach (simple one)?

@hpurmann
Copy link
Contributor

hpurmann commented Nov 25, 2016

Sure, I'm fine with that too. I just think that the overall codebase could profit from a more functional style. But yeah, consistency-wise, the first solution fits perfectly ;)

@torifat
Copy link
Member

torifat commented Nov 25, 2016

@hpurmann How using two loops instead of one is more functional? Or, I'm missing something here?

@torifat
Copy link
Member

torifat commented Nov 25, 2016

I think here instead of Array we could have just use Set.

@DenisGorbachev
Copy link
Contributor Author

So let's keep it simple :) I've reverted the code back to original version. Could you please accept the PR?

@@ -31,13 +31,17 @@ export async function run(
const scripts = map();
const binCommands = [];
let pkgCommands = [];
let visitedBinFolders = [];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use const instead of let.

And, please run yarn lint before submitting a PR 😄

@torifat
Copy link
Member

torifat commented Nov 25, 2016

@DenisGorbachev Sorry to bother you for one last time. Can you please just use Set. Like in https://github.com/yarnpkg/yarn/blob/master/src/cli/commands/why.js#L113 It would be performant than checking with includes. Thanks for your patience ❤️

@DenisGorbachev
Copy link
Contributor Author

@torifat sure, changed to Set - let's make yarn faster! 🚀

@torifat torifat merged commit c3fb645 into yarnpkg:master Nov 25, 2016
@torifat
Copy link
Member

torifat commented Nov 25, 2016

Thanks for your contribution 😄

@DenisGorbachev
Copy link
Contributor Author

@torifat @hpurmann Thank you for feedback & merge :)

@hpurmann
Copy link
Contributor

hpurmann commented Nov 26, 2016

@torifat Even though this is merged already and discussions about programming styles might lead nowhere, I still want to explain my comment and answer yours.

How using two loops instead of one is more functional? Or, I'm missing something here?

Ok, functional programming might be a bit far-fetched. I want to keep concerns separated. I want to call well-named pure functions instead of mutating and accessing the same data structure on different lines. To give an example:

let visited = []
for (const registry of registries) {
  let path = getPath(registry)
  // Do stuff here
  if (!visited.contains(path)) {
    // Do stuff here
    visited.push(entry)
  }
}

There are three lines where we access visited. We added these, and the addition is simple. But when reading it afterwards, I have to keep track of this collection and what it could mean to the execution.

In constrast, the example below uses a function to first collect and return the registry entries (which would probably be using a loop internally). Afterwards, we remove the duplicates.

const availablePaths = getPathsfromRegistries(registries)
const uniquePaths = uniq(availablePaths)

uniquePaths.map((path) => {
  // Do stuff here
})

or even easier, by using flow:

const uniquePaths = flow(
  getPaths,
  uniq
)(registries)

When looking at the actual example, there is no need to iterate over registries anyway. It's only used to construct the paths.

@torifat
Copy link
Member

torifat commented Nov 26, 2016

@hpurmann I'm an advocate of this pattern. And, I use things like ramda, ramda-fantasy, data.task a lot. You can check this out: https://github.com/torifat/yarn-update/blob/master/index.js#L15-L34

Yeah, I think this is better. You have to be careful though: lodash is not part of yarns dependencies (so it currently only works coincidentally). I'd add the package lodash.uniq separately to yarn.

The example you have given in your last comment and the change (a968fd0) you said better are not same.

I also prefer using lots of small functions instead of nested loops and if/else. Check this: https://github.com/yarnpkg/yarn/blob/master/src/cli/commands/upgrade-interactive.js#L56-L116

I hope you get my point.

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

Successfully merging this pull request may close these issues.

3 participants