AiC: Adventures in consensus

I just posted the first post of what I expect to be an “irregular series” of posts, entitled Adventures in consensus:

In the talk I gave at Rust LATAM, I said that the Rust project has always emphasized finding the best solution, rather than winning the argument. I think this is one of our deepest values. It’s also one of the hardest for us to uphold.

Let’s face it – when you’re having a conversation, it’s easy to get attached to specific proposals. It’s easy to have those proposals change from “Option A” vs “Option B” to “my option” and “their option”. Once this happens, it can be very hard to let them “win” – even if you know that both options are quite reasonable.

This is a problem I’ve been thinking a lot about lately. So I wanted to start an irregular series of blog posts entitled “Adventures in consensus”, or AiC for short. These posts are my way of exploring the topic, and hopefully getting some feedback from all of you while I’m at it.

This thread is a place to collect feedback for this post and future posts (I’ll update with links as they are posted).

Post links

26 Likes

Worse, I think the current process often starts with a particular solution . This encourages people to react to that solution .

I think this is key; and I think it would be worth splitting the RFCs in two documents:

  • A problem document, meant to explore the problem space: core issue, linked issues, usecases, stakeholders, assumptions which may have to be challenged…
  • Multiple “solution” documents, meant to explore the solution space: attacking the problem, identifying the trade-offs of the particular solution.

I think it may also be worth enriching the problem document with some sort of weighted objectives, but I am somewhat wary about it muddying the waters and starting looking like the embryo of a solution.

And I should also specify that I do not think this should be a waterfall; I’d expect all documents to evolve concurrently, with explorations of the solution space leading to realizations about the problem space, and to challenging assumptions that were made.

The idea behind the split, instead, is two-fold:

  • It cleanly separates the discussion space between problem and potential solutions.
  • It makes it easier to explore multiple solutions in parallel, by having a central place (the problem) linking all alternatives.

The latter is particularly powerful for archiving purposes, whether to document the living process of shaping Rust, understanding how certain decisions came to be and possibly challenging some, or to come back to a problem that was tabled for lack of time/resources later.

As a side effect, I think it also lightens the RFC process a bit: now, the start is posting a problem, not a solution, which the community will help shaping up. It seems like this would help avoid the bitter feeling of having poured a lot of work into a potential solution only to have it tabled or torn to pieces.

And ironically, I am here presenting a potential solution before even defining the problem in detail.

8 Likes

Bryan Cantrill has given a couple of talks on software as a reflection of values (here’s one that includes Rust). The premise is that a piece of software is a manifestation of the values that its creators and its users care deeply about, and are ready to put above the values that are espoused by other projects or people. Values are in tension (e.g., it’s hard to have a system with that is both approachable for beginners and powerful for experienced users), and if a project and a person share no common value, it’s pretty clear that the person won’t want to use that particular software.

So what are the values of Rust? Safety, performance, and expressivity are three that come to mind; are there others? (Cantrill identifies quite a few more.) I think that the community should think about this question and write down somewhere—ideally in big bold letters—the values of Rust. Then, when a proposal comes along, software as a reflection of values can be an evaluation criteria that is used in addition to the ones proposed by Niko. Where software as a reflection of value would particularly shine (I think) is when a proposal (a) is in line with the values of Rust, but (b) is in conflict with one or many values of a participant.

Let’s look at an example, async. Async makes it easier to write fast systems software without compromising safety, what’s not to like? Well, those improvements come at the expense of simplicity; though async is an embodiment of the Rust values (at least, the ones I identified above), it might conflict with the values of a participant. When this happens, the participant may want to push back against the proposal, but not for technical reasons: for moral reasons. But if that participant can realize that async is in line with the values of Rust, they may decide to put their unease aside and contribute to discussing the technical merits of the proposal.

9 Likes

I have a talk at QCon London based on Brian’s framing here, with my personal views about what Rust values. I don’t think the video is out yet though! I think it’s a fantastic way to think about things.

5 Likes

I think that RFC discussions could be better structured, so that the same arguments aren’t repeated over and over.

Maybe we should consider other platforms that are better suited to reaching consensus. GitHub Issues and message threads don’t scale well with hundreds of contributors. For example, I heard good things about pol.is.

1 Like

I posted something new =)

1 Like

I think there’s something here. RFCs can be big, monolithic documents, which can make them daunting to read and, for many people, actually writing one seems like an impossible task. So we end up with one RFC that proposes a solution, with a ton of comments that no one has time to read. Sometimes a new RFC is written with a different proposal, but this happens infrequently. Maybe splitting up RFCs into problem and multiple solution documents could help make those giant comment threads smaller, by splitting them up across different pull requests, and by giving people an outlet to propose and discuss their own solution in a new PR rather than in the comments on the single main PR.

I agree with the sentiments that we can improve the process by improving how we handle the different steps of the process, adding more smaller incremental steps, each with discussions at its appropriate level, allowing concurrent discussions, etc.

But one thing I want to call out is that the more we do this, the more we should IMO be thinking about how to summarize each of these discussions and merge them in a cohesive way somewhere, such that ideally people just read that, and are able to jump into the discussions without, e.g., repeating arguments.

I think we are currently failing hard at this.

For example, @matthieum called out that one monolithic document might not be a great idea, but I want to argue that currently we don’t even have that.

I was recently scouting for rationale from RFCs for the UCGs new inline rationale sections, and the current process requires a full-time an internet archeologist for that. The search must include:

  • internals post, rust-lang/rust/issues, rust-lang/rfcs/issues
  • previos closed RFCs
  • pre-RFCs
  • RFCs Rationale section: which often only contains rationale about why the alternatives were not picked, but the rationale about why was the merged solution picked is scattered
  • RFC Motivation / other sections for rationale
  • RFC thread for both arguments / inline discussions that were never updated to the rationale, and summary comments, which are never merged into the RFC rationale, as well as raised concerns by team members, etc which often result in changes to the RFC
  • Tracking issue, and summary comments there
  • Stabilization PRs, summary comments there
  • Bug reports for the feature, breaking changes, fixes, reverts, …

Most of what happens there is not summarized, and if it is, the summary does not land anywhere, and if it would, chances are that it would be changed later.

I think that a single source of information for a language feature that’s kept in sync would already be an improvement, even if it ends up being a huge document. Having multiple documents, more threads of discussions at different levels for the different stages, etc. would then be an improvement over that, but gathering, filtering, and sync’ing the relevant information, might end up being more work and we should keep that in mind.

6 Likes

There’s a new post in this series:

http://smallcultfollowing.com/babysteps/blog/2019/07/10/aic-unbounded-queues-and-lang-design/

It reminded me a lot of the first section of my Rust 2018 post:

https://dirkjan.ochtman.nl/writing/2018/01/14/rust-in-2018.html

2 Likes

Thanks for bringing that up! Re-reading again I definitely found myself nodding along a fair bit. I never did read the epic treatise on bug triage that you cited, I’ve added that to my queue.

It comes highly recommended. I am dealing with exactly that kind of “unused inventory” problem at the moment. The public & private dependencies RFC was accepted and languished for … a long time. In the meantime several other changes make the RFC no longer completely designed. Those other changes should have included an explanation of how they interact with this RFC, but I don’t blame them for not looking through all the languished RFCs to see “if this was ever implemented would this change still work”.

3 Likes

I think you captured the core tradeoff (focus vs. serendipity) & most meaningful constraint (reviewer bandwidth) very well, and at least intuitively I agree with both of them!

one of the things we’re going to have to figure out is how to draw good boundaries so that we can push out a useful subset of a feature (an “MVP”, if you will) and then leave the rest for later

I’m sure you’ve also thought about this, and the post was just nuanced enough as it is, but - although this is very possibly the least-bad approach - it also has tradeoffs and hazards. The failure mode here is that in terms of the end-user experience, the language ends up feeling like it’s full of jagged edges, with users frequently running into errors or limitations whenever they stray from the “happy path” of the design, and, upon asking about it, learn “yeah, a solution to that was discussed on the RFC repo at some point”. Since it helps to have a memorable term, I like to think of this failure mode as “Procrustean design”.

A specific (hypothetical but plausible!) dynamic which could exacerbate this: a given feature X is considered a high priority, so by extension, the MVP of X is also a high priority, but once X is shipped, the chopped-off pieces no longer qualify as particularly urgent, and languish.

(Of course, “whole features” usually don’t have clear & simple boundaries, so in some sense this is all subsumed by your suggestion that we need to find “good boundaries”.)

1 Like

I have indeed thought about this. I was talking to @wycats about this recently and he elaborated a useful rule of thumb: it often makes sense to try and reach the “80-20” point (point of diminishing returns, etc) as quickly as you can, but that once you think you’ve reached that point, we should try to avoid piecemeal extensions and instead tackle the problem holistically. I think that impl Trait is a good example of a feature that reached its 80-20 point, and where we should aim to put the whole picture together at this point (which reminds me that I still want to try and pull more of that together).

2 Likes