See a typo? Have a suggestion? Edit this page on Github
In yesterday’s blog post, I (lovingly) attacked a few things about Haskell. My goal was pretty explicit: I wanted to educate. I was hoping that by announcing some of these language warts loudly, people could avoid some footguns, and their Haskell experience would be more pleasant. This would lead to more Haskell success, which IMO is a Very Good Thing.
I can tell you all that not once did the thought cross my mind that I should try to get any of these issues resolved. Maybe that’s because I spend a lot more time educating these days. The reason doesn’t really matter.
The really exciting thing, though, is that I almost immediately found out that one of the warts I mentioned will hopefully soon be fixed:
That's the moment where I am pleased to announce that I have started a proposal to fix sum and product in base:— Ἑκάτη (@TechnoEmpress) October 28, 2020
And a merge request is in the works to implement it : https://t.co/W7Ua4XfXwd
Hope this addresses some of your concerns, @snoyberg :) https://t.co/ujere27Bzi
This is wonderful news, and I’m happy to hear it. In the ensuing discussion, there were some comments directed at me indicating that there is some desire to make changes like this more approachable. This isn’t the first I’m hearing of this. Over the past few months, I’ve had a few discussions with Haskell community members. I wish these discussions were more public and accessible, but we’ll get to that.
I truly believe people are trying to improve Haskell community processes right now. I’ve shared some thoughts with people to help encourage them towards what I think are vital improvements to make Haskell a better language, a better ecosystem, and a better community. Now that these conversations are (thankfully) beginning to happen more openly, I’d like to put some of my thoughts down in writing here.
The notes below turned out to be something of a stream-of-consciousness brain dump. There’s no particular order or priority. Also, one final thing. I’m making aspirational statements below. I certainly try to achieve these goals. I don’t always succeed. My failings as an individual and a maintainer do not preclude that correctness of my points below.
What is transparency?
Before diving into my points, I want to clarify what I consider transparency. It’s not simply about an existence proof that a sufficiently dedicated person could discover information. It’s the property that a reasonably interested person can easily find out information about a project. But it’s more than that. Simply having introspection is the first step. Understanding how things work, how to contribute, how to influence, and how to disagree are vital too. A truly transparent project, in my definition, provides an easy onramp for new and interested parties to come up to speed on current status, see the inner workings of current members, volunteer to be “part of the team,” and constructively argue for a new direction.
OK, that’s it for my definition. You can disagree with that definition, but hopefully you can now understand better my concrete points below.
Do you like mailing lists? Twitter? Reddit? Blog posts? RSS feeds? Slack? Discourse? Discord? Gitter? Keybase? Zoom?
I’m willing to bet no one in the world is going to answer yes to all of these.
An open, transparent community needs to advertise information. And it needs to do this in multiple media. A simple example of this is:
- Write a blog post
- In the blog post, reference a dedicated discussion point (comments section, a GitHub issue, a Slack channel, etc.)
- Reference it from an index page on a Wiki or website
- Personally, I think wikis are a waste of time
- Publish an RSS feed from that blog
- Provide a “subscribe via email” feature on that RSS feed
- Post the blog on Twitter, LinkedIn, Facebook, and Reddit
- Monitor feedback on multiple venues, and if worthy, write a follow up blog post to provide updates/clarify points, since not everyone will see a Reddit comment you make
- As an example: this blog post is exactly that
It takes a bit more effort to do all of this. But it’s completely worth it.
Almost as a counterpoint to the above: information needs to be centralized too. It’s great to have a Reddit thread where 23 comments deep someone finally explained something. But having that comment’s content and permalink put on the project’s main website or the
README.md of its GitHub repo is vital. Information discovery is difficult. If something is important, make it available centrally. And then, if relevant, advertise the presence of that information broadly, using the techniques above.
Appropriate signal to noise ratio
In the beginning of Hitchhiker’s Guide to the Galaxy, Arthur Dent discovers that, for months, there have been plans to demolish his house sitting in the basement of the planning office. He’s told he needs to take initiative to be involved in government to know about these kinds of things. Ultimately, some galactic aliens pull the same thing on us Earthlings and blow us up. (Oh, sorry, spoiler alert.)
Being told “but there was a GitHub issue 5 months ago that proposed this” is the same thing. Burying high priority information in the middle of a highly active channel (issue tracker, active mailing list, etc.) obscures things.
It’s not always obvious when a change is something that warrants a heavy signal. Mistakes will happen. Sometimes you’ll overshare. But much worse is undersharing. Examples:
BREAKING! Super super important! Everyone needs to know that we changed which hue of purple we used for our logo!!!!1111oneoneoneeleventyone
Yeah, of course we removed the
+operator from the language. We thought it wasn’t important. Didn’t you see the 17th comment on the issue discussing the new color scheme for the website?
Try to identify what people will consider a major change versus a minor change. If you’re not sure, ask. And if something will be a major change for some and minor for others: create multiple distribution channels. Not everyone in the Haskell community will consider a breaking change to Yesod a big deal. But Yesod users will. That’s why we have a dedicated Yesod blog and mailing list.
Canvass people directly
People are busy. People are lazy. People are socially awkward. People are unsure if their opinions are valuable. People are unsure if their opinions are welcome.
It is insufficient to put a message on a mailing list and ask for feedback. Even if you go through the steps above, you’re going to miss people.
When I’ve made major changes, I’ve tried (and sometimes failed) to reach out privately to affected parties and get their feedback. It’s vital.
Somewhat redundant with the above, but worth pointing out. Use technology that notifies people instead of requiring people to seek out information. “We updated a Wiki page, didn’t you go and check it out again in the past three months?” isn’t great. People are busy, and they forget things. A push model, rather than pull, is preferable.
Include outsiders. It’s too easy to reach for the input of the ingroup and your friends and end up creating a bubble. It’s almost impossible to detect that you’ve done this.
Strive to include people who think differently than you. Strive to include people who disagree with you. At least within reason. Which brings us to the next point…
Be upfront about your goals. Tying it back to the previous point: let’s say I’m trying to make Yesod a more open, transparent, and inclusive project. I personally am a strong believer in server-generated HTML for user interaction. But my goal for Yesod is to support Single Page Applications (SPAs) as well. Knowing this, it’s important for me to make sure that there are Yesod contributors and advisers who believe SPAs are important.
On the other hand, continuing with outsiders: we don’t need to go beyond the goals of the project. I don’t need to find a Go developer to advise on how Yesod can be better. Go is not part of the goals of Yesod. It’s OK that Yesod fails to meet the goals of a Gopher. They can, and should, and have, create their own web framework. And the two can live in harmony, possibly with competition between the two projects trying to win the ideological and technical battle of “which set of goals is better.”
My go-to example for this is Stackage. Stackage is incredibly clear about its goals. We want to build Haskell packages. Haskell packages are defined as using the Cabal format. We want to build snapshots of packages that build together. We want to make the process of contribution as lightweight as possible. We want to make it possible for end users to consume these snapshots and get more reliable builds.
There are other details, but that basically sums it up. Based on that, you can decide if this is a project you want to be a part of, contribute to, and use. Are you a Rubyist? This probably isn’t for you. Do you want to exclusively use dependency solving and provide no support for snapshots? More power to you, you do you. Do you write Haskell code, publish it on Hackage, and want to get notified if your package stops compiling with new dependencies or has restrictive upper bounds? Bingo.
Poorly defined goals have, in my opinion, been one of the central problems in the Haskell community. Furthermore, evolving goals have been worse. Goals of course need to evolve over time. But the fact that goals change implicitly instead of explicitly is a huge problem.
If you’re going to make a fundamental shift to the goals of a project, especially a project in massive use by many people, and especially if you know those people disagree with the new goals: you need to have a very open conversation about this. I’d probably go further and say that you basically can’t change the goals in this way. Rather, a subproject would make more sense.
And if you’re paying attention: that’s basically what Stackage is. Hackage’s starting goal was about an open source repository of Haskell code. It said nothing about snapshots. Forcing people uploading to Hackage to suddenly adopt a new goal would be inappropriate. Instead, a second project—clearly deriving from and depending upon the original project—was the right move here.
Be clear about what the various parts of the project are. Be clear about how decisions are made. Be clear about how members are chosen. Be clear about what responsibilities and authorities those members have. Be clear about how someone goes about trying to make changes.
Ask for help
People want projects to succeed. I can all but guarantee you that anyone who calls themselves a “Haskeller” wants the Haskell language to be successful (however they define success). People are also busy, and lazy, and distracted, and lack confidence, and lots of other things that will prevent them from participating. You won’t be able to overcome all of that. But there are some blockers you can fix:
- I want the project to succeed, but I don’t know what needs to be done
- I know what we overall need to do, but I don’t know how to do it
- I don’t know who I should speak with to volunteer
Reach out to people for help! Put out blog posts (and advertise them) calling for contributors. Give information on what needs to be done. Reach out to people individually that you think would be a good fit.
People may ignore the posts. People may say no to a direct invite. But you won’t know if you don’t ask. And even if someone says no, knowing that they were wanted in a project is wonderfully inclusive.
- The Haskell Foundation December 2, 2020
- Haskell: The Bad Parts, part 2 November 9, 2020
- Transparency October 29, 2020
- Haskell: The Bad Parts, part 1 October 28, 2020
- Force your code to break October 8, 2020
- Homeschool on PowerPoint September 11, 2020
- Stackage for Rust? August 17, 2020
- Book review: Loserthink August 10, 2020
- New book available: Begin Rust June 8, 2020
- There are no mutable parameters in Rust May 10, 2020
- A Lazy Rust Compiler April Fools', 2020
- Basics of Carbohydrates March 27, 2020
- Making nutrition decisions February 25, 2020
- The Warp Executable January 20, 2020
- Tokio 0.2 - Rust Crash Course lesson 9 December 5, 2019
- Down and dirty with Future - Rust Crash Course lesson 8 December 2, 2019
- Boring Haskell Manifesto November 21, 2019
- Haskell kata: withTryFileLock August 18, 2019
- How to lose weight July 15, 2019
- My new home network setup June 26, 2019
- Gym Etiquette Test April Fools', 2019
- Typing Resistance April Fools', 2019
- Shutting down haskell-lang.org February 18, 2019
- Call for new Stack issue triager February 12, 2019
- Mismatched global packages January 24, 2019
- Kids Coding, Part 4 January 18, 2019
- Kids Coding Interlude: the function game December 16, 2018
- Improving Commercial Haskell December 13, 2018
- FP Complete's opinion December 12, 2018
- New user empathy December 11, 2018
- Async, futures, and tokio - Rust Crash Course lesson 7 December 3, 2018
- Lifetimes and Slices - Rust Crash Course lesson 6 - exercise solutions November 28, 2018
- Lifetimes and Slices - Rust Crash Course lesson 6 November 26, 2018
- Rule of Three - Parameters, Iterators, and Closures - Rust Crash Course lesson 5 - exercise solutions November 21, 2018
- Why (I believe) Stackage succeeded November 20, 2018
- Rule of Three - Parameters, Iterators, and Closures - Rust Crash Course lesson 5 November 19, 2018
- Stack(age): History, philosophy, and future November 18, 2018
- Crates and more iterators - Rust Crash Course lesson 4 - exercise solutions November 14, 2018
- Crates and more iterators - Rust Crash Course lesson 4 November 12, 2018
- Proposal: Stack Code of Conduct November 7, 2018
- Iterators and Errors - Rust Crash Course lesson 3 - exercise solutions November 7, 2018
- Iterators and Errors - Rust Crash Course lesson 3 November 5, 2018
- Basics of Ownership - Rust Crash Course lesson 2 - exercise solutions October 31, 2018
- Basics of Ownership - Rust Crash Course lesson 2 October 29, 2018
- Kick the Tires - Rust Crash Course lesson 1 - exercise solutions October 24, 2018
- Kick the Tires - Rust Crash Course lesson 1 October 22, 2018
- Is it healthy? Depends on context October 19, 2018
- Introducing the Rust crash course October 18, 2018
- RAII is better than the bracket pattern October 8, 2018
- How I research health October 2, 2018
- Kids Coding, Part 3 August 28, 2018
- Kids Coding, Part 2 August 24, 2018
- Kids Coding, Part 1 August 23, 2018
- Post Fast Write-up July 15, 2018
- Thoughts on Fasting July 10, 2018
- Stop supporting older GHCs July 1, 2018
- Deprecating the Haskell markdown library June 15, 2018
- I am not snoyjerk May 28, 2018
- My open source goals May 28, 2018
- Building packages outside snapshots May 23, 2018
- Guide to matrix.org and riot.im May 14, 2018
- Stop breaking compatibility April Fools', 2018
- LambdaConf Haskell Hackathon 2018 March 28, 2018
- Quick guide to the Jewish Holidays March 25, 2018
- Haskell Ecosystem Requests February 18, 2018
- Stack Patching Policy February 14, 2018
- The Conduitpocalypse February 4, 2018
- SLURP January 24, 2018
- Breaking changes, dependency trees January 9, 2018
- Drop Conduit's Finalizers? January 3, 2018
- Review of The Bridge strength program January 1, 2018
- Dropped packages following LTS 10 December 25, 2017
- What Makes Haskell Unique December 17, 2017
- Stack and Nightly breakage December 7, 2017
- Future proofing test suites November 12, 2017
- Effective Ways to Get Help from Maintainers October 23, 2017
- Posture August 16, 2017
- Some Upcoming Crazy Thoughts July 16, 2017
- The Spiderman Principle July 5, 2017
- A Very Naive Overview of Exercise (Part 3) June 15, 2017
- A Very Naive Overview of Nutrition (Part 2) June 14, 2017
- A Very Naive Overview of Nutrition and Exercise (Part 1) June 13, 2017
- How to send me a pull request June 6, 2017
- Why I lift June 1, 2017
- Playing with lens-aeson May 29, 2017
- The Worst Function in Conduit May 7, 2017
- Stackage's no-revisions (experimental) field April 27, 2017
- Haskell Success Stories April 24, 2017
- Generalizing Type Signatures April 20, 2017
- Enough with Backwards Compatibility April Fools', 2017
- Better Exception Messages February 16, 2017
- Hackage Security and Stack February 14, 2017
- Stackage design choices: making Haskell curated package sets January 23, 2017
- Follow up on mapM_ January 19, 2017
- safe-prelude: a thought experiment January 16, 2017
- Foldable.mapM_, Maybe, and recursive functions January 10, 2017
- Conflicting Module Names January 5, 2017
- Functors, Applicatives, and Monads January 3, 2017
- Beware of readFile December 22, 2016
- Call for new Stackage Curator December 19, 2016
- An extra benefit of open sourcing December 13, 2016
- Haskell Documentation, 2016 Update November 28, 2016
- Haskell for Dummies November 23, 2016
- Spreading the Gospel of Haskell November 22, 2016
- Haskell's Missing Concurrency Basics November 16, 2016
- Designing APIs for Extensibility November 3, 2016
- New Conduit Tutorial October 13, 2016
- Proposed conduit reskin September 23, 2016
- Monads are like Lannisters September 12, 2016
- Using AppVeyor for Haskell+Windows CI August 31, 2016
- Restarting this blog August 24, 2016
- XSLT Rant Explained April 9, 2012
- Open Letter to XSLT Fans April 5, 2012
- Dysfunctional Programming: FindMimeFromData March 22, 2012
- First Post January 31, 2012