-
Notifications
You must be signed in to change notification settings - Fork 999
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
docs/coding-guidelines: Add document #2780
Conversation
Add document outlining a set of coding guidelines followed and to be followed across the rust-libp2p code base.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent document, lots of good knowledge here :)
Left some comments and ignored typos for now, we can deal with those once we settle on the content.
If you sqint, rust-libp2p is just a big hierarchy of [state | ||
machines](https://en.wikipedia.org/wiki/Finite-state_machine) where parents pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally, I am a fan of using a "one-line per sentence" rule for version-controlled markdown documents.
Git works on a line-by-line basis and sentences in natural language tend to change as a whole too. Using one sentence per line makes it really easy to use GitHub's suggestions to collaborate on documents like this and diffs are more meaningful too.
Just an idea :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But I have to admit I am also in the "use an editor with word wrap enabled"-camp :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mxinden Any comment on this? We don't have to resolve it here. Should I open a separate discussion?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like this, correct @thomaseizinger? mxinden@ecf86c8
With GitHubs diff highlighting showing what within a line has changed, I don't think there is a great benefit for it. As a downside, I think it adds complexity, e.g. having to explain this to newcomers.
Just an idea :)
I don't feel strongly about it. It seems like you don't feel strongly about it either. Thus I will proceed without the change.
That said, feel free to propose a new pull request with the commit above.
But I have to admit I am also in the "use an editor with word wrap enabled"-camp :D
Same here. I even stopped truncating my emails to 80 characters 🤯
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I get to choose, I'd pick one sentence per line.
We don't have to enforce it though (I am yet to find a tool that reliably does).
Are you happy with doing it on a personal preference basis?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you happy with doing it on a personal preference basis?
For markdown files on rust-libp2p? Yes, that is fine by me.
docs/coding-guidelines.md
Outdated
match self.child_2.poll(cx) { | ||
// As above. | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is important to mention that using continue in here will go back to child1 which could make progress again.
There is a subtle difference between looping over the entire thing and exhausting each child until it returns Pending. We want the former, not the latter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, though not sure how to put it into words.
There is this line already:
// or `continue`, thus polling `child_1` again. `child_1` can potentially make more progress:
continue
Could you make a suggestion @thomaseizinger ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest to just fill in the match
here too and make a comment next to the continue
of the Poll::Pending
branch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest to just fill in the
match
here too
As in the same as the above? What would be the benefit of that? Isn't that just duplicating the same comments once more?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't duplicate the entire explanation but perhaps have a complete example of the control flow and make one comment at the bottom that highlights that we always continue
to go back to the top. Even though it should be clear from the written text, I find that seeing the entire control flow is better.
Maybe also build in the case where the event from child2
is dispatched to child1
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added ed4d633. Let me know what you think.
When using channels (e.g. `futures::channel::mpsc` or `std::sync::mpsc`) | ||
always use the bounded variant, never use the unbounded variant. When using a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use clippy's mechanism of banning these functions!
https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea. Though I am failing to have clippy pick up my Clippy.toml
when I save it in the root of the repository.
disallowed-methods = [
{ path = "futures::sync::mpsc::channel", reason = "does not enforce backpressure" },
]
@thomaseizinger does this work for you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It reliably works for me after a cargo clean
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will be introduced with #2823.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
docs/coding-guidelines.md
Outdated
Using hierarchical state machines is a deliberate choice throughout the | ||
rust-libp2p code base. It makes reasoning about control and data flow easy and | ||
works well with Rust's `Future` model. The archetecture pattern of | ||
hierarchical state machines should be used wherever possible. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there downsides to this design? If so, should we list them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my experience, the main downsides are:
- It feels more verbose but I think it is not actually in reality when you would compare two solutions side by side.
- The mix of control flow (
loop
,return
,break
,continue
) inpoll
functions together with the asynchronous and thus decoupled communication via events can be very hard to understand.
Both are a form of complexity that we are trading for correctness and performance which seems typical in Rust land.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I documented the above in 0ef322a. @thomaseizinger I really liked your wording which I mostly adopted. Hope you don't mind.
@melekes in case you can think of other downsides, please comment and let's get them included in the discussion and the document.
docs/coding-guidelines.md
Outdated
|
||
// The child did not make progress. It has registered the waker for a | ||
// later wake up. Proceed with the other childs. | ||
Poll::Ready(_) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Poll::Ready(_) => { | |
Poll::Pending => { |
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙏 2b40afa
This blogpost might also go onto a further reading list: https://sans-io.readthedocs.io/how-to-sans-io.html |
I am a great fan of this coding style. It makes testing so easy. That said, I don't think we apply this coding style anywhere within the rust-libp2p code-base. E.g. a |
…oding-guidelines
Well, it does apply to some degree. |
…oding-guidelines
# Coding Guidelines | ||
|
||
<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc --> | ||
**Table of Contents** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neat. Though as you say, quite hidden. I suggest we keep the additional ToC, though that is not a strong opinion.
machines](https://en.wikipedia.org/wiki/Finite-state_machine) where parents pass | ||
events down to their children and children pass events up to their parents. | ||
|
||
![Architecture](architecture.svg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of embedding the file, you could reference it planttext.com: https://www.planttext.com/api/plantuml/svg/SoWkIImgAStDuL80Wk3onA9S1PiQNLs5eFpy4gVKZCIopFpI8dH9v_oylDJaaipyl83yV0oj8KM9USK5-KKbO0aKWo0A0ZBpqb7DngB8CoKrhoGphPAWGk_4bDJSdCn4RAwrKYZ8pydHqCIY5qKArKEeSd3le0gZU09L2iFfgD8O3aP8EwJcfG0Z0m00
The same token also works as an "edit" link: https://www.planttext.com/?text=SoWkIImgAStDuL80Wk3onA9S1PiQNLs5eFpy4gVKZCIopFpI8dH9v_oylDJaaipyl83yV0oj8KM9USK5-KKbO0aKWo0A0ZBpqb7DngB8CoKrhoGphPAWGk_4bDJSdCn4RAwrKYZ8pydHqCIY5qKArKEeSd3le0gZU09L2iFfgD8O3aP8EwJcfG0Z0m00
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not familiar with planttext. Is it a service we can rely on? What if they prune their database?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been using it for years without issues.
There is no database, I am pretty sure the diagram source code is embedded in the URL in some form of encoding.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That makes sense. I would argue though that there is benefit in being able to access the diagram and thus read the document without internet access.
If you sqint, rust-libp2p is just a big hierarchy of [state | ||
machines](https://en.wikipedia.org/wiki/Finite-state_machine) where parents pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mxinden Any comment on this? We don't have to resolve it here. Should I open a separate discussion?
Co-authored-by: Thomas Eizinger <[email protected]>
When using channels (e.g. `futures::channel::mpsc` or `std::sync::mpsc`) always use the bounded variant, never use the unbounded variant. When using a bounded channel, a slow consumer eventually slows down a fast producer once the channel bound is reached, ideally granting the slow consumer more system resources e.g. CPU time, keeping queues small and thus latencies low. When using an unbounded channel a fast producer continues being a fast producer, growing the channel buffer indefinitely, increasing latency until the illusion of unboundedness breaks and the system runs out of memory. One may use an unbounded channel if one enforces backpressure through an out-of-band mechanism, e.g. the consumer granting the producer send-tokens through a side-channel. See also libp2p#2780 (comment)
When using channels (e.g. `futures::channel::mpsc` or `std::sync::mpsc`) always use the bounded variant, never use the unbounded variant. When using a bounded channel, a slow consumer eventually slows down a fast producer once the channel bound is reached, ideally granting the slow consumer more system resources e.g. CPU time, keeping queues small and thus latencies low. When using an unbounded channel a fast producer continues being a fast producer, growing the channel buffer indefinitely, increasing latency until the illusion of unboundedness breaks and the system runs out of memory. One may use an unbounded channel if one enforces backpressure through an out-of-band mechanism, e.g. the consumer granting the producer send-tokens through a side-channel. See also libp2p#2780 (comment)
Description
Add document outlining a set of coding guidelines followed and to be followed across the rust-libp2p code base.
My goal is not to impose these guidelines onto anyone, nor to be dogmatic about them. Instead I would like to discuss their value, eventually establishing a shared mindset, helping newcomers getting started faster.
For now, this is a draft only. Lots of the wording still need polishing. Suggestions / feedback / disagreement is welcome anytime.
Links to any relevant issues
This might be a helpful resource for discussions like #2622 (comment) in the future.
Open Questions
Change checklist