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

Refactor option handling #3889

Merged
merged 93 commits into from
Jan 21, 2020
Merged

Conversation

cbeams
Copy link
Contributor

@cbeams cbeams commented Jan 10, 2020

This is the fourth and final PR in a series. It should ideally be merged immediately after PRs #3886, #3887 and #3888, in that order.

Introduction

As detailed in commit 614035f, this change replaces BisqEnvironment with a new Config class that unifies, simplifies and otherwise improves Bisq's option handling in a number of ways. Please read that commit message first to get proper context and rationale.

Guidance for reviewers

Many of the commits in this PR represent the step-by-step, option-by-option migration from BisqEnvironment to Config. I recommend carefully reviewing at least several of these commits to understand what this migration means and how things work in the new infrastructure, but carefully reviewing every one of them is probably overkill. Please note that every commit in this PR should compile and run without errors.

How these changes were tested

The majority of commits (and certainly the final one) were subjected to a complete Gradle build cycle including all tests, followed by bringing up a localnet environment using the Makefile introduced in PR #3718, e.g.:

$ ./gradlew build && make clean-localnet deploy

Note that the Bisq instances launched by make deploy make use of many Bisq command line options. So ensuring that these nodes came up error-free was an important part of making sure that the migration was working at every step.

Testing was also performed on an ad-hoc basis against a non-localnet Bisq instance, ensuring that passing certain options works as expected, e.g.

$ bitcoind # start my local Bitcoin node
...
$ ./gradlew build && ./bisq-desktop --appDataDir=$(mktemp -d) --ignoreLocalBtcNode

The option being tested above is --ignoreLocalBtcNode, and passing a newly created temp directory to --appDataDir was a technique I commonly used to avoid any possible interference with my real production Bisq installation. In this case, I would verify that --ignoreLocalBtcNode worked as expected by ensuring the local Bitcoin node popup did not appear in the Bisq client and that the default approach of connecting to Bisq's Bitcoin node federation took place as expected. I did not test each and every option in this way; after making a number of such migrations, I got quite confident in the process. If a migration deviated from the typical process in some way, then I usually manually tested that change.

Refactorings not strictly related to option handling

  • Introduction of ConfigFileEditor to encapsulate the process of making automated updates to the bisq.properties config file. See commit 614035f.

  • Introduction of LocalBitcoinNode to encapsulate everything to do with detecting whether a local Bitcoin node is running. Of particular note here is the elimination of a dedicated thread for doing the actual detection. See commit 30bef16 for details.

Functional / user-facing / non-refactoring changes

  • From commit 614035f:

    Note that while this change and those that follow it are principally a
    refactoring effort, certain functional changes have been introduced. For
    example, Bisq now supports a --configFile argument at the command line
    that functions very similarly to Bitcoin Core's -conf option.

  • Commit 799eb12 renames the numConnectionForBtc option to numConnectionsForBtc.

Other notes

Please disregard the unrelated Kotlin, Git and gRPC proof of concept commits in this PR. They belong respectively to PRs #3886, #3887 and #3888 and will disappear here as each gets merged.

@cbeams cbeams requested review from ripcurlx and sqrrm as code owners January 10, 2020 21:11
@cbeams
Copy link
Contributor Author

cbeams commented Jan 10, 2020

My section headings for the description did not come through in the original PR submission. I've re-added them above, and they should improve readability.

@bisq-github-admin-1 bisq-github-admin-1 requested review from a team and removed request for a team January 15, 2020 18:13
Copy link
Contributor

@ripcurlx ripcurlx left a comment

Choose a reason for hiding this comment

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

NACK - I activated yesterday codacy's PR Quality Review for the Bisq repository. It found for your PR a couple of issues which you can view in the Details link next to the PR check. Please review and push fixes for this issues to trigger a re-review by codacy. Thanks!

@cbeams
Copy link
Contributor Author

cbeams commented Jan 17, 2020

I've just pushed fixes for the code quality issues, but a number of false positives will remain unfixed. Please see my commit comment for details. @ripcurlx, this may be an example of a PMD rule we want to eliminate. Would like to know why it's a false positive, though. Those imports are in fact used.

@cbeams cbeams requested a review from ripcurlx January 17, 2020 11:55
@cbeams
Copy link
Contributor Author

cbeams commented Jan 17, 2020

Also note that the BisqGrpcClient issues in the Codacy report are fixed in my latest commit against PR #3888, so they don't really apply here anymore.

@ripcurlx
Copy link
Contributor

I've just pushed fixes for the code quality issues, but a number of false positives will remain unfixed. Please see my commit comment for details. @ripcurlx, this may be an example of a PMD rule we want to eliminate. Would like to know why it's a false positive, though. Those imports are in fact used.

I just removed the unused on demand import pattern that seems to have caused the issue in the ConfigTests and I ignored the issues in BisqGrpcClient based on #3889 (comment).

@ripcurlx
Copy link
Contributor

So only a merge conflict resolution with WalletsSetup.java is missing to make this PR mergeable again.

@cbeams
Copy link
Contributor Author

cbeams commented Jan 17, 2020

So only a merge conflict resolution with WalletsSetup.java is missing to make this PR mergeable again.

Right, I've fixed that locally, and just talked with @ripcurlx about how we want to actually go ahead with the merge. No need to go into detail about it here, but anyone else who would like to review this PR, please do, thanks.

@ripcurlx
Copy link
Contributor

ripcurlx commented Jan 20, 2020

^^ Travis build (https://travis-ci.org/bisq-network/bisq/builds/635462277) I just triggered it manually and everything seems to compile fine. Not sure why it is not updated by GitHub.

Comment on lines 87 to 67
'io.opencensus:opencensus-api:8e2cb0f6391d8eb0a1bcd01e7748883f0033b1941754f4ed3f19d2c3e4276fc8',
'io.opencensus:opencensus-contrib-grpc-metrics:29fc79401082301542cab89d7054d2f0825f184492654c950020553ef4ff0ef8',
'io.opencensus:opencensus-contrib-http-util:d62fd27175a842bde135f6f6b1d6f25d42e9bd59a87bc98709a4760fe399ee14',
'io.perfmark:perfmark-api:b734ba2149712409a44eabdb799f64768578fee0defe1418bb108fe32ea43e1a',
Copy link
Contributor

Choose a reason for hiding this comment

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

@cbeams As we decided to be as restrictive as possible with new dependencies: Could you please point out why they are necessary (especially for the non-google libs)? Although they are required for the GRPC API I think it is good practice to have some documentation (even if it is just a comment in the PR) every time we add new dependencies to the project.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. Some of these and a number of other dependencies are removed in a commit that currently exists only in my fork's grpc-api branch. These changes were made as part of further refactorings of @chimp1984's original PoC, and it was an oversight that I didn't include them here. It will require some rework of that commit to do so, but is probably worth it to make sure we don't ship a release that includes these deps, even if they will be removed soon thereafter. I'll push that additional commit as soon as possible. Though note that I'll probably push it against the grpc-poc branch (PR #3888), as it's really part of that change as opposed to this one.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks! Really enjoyed the command line access already 👍

Copy link
Member

Choose a reason for hiding this comment

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

@cbeams agreed, makes most sense to push to #3888

If there are still new deps please leave a comment in that PR as to why they're reasonable to introduce. I think it will be worthwhile doing that going forward so we have some motivation to refer to.

result = paymentAccounts.toString();
break;
case "placeOffer":
// test input: placeOffer CNY BUY 750000000 true -0.2251 1000000 500000 0.12 5a972121-c30a-4b0e-b519-b17b63795d16
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT: 0.12 should be at least 0.15 otherwise the security deposit is too low for our current setup

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Please add this comment to #3888.

log.error(e.toString(), e);
}
break;
case "stopServer":
Copy link
Contributor

Choose a reason for hiding this comment

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

Somehow this command didn't work for me.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Please add this comment to #3888.

Copy link
Contributor

@ripcurlx ripcurlx left a comment

Choose a reason for hiding this comment

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

NACK - Because of #3889 (review)
ACK - For functionality and the remaining parts of the code 👍

Bildschirmfoto 2020-01-20 um 11 15 36
Bildschirmfoto 2020-01-20 um 11 10 16
Bildschirmfoto 2020-01-20 um 11 43 05
Bildschirmfoto 2020-01-20 um 11 31 36

@cbeams
Copy link
Contributor Author

cbeams commented Jan 20, 2020

@ripcurlx re: #3889 (review), this is also regarding #3888. To be clear, can you re-iterate that your ACK is for the changes specific to this PR, i.e. all things Config and related to option handling?

@ripcurlx
Copy link
Contributor

@ripcurlx re: #3889 (review), this is also regarding #3888. To be clear, can you re-iterate that your ACK is for the changes specific to this PR, i.e. all things Config and related to option handling?

Actually for both - So I read through all the changes regarding Config changes and it worked for my local setup. Regarding the remarks in #3888: I didn't run the code before, just reviewed the changes, so I checked this time the GRPC prototype in my local setup as well.

@cbeams
Copy link
Contributor Author

cbeams commented Jan 20, 2020

@ripcurlx, @sqrrm, please note that this PR needs to be reworked against the latest changes in #3888. I'm doing that now, will notify when complete.

Prior to this commit, BisqExecutable has been responsible for parsing
command line and config file options and BisqEnvironment has been
responsible for assigning default values to those options and providing
access to option values to callers throughout the codebase.

This approach has worked, but at considerable costs in complexity,
verbosity, and lack of any type-safety in option values. BisqEnvironment
is based on the Spring Framework's Environment abstraction, which
provides a great deal of flexibility in handling command line options,
environment variables, and more, but also operates on the assumption
that such inputs have String-based values.

After having this infrastructure in place for years now, it has become
evident that using Spring's Environment abstraction was both overkill
for what we needed and limited us from getting the kind of concision and
type saftey that we want. The Environment abstraction is by default
actually too flexible. For example, Bisq does not want or need to have
environment variables potentially overriding configuration file values,
as this increases our attack surface and makes our threat model more
complex. This is why we explicitly removed support for handling
environment variables quite some time ago.

The BisqEnvironment class has also organically evolved toward becoming a
kind of "God object", responsible for more than just option handling. It
is also, for example, responsible for tracking the status of the user's
local Bitcoin node, if any. It is also responsible for writing values to
the bisq.properties config file when certain ban filters arrive via the
p2p network. In the commits that follow, these unrelated functions will
be factored out appropriately in order to separate concerns.

As a solution to these problems, this commit begins the process of
eliminating BisqEnvironment in favor of a new, bespoke Config class
custom-tailored to Bisq's needs. Config removes the responsibility for
option parsing from BisqExecutable, and in the end provides "one-stop
shopping" for all option parsing and access needs.

The changes included in this commit represent a proof of concept for the
Config class, where handling of a number of options has been moved from
BisqEnvironment and BisqExecutable over to Config. Because the migration
is only partial, both Config and BisqEnvironment are injected
side-by-side into calling code that needs access to options. As the
migration is completed, BisqEnvironment will be removed entirely, and
only the Config object will remain.

An additional benefit of the elimination of BisqEnvironment is that it
will allow us to remove our dependency on the Spring Framework (with the
exception of the standalone pricenode application, which is Spring-based
by design).

Note that while this change and those that follow it are principally a
refactoring effort, certain functional changes have been introduced. For
example, Bisq now supports a `--configFile` argument at the command line
that functions very similarly to Bitcoin Core's `-conf` option.
Set OptionParser.allowsUnrecognizedOptions(true) to make sure
BisqEnvironment doesn't fail while options are still being transferred
one-by-one to Config.
NOTE: This removes entirely the old BisqExecutable.appDataDir method
implemented for the v0.5.3 hotfix that renames the data dir from 'bisq'
to 'Bisq'. See a7f3d68 for details.
cbeams added 15 commits January 20, 2020 16:46
This adds a few basic comments to help understand the structure of the
Config class and also reorders several assignments and statements for
clarity.
Prior to this commit, the way that the appDataDir and its subdirectories
were created was a haphazard process that worked but in a fragile and
non-obvious way. When Config was instantiated, an attempt to call
btcNetworkDir.mkdir() was made, but if appDataDir did not already exist,
this call would always fail because mkdir() does not create parent
directories. This problem was never detected, though, because the
KeyStorage class happened to call mkdirs() on its 'keys' subdirectory,
which, because of the plural mkdirs() call ended up creating the whole
${appDataDir}/${btcNetworkDir}/keys hierarchy. Other btcNetworkDir
subdirectories such as tor/ and db/ then benefited from the hierarchy
already existing when they attempted to call mkdir() for their own dirs.
So the whole arrangement worked only because KeyStorage happened to make
a mkdirs() call and because that code in KeyStorage happened to get
invoked before the code that managed the other subdirectories.

This change ensures that appDataDir and all its subdirectories are
created up front, such that they are guaranteed to exist by the time
they are injected into Storage, KeyStorage, WalletsSetup and TorSetup.
The hierarchy is unchanged, structured as it always has been:

    ${appDataDir}
    └── btc_mainnet
        ├── db
        ├── keys
        ├── wallet
        └── tor

Note that the tor/ subdirectory actually gets deleted and re-created
within the TorSetup infrastructure regardless of whether the directory
exists beforehand.
Previously this static property had been managed within
BaseCurrencyNetwork itself and was accessed directly by callers. Now it
is managed within Config, made private and accessed only via the
new and well-documented baseCurrencyNetwork() method. The same goes for
baseCurrencyNetworkParameters().

It is unfortunate that we must retain these mutable static fields and
accessors, but after trying to eliminate them entirely, this approach is
the lesser of two evils; attempting to use a Config instance and
instance methods only ends up being quite cumbersome to implement,
requiring Config to be injected into many more classes than it currently
is. Getting access to the BaseCurrencyNetwork is basically a special
case, and treating it specially as a static field is in the end the most
pragmatic approach.
See Javadoc added in this change and the previous commit message for
further detail and context.
This new class encapsulates all functionality related to detecting a
local Bitcoin node and reporting whether or not it was detected.
Previously this functionality was spread across the Config class
(formerly BisqEnvironment) with its mutable static
isLocalBitcoinNodeRunning property and the BisqSetup class with its
checkIfLocalHostNodeIsRunning method. All of this functionality now
lives within the LocalBitcoinNode class, an instance of which is wired
up via Guice and injected wherever necessary.

Note that the code for detecting whether the node is running has been
simplified, in that it is no longer wrapped in its own dedicated Thread.
There appears to be no performance benefit from doing so, and leaving it
in place would have made testing more difficult than necessary.

Several methods in BisqSetup have also been refactored to accept
callbacks indicating which step should be run next. This has the effect
of clarifying when the step2()-step5() methods will be called.
This method is used only by BisqExecutable and so has been moved there,
made private and documented accordingly.
This test is now named consintently and sorted next to other config file
tests.
This behavior had already been implemented prior to this commit, but has
now been tested and improved with refactoring and logging messages.

Note that this approach emulates Bitcoin Core's own behavior. When
running, for example, `bitcoind -conf=rel/path/to/bitcoin.conf`, the
relative path is prefixed / fully qualified by the value of the
`datadir` option. So if `datadir` equals `~/Library/Application
Support/Bitcoin`, then the `conf` option value above would be fully
qualified as

    ~/Library/Application Support/Bitcoin/rel/path/to/bitcoin.conf

If the argument to `-conf` is an absolute path, e.g.
`/tmp/bitcoin.conf`, then that absolute path is used without further
modification or qualification. It is assumed that the rationale for this
behavior is to avoid accidentally running against the wrong conf file
because `bitcoind` was invoked in a different directory than usual or
because a malicious actor replaced the relative conf file with their own
version.

Bisq's new `--configFile` option works (and is now tested to work) in
the same way: relative paths get prefixed by the value of
Config.getAppDataDir(), and absolute paths are processed unmodified.
Previously (as of the prior commit), a warning was issued if a
non-default config file path was specified at the command line, and then
the default config file path was used as a fallback. On review, however,
it would be better to halt execution immediately if the config file does
not exist. There is no risk of breaking backward compatibility by doing
this as Bisq never had a --configFile option before the recent commits
that introduce it. Furthermore, there is no clear benefit to the
fallback approach. If the user specifies a given config file and it does
not exist, they may not see the warning message in the log, and they may
be left with the impression that they are running against their custom
config file when in fact they are running against the default (which may
be empty or non-existent itself). Thus throwing an exception as is now
done in this commit should make everything more explicit and clear.
Previously ConfigTests constructed Config instances with string-based
options, e.g.:

    Config config = new Config("--appName=My-Bisq");

The advantage here is clarity, but the downside is repetition of the
option names without any reference to their corresponding Config.*
constants.

One solution to the problem would be to format the option strings using
constants declared in the Config class, e.g.:

    Config config = new Config(format("--%s=My-Bisq", APP_NAME));

but this is verbose, cumbersome to read and write and requires repeating
he '--' and '=' option syntax.

This commit introduces the Opt class and the opt() and configWithOpts()
methods to ConfigTests to make testing easier while using constant
references and preserving readability. e.g.:

    Config config = configWithOpts(opt(APP_NAME, "My-Bisq"));

In the process of making these changes a bug was discovered in the
monitor submodule's P2PNetworkLoad class and that has been fixed here as
well.

This change also required introducing several option name constants that
had not previously been extracted in order to be referenced within
ConfigTests. For consistency and completeness, all additional option
names that did not previously have a contstant now have one.
There is currently no explicit rule for how option-related elements are
ordered in the code, but it is important to understand that the order in
which options are registered via parser.accept() calls is the order in
which they appear in --help output.

It would be nice to group options together into sections and separate
them in the --help output with section headers similar to the way that
Bitcoin Core's help output does it, but this is not a built-in option
with the JOpt Simple library, and not worth trying to hack into place at
the moment.
See updated Config Javadoc for rationale.
Previously, Travis CI was failing non-deterministically due to a race
condition in which a thread was started in order to call the blocking
ServerSocket.accept() method, and sometimes the subsequent attempt by
LocalBitcoinNode.detectAndRun() to connect to that socket's port would
occur before the thread had actually called the accept() method.

This commit simplifies the approach by removing the thread entirely. As
it turns out, calling accept() is not necessary; simply constructing a
new ServerSocket() binds to and listens on the given port, such that a
subsequent attempt to connect() will succeed.
Per Codacy report at
https://app.codacy.com/gh/bisq-network/bisq/pullRequest?prid=4835062

Note that the items claiming that bisq.common.config.Config.* is an
unused import are false positives. These imports are in fact used in
every case.
@cbeams cbeams force-pushed the refactor-option-handling branch from 918c6c1 to dd5690f Compare January 20, 2020 15:53
@cbeams
Copy link
Contributor Author

cbeams commented Jan 20, 2020

I've just rebased this PR branch against current master which includes the merge for #3888.

@ripcurlx, your NACK has been addressed in #3888, which as mentioned above is now merged. Please re-review and ACK if you see fit. No substantive changes have been made; only those that were necessary to eliminate conflicts resulting from the rebase.

@sqrrm you should be good to go to review this now.

Copy link
Member

@sqrrm sqrrm left a comment

Choose a reason for hiding this comment

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

NACK

See comments on exception usage.

Comments on braces are not blocking but it would be good to address the multiline blocks.

Apart from those comments it looks ready to merge.

@sqrrm
Copy link
Member

sqrrm commented Jan 21, 2020

The exception issue is gone so no longer blocking, would still be good to address the braces.

@cbeams
Copy link
Contributor Author

cbeams commented Jan 21, 2020

@sqrrm wrote:

[it] would still be good to address the braces.

First some data:

Of 171 for loops in the codebase, 12 (7%) are written without braces:

~/dev/bisq[master]
$ git grep 'for (.*) {$' | wc -l
     171

~/dev/bisq[master]
$ git grep 'for (.*)$' | wc -l
      15

Note that 3 of the 15 above are actually aberrations in which the brace is on a newline (@wiz, I'm looking at you), so the total number is actually 12.

Of 3346 if statements in the codebase, 1796 (53%) are brace-free.

~/dev/bisq[master]
$ git grep 'if (.*) {$' | wc -l
    3346

~/dev/bisq[master]
$ git grep 'if (.*)$' | wc -l
    1796

As far as I am aware, we have not written down any rules on this. There is nothing in the bisq-network/style repository's issues, for example.

In the absence of any explicit rule, I would generally agree that one should fall back to the default rule to "follow convention" and thus the for loops should have braces added, and the if statements may be left as-is given that more than half of all such statements in the codebase already take this approach.

With that said, I'd like to argue for embracing braceless for loops under certain conditions on the grounds of elegance, aesthetics, readability and concision. Before we get there, though, consider the strong case for using braceless if statements in guard logic that you want to be as concise and readable as possible, e.g.:

public void myMethod(String arg) {
    if (arg == null)
        throw new IllegalArgumentException(...);

    // normal logic follows
}

To add braces around the guard logic is simply to add line noise. One wants the eye to flow over the guard logic, understanding it intuitively as guard logic, and to then get to the meat of the actual method. Adding braces makes it feel "heavier", subtly making the reader wonder whether there might be something there that requires more thought than: "this is just a null check".

I would argue the same for the for loops in question in this PR. While they do not represent guard logic, they have a clear and focused purpose, and the ability to write the loop without braces expresses the elemental nature of the logic within; that there is no fat, nothing extra, no side effects, just pure iteration, filtering and returning. For example here is such a for loop from CompositeOptionSet in this PR:

public boolean has(OptionSpec<?> option) {
    for (OptionSet optionSet : optionSets)
        if (optionSet.has(option))
            return true;

    return false;
}

I argue that nothing beneficial comes from adding braces here, and that doing so is to follow a convention blindly, purely for the sake of consistency, and at the cost of concision, readability and clarity.

Now let's consider a counterexample. The following is also taken from this PR in ConfigFileEditor#clearOption, lines 36-50:

for (String line : lines) {
    if (ConfigFileOption.isOption(line)) {
        ConfigFileOption existingOption = ConfigFileOption.parse(line);
        if (existingOption.name.equals(name)) {
            fileAlreadyContainsTargetOption = true;
            if (!existingOption.arg.equals(arg)) {
                ConfigFileOption newOption = new ConfigFileOption(name, arg);
                writer.println(newOption);
                log.warn("Overwrote existing config file option '{}' as '{}'", existingOption, newOption);
                continue;
            }
        }
    }
    writer.println(line);
}

// additional logic follows

It so happens that the way this is written, it would cause logic and/or compiler errors if any of these braces were left out, but consider if it had been written slightly differently and the author chose to eliminate braces wherever possible (note that this code is wrong and not functionally equivalent to the above; the changes I'm making are just for the purposes of illustration):

for (String line : lines)
    if (ConfigFileOption.isOption(line)) {
        ConfigFileOption existingOption = ConfigFileOption.parse(line);
        if (existingOption.name.equals(name)) {
            fileAlreadyContainsTargetOption = true;
            if (!existingOption.arg.equals(arg)) {
                ConfigFileOption newOption = new ConfigFileOption(name, arg);
                writer.println(newOption);
                log.warn("Overwrote existing config file option '{}' as '{}'", existingOption, newOption);
            }
            else
                writer.println(line);                
        }
    }

// additional logic follows

In the latter example above, the author has omitted braces from the for loop and from the else statement, while all other required braces remain in place. This is the kind of madness we are trying to avoid when we make rules about using braces. In a complex block of logic like the above, selectively omitting braces makes the whole construction much harder to read and reason about. Frankly, I wouldn't want anyone who thinks this is a good idea to be committing to the Bisq codebase. Nor do I want to prevent any such possibility of this by decreeing an (IMO) dumbed-down style rule like "always use braces". The real rule here is something more like "use braceless loops and conditionals judiciously", where your judgement demonstrates you know the difference between the good and bad examples above. If you don't it's a red flag about your coding skill and no overly strict set of style rules is going to save you.

So: lest this become a bikeshed session, I propose we leave the braceless for loops as-in in this PR on the merit of the arguments above, and that if strong opinions otherwise present themselves, that we take it to Keybase, a bisq-network/style discussion or similar. In any case, I am happy to write a style rule (shorter than the text above) titled something like "Use braceless loops and conditionals judiciously" in order to make our guidelines about this clear. If the conversation continues and we end up at a rough consensus that says we should in fact always use braces in for loops, I'll come back and revise this code accordingly. I'd appreciate not holding up the merge on it in the meantime, though.

@sqrrm
Copy link
Member

sqrrm commented Jan 21, 2020

I agree that the guard ifs are better without braces, but I don't agree on the for loops.

Since there is some contention here, and I was following a discussion I had with Manfred a while back on using braces I'll ack this one. I also don't think it's important enough to even discuss too much. Let's move on and make sure we avoid cases like your horrible example.

Copy link
Member

@sqrrm sqrrm left a comment

Choose a reason for hiding this comment

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

utACK

@sqrrm sqrrm merged commit d4e566f into bisq-network:master Jan 21, 2020
@wiz
Copy link
Contributor

wiz commented Jan 21, 2020

Note that 3 of the 15 above are actually aberrations in which the brace is on a newline (@wiz, I'm looking at you), so the total number is actually 12.

Guilty as charged. Would like me to do a PR to fix that?

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.

4 participants