The following is a case study I prepared for my open source development class. It includes notes, links, and an interview I conducted with Christopher Chedeau (vjeux) in November 2018.
“Prettier is an opinionated code formatter”
Prettier takes source code input (e.g., JavaScript), parses it into an abstract syntax tree (AST) and uses that tree to output a pretty-printed version of the same code.
You can try it in the browser, entering JavaScript code on the left, and having it formatted on the right using the Prettier Playground
A good introduction to Prettier, and the problems it tries to solve, can be seen in this short talk by James Long introducing Prettier at React Conf in 2017.
James said he hit a “breaking point” when he tried to get his editor to properly indent JSX code and it couldn’t do it correctly:
“I’m going to fix this,” and prettier was born.
James says that he wanted to fix this problem because:
He goes on to focus on three areas where Prettier can help developers:
Today Prettier supports many languages, including:
JavaScript, JSX, Flow, TypeScript, JSON, Markdown, YAML, HTML, Vue, Angular, CSS, Less, SCSS, with support coming for Elm, Java, PHP, PostgresSQL, Python, Ruby, Swift, GraphQL
It’s also widely supported in many development tools and editors:
Atom, Emacs, Sublime, Vim, Visual Studio, VSCode, WebStorm
2 Dec 2016 - James tweets about his intial work. “I have other things I should be working on” with a short animation of what his code could already do
10 Jan, 2017 - James announces the start of the Prettier project on his blog. The post gets a lot of attention on Hacker News.
20 Feb, 2017 - James announces he’s moving Prettier to its own GitHub Organization. This is a significant step, in that it sets the stage for Prettier to become a community project vs. one person’s. Doing this always requires someone (the original developer) to be willing to part with some aspect of what they’ve built, namely, absolute control, 1:1 name recognition, etc. There is a cost to this investment.
13 April, 2017 - Prettier reaches 1.0
23 May, 2017 - Prettier reaches 10K starts on GitHub
16 Jan, 2018 - Prettier was the 7th most popular JS project on GitHub in 2017
26 Feb, 2018 - Facebook is now using Prettier for 100% of its JavaScript codebase
20 March, 2018 - Prettier wins an open source award
18 Jan, 2019 - Prettier wins Dev Tool of the Year Golden Kitty Award from Product Hunt
Prettier is a massive test suite, which also happens to pretty-print code as a side effect:
Directory | Lines Of Code (sloc) | % of Project |
---|---|---|
src/ |
25,122 | 25% |
tests/ |
63,614 | 65% |
As of November 2018, there are 5,711 tests in in 911 test suites.
“Christopher Chedeau pushed this massive test suite and said, get this working!” – James Long
A complete visualization of the repo’s development from creation to November 2018
is available. The structure of the project,
as visualized via gource, really helps to tell a story about how the code was built:
tests/
on the left dramatically outweigh the src/
in upper right, and the community’s time
is largely focused on building and improving test coverage.
If you look at the statistics for the Prettier repository, we see that it starts out as being just one person (James) for the first month, doubles to two in the second month (James and Christopher Chedeau), then explodes to 28 people in the third. Since then it has averaged 16 contributors per month consistently. As of the time of writing, there have been 379 contributors in total.
I reached out to the early developers of Prettier, and asked about how the project started, and how it became so successful. What follows is an email interview I had with Facebook’s Christopher Chedeau (vjeux), who has played a significant role in building, sustaining, and growing prettier and its community. At the request of Christopher, I’ve made this public, as I think it’s an interesting behind-the-scenes look at how prettier got made.
@humphd - I think it’s amazing what you, James, and the community have managed to do with Prettier. I’m interested in the ways in which you accomplished it, and what lessons there are for others to emulate. Prettier could have been quietly ignored like so many other attempts at doing this, but somehow you managed to make it stick. What was the process like?
@vjeux - I think that the story of the beginning is interesting. Here’s my side of it.
At my school EPITA, a 5 year computer science-focused engineering school in France, a lot of the curriculum is based on coding projects graded on a 20-point scale. They put in place what they call a “moulinette” a little program which automatically checks for code style and for every single mistake you make, you lose 2 points. This was a very harsh but effective way to teach you how to properly format your code. Of course they wouldn’t give you access to the moulinette, only a pdf of the style guide.
When gofmt was announced, I got very intrigued. I knew that the status quo of having everyone to be military trained to format code was a bit silly but I didn’t know of a better way. I’ve been waiting ever since for an equivalent for JavaScript and saw many attempts but none succeeded.
Jordan Walke who I’ve been working with for a few years with React and React Native left the React Native team which I was on to work on a new project which involved building a pretty printer for OCaml syntax where anyone can build their own syntax (which turned into Reason. This will become relevant later…
At some point, I started becoming friends with Julien Verlaguet who built Hack. A few months in, he told me that he spent a lot of time designing, building and shipping a Hack formatter and walked me through all the lessons he learned from that project, both in terms of technical design and how to go about shipping it.
I was on the Nuclide team at the time and was looking into making the tooltip that shows the Flow type when you mouse over a variable better when the type was big. I wrote (and shipped) a small printer based on the concepts that Julien taught me and wrote an internal Facebook note about it.
This note got a fair bit of attention internally and many folks chimed in saying that they’ve hacked on similar things in the past: Kyle Davis pointed to a previous attempt at doing a js formatter he did, Miller Medeiros shared that he built esformatter before joining Facebook and Jordan Walke explained some of refmt decisions.
Pieter Vanderwerff, who maintained react-bootstrap before joining Facebook, decided to hack on a pretty printer for JavaScript using reason and refmt infrastructure after reading this note.
I don’t remember why but I was chatting about this with James Long and he mentioned to me that he started working on a pretty printer by forking recast, a project built by Benjamin Newman, who used to work at Facebook.
I got so excited that two people were working on a js pretty printer. I didn’t want those two projects to be another failure, I felt like this time it could happen for real! I knew that at this point what was needed was to get both Pieter and James motivated to work on it during the winter break of 2016. I basically played the role of a cheerleader. I setup the same set of unit tests for the two projects, built small scripts to count down the number of syntax structures left to handle, ran their code through real world examples and summarized classes of issues that needed to be addressed.
Unfortunately, at the end of the winter break, both Pieter and James had to go back to their real work and weren’t willing to focus their time and attention to it. This was so sad because while both projects were early, they both were in a state where you could run it on your codebase and be convinced that with more work you could reasonably convert the entire codebase. I’ve been looking for this for so long.
I did a lot of soul searching and decided that I would focus all my energy and commit to work on it full time. It wasn’t an easy sell to my manager, but fortunately I had enough social capital at Facebook that I was able to do it.
I asked myself a lot, “All the previous projects failed, why would this one work?” Here are a few things that convinced me:
@humphd - I love the role that tests play in the project. This is something we’ve discussed on Twitter in the past, and I know you are very fond of automated testing. I think that tests for Prettier, in addition to playing their usual role in software development, also allowed you to gain people’s confidence and trust that their needs were being met in the direction of the project. Being able to say “this is important to me” via a test helps give a sense of agency, and eventually buy-in from the wider community. Can you talk about your approach to testing, and how Prettier uses them?
@vjeux - I saw that both projects (James’s and Pieter’s pretty printers) were being developed by pretty printing a dummy JavaScript file that they expanded as they implemented more code. It was super painful because “coverage” was super small and they had to hunt down examples of real code that contain all the possible syntax in order to print it.
The Flow team had built their own JavaScript parser recently, so I figured that they would have all the possible variations in their tests. Bingo! I needed to find a way to actually run the pretter-printers against those files, but I wasn’t super excited about building my own. Around the same time Christoph Nakazawa was working on Jest snapshot tests. That feature wasn’t designed for this use case but I was able to hack my way around it. I put all those tests in both projects and they were able to iterate much faster as a result.
The side effect I didn’t really anticipate is that it made it extremely easy to review pull requests. You could just look at the before/after and without even reviewing the code, you could see if the output looked better. Not only that, but if someone wants to play with an idea, they can hack it up, run the tests and see all the things that it would change. Unlike many tests, they were not binary (right or wrong), they showed differences and then it was up to a human to say if the differences were acceptable or not.
The project itself also has an interesting characteristic which is that theres a very long tail of features. In order for it to succeed, you need to go through hundreds of small combinations of syntax. I spent the first 6 months grinding through them and what was amazing is that I only committed half the number of commits. The open source community shipped as many of them as I could. The next 6 months I was only at a third. I stopped being actively involved nowadays and I just checked, I’m only at 20%.
@humphd - Prettier is like a lot of open source projects, in that it starts out as one person’s project, and then manages to draw others around it, before creating a sustaining community. Let me read you a few tweets that speak to a bit of this, and then I’d love to hear your take on what it took to sustain the project, and get it to where it is today
I created Prettier solely for @actualbudget. I was so tired of being bogged down with formatting. @Vjeux pushed me to open-source it and helped make it a standard tool. Solving your own problems is the best! I’m really amazed at how quickly it was adopted! It thrived as an OSS project - easy to work on w/snapshot tests, and made everyone feel involved in the style decisions. – James Long, 30 Nov, 2017
I’m losing interest in prettier since it mostly “just works” but there are so many style opinions that issues keep coming. Who thinks it’s fun to keep arguing about that? I haven’t been contributing to prettier for a while now. @vjeux has been carrying the torch but will move on at some point. I’m sure we can figure out a community-centered way to manage prettier, but this brings up my main struggle with open source. When a project starts getting popular, it’s hard to say no to small tweaks. But people request so many of them. It forces the project to become much more generalized, which makes software a lot more difficult to build. Coherence, performance, accessibility, maintainability, code size, testing, it all suffers when you have to generalize something, which isn’t a bad thing, but it’s much harder. Most projects do not need it. Most times a laser-focused project is a lot more powerful because you can focus on just a few edge cases, you can do things otherwise impossible for your specific project. Unfortunately I like building laser-focused projects that take my ideas as far as they can. This seems incompatible with open source. I’ve ended up writing my own libs and keeping them to myself. My own component interface, css-in-js, etc :/ It’s working great though! It doesn’t help that I’m contracting now, so literally whenever I choose to spend time on open source now I’m losing money. – James Long 26 Jun 2017
Prettier was an interesting project where James Long open sourced it before it was used anywhere. Having a ton of people in open source using it early on side projects before it was solid enough to be widely deployed at Facebook really helped. – Christopher Chedeau 9 June, 2018
@vjeux - While I believe that open source was a big part of prettier’s success, I want to call out that Facebook, a company, was a critical reason why this project succeeded.
For 6 months my full time job was to work on prettier and Facebook paid James Long for a 2-week long contract (he wasn’t interested in working on it more), without this funding, the project wouldn’t have taken off.
The primary reason I worked on prettier was to get it to work on Facebook’s codebase. The fact that it worked outside of Facebook was a nice side effect but I would have done it without it. An historical artifact is that all the options early on were added so that it would adhere to Facebook style guide. Facebook codebase was invaluable for this project as it helped find real-world examples of syntax in order to come up with a reasonable way to print it in various conditions, some rough numbers as to how people print various constructs in practice and a huge source of edge cases in order to harden the printer.
The fact that I worked at Facebook meant that I had direct access to people that built pretty printers for various languages including JavaScript in the past. Prettier itself was started as a fork of a project coming from Facebook. Without having all those people concentrated in one place, I would likely never have convinced myself to spend 6 months working on such a project.
@humphd - So much is said these days about the sustainability of open source, and here you really see the need for a significant support system to be in place in order to sustain the work. Facebook’s role seems like a tremendous positive, and yet also points to some issues in reproducing this. On the one hand it provides a framework for others to follow, namely, you need to be supported by a large ORG/COM to get beyond the initial “HackerNews” style release and into production. But if you don’t have that kind of support, you’re going to struggle. A lot more people don’t work at Facebook than do, and can’t reproduce this result as you have.
@vjeux - I’ve mostly experienced open source within Facebook, so it has shaped the way I think about it. In our case, projects should first be useful for Facebook and then we spend 10-20% extra time to build a community around it to get all the benefits that people talk about.
I know that this setup has been proven to produce good results so I approached it the same way for prettier. It’s probably not the only way but it is certainly one way to go about it.
@humphd - Thinking about the long tail of features is very useful. People love to talk about the final 10% of the project taking 90% of the time, and that’s really what this is. There are so many edge cases, I can’t imagine. At this point, for a project like Prettier to work, it’s no longer enough for someone like Facebook to pay a single person: you need the wider community to get engaged, file bugs from their big code and real-world uses cases, do fixes, etc. So to get this done, we can almost imagine a flow like this: 1 person starts something cool, add cheerleader(s) to prop that person up, build a project around them, at some point it needs to get support from an ORG/COM with $$$ to pay for dev time, and then you need support from outside that ORG, in order to solve the problems at a scale larger than one company can imagine.
@vjeux - We [Facebook] have something we call the “prod infra playbook” that reads something like:
It looks a bit similar to your list.
@humphd - There’s a part of your story that is implicit, and would be interesting to tease out: why does everyone suddenly care about pretty printers and standardized code formatting? I have some theories, but consider how long we’ve been working without such tooling (I’ve been programming JS since the late 1990s and never had it). Then, all of a sudden, everyone is doing it, across all kinds of languages. It would be interesting to consider what the tipping point was–gofmt? Also, for something like prettier to work, you would imagine needing top-down approach. Prettier seems to have accomplished what it did bottom-up, without a committee or standards process. It seems to have happened via influence, the ability to project confidence, and network effects. This tweet from James hints at it:
“Code formatting is largely a social problem and you aren’t going to win unless it comes from somebody already deep inside the community who people trust will make good formatting decisions” –James Long, 25 May, 2018
you’ve also talked about this a bit on Twitter:
“I believe that prettier success is in part because its formatting is not tied to a specific IDE. If you are using Visual Studio but have contributors using Sublime and others using Emacs, they should all be able to have the same format.” –Christopher Chedeau, 24 May, 2018
@vjeux - My biggest theory about this is the decentralization of language and tools. None of the pretty printers that came to market had any technological breakthrough. Prettier is based on Wadler’s paper from 1999!
But, until very recently, all the language tools were developed by the programming language creators or the language IDEs. And not the actual users of those languages. If you put yourself in their shoes, they want everyone to be able to use their product so it’s not in their best interest to make an opinionated printer that has the potential to alienate a lot of existing users.
Go is interesting in that it was designed to fix problems that Google engineers had, so they could push for more opinionated things.
In the JavaScript world, we’ve seen in the recent years a huge push towards tooling that manipulates the AST such as eslint, codemods, flow/typescript… so now if you want to enforce a code style, you could take the matter into your own hands and do it yourself.
If you look at the C++ world, you need to be inside of the compiler (clang-format) to be able to pull this off.
@humphd - Thanks for doing this interview. In my opinion it’s no coincidence that you have been so successful with Prettier. In a time where so much of the web is filled with hate, anger, ego, and tribalism, I’ve been impressed with your alternative approach to software, community, and open source. I can’t think of too many more useful examples for my students to examine as they prepare to embark on their own careers, and for others looking at open source projects.
@vjeux - I’m super proud that we’ve been able to build a welcoming community with React. I gave some context around how I tried to make it happen at the React Advanced meetup, you may be interested.