├── src ├── draft │ └── .gitkeep ├── contributing.md ├── adrs │ ├── 1146361044 │ │ └── README.md │ ├── 1358452048 │ │ └── README.md │ ├── 1475937194 │ │ └── README.md │ ├── 2068541249 │ │ └── README.md │ ├── 2131725034 │ │ └── README.md │ ├── 3122196229 │ │ └── README.md │ ├── 3223845695 │ │ └── README.md │ ├── 3519904902 │ │ └── README.md │ ├── 3610135900 │ │ └── README.md │ ├── 4031218897 │ │ └── README.md │ ├── 0000000000 │ │ ├── workflow.png │ │ └── README.md │ ├── 8042638751 │ │ └── README.md │ ├── 5508488323 │ │ └── README.md │ ├── 6860374633 │ │ ├── v1 │ │ │ └── dataschema.json │ │ └── README.md │ ├── 4860595695 │ │ └── README.md │ ├── 8618797096 │ │ └── README.md │ ├── 6819030042 │ │ └── README.md │ ├── 8702033095 │ │ └── README.md │ ├── 7565730517 │ │ └── README.md │ ├── 0000000001 │ │ └── README.md │ ├── 4937890790 │ │ └── README.md │ ├── 0541531435 │ │ └── README.md │ ├── 4615273139 │ │ └── README.md │ ├── 5541831634 │ │ └── README.md │ └── 0129349218 │ │ └── README.md └── index.md ├── .tool-versions ├── .vitepress ├── theme │ ├── index.css │ ├── index.ts │ └── MyLayout.vue ├── config.ts └── helpers.ts ├── .prettierrc.mjs ├── postcss.config.js ├── Makefile ├── .markdownlint.json ├── .gitignore ├── .github ├── ISSUE_TEMPLATE │ ├── support.md │ └── adr-proposal.md ├── dependabot.yml ├── workflows │ ├── ci.yml │ └── deploy.yml └── stale.yml ├── tailwind.config.js ├── .editorconfig ├── .prettierignore ├── FAQ.md ├── scripts └── start_adr.sh ├── templates └── adr.md ├── CONTRIBUTING.md ├── package.json ├── LICENSE ├── README.md └── CODE_OF_CONDUCT.md /src/draft/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | nodejs 22.20.0 2 | -------------------------------------------------------------------------------- /.vitepress/theme/index.css: -------------------------------------------------------------------------------- 1 | @import 'tailwindcss'; 2 | -------------------------------------------------------------------------------- /src/contributing.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.prettierrc.mjs: -------------------------------------------------------------------------------- 1 | export { default } from '@straw-hat/prettier-config/base'; 2 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | '@tailwindcss/postcss': {}, 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /src/adrs/0000000000/workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/straw-hat-team/adr/HEAD/src/adrs/0000000000/workflow.png -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | generate_adr_id: 2 | npx nanoid-cli --size 10 --alphabet "0123456789" 3 | 4 | start_adr: 5 | ./scripts/start_adr.sh 6 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "default": true, 3 | "MD026": false, 4 | "MD013": { 5 | "line_length": 120 6 | }, 7 | "MD025": false 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | !adrs/draft/.gitkeep 4 | !.tool-versions 5 | 6 | /.vitepress/dist/ 7 | /.vitepress/cache 8 | /.vitepress/config.ts.* 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/support.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Help or Question❓ 3 | about: For general support 4 | title: '[Support] ' 5 | labels: 'Type: Support' 6 | --- 7 | 8 | Describe what you need help with ... 9 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | darkMode: 'class', 4 | content: ['./src/**/*.md', './.vitepress/theme/**/*.vue'], 5 | theme: { 6 | extend: {}, 7 | }, 8 | plugins: [], 9 | }; 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | max_line_length = 80 11 | 12 | [Makefile] 13 | indent_style = tab 14 | -------------------------------------------------------------------------------- /.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | import './index.css'; 2 | 3 | import type { Theme } from 'vitepress'; 4 | import DefaultTheme from 'vitepress/theme'; 5 | import MyLayout from './MyLayout.vue'; 6 | 7 | export default { 8 | extends: DefaultTheme, 9 | Layout: MyLayout, 10 | } satisfies Theme; 11 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .yarnrc 2 | yarn.lock 3 | /coverage 4 | /dist 5 | .DS_Store 6 | LICENSE 7 | .editorconfig 8 | .gitignore 9 | *.cmd 10 | *.log 11 | .prettierignore 12 | .env* 13 | .npmrc 14 | .next 15 | out 16 | .yarn 17 | .idea 18 | .pnp.cjs 19 | .pnp.loader.mjs 20 | .vitepress/dist 21 | .vitepress/cache 22 | pnpm-lock.yaml 23 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | - package-ecosystem: github-actions 5 | directory: / 6 | schedule: 7 | interval: monthly 8 | open-pull-requests-limit: 3 9 | 10 | - package-ecosystem: npm 11 | directory: / 12 | schedule: 13 | interval: monthly 14 | open-pull-requests-limit: 3 15 | groups: 16 | prod: 17 | dependency-type: production 18 | dev: 19 | dependency-type: development 20 | -------------------------------------------------------------------------------- /src/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | 4 | hero: 5 | name: Straw Hat 6 | text: Architecture Decision Record 7 | tagline: 'TL;DR: lots of documentation on how Straw Hat Team works.' 8 | image: 9 | src: /logo.png 10 | alt: VitePress 11 | actions: 12 | - theme: brand 13 | text: Genesis ADR 14 | link: /adrs/0000000000/README 15 | - theme: alt 16 | text: View on GitHub 17 | link: https://github.com/straw-hat-team/adr 18 | --- 19 | -------------------------------------------------------------------------------- /FAQ.md: -------------------------------------------------------------------------------- 1 | # Frequently Asked Questions 2 | 3 | ## I have a question that isn't answered here. What do I do? 4 | 5 | We're still pretty new and haven't built up a long list of frequently asked 6 | questions, so if you have a question not answered here, you can always 7 | [ask us on GitHub](https://github.com/straw-hat-team/adr/issues/new) by filing an 8 | issue. 9 | 10 | And if you already know the answer to a question that would be helpful for others, 11 | **send us a pull request** adding it to this page! 12 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | qa: 7 | name: Quality Assurance 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v6 11 | with: 12 | fetch-depth: 0 13 | - uses: pnpm/action-setup@v4 14 | - uses: actions/setup-node@v6 15 | with: 16 | node-version-file: .tool-versions 17 | cache: pnpm 18 | - run: pnpm install --frozen-lockfile 19 | - run: pnpm format:prettier --check 20 | - run: pnpm lint:markdownlint 21 | -------------------------------------------------------------------------------- /scripts/start_adr.sh: -------------------------------------------------------------------------------- 1 | adr_id() { 2 | local result=$(npx nanoid-cli --size 10 --alphabet "0123456789") 3 | echo $result 4 | } 5 | 6 | main() { 7 | dir_name=$(adr_id) 8 | template=./templates/adr.md 9 | output=./src/adrs/$dir_name/README.md 10 | 11 | echo "creating directory ./src/adrs/$dir_name/" 12 | mkdir ./src/adrs/$dir_name/ 13 | 14 | echo "copy $template template into $output" 15 | cp $template $output 16 | 17 | sed -i '' "s//$dir_name/g" $output 18 | sed -i '' "s//$(date +'%Y-%m-%d')/g" $output 19 | echo "ADR created at $output" 20 | } 21 | 22 | main 23 | -------------------------------------------------------------------------------- /src/adrs/8042638751/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: '8042638751' 3 | title: JSX files extension 4 | state: Approved 5 | created: 2020-12-01 6 | tags: [jsx] 7 | category: JavaScript 8 | --- 9 | 10 | # JSX files extension 11 | 12 | ## Context 13 | 14 | In some cases, people use `.js` extension with files containing JSX syntax. 15 | 16 | As of today, JSX syntax is not valid JavaScript, and using `.js` over `.jsx` 17 | breaks many tools that use `.jsx` files in order to switch the parsers to support 18 | JSX. 19 | In the best case, the tools allow you to configure the default parser for 20 | the files, but that is rarely done in services where they do basic parsing or 21 | relying on extensions in order to swap the parsers. 22 | 23 | ## Resolution 24 | 25 | - You **MUST** use `.jsx` file extension when the file contains JSX. 26 | -------------------------------------------------------------------------------- /templates/adr.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: 3 | title: [short title of solved problem and solution] 4 | state: 5 | replaced_by: 6 | created: 7 | tags: [] 8 | category: 9 | --- 10 | 11 | # [short title of solved problem and solution] 12 | 13 | ## Context 14 | 15 | 18 | 19 | ## Resolution 20 | 21 | Chosen option: "[option 1]", because [justification. e.g., only option, which 22 | meets k.o. criterion decision driver | which resolves force force | … | comes 23 | out best (see below)]. 24 | 25 | ## Links 26 | 27 | 31 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We'd love to accept your patches and contributions to this project. 4 | 5 | ## Development 6 | 7 | - Clone the repository: 8 | 9 | ```shell 10 | git clone git@github.com:straw-hat-team/adr.git 11 | ``` 12 | 13 | - Create a new branch: 14 | 15 | ```shell 16 | git checkout -b [my branch name] 17 | ``` 18 | 19 | - Submit a pull request in GitHub. 20 | 21 | ### Proposing a new ADR? 22 | 23 | Make sure you have read the following ADRs: 24 | 25 | - [ADR#0000000000](/adrs/0000000000/README.md) 26 | - [ADR#0000000001](/adrs/0000000001/README.md) 27 | 28 | Use the following command to get started: 29 | 30 | ```shell 31 | make start_adr 32 | ``` 33 | 34 | Follow the template to proposal a new ADR. 35 | 36 | ## Code reviews 37 | 38 | All submissions, including submissions by project members, require review. We 39 | use GitHub pull requests for this purpose. 40 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/adr-proposal.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: ADR Proposal 3 | about: Suggest an ADR for this project 4 | title: '[Proposal] ' 5 | labels: 'State: Draft, Type: ADR' 6 | --- 7 | 8 | # [short title of solved problem and solution] 9 | 10 | - **State:** 11 | - **Replaced by:** 12 | - **Created:** 13 | - **Tags:** 14 | 15 | ## Context 16 | 17 | 20 | 21 | ## Resolution 22 | 23 | Chosen option: "[option 1]", because [justification. e.g., only option, which 24 | meets k.o. criterion decision driver | which resolves force force | … | comes 25 | out best (see below)]. 26 | 27 | ## Links 28 | 29 | 33 | -------------------------------------------------------------------------------- /src/adrs/1146361044/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: '1146361044' 3 | title: Helper vs Util 4 | state: Approved 5 | created: 2022-07-11 6 | tags: [naming] 7 | category: General 8 | --- 9 | 10 | # Helper vs Util 11 | 12 | ## Context 13 | 14 | At some point in your career you came across the debate of "Utils" vs "Helpers". 15 | 16 | Which one should you use in our code? 17 | 18 | Giving the opportunity to bikeshedding, and/or creating diverging codebases 19 | across the organization. 20 | 21 | We decided that across all the codebases we will be using `Helper`, regardless 22 | of the programming language or ecosystem. 23 | 24 | There is no right or wrong answer here, just a matter of preferences and stick 25 | to a single way because it doesn't really matter which one you use except that 26 | it will matter for some at some point in their life, and it is not worth the 27 | debate in the long-term. 28 | 29 | ## Resolution 30 | 31 | - You **MUST** use `Helper(s)` over `Util` across all the codebases. 32 | -------------------------------------------------------------------------------- /src/adrs/5508488323/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: '5508488323' 3 | title: Lodash Importing 4 | state: Approved 5 | created: 2022-03-21 6 | tags: [javascript] 7 | category: JavaScript 8 | --- 9 | 10 | # Lodash Importing 11 | 12 | ## Context 13 | 14 | Lodash could become quite large in the final bundle of your application. 15 | 16 | Default or destructuring imports from `lodash` are not tree-shaking friendly, 17 | therefore, you will end up bundling all the functions from the package. 18 | 19 | ```ts 20 | import _ from 'lodash'; // bad 21 | import { merge } from 'lodash'; // bad 22 | ``` 23 | 24 | [Lodash team mentioned that you could import the submodule, or rely on a Babel plugin](https://lodash.com/per-method-packages) 25 | . Using the Babel plugin requires build-tool knowledge, and it is less explicit 26 | about the intention. Saving little to no time over typing the submodule. 27 | 28 | ## Resolution 29 | 30 | - You **MUST** import from the submodules of the `lodash` package: 31 | 32 | ```ts 33 | import funcNameExample from 'lodash/func-name-example'; 34 | ``` 35 | -------------------------------------------------------------------------------- /src/adrs/6860374633/v1/dataschema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema#", 3 | "title": "Error", 4 | "description": "A single error", 5 | "type": "object", 6 | "additionalProperties": false, 7 | "properties": { 8 | "errormessage": { 9 | "description": "Human-readable error message, intended to be used by developers", 10 | "type": "string" 11 | }, 12 | "errorlink": { 13 | "description": "A URL to the more detailed information about the error", 14 | "type": "string", 15 | "pattern": "uri" 16 | }, 17 | "metadata": { 18 | "description": "An object containing metadata associated with the error", 19 | "type": "object", 20 | "patternProperties": { 21 | "^[A-Za-z][A-Za-z0-9_]*$": { 22 | "anyOf": [ 23 | { "type": "string" }, 24 | { 25 | "type": "array", 26 | "items": { 27 | "type": "string" 28 | } 29 | } 30 | ] 31 | } 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "packageManager": "pnpm@10.6.3+sha512.bb45e34d50a9a76e858a95837301bfb6bd6d35aea2c5d52094fa497a467c43f5c440103ce2511e9e0a2f89c3d6071baac3358fc68ac6fb75e2ceb3d2736065e6", 3 | "name": "@straw-hat/adr-webapp", 4 | "type": "module", 5 | "scripts": { 6 | "docs:dev": "vitepress dev", 7 | "docs:build": "vitepress build", 8 | "docs:preview": "vitepress preview", 9 | "lint:markdownlint": "markdownlint **/*.md", 10 | "format:prettier": "prettier --ignore-unknown --no-error-on-unmatched-pattern --write '**/*'" 11 | }, 12 | "dependencies": { 13 | "fast-glob": "3.3.3", 14 | "gray-matter": "4.0.3", 15 | "vite": "7.2.6", 16 | "zod": "4.1.13" 17 | }, 18 | "devDependencies": { 19 | "@straw-hat/prettier-config": "3.1.5", 20 | "@tailwindcss/postcss": "4.1.17", 21 | "@vueuse/core": "14.1.0", 22 | "body-scroll-lock": "4.0.0-beta.0", 23 | "markdownlint-cli": "0.46.0", 24 | "postcss": "8.5.6", 25 | "prettier": "3.7.3", 26 | "prettier-plugin-organize-imports": "4.3.0", 27 | "tailwindcss": "4.1.17", 28 | "vitepress": "1.6.4", 29 | "vue": "3.5.25" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/adrs/1475937194/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: '1475937194' 3 | title: Pattern matching in function heads and control-flow 4 | state: Approved 5 | created: 2025-03-16 6 | tags: [pattern-matching] 7 | category: Elixir 8 | --- 9 | 10 | # Pattern matching in function heads and control-flow 11 | 12 | ## Context 13 | 14 | Pattern matching in function heads should be used exclusively for control flow 15 | and not as a convenient way to extract values out of maps or structs. 16 | 17 | This helps indicate to the reader of the code that the pattern matching 18 | influences the control-flow of the code and as-such runtime behaviour. 19 | 20 | This is also outlined [in the official docs as an anti-pattern](https://hexdocs.pm/elixir/main/code-anti-patterns.html#complex-extractions-in-clauses) 21 | 22 | ## Resolution 23 | 24 | - You **MUST** pattern matching in function heads for control-flow purposes. 25 | - You **MUST NOT** use pattern matching in function heads as a convenience for 26 | destructuring variables out into the function body. 27 | 28 | ## Links 29 | 30 | - 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Straw Hat Team 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy VitePress site to Pages 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | workflow_dispatch: 7 | 8 | permissions: 9 | contents: read 10 | pages: write 11 | id-token: write 12 | 13 | concurrency: 14 | group: deploy 15 | cancel-in-progress: false 16 | 17 | jobs: 18 | build: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@v6 22 | with: 23 | fetch-depth: 0 24 | - uses: pnpm/action-setup@v4 25 | - uses: actions/configure-pages@v5 26 | - uses: actions/setup-node@v6 27 | with: 28 | node-version-file: .tool-versions 29 | cache: pnpm 30 | - run: pnpm install --frozen-lockfile 31 | - run: pnpm docs:build 32 | - uses: actions/upload-pages-artifact@v4 33 | with: 34 | path: .vitepress/dist 35 | 36 | deploy: 37 | environment: 38 | name: github-pages 39 | url: ${{ steps.deployment.outputs.page_url }} 40 | needs: build 41 | runs-on: ubuntu-latest 42 | name: Deploy 43 | steps: 44 | - name: Deploy to GitHub Pages 45 | id: deployment 46 | uses: actions/deploy-pages@v4 47 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | daysUntilStale: 90 2 | daysUntilClose: 30 3 | 4 | exemptLabels: 5 | - 'State: Deferred' 6 | 7 | staleLabel: 'State: Withdrawn' 8 | 9 | issues: 10 | markComment: > 11 | This issue has been automatically marked as "Withdrawn". **If this issue 12 | still relevant, please leave any comment** (for example, "bump"), and we'll 13 | keep it open. We are sorry that we haven't been able to prioritize it yet. 14 | If you have any new additional information, please include it with your 15 | comment. 16 | 17 | closeComment: > 18 | Closing this issue after a prolonged period of inactivity. If this issue is 19 | still relevant, feel free to re-open the issue. Thank you! 20 | 21 | pulls: 22 | markComment: > 23 | This pull request has been automatically marked as "Withdrawn". **If this 24 | pull request is still relevant, please leave any comment** (for example, 25 | "bump"), and we'll keep it open. We are sorry that we haven't been able to 26 | prioritize reviewing it yet. Your contribution is very much appreciated!. 27 | 28 | closeComment: > 29 | Closing this pull request after a prolonged period of inactivity. If this 30 | issue is still relevant, please ask for this pull request to be reopened. 31 | Thank you! 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Architecture Decision Record (ADR) 2 | 3 | TL;DR: ADRs are lots of documentation on how Straw Hat Team works. 4 | 5 | ## Overview 6 | 7 | ADR stands for Architecture decision record, a design document providing 8 | high-level, concise documentation for software development. The goal is for 9 | these documents to serve as the source of truth for software-related 10 | documentation at Straw Hat Team and the way teams discuss and come to consensus 11 | on software development guidance. 12 | 13 | ## Getting started 14 | 15 | ### New to ADR? 16 | 17 | If you're new to ADRs, check out the [Frequently Asked Questions](./FAQ.md) 18 | which answer some common questions about how ADRs work and what you need to 19 | know. 20 | 21 | ### Genesis ADR 22 | 23 | [ADR#0000000000](./adrs/0000000000/README.md) is the genesis ADR. 24 | 25 | ### Have an idea for an ADR? 26 | 27 | If you have an idea for an ADR that isn't written yet (yes, there are plenty!) 28 | check out [Contributing to the project](./CONTRIBUTING.md) to see how you can 29 | write ADRs for others to follow. 30 | 31 | ## License 32 | 33 | Except as otherwise noted, the content of this repository is licensed under the 34 | [Creative Commons Attribution 4.0 License](https://creativecommons.org/licenses/by/4.0/), 35 | and code samples are licensed under the [MIT License](./LICENSE). 36 | -------------------------------------------------------------------------------- /src/adrs/3519904902/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: '3519904902' 3 | title: Enforcing Named Bindings in Ecto Queries 4 | state: Approved 5 | created: 2024-08-21 6 | tags: [ecto, elixir, sql] 7 | category: Elixir 8 | --- 9 | 10 | # Enforcing Named Bindings in Ecto Queries 11 | 12 | ## Context 13 | 14 | Ecto allows the use of named bindings when composing queries. We will enforce 15 | named bindings across all queries in our codebase. 16 | 17 | ### Clarity and Readability 18 | 19 | Named bindings indicate what each part of the query references, reducing 20 | confusion and increasing the code's maintainability. 21 | 22 | ### Avoiding Errors 23 | 24 | When queries are combined, positional bindings can lead to operations being 25 | applied to the wrong entities, causing subtle bugs. Named bindings eliminate 26 | this risk by explicitly naming each binding. 27 | 28 | ### Consistency 29 | 30 | Adopting a standard practice across the codebase simplifies onboarding and code 31 | reviews. 32 | 33 | ## Consequences 34 | 35 | - Refactoring Effort: Existing queries using positional bindings will need to be 36 | refactored to use named bindings. 37 | - Learning Curve: Developers need to get accustomed to consistently using named 38 | bindings. 39 | 40 | ## Resolution 41 | 42 | - You **MUST** use named bindings in all Ecto queries except when impossible. 43 | 44 | ## Links 45 | 46 | - [Ecto Query Named Bindings](https://hexdocs.pm/ecto/Ecto.Query.html#module-named-bindings) 47 | -------------------------------------------------------------------------------- /.vitepress/config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vitepress'; 2 | import path from 'node:path'; 3 | import { 4 | readFrontmatter, 5 | orderByCreated, 6 | AdrFrontmatter, 7 | toSidebarItem, 8 | groupByCategory, 9 | hasAnyCategory, 10 | } from './helpers'; 11 | 12 | export default async () => { 13 | const frontmatters = await readFrontmatter(['adrs/**/*.md'], { 14 | rootDir: path.join(__dirname, '../src'), 15 | schema: AdrFrontmatter, 16 | }); 17 | const categories = frontmatters.sort(orderByCreated).reduce(groupByCategory, {}); 18 | 19 | return defineConfig({ 20 | base: '/adr/', 21 | srcDir: './src', 22 | lang: 'en-US', 23 | title: "Straw Hat's ADRs", 24 | description: 'TL;DR: ADRs are lots of documentation on how Straw Hat Team works.', 25 | themeConfig: { 26 | footer: { 27 | message: 28 | 'Except as otherwise noted, the content of this repository is licensed under the Creative Commons Attribution 4.0 License and code samples are licensed under the MIT', 29 | copyright: 'Copyright © 2020-present Straw Hat, LLC', 30 | }, 31 | editLink: { 32 | text: 'Edit this page on GitHub', 33 | pattern: 'https://github.com/straw-hat-team/adr/tree/main/src/:path', 34 | }, 35 | nav: [ 36 | { text: 'Contributing', link: '/contributing' }, 37 | { text: 'GitHub', link: 'https://github.com/straw-hat-team/adr' }, 38 | ], 39 | sidebar: ['General', 'Platform', 'Elixir', 'JavaScript'].filter(hasAnyCategory(categories)).map((category) => ({ 40 | text: category, 41 | collapsible: true, 42 | collapsed: false, 43 | items: categories[category].map(toSidebarItem) ?? [], 44 | })), 45 | }, 46 | }); 47 | }; 48 | -------------------------------------------------------------------------------- /src/adrs/2131725034/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: '2131725034' 3 | title: React Component and Hooks Props Naming 4 | state: Approved 5 | created: 2022-01-24 6 | tags: [react] 7 | category: JavaScript 8 | --- 9 | 10 | # React Component and Hooks Props Naming 11 | 12 | ## Context 13 | 14 | When it comes to React, they are two categories of properties: 15 | 16 | - Data (Information) 17 | - Callbacks (Events, Control Flow) 18 | 19 | Data properties are primarily used for displaying information or transforming 20 | into another set of data. 21 | 22 | Callbacks are used to control the flow of data. Functions such 23 | as`onFilterAccount` and `onSortBy` would be used to filter and sort data. 24 | Callbacks can also react to events. The browser already makes a distinction 25 | between data and callback properties by prefixing the event handlers with `on`, 26 | for example: `onClick`, `onChange`, etc. The `on` prefix is used to indicate 27 | that the property is a callback and the component or hook controls the execution 28 | of the callback. 29 | 30 | Understanding a React component API allows engineers to focus their attention on 31 | more important manners such as the business requirements. 32 | 33 | When it comes to debugging problems in production and minified code where 34 | finding where the problem is a challenge and time critical. Being able to reduce 35 | the cognitive load reading through the code base is crucial. 36 | 37 | Inconsistent property naming promotes bikeshedding, which slows down software 38 | development cycles in code review and results in unnecessary disagreements 39 | between developers. 40 | 41 | ## Resolution 42 | 43 | - React Component and Hook `data` properties **MUST** be a noun. 44 | - React Component and Hook `callback` properties **MUST** a verb prefix 45 | with `on`. 46 | -------------------------------------------------------------------------------- /src/adrs/3223845695/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: '3223845695' 3 | title: Documentation structure 4 | state: Approved 5 | created: 2021-12-21 6 | tags: [documentation] 7 | category: General 8 | --- 9 | 10 | # Documentation structure 11 | 12 | ## Context 13 | 14 | Getting documentation right is a key part of the development process, but that 15 | is rarely the case. Most people lack of the discipline or the ability to write 16 | good documentation. 17 | More often than not, the documentation is written in a style that complex 18 | different concerns. 19 | Or the structure of the documentation website is customized so much that readers 20 | must understand what is what. 21 | 22 | As of today, [Diátaxis Framework](https://diataxis.fr/) has been successfully 23 | implemented in projects such as: [Django](https://www.djangoproject.com/) or 24 | [Gatsby](https://www.gatsbyjs.com/docs/). 25 | 26 | The framework may not perfect, but it is a good starting point. The project 27 | love collaboration and is open to contributions. Recommend collaborating and 28 | align with such project. 29 | 30 | ## Resolution 31 | 32 | - You **MUST** follow the [Diátaxis Framework](https://diataxis.fr/) writing 33 | documentation. 34 | - Your Top-Level Documentation structure or navigation **MUST** include the 35 | following: 36 | - Tutorials or Tutorial 37 | - How-to Guides or How-tos 38 | - References or Reference 39 | - Explanations or Explanation 40 | 41 | ### Example 42 | 43 | ```markdown 44 | # My Project 45 | 46 | ## Documentation 47 | 48 | - [Tutorials](./docs/tutorials/README.md) 49 | - [How-tos](./docs/how-tos/README.md) 50 | - [References](./docs/references/README.md) 51 | - [Explanations](./docs/explanations/README.md) 52 | ``` 53 | 54 | ## Links 55 | 56 | - [Diátaxis Framework](https://diataxis.fr/) 57 | -------------------------------------------------------------------------------- /src/adrs/4031218897/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: '4031218897' 3 | title: React Hook Arguments Convention 4 | state: Approved 5 | created: 2022-12-30 6 | tags: [react, react-hooks] 7 | category: JavaScript 8 | --- 9 | 10 | # React Hook Arguments Convention 11 | 12 | ## Context 13 | 14 | ### Positioned Arguments vs. Single Argument 15 | 16 | Positioned arguments, meaning `function (arg1, arg2, arg3)`, suffer from the 17 | problem that they don’t have names when you use them as a caller, working only 18 | for simple situations with one or maybe two arguments. 19 | 20 | Having one or two arguments is rarely the case, and even that, needs 21 | clarification. For example, given the following hook 22 | calling `useFetchPerson(arg1, arg2)`, you can not tell what is what by just 23 | looking at the shape vs. `useFetchPerson({firstName: "", lastName: ""})` having 24 | an object brings more clarity because the keys have names. 25 | 26 | Objects allow you to avoid breaking changes since you can always add new keys 27 | without removing or renaming the old ones in the worst case and without having 28 | to refactor so much all over the place. 29 | 30 | When you are inside the hook (unless you have a destructuring assignment due to 31 | default values), having a single variable that lets you know what values are 32 | static is beneficial since the cognitive load to figure out what are computed 33 | values and what is pass-thru is lower if you see `props.[name of something]` you 34 | can assume it is a static value, which is passed to your hook. Knowing that you 35 | will need to look up outside the hook if you have an issue or want to see where 36 | the value comes from is straightforward. 37 | 38 | ### Naming the argument 39 | 40 | Since, by convention, in a React Component, you call the single argument 41 | `props`, and in a React codebase, you will enter and leave the React context, 42 | it is better to keep the single argument named `props` in a hook as well. The 43 | `props` name is generic enough that it still makes sense, and it keeps the 44 | clarity around the React codebase, which is the static value that comes from a 45 | single argument. 46 | 47 | ## Resolution 48 | 49 | - You **MUST** use a single argument in React Hooks. 50 | - You **MUST** call the single argument `props`. 51 | -------------------------------------------------------------------------------- /src/adrs/4860595695/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: '4860595695' 3 | title: Human-Readable IDs 4 | state: Approved 5 | created: 2024-03-24 6 | category: Platform 7 | tags: [id] 8 | --- 9 | 10 | # Human-Readable IDs 11 | 12 | ## Context 13 | 14 | Choosing the right type of IDs for APIs affects usability, security, and 15 | developer experience. Working with just UUIDs, integers, or random characters 16 | can be cumbersome and error-prone. These IDs are often hard to remember, debug, 17 | and integrate with other systems because they lack context about the resource 18 | type. 19 | 20 | That difficulty is exacerbated for Business Analysts dealing with massive 21 | amounts of data from different sources, needing to understand the data structure 22 | and relationships between resources. Or for developers without much experience 23 | working with the system or domain. 24 | 25 | Polymorphic values are a common pattern where you need to fetch a resource by 26 | its ID without knowing the resource's type. Some APIs use a hash map to store 27 | the type and ID, but this approach lacks human readability, requiring the type 28 | and ID to be printed together for usefulness. 29 | 30 | In distributed systems, simplifying data understanding is critical. Whether 31 | using ETL software, data warehouses, or freelancers who don't have time to learn 32 | all the data combinations, it's important to keep data self-sufficient and 33 | easily understandable. 34 | 35 | ### Positive Consequences 36 | 37 | - Usability: Easier for humans to read, remember, and use. 38 | - Debugging: Simplifies identifying and understanding issues. 39 | - Integration: Eases integration with other systems by providing context. 40 | 41 | ### Negative Consequences 42 | 43 | - Potential Length: Human-readable IDs might be longer. 44 | 45 | ## Resolution 46 | 47 | - You **MUST** use a human-readable ID as a single value to identify a resource. 48 | - You **MUST** include the resource type as a prefix in the ID. 49 | - You **MUST** `[resource type]_[resource id]` as the format for human-readable 50 | IDs. 51 | 52 | ## Links 53 | 54 | - [Designing APIs for humans: Object IDs](https://dev.to/stripe/designing-apis-for-humans-object-ids-3o5a) 55 | - [About Data vs. Information](https://strawhatllc.notion.site/Data-Information-Knowledge-and-Wisdom-142b2220e11d8004a842fd982fde319c) 56 | -------------------------------------------------------------------------------- /src/adrs/8618797096/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: '8618797096' 3 | title: Usage of JSX Fragment 4 | state: Approved 5 | created: 2020-11-15 6 | tags: [jsx] 7 | category: JavaScript 8 | --- 9 | 10 | # Usage of JSX Fragment 11 | 12 | ## Context 13 | 14 | Today we have a way to specify fragments in our React, Preact codebase or 15 | any other library that adopts such technology. 16 | 17 | - Using `Fragment` from React import: 18 | 19 | ```tsx 20 | import { Fragment } from 'react'; 21 | function MyApp() { 22 | return ; 23 | } 24 | ``` 25 | 26 | - Importing everything under a scope: 27 | 28 | ```tsx 29 | import * as React from 'react'; 30 | function MyApp() { 31 | return ; 32 | } 33 | ``` 34 | 35 | - Using JSX fragment short syntax: 36 | 37 | ```tsx 38 | function MyApp() { 39 | return <>; 40 | } 41 | ``` 42 | 43 | There are no rules about this introducing inconsistency in the codebase, or in 44 | some cases, refactoring of the import style is demanded. 45 | 46 | As mentioned before, since React introduced JSX to our toolkit, multiple 47 | libraries have adopted JSX, for example, a really popular alternative to React: 48 | [Preact](https://preactjs.com/). 49 | 50 | TypeScript [introduced a way to specify the Fragment factory](https://github.com/microsoft/TypeScript/pull/38720) 51 | to allow people to have more control over the compiled JSX code. 52 | 53 | Using `React.Fragment` couples the JSX to React, although most of your code will 54 | probably never move to another library like Preact, the usage of 55 | `React.Fragment` introduces more fragmentation in the ecosystem with little 56 | benefits from it. 57 | 58 | React team [introduced a new JSX Transform](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html) 59 | that doesn't require React to be imported in the file, allowing JSX to be more 60 | agnostic of the library. 61 | 62 | ## Resolution 63 | 64 | - You **MUST** use JSX fragment short syntax `<>`. 65 | 66 | ## Links 67 | 68 | - [react/jsx-fragments](https://github.com/yannickcr/eslint-plugin-react/blob/main/docs/rules/jsx-fragments.md) 69 | ESLint rule about JSX short syntax. We suggest to enable the rule with the 70 | following config: 71 | 72 | ```json 73 | { 74 | "rules": { 75 | "react/jsx-fragments": ["error", "syntax"] 76 | } 77 | } 78 | ``` 79 | -------------------------------------------------------------------------------- /src/adrs/3122196229/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: '3122196229' 3 | title: NodeJS files and directories names convention 4 | state: Approved 5 | created: 2020-11-10 6 | tags: [nodejs] 7 | category: JavaScript 8 | --- 9 | 10 | # NodeJS files and directories names convention 11 | 12 | ## Context 13 | 14 | Across the ecosystem, we can find all sort of files and directories naming 15 | conventions in NodeJS projects. 16 | 17 | That has caused misalignment, shifting the focus away from more important 18 | matters, also have created conventions that introduce problems such: 19 | 20 | - Disagreement around the English language, making it even more difficult for the 21 | non-English speaker to figure out the right decision. 22 | - Case sensitive vs. case insensitive file systems, causing issues in different 23 | environments such as your local computer vs. CI/CD computers. 24 | - Format mismatching around separating English words. 25 | 26 | The `camelCase`, and/or `PascalCase` for naming convention, although this seems 27 | the right solution, there are some caveats. 28 | 29 | What happens for the following cases `httpClient.ts` vs. `HTTPClient.ts` vs. 30 | `HttpClient.ts`? 31 | 32 | - Which one is the more appropriate choice here without getting into 33 | disagreement and use the phrase "it depends"? 34 | 35 | In some cases, the file `PascalCase` is used if the file is a class or 36 | a React component, otherwise follow `camelCase` is used. 37 | 38 | - What happens when the file contains more than a class or a React component? How 39 | do we take the appropriate decision about it without getting into 40 | disagreement and use the phrase "it depends"? 41 | 42 | Also, does that means that if we refactor the code and we move the React 43 | component out of a file, that file name must change? 44 | 45 | That would introduce more potential refactoring like renaming file paths, 46 | adding more unnecessary lines of code changes and extra work in code reviews. 47 | 48 | As well as issues in `CI` environments, where it may be the case that `git` 49 | didn't rename the file due to case-insensitive file systems, and you must use 50 | `git mv [old file] [new file]` to fix such issue. 51 | 52 | ## Resolution 53 | 54 | File or directory names: 55 | 56 | - **MUST NOT** contain any leading or trailing spaces 57 | - **MUST** be lowercase i.e., no uppercase or mixed case names are allowed 58 | - **MUST** separate what constitutes an English word by `-` 59 | - **MUST NOT** contain any of the following characters: `~)('!*` 60 | - **MUST NOT** start with `.` or `_` 61 | -------------------------------------------------------------------------------- /src/adrs/6819030042/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: '6819030042' 3 | title: Acronyms Usage 4 | state: Approved 5 | created: 2024-09-27 6 | tags: [naming, acronyms] 7 | category: Platform 8 | --- 9 | 10 | # Acronyms Usage 11 | 12 | ## Context 13 | 14 | Inconsistency in the usage of acronyms within codebases leads to debates over 15 | naming conventions, making code reviews and collaboration more 16 | challenging—especially for non-native English speakers. Promoting unnecessary 17 | discussions and detracts from more critical development tasks. 18 | 19 | A simple internet search reveals numerous conflicting opinions on how to handle 20 | acronyms in naming conventions. For example, consider XMLHttpRequest from 21 | browser APIs. 22 | 23 | - Which naming convention provides the best readability and consistency? 24 | - How should acronyms be integrated into different casing styles like camelCase, 25 | PascalCase, or snake_case? 26 | - How should acronyms be handled in programming languages with strict naming 27 | conventions, such as Go? 28 | 29 | In Go, for instance, `type HTTPHeader` and `type httpHeader` are not the same, 30 | which can lead to errors. This is because Go uses the visibility of the first 31 | letter to determine whether a variable or function is public or private. This 32 | means that `HTTPHeader` is public, while `httpHeader` is private. 33 | 34 | Should it be `type hTTP`? 35 | 36 | Familiar acronyms will be understood regardless of their form. Until we 37 | encounter quantifiable and quantifiable evidence that one form is more readable 38 | than another, we are moving forward with the following guidelines. 39 | 40 | ## Resolution 41 | 42 | - You **MUST NOT** use upper case acronyms in names in source code across all 43 | languages, regardless of their preferred casing style. 44 | - Except for technical limitations 45 | - Except for declaring constants in all caps, where the acronym is part of the 46 | name. 47 | - You **MAY** use proper acronyms spelling in documentation. 48 | - You **MAY** spell out the acronym provided they are defined upon first use 49 | within the documentation. 50 | 51 | ## Examples 52 | 53 | - Instead of `XMLHttpRequest`, use `XmlHttpRequest`. 54 | - Instead of `HTTPServer`, use `HttpServer`. 55 | - Instead of `URL`, use `Url`. 56 | - Instead of `ID`, use `Id`. 57 | - Instead of `API`, use `Api`. 58 | - Instead of `TCP`, use `Tcp`. 59 | - Instead of `HTTP`, use `Http`. 60 | - Instead of `JSON`, use `Json`. 61 | - Instead of `HTML`, use `Html`. 62 | - Instead of `CSS`, use `Css`. 63 | - Instead of `CLI`, use `Cli`. 64 | -------------------------------------------------------------------------------- /src/adrs/8702033095/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: '8702033095' 3 | title: URL Path Design 4 | state: Approved 5 | created: 2021-12-13 6 | tags: [seo, url, openapi] 7 | category: Platform 8 | --- 9 | 10 | # URL Path Design 11 | 12 | ## Context 13 | 14 | The lack of alignment in URL design across products causes multiple issues in 15 | software development. 16 | 17 | Suboptimal SEO where some Search Engines don't recognize underscores in URLs. A 18 | URL containing "my_page" will be indexed as "my page" (as one term) while a URL 19 | containing "my-page" will be indexed as "my" "page" (as two terms). 20 | 21 | Worth saying that this is primarily how Google Search Engine does things, 22 | regardless, it is safe to say that it is prudent following Google Search 23 | optimizations. 24 | 25 | Suboptimal user-experience since camelCase and underscore also require the user 26 | to use the shift key, whereas hyphenated does not on desktop keywords; and 27 | characters like underscore are hidden behind special symbols in mobile phones 28 | keywords. 29 | 30 | Lack of shared tooling, forcing developers to reimplement tools or promoting 31 | bikeshedding. 32 | 33 | ## Resolution 34 | 35 | > These rules apply to URL Paths. URL Query Params have their own rules. 36 | 37 | Creating "perfect software" is close to impossible. The following suggestions 38 | may feel like suggestions because we don't have the full scope of the situation. 39 | 40 | Therefore, you **MAY** follow the following resolutions unless you have a 41 | technical limitation. You **MUST** assumed such rules de facto in conversations. 42 | 43 | You **MUST** use the following characters anywhere in the path: 44 | 45 | - U+0061 to U+007A ("a-z") 46 | - U+0030 to U+0039 ("0-9") 47 | - U+007E ("~") 48 | - U+002E (".") 49 | - U+0080 and above (non-ASCII Unicode characters; not recommended, not URL safe) 50 | 51 | You **MAY** use the following characters are allowed in path, except as the 52 | first or last character: 53 | 54 | - U+002D HYPHEN-MINUS, "-" 55 | - U+005F LOW LINE, "\_” 56 | 57 | - You **MUST** separate terms using hyphen character 58 | - You **MUST** use underscore for new compound words or composed terms 59 | - You **MUST** use non-reserved characters, URL safe characters specified in 60 | [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986#page-13) 61 | 62 | ## Links 63 | 64 | - [Underscores vs. dashes in URLs](https://www.youtube.com/watch?v=AQcSFsQyct8&ab_channel=GoogleSearchCentral) 65 | - [Keep a simple URL structure](https://developers.google.com/search/docs/advanced/guidelines/url-structure) 66 | -------------------------------------------------------------------------------- /.vitepress/theme/MyLayout.vue: -------------------------------------------------------------------------------- 1 | 8 | 56 | -------------------------------------------------------------------------------- /src/adrs/3610135900/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: '3610135900' 3 | title: Secret Value Syntax 4 | state: Approved 5 | created: 2023-08-13 6 | tags: [secret] 7 | category: Platform 8 | --- 9 | 10 | # Secret Value Syntax 11 | 12 | ## Context 13 | 14 | The current ecosystem lacks a standardized format for secret values. This 15 | decentralization of secret format decisions leads to a situation where 16 | developers often define the format themselves. Such a disparate approach results 17 | in many developers either forgetting to set up scanning tools or being unable to 18 | utilize preconfigured scanning tools. 19 | 20 | The lack of a consistent secret format hinders tools that would otherwise help 21 | guard against vulnerabilities and potential security risks. The changes in 22 | GitHub Authentication Token Formats, among other companies adding more 23 | meaningful prefixes to their secrets, highlight the need for a more standardized 24 | approach. 25 | 26 | ### Decision Drivers: 27 | 28 | **Security:** A standard format would enable more effective use of secret 29 | scanning tools, reducing the chances of leaks or unauthorized access. 30 | 31 | **Consistency:** A consistent secret format can streamline processes and reduce 32 | the chance of human error. 33 | 34 | **Usability:** Developers can more easily take advantage of preconfigured 35 | scanning tools with a standardized format. 36 | 37 | ## Resolution 38 | 39 | The agreed-upon structure will be similar to the URN syntax: 40 | 41 | ```txt 42 | SECRET = "secret:[NID]:[NSS]:[secret value] 43 | ``` 44 | 45 | - "secret:" is the required case-sensitive scheme at the beginning. 46 | - NID (Namespace Identifier) defines the specific context or namespace. 47 | It is an optional case-sensitive and consist of only lower case alphanumeric 48 | characters and dashes value. Regex: `[a-z0-9-]`. 49 | - NSS (Namespace-Specific String) is unique within the specific namespace. 50 | It is an optional case-sensitive and consist of only lower case alphanumeric 51 | characters and dashes value. Regex: `[a-z0-9-]`. 52 | 53 | The secret regex value is: 54 | 55 | ```txt 56 | ^secret:(?:[a-z0-9-]*):(?:[a-z0-9-]*):(.+)$ 57 | ``` 58 | 59 | For example, a Personal Access Token for GitHub could be in the format: 60 | 61 | ```txt 62 | secret:github:ghp:ghp_000000000000000000000000000000000000 63 | ``` 64 | 65 | ## Links 66 | 67 | - 68 | - 69 | - 70 | - 71 | -------------------------------------------------------------------------------- /src/adrs/1358452048/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: '1358452048' 3 | title: Slots reserved React property key 4 | state: Approved 5 | created: 2020-12-14 6 | tags: [react] 7 | category: JavaScript 8 | --- 9 | 10 | # Slots reserved React property key 11 | 12 | ## Context 13 | 14 | You may have components that you would like the users to have control over 15 | some underline components. 16 | 17 | For example, let's assume that we would like to change the container and the 18 | label components for the following component. 19 | 20 | ```tsx 21 | function Badge(props) { 22 | const displayValue = '...'; // calculate something, does not matter the details 23 | 24 | return ( 25 |
26 | {props.children} 27 |
{displayValue}
28 |
29 | ); 30 | } 31 | ``` 32 | 33 | Also, although some implementations are not technically wrong, they may miss 34 | some concern. 35 | 36 | For example, using render function over components: 37 | 38 | ```tsx 39 | function Badge(props) { 40 | return ( 41 |
42 | {props.children} 43 | {props.renderLabel({ className: 'label', children: displayValue })} 44 |
45 | ); 46 | } 47 | ``` 48 | 49 | In the previous example, React loses the ability to figure out if the component 50 | needs to be re-rendered since it is no longer a component but a function call. 51 | 52 | Also, subjectively speaking, it feels non-React since we lose the JSX syntax. 53 | 54 | We have no alignment in how to accomplish the tasks, which means people have to 55 | learn new idioms across codebase even when the intention is the same. 56 | 57 | What key should we use for this? Should we pass a function or a component, or 58 | something else? Defining the TypeScript definitions and so on. 59 | 60 | ## Resolution 61 | 62 | - You **MUST** use `slots` key in React props to pass custom components. 63 | - The `slots` **MUST** be an object. 64 | - The `slots` object key **MUST** in pascalCase. 65 | - The `slots` object value **MUST** a React component. 66 | 67 | ## Example 68 | 69 | ```tsx 70 | import * as React from 'react'; 71 | 72 | // You could reuse this across your system 73 | type PropsWithSlots, P> = P & { 74 | slots?: C; 75 | }; 76 | 77 | // Define the slots for your component 78 | type BadgeSlots = Partial<{ 79 | root: React.ElementType<{ 80 | className: string; 81 | }>; 82 | label: React.ElementType<{ 83 | className: string; 84 | counter?: number; 85 | something: any; 86 | children: string; 87 | }>; 88 | }>; 89 | 90 | type BadgeProps = React.PropsWithChildren< 91 | PropsWithSlots< 92 | BadgeSlots, 93 | { 94 | counter?: number; 95 | something?: any; 96 | } 97 | > 98 | >; 99 | 100 | export function Badge(props: BadgeProps) { 101 | const displayValue = '...'; // calculate something, does not matter the details 102 | const Root = props.slots?.root ?? 'div'; 103 | const Label = props.slots?.label ?? DefaultLabel; 104 | 105 | return ( 106 | 107 | {props.children} 108 | 111 | 112 | ); 113 | } 114 | ``` 115 | -------------------------------------------------------------------------------- /src/adrs/7565730517/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: '7565730517' 3 | title: Logging Level and Error Reporting Usage 4 | state: Draft 5 | created: 2025-03-31 6 | tags: [error-reporting, logging, sentry, observability] 7 | category: Platform 8 | --- 9 | 10 | # Logging Level and Error Reporting Usage 11 | 12 | ## Context 13 | 14 | Currently, the volume and quality of logs—particularly Sentry errors—are 15 | reducing the effectiveness of the tool for debugging and operations. Much of the 16 | logging noise stems from messages that do not require action, creating false 17 | alarms and distracting from actionable issues. 18 | 19 | ### Sentry 20 | 21 | Sentry should be a high-signal tool. All logs sent to Sentry must be actionable. 22 | 23 | - Do not log messages to Sentry unless they require immediate investigation or 24 | fixing. Use the regular logger module for informational or ignorable issues. 25 | - If a Sentry issue is raised: 26 | - Immediately assign it to yourself. 27 | - Fix it promptly. If unsure how to proceed, ask for help immediately. 28 | - The long-term goal is to have a silent Sentry. 29 | 30 | ### Logger 31 | 32 | Use the logger module for all standard logging purposes. 33 | 34 | - `error` logs are treated as `500` errors and must be addressed. 35 | - Prefer `error` over `critical`, `alert`, or `emergency` unless there is 36 | a strong justification, in which case document the reasoning clearly. 37 | - `critical`, `alert`, and `emergency` should be reserved for extreme 38 | situations, such as data corruption or unrecoverable system failures. 39 | - `warning` logs are treated like `400` errors. 40 | - They signal that attention might be needed, but action is not always 41 | required. 42 | - If a warning proves meaningless or too frequent, it should either be 43 | removed, lowered, or replaced with metrics. 44 | - Info/debug logs are always acceptable for internal understanding and 45 | observability. 46 | 47 | Any log with the `error` `critical` `alert` or `emergency` must be acted 48 | upon. Ideally, we should not have any of those logs. Treat them as an `500` 49 | error. Being said, use `error` level instead of `critical` `alert` or 50 | `emergency` unless there is a strong reason not to; please document it in that 51 | case. 52 | 53 | Use `warning` to call the attention, but it may or may not require action. 54 | Ideally, we move the warning to a lower or higher level or add metrics instead. 55 | Treat `warning` the log level as an `400` error. 56 | 57 | ## Resolution 58 | 59 | - You `MUST NOT` log to Sentry unless the issue is actionable and needs fixing. 60 | - You `MUST` treat `error` logs as production issues to be fixed. You `SHOULD` 61 | validate log level usage as part of code reviews. PRs introducing `error` or 62 | higher logs must justify them. 63 | - You `SHOULD` avoid using `critical`, `alert`, or `emergency` unless 64 | strictly necessary. 65 | - You `SHOULD` avoid noise from `warning` logs; triage them regularly. 66 | - You `MUST` ensure all log levels reflect the severity and actionability of the 67 | issue. 68 | - You `SHOULD` consider replacing repetitive logs with metrics when appropriate. 69 | You `SHOULD` prefer metrics for tracking recurring behavior or performance 70 | patterns instead of relying on log statements. 71 | - You `MUST` use `info` or `debug` levels for logs that are purely 72 | observational and don’t require intervention. 73 | 74 | ## Terminology 75 | 76 | ### Error Reporter 77 | 78 | An Error Reporter would be a service like [Sentry](https://sentry.io/), 79 | [Datadog Error Tracking](https://www.datadoghq.com/product/error-tracking/). 80 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | - Using welcoming and inclusive language 18 | - Being respectful of differing viewpoints and experiences 19 | - Gracefully accepting constructive criticism 20 | - Focusing on what is best for the community 21 | - Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | - The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | - Trolling, insulting/derogatory comments, and personal or political attacks 28 | - Public or private harassment 29 | - Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | - Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at `code-of-conduct@straw-hat-llc.com`. 59 | All complaints will be reviewed and investigated and will result in a response 60 | that is deemed necessary and appropriate to the circumstances. The project team 61 | is obligated to maintain confidentiality with regard to the reporter of an 62 | incident. Further details of specific enforcement policies may be posted 63 | separately. 64 | 65 | Project maintainers who do not follow or enforce the Code of Conduct in good 66 | faith may face temporary or permanent repercussions as determined by other 67 | members of the project's leadership. 68 | 69 | ## Attribution 70 | 71 | This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), 72 | [version 1.4](https://www.contributor-covenant.org/version/1/4/code-of-conduct.html). 73 | 74 | For answers to common questions about this code of conduct, see [FAQ](https://www.contributor-covenant.org/faq) 75 | -------------------------------------------------------------------------------- /.vitepress/helpers.ts: -------------------------------------------------------------------------------- 1 | import { normalizePath } from 'vite'; 2 | import fs from 'node:fs'; 3 | import path from 'node:path'; 4 | import matter from 'gray-matter'; 5 | import glob from 'fast-glob'; 6 | import { z } from 'zod'; 7 | 8 | type ReadFrontmatterResult = Array<{ filePath: string; frontmatter: T }>; 9 | 10 | /** 11 | * Read frontmatter from files. 12 | * 13 | * @param patterns the glob pattern to search for files. 14 | * @param opts 15 | * @param opts.rootDir the root directory to search for files. 16 | * @param opts.schema the Zod Schema to validate the frontmatter. 17 | * @returns a list of frontmatter objects. 18 | */ 19 | export async function readFrontmatter( 20 | patterns: string[], 21 | opts?: { 22 | rootDir?: string; 23 | schema?: z.ZodObject; 24 | }, 25 | ): Promise> { 26 | const pattern = patterns.map((pattern) => { 27 | const finalPath = opts?.rootDir ? path.join(opts.rootDir, pattern) : pattern; 28 | return normalizePath(finalPath); 29 | }); 30 | const files = await glob(pattern, { ignore: ['**/node_modules/**', '**/dist/**'] }); 31 | 32 | return files.sort().map((filePath: string) => { 33 | const content = fs.readFileSync(filePath, 'utf-8'); 34 | const { data } = matter(content); 35 | 36 | try { 37 | const frontmatter = opts?.schema?.parse(data) ?? data; 38 | return { 39 | filePath, 40 | frontmatter, 41 | }; 42 | } catch (e) { 43 | throw new InvalidFrontmatterError(filePath, e); 44 | } 45 | }); 46 | } 47 | 48 | class InvalidFrontmatterError extends Error { 49 | #zodError: z.ZodError; 50 | #filePath: string; 51 | 52 | constructor(filePath: string, zodErr: z.ZodError) { 53 | super(); 54 | this.name = 'InvalidFrontmatterError'; 55 | this.#zodError = zodErr; 56 | this.#filePath = filePath; 57 | } 58 | 59 | get message() { 60 | const issues = this.#zodError.errors 61 | .map((zodIssue, index) => { 62 | return [ 63 | ` ${index + 1}. Error Code: ${zodIssue.code}`, 64 | ` - Path: ${zodIssue.path.join(' > ')}`, 65 | ` - Expected: ${zodIssue.expected}`, 66 | ` - Received: ${zodIssue.received}`, 67 | ` - Message: ${zodIssue.message}`, 68 | ]; 69 | }) 70 | .flat() 71 | .join('\n'); 72 | 73 | return `${this.#filePath}\n\n${issues}\n`; 74 | } 75 | } 76 | 77 | const categories = ['General', 'Platform', 'Elixir', 'JavaScript'] as const; 78 | 79 | type Category = (typeof categories)[number]; 80 | 81 | export const AdrFrontmatter = z.object({ 82 | id: z.string(), 83 | title: z.string(), 84 | created: z.coerce.date(), 85 | state: z.enum(['Draft', 'Reviewing', 'Approved', 'Withdrawn', 'Rejected', 'Deferred', 'Replaced']), 86 | tags: z.array(z.string()), 87 | category: z.enum(categories), 88 | }); 89 | 90 | type IAdrFrontmatter = z.infer; 91 | 92 | export function orderByCreated(r1: ReadFrontmatterResult, r2: ReadFrontmatterResult) { 93 | return r1.frontmatter.created - r2.frontmatter.created; 94 | } 95 | 96 | export function groupByCategory( 97 | acc: Record>>, 98 | r: ReadFrontmatterResult, 99 | ) { 100 | acc[r.frontmatter.category] ??= []; 101 | acc[r.frontmatter.category].push(r); 102 | return acc; 103 | } 104 | 105 | export function toSidebarItem(r: ReadFrontmatterResult) { 106 | return { 107 | text: r.frontmatter.title, 108 | link: `/adrs/${r.frontmatter.id}/README.md`, 109 | }; 110 | } 111 | 112 | export function hasAnyCategory(categories: Record>>) { 113 | return (category: Category) => categories[category]?.length > 0; 114 | } 115 | -------------------------------------------------------------------------------- /src/adrs/6860374633/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: '6860374633' 3 | title: Error CloudEvents Adapter 4 | state: Approved 5 | created: 2020-11-10 6 | tags: [messaging, errors, cloudevents, adapter] 7 | category: Platform 8 | --- 9 | 10 | # Error CloudEvents Adapter 11 | 12 | This document describes how to Errors events into a CloudEvents. 13 | 14 | ## Table of Contents 15 | 16 | - [Error CloudEvents Adapter](#error-cloudevents-adapter) 17 | - [Table of Contents](#table-of-contents) 18 | - [Purpose](#purpose) 19 | - [Context Attributes Extension](#context-attributes-extension) 20 | - [dataschema](#dataschema) 21 | - [data](#data) 22 | - [Event Data](#event-data) 23 | - [errormessage](#errormessage) 24 | - [errorlink](#errorlink) 25 | - [metadata](#metadata) 26 | - [Example](#example) 27 | 28 | ## Purpose 29 | 30 | Errors are everywhere. However, error's producers tend to describe errors 31 | differently. 32 | 33 | The lack of a common way of describing errors means developers are continually 34 | re-learning how to consume errors. That also limits the potential for libraries, 35 | tooling, and infrastructure to aid of error data across delivery environments, 36 | like SDK or logger systems. The portability and productivity that can be 37 | achieved from error data are hindered overall. 38 | 39 | This ADR is a specification for describing error data in standard formats to 40 | provide interoperability across services, platforms, and systems. 41 | 42 | ## Context Attributes Extension 43 | 44 | ### dataschema 45 | 46 | - Constraints: 47 | - REQUIRED 48 | - MUST be 49 | 50 | ### data 51 | 52 | - Constraints: 53 | - REQUIRED 54 | 55 | ## Event Data 56 | 57 | ### errormessage 58 | 59 | - Type: String 60 | - Description: contains a generic description of the error condition in English. 61 | It is intended for a human audience. Simple programs display the message 62 | directly to the end user if they encounter an error condition they don't know 63 | how or don't care to handle. Sophisticated programs with more exhaustive error 64 | handling and proper internationalization are more likely to ignore the error 65 | message. 66 | - Constraints: 67 | - OPTIONAL 68 | - If present, **MUST** be a non-empty string 69 | 70 | ### errorlink 71 | 72 | - Type: URI 73 | - Description: URL to documentation related to the error. 74 | - Constraints: 75 | - OPTIONAL 76 | - If present, **MUST** be a non-empty URI 77 | 78 | ### metadata 79 | 80 | - Type: Object 81 | - Description: The metadata associated to the error. 82 | - Constraints: 83 | - OPTIONAL 84 | - If present, **MUST** be an object 85 | - If present, the object key **MUST** be an string 86 | - If present, the object value **MUST** be an array of string or an string 87 | 88 | ## Example 89 | 90 | The following example shows a CloudEvent Error serialized as JSON: 91 | 92 | ```json 93 | { 94 | "specversion" : "1.x-wip", 95 | "id" : "YH9UUdlCjQztui7untrQE", 96 | "type" : "com.straw-hat-team.sso.not_found", 97 | "source" : "https://github.com/straw-hat-team/sso", 98 | "time" : "2018-04-05T17:31:00Z", 99 | "subject" : "/account", 100 | "datacontenttype" : "application/json", 101 | "data" : "{ 102 | \"errormessage\":\"Resource not found\", 103 | \"errorlink\":\"https://github.com/straw-hat-team/sso/docs/errors/E0000008.md\", 104 | \"metadata\":{ 105 | \"account_id\":\"something\" 106 | } 107 | }" 108 | } 109 | ``` 110 | 111 | You may use a `subject` that identify particular field from the input data. 112 | The following example shows a CloudEvent Error serialized as JSON: 113 | 114 | ```jsonc 115 | { 116 | "specversion" : "1.x-wip", 117 | "id" : "e8QIbN7KDaQDSagrWM8d8", 118 | "type" : "com.straw-hat-team.payment.insufficient_fund", 119 | "source" : "https://github.com/straw-hat-team/payment", 120 | "time" : "2018-04-05T17:31:00Z", 121 | "subject" : "/payment/amount", 122 | "datacontenttype" : "application/json", 123 | "data" : "{ 124 | \"errormessage\":\"Can not transfer an amount greater than the current balance\", 125 | \"errorlink\":\"https://github.com/straw-hat-team/payment/docs/errors/E0000001.md\", 126 | \"metadata\":{ 127 | \"amount_requested\":\"500000\", 128 | \"current_balance\":\"200000\" 129 | } 130 | }" 131 | } 132 | ``` 133 | -------------------------------------------------------------------------------- /src/adrs/0000000001/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: '0000000001' 3 | title: ADR Style guide 4 | state: Approved 5 | created: 2020-11-8 6 | tags: [genesis] 7 | category: General 8 | --- 9 | 10 | # ADR Style guide 11 | 12 | ADRs are most useful when they are clear and concise, and cover a single topic 13 | or inquiry well. In the same way that ADRs describe consistent patterns and 14 | style for use in APIs, they also follow consistent patterns and style. 15 | 16 | ## Guidance 17 | 18 | ADRs must cover a single, discrete topic, and should fundamentally answer the 19 | question, "What do I do?" with actionable guidance. ADRs may also cover what not 20 | to do. 21 | 22 | While the length of ADRs will necessarily vary based on the complexity of the 23 | question, most ADRs should be able to cover their content in roughly two 24 | printed pages. 25 | 26 | ## Requirement keywords 27 | 28 | ADRs **SHOULD** use the following requirement level keywords: "MUST", "MUST NOT", 29 | "SHOULD", "SHOULD NOT", and "MAY", which are to be interpreted as described in 30 | [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) and 31 | [RFC 8174](https://datatracker.ietf.org/doc/html/rfc8174). 32 | 33 | When using these terms in ADRs, they **MUST** be upper-case and **bold**. These 34 | terms should not be used in other ways. 35 | 36 | ## Assigning ADR Numbers 37 | 38 | The ADR editors are responsible for assigning a number to each ADR when it is 39 | accepted as a draft for review. Importantly, all ADRs have numbers, not just 40 | approved ones. The ADR Index clearly delineates which ADRs are approved and 41 | binding and which are under discussion. 42 | 43 | Beyond this, ADR numbers are assigned arbitrarily using `nanoid` 44 | `limited to 10 character` and `only 0123456789 characters`. 45 | 46 | In general, the editors will generate the next ADR number to assign to a draft 47 | ADR. 48 | 49 | ## Referencing ADRs 50 | 51 | When ADRs reference other ADRs, the prosaic text must use the format 52 | ADR#XXXXXXXXXX (e.g., [ADR#0000000000](../0000000000/README.md)), and must 53 | link to the relevant ADR. ADR links may point to a particular section of the 54 | ADR if appropriate. 55 | 56 | > ADR links must use the relative path to the file in the repository, this 57 | > ensures that the link works both on the ADR site, when viewing the Markdown 58 | > file on GitHub, using the local development server, or a branch. 59 | 60 | ## File structure 61 | 62 | ADRs **MUST** be written in Markdown, and the directory **MUST** be named using 63 | their ten-digit number (example: 3870009043), with a `README.md` file in it, for 64 | example: `adrs/3870009043/README.md`. 65 | 66 | ADRs **MAY** have other supporting files in the ADR directory. 67 | 68 | ## Document structure 69 | 70 | ADRs **MUST** begin with a top-level heading with the ADR's title (# Title). 71 | ADRs **SHOULD** then begin with the metadata information about the ADR 72 | 73 | - **State:** the estate of the ADR. 74 | - **Replaced by:** the link to the ADR that was replaced by. 75 | - **Created:** when the ADR was created following the **YYYY-MM-DD** format. 76 | - **Tags:** the tags separated by comma, and the tags **MUST** be lowercase. 77 | 78 | Followed by the content of the ADR. Below is an example ADR shell that uses 79 | each major section: 80 | 81 | ```md 82 | # The title of the ADR 83 | 84 | - **State:** Replaced 85 | - **Replaced by:** [ADR#0000000000](../ADRs/../adrs/0000000000/README.md) 86 | - **Created:** 2020-11-08 87 | - **Tags:** genesis 88 | 89 | 92 | 93 | ## Context and Problem Statement 94 | 95 | 99 | 100 | ## Decision Drivers 101 | 102 | 107 | 108 | ## Considered Options 109 | 110 | ### Option [1] 111 | 112 | [example | description | pointer to more information | …] 113 | 114 | - Good, because [argument a] 115 | - Good, because [argument b] 116 | - Bad, because [argument c] 117 | - … numbers of consequences 118 | 119 | ## Decision Outcome 120 | 121 | Chosen option: "[option 1]", because [justification. e.g., only option, which 122 | meets k.o. criterion decision driver | which resolves force force | … | comes 123 | out best (see below)]. 124 | 125 | ### Advantages 126 | 127 | - [e.g., improvement of quality attribute satisfaction, follow-up decisions 128 | required, …] 129 | - … 130 | 131 | ### Disadvantages 132 | 133 | - [e.g., compromising quality attribute, follow-up decisions required, …] 134 | - … 135 | 136 | ## Links 137 | 138 | 142 | ``` 143 | 144 | ADRs **SHOULD** attempt to follow this overall format if possible, but ADRs 145 | **MAY** deviate from it if necessary. 146 | -------------------------------------------------------------------------------- /src/adrs/4937890790/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: '4937890790' 3 | title: JavaScript Modules exports convention 4 | state: Approved 5 | created: 2021-02-17 6 | tags: [js, ts] 7 | category: JavaScript 8 | --- 9 | 10 | # JavaScript Modules exports convention 11 | 12 | ## Context 13 | 14 | We don't have a consistent way to export a module's functions and variables 15 | across the JavaScript ecosystem. Teams that don't choose a camp are inflicting 16 | an unnecessary cognitive load on themselves. 17 | 18 | What is one of the most challenging things in computer science? Naming. 19 | 20 | Using default-exports over named-exports forces the user to think about the name 21 | of the import. 22 | 23 | Let's use the following example: 24 | 25 | ```ts 26 | import [name here] from 'base-button' 27 | ``` 28 | 29 | What should be the right name for the import? 30 | 31 | - `Button` 32 | - `baseButton` 33 | - `BaseButton` 34 | - `MyButton` or any other name you would like it to be 35 | 36 | For a simple default import, you already have at least three different 37 | variations to think about and combinations of any name for that matter. 38 | 39 | Besides that, in some cases, you even have to think about the context of the 40 | file. 41 | 42 | For example, if the `base-button` is in React components, probably the right 43 | import name would be either `Button` or `BaseButton` or anything that it uses 44 | `PascalCase.` That is a limitation of React itself. You can not be "100% sure" 45 | unless you inspect the file and understand the context of such default-export. 46 | 47 | It is not a simple task; therefore, people rely on linters and code reviewers to 48 | improve the source code's quality. 49 | 50 | Naming is hard. When you are authoring code, do not make the consumers of your 51 | code -- the importers of your exports -- figure out what names to use. As an 52 | author, you have the advantage of having thought about its intent and purpose; 53 | you are aware of its context and limitations and most likely gave it a name 54 | inside your module. That name is good enough, and by using named exports, you 55 | are doing your consumers a favor, by freeing them from having to rediscover that 56 | name. 57 | 58 | Also, using default-exports makes it harder to understand the context of things 59 | across the codebase. 60 | 61 | For example, take the following files: 62 | 63 | File #1: 64 | 65 | ```ts 66 | // Notice the import name 67 | import Button from '...'; 68 | 69 | export function Something() { 70 | return ( 71 | <> 72 | ... 73 |