DESOSA 2022

Prettier - Quality and Evolution

Satisfaction of Quality Attributes

Usability

Since Prettier does not have a graphical user interface, it focuses on smoothly integrating into users’ existing coding tools. Prettier can therefore be used in a variety of IDEs, in the shell, and in a CI/CD-pipeline. Prettier enables users to format their code automatically, with the click of a button, or with a command. The fact that users can decide for themselves how to use Prettier makes it easy for them to learn and memorize its use. This is aimed at the user´s satisfaction: easily formatted code.

Modifiability

Prettier supports the ability for developers to add new languages for Prettier to format using plugins1. Next to the four official plugins, this has resulted in twelve community plugins.

Consistency

Naturally for an opinionated code formatter, Prettier’s source code follows several architectural style constraints, namely, it uses ESLint for linting, and Prettier for formatting2. Prettier also seems to use camelCase as a naming convention3, which is the standard JavaScript naming convention4. However, the lack of documentation for naming conventions and architectural decisions means that Prettier fails to fulfill all the criteria for consistency5.

Simplicity

One interesting thing to note is the fact that version 2.6 of Prettier introduces a new config option6. This conflicts with the simplicity quality attribute (QA), since the change compromises simplicity. It could also be argued that Prettier providing plugins for different languages1 goes against the simplicity QA, since it replaces one general solution with a specific solution for each language.

Software Quality Processes

Versioning Prettier uses semantic versioning7, where versions have the format X.Y.Z, where X is a major release, Y is a minor release, and Z is a patch8. By using semantic versioning, Prettier ensures that they can release a new version without having to worry about dependency management, since they can specify with which versions of dependency the system works.

Templates Prettier has a template for creating issues. This ensures that all the issues follow the same style and are easily readable for maintainers9. They have also a script to make all changelogs for pull requests follow the same pattern10.

Contributor role Another way in which Prettier ensures the software quality is the fact that only contributors have some rights, e.g., start all pipelines, change labels, request reviews, and assign PR/issues. This ensures that the software will not be altered without permission from developers connected to Prettier7.

Issue labels Prettier also uses labels to characterize issues. These labels fall into one of the following groups: area, difficulty, language, priority, scope, status and type11. An issue can have multiple labels, and these labels create a better overview of the issues.

Continuous Integration

Continuous integration (CI) is a software development practice where the developers regularly merge their code into a shared mainline12. Prettier is using their main-branch 7 as this mainline. It is updated frequently, and there are rarely any days without commits13. To improve the CI process, the Prettier repository has more than 15300 tests14, and commits are required to include relevant tests2.

As part of Prettier’s CI process, they use GitHub Actions15 which are automated tests that run in a Docker container for each commit or pull request16. The GitHub Actions are defined in the .github/workflows-folder17. The Prettier CI pipeline is running a linter18, building with different operating systems and versions of Node19, testing that the Jest tests pass19, testing the code coverage with Codecov19 20, and testing that deploying with Netlify still works19.

Figure: Completed CI Pipeline

When discussing CI, it is also natural to discuss continuous delivery. Prettier does not implement continuous deployment (CD) through an automated CI/CD-pipeline, but frequently releases versions when there have been significant changes21, known as continuous delivery, using release scripts22. These new versions can then be fetched through npm23. It could be argued that Prettier is on the borderline to CD as the version in the main branch should be functioning and it is possible to download and run it, but this is not how Prettier is intended to be used24.

Test Processes and Coverage

As mentioned, Prettier uses the Jest framework and GitHub Actions15 for testing. The Jest tests are used by Prettier developers as unit and integration tests25 26. When writing code for the command line the developers can use Benchmark.js27 for performance testing2.

The GitHub Actions combine the tests into integration, system, and acceptance tests. The Prettier developers have also made a repository for automating regression tests28 using GitHub Actions to make sure that the new changes do not impact the existing functionality.

Figure: The test tools

Prettier has been developed with a test-driven development29 (TDD) mindset where all new code needs tests2. The first pull request30 to the Prettier repository added 377 tests with an aim to get all those tests to pass. Using TDD helps make sure that the test coverage is covering most of the functionality, which is important for consistency.

Figure: Test coverage using ‘–coverage’ option in Yarn

Using Jest’s built-in tool for measuring test coverage, Prettier scores above 90%. TDD is a likely contributor to the high results. Codecov reports that Prettier ranks above 99% of projects in test coverage31.

Hotspot Components

The term hotspot component refers to a file, module, or software component that has been frequently changed32. Usually, when maintaining software, files and codebases change regularly. Prettier is no exception to this. When looking at the repository7 we can see that Prettier is still a very actively maintained program. Almost every day, features are added, bugs are squished, or refactors are made.

Figure: Bash command showcasing the most changed files in the Prettier repository.

Metadata-files and information files such as package.json, yarn.lock, README.md, and CHANGELOG.md are changed often. What does spark interest is the third most edited file, printer.js. According to the hotspot search, this file got edited a lot, but when looking into the repository7, it does not exist anymore. Instead, the printing logic has been distributed into the different language-specific folders. Most other hotspots are also some source files that handle printing or the main index files, essentially the more important files are the hotspots, which is to be expected.

By using another tool named CodeScene, we can also provide a more graphical representation33:

Figure: Graphical representation from Codescene of the most changed files (15+ commits).

These clusters are the files that have the most changes within them. These files have a lot of commits, and the clusters grouped together are files that are in the same folder. Prettier also have some coupling between files that might indicate that they should move some logic into shared files:

Figure: The most coupled files according to Codescene.

Code Quality

Code quality could relate to the coding style, layout, or performance of the code. Problems with coding style and layout are solved by Prettier by always running the Prettier formatter on the code. For example, the printer-estree.js34 function of prettier is among the most edited source files.

If we look at the commit history35, most changes are relatively small, like an extra dependency being added or an additional function call or comment. Some commits removing dead code that was deemed redundant also exist. The purpose of these commits seems to be focused on refactoring rather than complete rewrites. The Prettier maintainers refactor code to keep the code quality high, by improving DRY36, KISS37, and splitting the logic. Distributing code over multiple files makes the overview of the capabilities of the code much clearer. Code files containing 3000 lines is not convenient, since it makes reading and debugging more difficult. All in all, we see that the Prettier maintainers are putting effort into refactoring to improve the quality. A concrete example of this is an issue about moving CLI-only code to the CLI folder38.

Quality Culture

Arie van Deursen describes the culture of a project as “the way things are changed”39 and could be the habit of always adding a test case for new features. Quality culture can be divided into two categories: prescriptive and descriptive. Prescriptive quality culture describes the intended quality practices, e.g., those specified in Prettier’s CONTRIBUTING.md2, whereas descriptive is about the practices that take place.

We have looked at open and closed issues to see, among other things, how bugs are reported, and new features discussed. We have selected the following to relevant issues to base our discussion:

  1. Issue:12388
  2. Issue:12324
  3. Issue:12481
  4. Issue:9369
  5. Issue:4639
  6. Issue:4103
  7. Issue:12209
  8. Issue:10157
  9. Issue:12410
  10. Issue:6888

Numbers 1, 2, 3 in the list above are examples of when Prettier formatting does not work as intended. The issues specify the configuration they use, input, output, and a link to Prettier Playground. The expected output is also specified in some issues40 41 42. These three are typical of formatting issues and follow one of the previously discussed issue templates. Typically, a maintainer updates the issues with appropriate labels and comments within 24 hours40. The remaining issues are more about features or general enhancement of the system. They do not follow a strict template and are more for discussion. Issues discussion options, either a new one or change defaults, generally generate some attention, which can be seen in issues 9369 and 4639. Issue 6888 is a bit different, as it discusses a new major release of Prettier and mostly consists of feature requests and links to other issues.

Looking at pull requests (PRs) and how they are discussed and reviewed is another approach to understanding the quality culture in practice. We have selected ten PRs that we think are representative of the project.

  1. PR:12381
  2. PR:12394
  3. PR:12393
  4. PR:6644
  5. PR:1129
  6. PR:7536
  7. PR:7668
  8. PR:11891
  9. PR:7430
  10. PR:6773

In the list, the first three PRs are by us. In number two we fixed a bug that caused an error. A PR was put up and a maintainer reviewed it a noted that it did not fix the problem entirely. We fixed it and suggested another possible approach. Finally, the maintainer commits a small tweak and another one approved and merged it43. In the third PR, a working solution was submitted, but the reviewer suggested refactoring. We partly solved it, but the maintainer refactored the code further, making the code more reusable and easier to read. Another maintainer noted that the yarn module we used did not cover every case. The module and the tests were updated and the PR was approved and merged44. These two examples show that maintainers are quick to respond, helpful in their comments, and thorough in their review43 44.

The rest of the PRs add, change, or remove features. The most interesting is 6644. It adds a new configuration option, which is something Prettier is careful about doing. The PR was finished in October 2019, but not released until March 2022 after a long discussion with over 100 comments on the PR. This shows the thought and care that goes into making a big change45. PR six and seven are also interesting as they show that they remove dead code46 47.

Technical Debt

Technical debt can be described as “the refactoring effort needed to add a feature non-invasively”39. Technical debt can be caused by poorly written code, a narrow understanding of a problem, or code becoming obsolete39. As discussed, Prettier makes a conscient effort to remove obsolete code. The Project also uses Dependabot to minimize the risk of external libraries introducing security issues and bugs7. One of the biggest sources of technical debt is Prettier’s usage of CommonJS modules. It has been used to support imports and exports in node.js. Since its introduction, ECMAScript modules (ESM) were released, which standardized the module-system in JavaScript48. ESM is supported in Node version 12+ and since Node v10 is being deprecated this year, Prettier is switching to ESM49.

Adding a configuration option to Prettier can be seen as an architectural choice since it is irreversible. In this sense, the cautious approach Prettier uses when adding options could be to reduce future technical debt. They mention four options specifically on websites as not sensible50. When adding or changing a new feature, contributors must make sure that formatting with all different configurations still works, which will require more complex code and more extensive tests.

Sources


  1. Prettier. Plugins · Prettier. Retrieved March 17th, 2022, from https://prettier.io/docs/en/plugins.html ↩︎

  2. Contributing to Prettier. Retrieved March 17th, 2022, from https://github.com/prettier/prettier/blob/main/CONTRIBUTING.md ↩︎

  3. Contributing to Prettier. Retrieved March 18th, 2022, from https://github.com/prettier/prettier/blob/main/commands.md ↩︎

  4. JavaScript Naming Convention Best Practices Retrieved March 20th, from https://javascript.plainenglish.io/javascript-naming-convention-best-practices-b2065694b7d ↩︎

  5. Diomidis Spinellis (2022, Feb. 16). Envisioning the System (E1, E2). TU Delft, https://se.ewi.tudelft.nl/delftswa/2022/. Retrieved February 11, 2022. ↩︎

  6. Prettier 2.6: new singleAttributePerLine option and new JavaScript features!. Retrieved March 17th, 2022, from https://prettier.io/blog/2022/03/16/2.6.0.html ↩︎

  7. Prettier, Prettier repo, Retrieved March 20th, from https://github.com/prettier/prettier ↩︎

  8. Semantic Versioning 2.0.0. Retrieved March 18th, 2022, from https://semver.org/ ↩︎

  9. Github. Prettier ISSUE_TEMPLATE. Retrieved March 16th, from https://github.com/prettier/prettier/tree/main/.github/ISSUE_TEMPLATE↩︎

  10. Github. Prettier generate-changelog.mjs. Retrieved March 16th, from https://github.com/prettier/prettier/blob/main/scripts/generate-changelog.mjs↩︎

  11. Github. Prettier Issue Labels. Retrieved March 16th, from https://github.com/prettier/prettier/wiki/Issue-Labels↩︎

  12. Amazone. (2022). What is Continuous Integration? – Amazon Web Services. Amazon Web Services, Inc. Retrieved March 11, 2022, from https://aws.amazon.com/devops/continuous-integration/ ↩︎

  13. Prettier. Prettier repo commits. Retrieved March 11, 2022, from https://github.com/prettier/prettier/commits/main ↩︎

  14. Prettier. Prettier tests. Retrieved March 11, 2022, from https://github.com/prettier/prettier/tree/main/tests ↩︎

  15. GitHub. (2022). GitHub Actions Documentation. GitHub Docs. Retrieved March 11, 2022, from https://docs.github.com/en/actions ↩︎

  16. GitHub. (2022a). Continuous Integration and Continuous Delivery (CI/CD) Fundamentals. GitHub Resources. Retrieved March 11, 2022, from https://resources.github.com/ci-cd/ ↩︎

  17. Prettier. Prettier workflow. Retrieved March 11, 2022, from https://github.com/prettier/prettier/tree/main/.github/workflows ↩︎

  18. Prettier. Prettier linter. Retrieved March 11, 2022, from https://github.com/prettier/prettier/blob/main/.github/workflows/lint.yml ↩︎

  19. Prettier. Prettier building. Retrieved March 11, 2022, from https://github.com/prettier/prettier/blob/main/.github/workflows/dev-test.yml ↩︎

  20. Codecov. (2021, November 24). Codecov - The Leading Code Coverage Solution. Retrieved March 11, 2022, from https://about.codecov.io/ ↩︎

  21. Prettier. Prettier releases. Retrieved March 11, 2022, from https://github.com/prettier/prettier/releases ↩︎

  22. Prettier. Prettier release script. Retrieved March 11, 2022, from https://github.com/prettier/prettier/tree/main/scripts/release ↩︎

  23. npm. (2021, December 4). npm: prettier. Retrieved March 11, 2022, from https://www.npmjs.com/package/prettier ↩︎

  24. Prettier. (2022a). Install · Prettier. Retrieved March 11, 2022, from https://prettier.io/docs/en/install.html ↩︎

  25. Prettier. Prettier integration testing. Retrieved March 11, 2022, from https://github.com/prettier/prettier/tree/main/tests/integration ↩︎

  26. Prettier. Prettier integration jest. Retrieved March 11, 2022, from https://github.com/prettier/prettier/blob/main/jest.config.js ↩︎

  27. npm. (2017, March 28). npm: benchmark. Retrieved March 11, 2022, from https://www.npmjs.com/package/benchmark ↩︎

  28. Prettier. Prettier regression testing. Retrieved March 11, 2022, from https://github.com/prettier/prettier-regression-testing ↩︎

  29. Hamilton, T. (2022, February 26). What is Test Driven Development (TDD)? Tutorial with Example. Guru99. Retrieved March 11, 2022, from https://www.guru99.com/test-driven-development.html ↩︎

  30. Prettier. (2016, December 23). Add testing. Retrieved March 11, 2022, from https://github.com/prettier/prettier/pull/1 ↩︎

  31. Codecov. (2022, March 11). Codecov. Retrieved March 11, 2022, from https://app.codecov.io/gh/prettier/prettier ↩︎

  32. TU Delft, Software Architecture assignments, retrieved March 17th, https://se.ewi.tudelft.nl/delftswa/2022/assignment.html#essays ↩︎

  33. CodeScene, retrieved March 16th, https://codescene.com/ ↩︎

  34. Prettier. Prettier repository, Retrieved March 14th, from https://github.com/prettier/prettier/blob/main/src/language-js/printer-estree.js ↩︎

  35. Prettier. Prettier repository, retrieved March 14th, https://github.com/prettier/prettier/commits/main/src/language-js/printer-estree.js ↩︎

  36. Cneude, M. (2021, August 9). The DRY Principle: Benefits and Costs with Examples. The Valuable Dev. Retrieved March 17, 2022, from https://thevaluable.dev/dry-principle-cost-benefit-example/ ↩︎

  37. Interaction Design Foundation. (2020, September 16). KISS (Keep it Simple, Stupid) - A Design Principle. The Interaction Design Foundation. Retrieved March 17, 2022, from https://www.interaction-design.org/literature/article/kiss-keep-it-simple-stupid-a-design-principle ↩︎

  38. Prettier. Prettier Repository, retrieved March 16th, https://github.com/prettier/prettier/issues/12174 ↩︎

  39. Arie van Deursen. (2022, Mar. 4). Configurability and Change. TU Delft, https://se.ewi.tudelft.nl/delftswa/2022/. Retrieved March 19, 2022. ↩︎

  40. Prettier. </template> in VS code breaks prettier. Retrieved March 18, 2022, https://github.com/prettier/prettier/issues/12388 ↩︎

  41. Prettier. CSS values are transformed into lower case. Retrieved March 18, 2022, https://github.com/prettier/prettier/issues/12324 ↩︎

  42. Prettier. Comment in default block of switch is moving unexpectedly. Retrieved March 18, 2022, https://github.com/prettier/prettier/issues/12481 ↩︎

  43. Prettier. Allow lang attribute of <template> to be empty. Retrieved March 18, 2022, https://github.com/prettier/prettier/pull/12394 ↩︎

  44. Prettier. Fix lowercasing postcss values. Retrieved March 18, 2022, https://github.com/prettier/prettier/pull/12393 ↩︎

  45. Prettier. Enforce Single Attribute Per Line (#5501). Retrieved March 18, 2022, https://github.com/prettier/prettier/pull/6644 ↩︎

  46. Prettier. Remove deprecated options. Retrieved March 18, 2022, https://github.com/prettier/prettier/pull/7536 ↩︎

  47. Prettier. remove –stdin. Retrieved March 18, 2022, https://github.com/prettier/prettier/pull/7688 ↩︎

  48. Logrocket. (29 Dec 2021). CommonJS vs. ES modules in Node.js. Retrieved March 19 2022, https://blog.logrocket.com/commonjs-vs-es-modules-node-js/ ↩︎

  49. Prettier. Drop support for Node.js 10, switch to ES Module. Retrieved March 18, 2022, https://github.com/prettier/prettier/issues/10157 ↩︎

  50. Prettier. (2022). Option Philosophy. Retrieved March 18, 2022, from https://prettier.io/docs/en/option-philosophy.html ↩︎

Prettier
Authors
Hallvard Molin Morstøl
Akram Hamdi
Rutger Doting
Niklas Vatn