Compare commits
No commits in common. "8498bfca495a91c2333e60bd58fb300f7428703f" and "a85f9adc9bffc25893baffa829a01ff4d5529d3c" have entirely different histories.
8498bfca49
...
a85f9adc9b
8
.cz.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[tool.commitizen]
|
||||
name = "cz_conventional_commits"
|
||||
tag_format = "$version"
|
||||
version_scheme = "semver"
|
||||
version_provider = "npm"
|
||||
update_changelog_on_bump = true
|
||||
major_version_zero = true
|
||||
changelog_incremental = true
|
||||
30
.eslintrc.cjs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
module.exports = {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
},
|
||||
extends: [
|
||||
'standard-with-typescript',
|
||||
'plugin:react/recommended',
|
||||
'plugin:cypress/recommended',
|
||||
'prettier',
|
||||
],
|
||||
overrides: [
|
||||
{
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
files: ['.eslintrc.{js,cjs}'],
|
||||
parserOptions: {
|
||||
sourceType: 'script',
|
||||
},
|
||||
},
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
project: ['./tsconfig.json'],
|
||||
},
|
||||
plugins: ['react', 'cypress'],
|
||||
rules: {},
|
||||
};
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
name: Content update
|
||||
about: Content creation or edition
|
||||
title: '[Content]: '
|
||||
ref: 'content-update'
|
||||
assignees:
|
||||
- aleidk
|
||||
labels:
|
||||
- Priority/Low
|
||||
- Severity/Low
|
||||
- Status/Pending
|
||||
- Type/Content
|
||||
body:
|
||||
- type: dropdown
|
||||
id: topic
|
||||
attributes:
|
||||
label: "Topic:"
|
||||
multiple: true
|
||||
default: 0
|
||||
options:
|
||||
- Garden
|
||||
- Blog
|
||||
- Devlog
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: content
|
||||
attributes:
|
||||
label: "Content description:"
|
||||
description: Brief ideas of what this content is about.
|
||||
placeholder: Lorem Ipsum...
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: extra
|
||||
attributes:
|
||||
label: "Extra data and references:"
|
||||
placeholder: Lorem Ipsum...
|
||||
validations:
|
||||
required: false
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
name: Feature request
|
||||
about: Request a new feature to be added
|
||||
title: '[Feature]: '
|
||||
ref: 'development'
|
||||
assignees:
|
||||
- aleidk
|
||||
labels:
|
||||
- Priority/Low
|
||||
- Severity/Low
|
||||
- Status/Pending
|
||||
- Type/Feature
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
We appreciate your feedback on how to improve this project. Please be sure to include as much details and any resources if possible!
|
||||
|
||||
- type: dropdown
|
||||
attributes:
|
||||
multiple: false
|
||||
label: Type of Feature
|
||||
default: 0
|
||||
options:
|
||||
- "✨ New Feature"
|
||||
- "📝 Documentation"
|
||||
- "🎨 Style and UI"
|
||||
- "🔨 Code Refactor"
|
||||
- "⚡ Performance Improvements"
|
||||
- "✅ New Test"
|
||||
- "🪢 Architecture"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: Give us a brief description of the feature or enhancement you would like.
|
||||
placeholder: As <who> <when> <where>, I want <what> because <why>
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: completion-criteria
|
||||
attributes:
|
||||
label: Completion criteria
|
||||
description: Tell us what this feature needs to do to be considered completed using verificable items.
|
||||
placeholder: |
|
||||
- [ ] Read the configuration file using the yaml format
|
||||
- [ ] Fetch data from an the json-placehoder API
|
||||
- [ ] Save the data in the database
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: additional-information
|
||||
attributes:
|
||||
label: Additional Information
|
||||
description: |
|
||||
Please leave any additional information on the feature request that could be helpful! like proposed solutions, examples, links, screenshots, etc.
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
name: Bug report
|
||||
about: Something isn't working as expected
|
||||
title: '[Bug]: '
|
||||
ref: 'development'
|
||||
assignees:
|
||||
- aleidk
|
||||
labels:
|
||||
- Priority/Low
|
||||
- Severity/Low
|
||||
- Status/Pending
|
||||
- Type/Bug
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
We appreciate your feedback on how to improve this project. Please be sure to include as much details and any resources if possible!
|
||||
|
||||
- type: checkboxes
|
||||
id: terms
|
||||
attributes:
|
||||
label: Before submitting, I checked...
|
||||
options:
|
||||
- label: The [issue tracker](../) in case this has been reported before
|
||||
required: true
|
||||
- label: The severity of the bug
|
||||
required: true
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: "Expected behavior:"
|
||||
description: A clear and concise description of what you expected to happen. Include screenshots and/or logs if relevant.
|
||||
placeholder: As <who> <when> <where>, I want <what> because <why>
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: current
|
||||
attributes:
|
||||
label: "Current behavior:"
|
||||
description: A clear and concise description of what actually happened. Include screenshots and/or logs if relevant.
|
||||
placeholder: As <who> <when> <where>, I want <what> because <why>
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: reproduce
|
||||
attributes:
|
||||
label: "Steps to reproduce:"
|
||||
description: Anambiguous set of steps to reproduce this bug. Include code snippets if relevant.
|
||||
placeholder: |
|
||||
1. Use x argument / navigate to
|
||||
2. Fill this information
|
||||
3. Go to...
|
||||
4. See error
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
attributes:
|
||||
multiple: false
|
||||
label: Is this a regresion?
|
||||
description: Did this behaviour used to work in the previous version?
|
||||
default: 0
|
||||
options:
|
||||
- "I don't know"
|
||||
- "This is a new feature"
|
||||
- "Yes"
|
||||
- "No"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: environment
|
||||
attributes:
|
||||
label: "Your environment:"
|
||||
description: Tell us details about the environment you experienced the bug in. A minimal/isolated enviroment to reproduce would be apreciated.
|
||||
placeholder: |
|
||||
- Version used:
|
||||
- Browser Name and version:
|
||||
- Operating System and version (desktop or mobile):
|
||||
- Link to your project:
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
id: additional-information
|
||||
attributes:
|
||||
label: "Additional Information:"
|
||||
description: |
|
||||
Please leave any additional information on the bug that could be helpful! like proposed solutions, examples, links, screenshots, etc.
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
name: Publish image
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
create-docker-images:
|
||||
runs-on: host
|
||||
steps:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: git.alecodes.page
|
||||
username: ${{ vars.CONTAINER_REGISTRY_USER }}
|
||||
password: ${{ secrets.CONTAINER_REGISTRY_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
push: true
|
||||
tags: |
|
||||
git.alecodes.page/alecodes/page:latest
|
||||
git.alecodes.page/alecodes/page:${{ github.sha }}
|
||||
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- create-docker-images
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: 'Docker Stack Deploy'
|
||||
uses: https://github.com/cssnr/stack-deploy-action@v1
|
||||
with:
|
||||
host: ${{ vars.DOCKER_SWARM_HOST }}
|
||||
port: ${{ vars.DOCKER_SWARM_PORT }}
|
||||
user: ${{ secrets.DOCKER_SWARM_USER }}
|
||||
ssh_key: '${{ secrets.DOCKER_SWARM_SSH_KEY }}'
|
||||
file: 'docker-stack.yaml'
|
||||
name: 'personal_page'
|
||||
|
||||
rebase:
|
||||
runs-on: ubuntu-latest
|
||||
needs: deploy
|
||||
if: success()
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: '0'
|
||||
ref: content-update
|
||||
|
||||
- name: Update branch
|
||||
run: |
|
||||
set -x
|
||||
git config --global user.name "robo"
|
||||
git config --global user.email "robo@alecodes.page"
|
||||
git rebase origin/main
|
||||
git push origin content-update --force-with-lease
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
lint:
|
||||
zola check --drafts
|
||||
|
||||
dev:
|
||||
@zola serve --port 3000 --fast
|
||||
|
||||
build:
|
||||
@zola build
|
||||
16
.prettierrc.cjs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
module.exports = {
|
||||
tabWidth: 2,
|
||||
singleQuote: true,
|
||||
endOfLine: 'auto',
|
||||
'eol-last': 2,
|
||||
trailingComma: 'all',
|
||||
plugins: [require.resolve("prettier-plugin-astro")],
|
||||
overrides: [
|
||||
{
|
||||
files: "*.astro",
|
||||
options: {
|
||||
parser: "astro",
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
2
.rtx.toml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
[tools]
|
||||
node = "20"
|
||||
4
.vscode/extensions.json
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"recommendations": ["astro-build.astro-vscode"],
|
||||
"unwantedRecommendations": []
|
||||
}
|
||||
11
.vscode/launch.json
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"command": "./node_modules/.bin/astro dev",
|
||||
"name": "Development server",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
30
.woodpecker.yml
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
when:
|
||||
- branch: main
|
||||
|
||||
steps:
|
||||
build-and-publish:
|
||||
when:
|
||||
branch: main
|
||||
image: node:20-alpine
|
||||
secrets:
|
||||
- codeberg_ssh_key
|
||||
commands:
|
||||
- apk add git openssh-client
|
||||
- git config --global user.email "woodpecker@bot.net"
|
||||
- git config --global user.name "woodpecker-bot"
|
||||
- git remote add codeberg-ssh git@codeberg.org:aleidk/personal-page.git
|
||||
- mkdir -p $HOME/.ssh
|
||||
- ssh-keyscan -t rsa codeberg.org >> $HOME/.ssh/known_hosts
|
||||
- echo "$CODEBERG_SSH_KEY" > $HOME/.ssh/id_rsa
|
||||
- chmod 0600 $HOME/.ssh/id_rsa
|
||||
- corepack enable
|
||||
- corepack prepare pnpm@latest --activate
|
||||
- pnpm install
|
||||
- pnpm build
|
||||
- |
|
||||
cat >dist/.domains <<EOL
|
||||
blog.panconpalta.win
|
||||
personal-page.aleidk.codeberg.page
|
||||
pages.personal-page.aleidk.codeberg.page
|
||||
EOL
|
||||
- pnpm exec gh-pages --dist dist --branch pages --dotfiles --remote codeberg-ssh
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
FROM --platform=linux/amd64 ghcr.io/getzola/zola:v0.19.2 AS builder
|
||||
|
||||
COPY . /project
|
||||
WORKDIR /project
|
||||
RUN ["zola", "build"]
|
||||
|
||||
FROM ghcr.io/static-web-server/static-web-server:2
|
||||
WORKDIR /
|
||||
COPY --from=builder /project/dist /public
|
||||
|
|
@ -35,5 +35,3 @@ Cool websites for inspiration:
|
|||
- [Cory Hughart](https://coryhughart.com/)
|
||||
- [Brad Frost](https://bradfrost.com/)
|
||||
- [dvlpr](https://dvlpr.pro/#home)
|
||||
- [Gwern Branwen](https://gwern.net/)
|
||||
- [Maggie Appleton](https://maggieappleton.com/)
|
||||
|
|
|
|||
5
_master_wiki/.gitignore
vendored
|
|
@ -1,5 +0,0 @@
|
|||
.obsidian/wokspace.json
|
||||
.obsidian/workspace-mobile.json
|
||||
.env
|
||||
.obsidian/workspace.json
|
||||
.trash
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
created: 2024-04-14 12:43
|
||||
updated: 2024-04-15 20:56
|
||||
---
|
||||
- [Carmen Ansio](https://www.youtube.com/@CarmenAnsio)
|
||||
- Marina Aísa
|
||||
- Sarah Drasner
|
||||
- [Kevin Powell](https://www.youtube.com/@KevinPowell)
|
||||
- Miriam Suzanne
|
||||
- [Manz Dev](https://www.youtube.com/@ManzDev)
|
||||
- [Una Kravets](https://www.youtube.com/@UnaKravets/videos)
|
||||
- [Serudda](https://www.youtube.com/@serudda/videos)
|
||||
- Josh Comeau
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
---
|
||||
created: 2023-08-17 10:05
|
||||
updated: 2024-03-12 13:49
|
||||
---
|
||||
Diseñar está completamente fuera de mi zona de confort, así que estudiar como hacer, y hacer el esfuerzo de planear como diseñar la página antes de tirarme de hocico a hacerlo ha sido una experiencia bastante satisfactoria
|
||||
|
||||
Pensar que debo realizar, que quiero comunicar y como lo quiero comunicar ha enrutado el diseño y permitiendo que sea más facil
|
||||
|
||||
el feedback tambien ha sido satisfactorio, porque me ha hecho entender mejor que debo hacer y que no, tambien algúnos comentarios han contradecido completamente lo que yo creería que sería mejor, lo cuál ha enfocado mejor el diseño final en lo que realmente debe (y como debe) ser la página
|
||||
|
||||
## Cómo enfatizar un elemento
|
||||
|
||||
Para hacer que un elemento destaque del fondo, debemos ocupar _**Elevación**_,esto hará que el elemento parezca estar más cerca de la pantalla, haciendo que resalte de lo demás y atrapando la atención del usuario.
|
||||
|
||||
La manera de lograr esto depende del tema:
|
||||
|
||||
### Light Theme
|
||||
|
||||
Contrastar el contorno del elemento con su entorno, para esto podemos:
|
||||
|
||||
- Utilizar sombras, esto destaca el contorno de un elemento y su grado de elevación.
|
||||
- sombras más pequeñas y definidas indican mayor proximidad al fondo.
|
||||
- sombras más grandes y difuminadas indican mayor lejanía del fondo.
|
||||
- Distintos colores diferencian elementos pero no proveen su grado de elevación.
|
||||
- Opacidad muestra los contornos de los elementos y su solapamiento, pero no su grado de elevación.
|
||||
- Podemos oscurecer el fondo para destacar un elemento sobre todo lo demás, esto ofrece una gran, pero no especifica cantidad de elevación.
|
||||
|
||||
### Dark Theme
|
||||
|
||||
- Utilizar colores claros para denotar el grado de elevación:
|
||||
- Utilizar colores directamente. mientras más claro sea el color, más elevado estará un componente.
|
||||
- Aplicar un _"overlay"_ de un color claro, con distintos grados de transparencia. Mientras menos transparente más elevado estará el componente. No aplicar este esto a los colores primarios o similares.
|
||||
- _**NO**_ aplicar "light glows" en lugar de sombras oscuras para expresar elevación, porque no logran el mismo efecto.
|
||||
|
||||
### References of common elevations
|
||||
|
||||
| Component | Default elevation values (dp) | White overlay transparency |
|
||||
| --------------------------------------------------------- | ----------------------------- | -------------------------- |
|
||||
| Dialog | 24 | 16% |
|
||||
| Modal bottom sheet Modal side sheet | 16 | 15% |
|
||||
| Navigation drawer | 16 | 15% |
|
||||
| Floating action button (FAB - pressed) | 12 | 14% |
|
||||
| Standard bottom sheet Standard side sheet | 8 | 12% |
|
||||
| Bottom navigation bar | 8 | 12% |
|
||||
| Bottom app bar | 8 | 12% |
|
||||
| Menus and sub menus | 8 | 12% |
|
||||
| Card (when picked up) | 8 | 12% |
|
||||
| Contained button (pressed state) | 8 | 12% |
|
||||
| Floating action button (FAB - resting elevation) Snackbar | 6 | 11% |
|
||||
| Top app bar (scrolled state) | 4 | 9% |
|
||||
| Top app bar (resting elevation) | 0 or 4 | 0% - 9% |
|
||||
| Refresh indicator Search bar (scrolled state) | 3 | 8% |
|
||||
| Contained button (resting elevation) | 2 | 7% |
|
||||
| Search bar (resting elevation) | 1 | 5% |
|
||||
| Card (resting elevation) | 1 | 5% |
|
||||
| Switch | 1 | 5% |
|
||||
| Text button | 0 | 0% |
|
||||
| Standard side sheet | 0 | 0% |
|
||||
|
||||
Reference:
|
||||
|
||||
- [Material Design - UI](https://m2.material.io/design/environment/elevation.html)
|
||||
- [Material Design - Dark Theme](https://m2.material.io/design/color/dark-theme.html)
|
||||
|
||||
|
||||

|
||||
|
Before Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 1.9 MiB |
|
|
@ -1,6 +0,0 @@
|
|||
---
|
||||
created: 2024-02-29 18:36
|
||||
updated: 2024-03-12 13:49
|
||||
---
|
||||
## Layouts
|
||||
- [How to Properly Layout A Website (For Beginners)](https://www.youtube.com/watch?v=3C_22eBWpjg&t=604s)
|
||||
|
Before Width: | Height: | Size: 851 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
|
@ -1,147 +0,0 @@
|
|||
---
|
||||
created: 2024-04-03 12:11
|
||||
updated: 2024-04-03 13:52
|
||||
---
|
||||
|
||||
# Story Telling
|
||||
|
||||
## El Arco Narrativo
|
||||
|
||||
- Ir de un punto álgido a otro bajo y volver a subir es lo que have que una historia de la satisfactoria sensación de estar completa
|
||||
- Una historia comienza con un _"llamado a la acción"_, el verbo mueve al sujeto.
|
||||
|
||||
## El Viaje Del Héroe
|
||||
|
||||
Se puede utilizar el patrón del _"viaje del héroe"_ en el diseño para guiar a los usuarios:
|
||||
|
||||
- Un incidente iniciante o una problemática que incita al "héroe" a moverse de donde está
|
||||
- El "llamado a la aventura" es donde se incita al usuario a algo
|
||||
- El "cruce del umbral", en donde el usuario entra en el otro sector (posiblemente hostil) en donde tendrá que pasar la "prueba de fuego"
|
||||
- El camio de vuelta, donde regresamos al origen pero co algo nuevo ("regreso con el elixir")
|
||||
|
||||
## Story Boards
|
||||
|
||||
Los story boards son herramientas para planificar la acción transformadora de una historia.
|
||||
|
||||
Contar una historia en 6 fotogramas es una buena manera de contar los elementos esenciales de la forma narrativa
|
||||
|
||||
## Ingredientes De Una Historia
|
||||
|
||||
- **Arco**: la acción tiene un principio, un nudo y un final.
|
||||
- **Cambio**: la acción transforma a un personaje o una situación.
|
||||
- **Tema**: la acción se construye a partir de detalles concretos y relevantes.
|
||||
- **Plausibilidad**: la acción es verosímil y sigue sus propias reglas.
|
||||
|
||||
## Regla De 3
|
||||
|
||||
Contar una historia en 3 pasos es una herramienta poderosa:
|
||||
|
||||
- 3 pasos da la sensación de facilidad y rapidez, aunque estos 3 pasos engloben más en secreto, agrupar tareas suele estar bien mientras no genere confusión
|
||||
- Si se utilize de modo que el ultimo elemento es inesperado, puede sorprender y generar una sensación de satisfacción
|
||||
- Ayuda a la memorización de elementos clave, sobre todo combinado con el item anterior
|
||||
|
||||
Esta regla se puede extender a 4 pasos, perdiendo cierta efectividad. Más de
|
||||
4 pasos no suele set rentable, ya que da una sensación de set demasiado largo y "latero"
|
||||
|
||||
## Conexiones Forzadas
|
||||
|
||||
Aplicar conceptos e ideas, que en un principio pueden parecer contrarias o inconexas puede llevar a nuevas ideas y diseños interesantes, se puede emplear un concepto (Extraterrestre, colosal, vulgar, zoologico, etc) a un elemento a diseñar y ver que ocurre.
|
||||
|
||||
## Emoción
|
||||
|
||||
El diseño destinado a susitar emociones require pensar en como los usuarios anticiparán una experiencia y cómo la recordarán después.
|
||||
|
||||
>[!quote]
|
||||
> "Las emociones son una palanca para la acción."
|
||||
>
|
||||
> "Los diseñadores necesitan adoptar estrategias para acceder a los contextos emocionales de los productos que tienen que diseñar, pensando en la gente que los usará."
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Economía De la Experiencia
|
||||
|
||||
Durante una experiencia, los usuarios generan significados y asociaciones que adquieren una mayor importancia que la del propio acontecimiento
|
||||
|
||||
Una experiencia es algo más de lo que se consume en el memento. Integra al consumidor en una representación teatral, creando un recuerdo perdurable y un lazo emocional.
|
||||
|
||||

|
||||
|
||||
Las experiencias se crean cuando los diseñadores deplazan el **foco** de los objetos a las acciones:
|
||||
|
||||
> [!info]
|
||||
> Esto no necesariamente significa que el usuario realice algo, sino mover el principal elemento a una acción:
|
||||
> - Auto -> conducir
|
||||
> - Restaurant -> Cenar
|
||||
> - Universidad -> Aprender
|
||||
|
||||
## El Viaje Emocional
|
||||
|
||||
Si una trama consiste en más de una series de sucesos que conforman una historia, un viaje emocional consiste en los sentimientos que esos sucesos despiertan
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
La forma en que concluye una experiencia afecta el juicio que los usuarios emitirán sobre el acontecimiento completo.
|
||||
|
||||
Prestar especial atención a la forma en la que concluyen las acciones, ofreciendo un extra de carga emocional para recompensar a los usuarios por su tiempo y esfuerzo.
|
||||
|
||||
## Cocreación
|
||||
|
||||
Los diseñadores trabajan junto a los usuarios, los cuales son considerados "un experto en el tema tratado".
|
||||
|
||||
## Técnicas Útiles
|
||||
|
||||
### Mapa De Palabras
|
||||
|
||||
Cada participante escribe un tema en el centro de una hoja, mediante un proceso de libre asociación, los participantes dibujan o escriben conceptos asociados para crear nodos de ideas
|
||||
|
||||

|
||||
|
||||
### Fuerzas Positivas Y Negativas
|
||||
|
||||
Crear una matriz de conceptos + y -
|
||||
|
||||
| | Pros | Cons |
|
||||
| -------------------------------------- | -------------------------------------- | --------------------------------------------------- |
|
||||
| Cómo hacer que más gente tome la micro | - ahorrar dinero<br>- Leer en el viaje | - Tiempo de viaje<br>- No hay lugar para bicicletas |
|
||||
|
||||
> [!question]
|
||||
> Tendrá que ver con [[FODA]]??
|
||||
|
||||
### Asociación
|
||||
|
||||
Se le asignan emociones o personalidad a una idea
|
||||
|
||||

|
||||
|
||||
### Estudio De Personaje
|
||||
|
||||
Crear una planilla para un producto como si fuera una persona:
|
||||
|
||||
- Que edad tiene?
|
||||
- En que trabaja?
|
||||
- Cómo vive?
|
||||
- Cómo viste?
|
||||
- Donde pasará sus vacaciones?
|
||||
|
||||
Se puede partir tratando de imaginar al usuario que va dirigido el producto y simular su estilo de vida
|
||||
|
||||
Ej:
|
||||
|
||||
Perfile #1, Altavoz inalámbrico:
|
||||
|
||||
- Edad: 25
|
||||
- Ocupación: Programador
|
||||
- Vivienda: Depto. urbano
|
||||
- Transporte: Bicicleta
|
||||
- Ropa: Jeans y vintage
|
||||
|
||||
## Color Y Las Emociones
|
||||
|
||||
## References
|
||||
|
||||
- El diseño como STORYTELLING - Ellen Lupton
|
||||
- [Design notes on pdf](Design_Cheatsheet.pdf)
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
created: 2024-02-28 13:18
|
||||
updated: 2024-03-12 13:49
|
||||
---
|
||||
|
||||
| Library | Description |
|
||||
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
||||
| [shadcn/ui](https://ui.shadcn.com/) | Beautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Open Source. |
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
---
|
||||
created: 2024-04-15 20:56
|
||||
updated: 2024-04-15 20:56
|
||||
---
|
||||
# Devtools
|
||||
|
||||
List of tools to solve common problems
|
||||
|
||||
## Tasks Runners
|
||||
|
||||
- [Overseer](https://github.com/stevearc/overseer.nvim): nvim task management
|
||||
|
||||
## Debugging
|
||||
|
||||
- [debugprint.nvim](https://github.com/andrewferrier/debugprint.nvim): manage print statements with useful information inside neovim
|
||||
|
||||
## Nvim Tools
|
||||
|
||||
### Focus Mode
|
||||
|
||||
- [Zen mode](https://github.com/folke/zen-mode.nvim): focus on the current portion of a file only
|
||||
|
||||
### Codebase Navigation
|
||||
|
||||
- Telescope
|
||||
- [Graple](https://github.com/stevearc/overseer.nvim), bookmarks files to instant navigation in 1 key chord
|
||||
|
||||
### File Navigation
|
||||
|
||||
- [flash.nvim](https://github.com/folke/flash.nvim): jump to any place, enhances search, `f`,`F`,`t`,`T`, motions
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
# Docker
|
||||
|
||||
## Publish Container Images
|
||||
|
||||
To easily create multi-arch containers and publish them to a registry, use this snipped (note you need to be logged in the registry):
|
||||
|
||||
Create builder container:
|
||||
```bash
|
||||
docker buildx create --name mybuilder --use --bootstrap
|
||||
```
|
||||
|
||||
Build and publish image:
|
||||
```bash
|
||||
docker buildx build --push \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
--tag ghcr.io/<name-space>/<image>:latest .
|
||||
```
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
created: 2024-02-20 11:39
|
||||
updated: 2024-03-12 13:49
|
||||
---
|
||||
When a feature or module is shipt, I need to asure the following things before submiting:
|
||||
|
||||
- Clean & readable code
|
||||
- Linter without errors
|
||||
- Design is as close as posible to the proposal
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
---
|
||||
created: 2024-02-20 11:27
|
||||
updated: 2024-03-12 13:49
|
||||
tags:
|
||||
- dev-tools
|
||||
---
|
||||
# Fix messy commits
|
||||
|
||||
Ya que estas opciones sobre escriben el historial de git, solo deben aplicarse en local y no commits publicados a un remote.
|
||||
|
||||
Como alternativa se puede intentar actualizar el historial remoto siempre y cuando el historial sea igual al local (osea, nosotros fuimos los últimos en actualizarlo y nadie ha hecho nada más). Para esto utilizamos `git push --force-with-lease`.
|
||||
|
||||
## Last commit
|
||||
|
||||
Si solo necesitamos agregar un cambio pequeño al ultimo commit (typo o correr el formatter), podemos aplicarlo con `git commit --ammend`, se puede sobre escribir el mensaje con `-m`.
|
||||
|
||||
## Mutiple commits
|
||||
|
||||
Se pueden arreglar el historial de commits con un `git rebase -i [since commit or branch]` y utilizar las estrategias de pick, squash, reword y drop.
|
||||
|
||||
En caso de que sepamos que haremos un commit que luego no necesitaremos, podemos hacer:
|
||||
- `git commit --fixup [commit hash]` -> descarta el commit message de este commit y mantiene el del commit de referencia
|
||||
- `git commit --squash [commit hash]` -> git juntará los mensajes de todos los commits a hacer squash y el commit de referencia.
|
||||
|
||||
Finalmente podemos hacer `git rebase -i --autosquash` y git eligirá las opciones necesarias a tomar en vez de tener que hacerlo de manera manual.
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
created: 2024-02-13 22:36
|
||||
updated: 2024-03-12 13:49
|
||||
tags:
|
||||
- dev-tools
|
||||
---
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
Before Width: | Height: | Size: 194 KiB |
|
Before Width: | Height: | Size: 361 KiB |
|
Before Width: | Height: | Size: 238 KiB |
|
|
@ -1,65 +0,0 @@
|
|||
# So You Think You Know Git Part 2 - DevWorld 2024
|
||||
|
||||
## Switch and Restore
|
||||
|
||||
Wrapper around the `checkout` command to make more sense. You can do:
|
||||
|
||||
- `git switch branch` instead of `git checkout bracnh`
|
||||
- `git restore file.txt` instead of `git checkout file.txt`
|
||||
|
||||

|
||||
|
||||
## Git Hooks
|
||||
|
||||

|
||||
|
||||
useful ones:
|
||||
|
||||

|
||||
|
||||
uses:
|
||||
|
||||
- Commit message formatting
|
||||
- package install
|
||||
- update ctags
|
||||
- submodule status
|
||||
- tabs or spaces
|
||||
- linting
|
||||
- large files
|
||||
- test passes
|
||||
|
||||
Helpers (installable external tools):
|
||||
|
||||
- pre-commits
|
||||
- husky
|
||||
|
||||
## Attributes
|
||||
|
||||
run files through intermediates and diff that:
|
||||
|
||||
```bash
|
||||
echo '*.png diff=lexif' >> .gitattributes
|
||||
git config diff.exif.textconv exiftool
|
||||
```
|
||||
|
||||
## Fixup Commits
|
||||
|
||||
`git commit --fixup=<commit>`
|
||||
`git rebase --autosquash`
|
||||
|
||||
## Rebasing Stacks
|
||||
|
||||
move dangling branches reference when doing a rebase
|
||||
|
||||
`git rebase --update-refs`
|
||||
|
||||
## Scaling Git
|
||||
|
||||
top level command `scalar`, it's only used to clone huge repositories.
|
||||
|
||||
## Worktrees
|
||||
|
||||
- working on more than one branch at a time
|
||||
- provide a new working directory to each branch
|
||||
|
||||

|
||||
|
|
@ -1,24 +0,0 @@
|
|||
---
|
||||
created: 2024-02-20 11:43
|
||||
updated: 2024-03-12 13:49
|
||||
---
|
||||
|
||||
## How to make an Iframe 100% it's parent width while maintaining the aspect ratio
|
||||
|
||||
In this example, we need to wrap the iframe in a container class and provide the following styles:
|
||||
|
||||
```css
|
||||
.container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding-bottom: 56.25%;
|
||||
}
|
||||
iframe {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
```
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
---
|
||||
created: 2024-02-20 11:34
|
||||
updated: 2024-03-12 13:49
|
||||
tags:
|
||||
- dev-tools
|
||||
---
|
||||
## Revertir cambios
|
||||
|
||||
Si necesitamos _"deshacer"_ los cambios introducidos en uno o multiples commits, podemos utilizar `git revert --no-edit older_commit_hashˆ..newer_commit_hash`, donde:
|
||||
|
||||
- git realizará un nuevo commit con los cambios contrarios por cada commit en el rango
|
||||
- utilizar `ˆ` en el `old_commit_hash` incluirá ese commit en la reversión de cambios, si no se agrega se empezará a revertir de un commit más adelante.
|
||||
- `--no-edit` es utilizado para que git no nos pregunte por el message de cada nuevo commit
|
||||
- primero debe ser el commit más antiguo, porque git creará nuevos commits en orden provisto y de hacerlo al revés aparecerán conflictos
|
||||
- si solo se quiere revertir un commit, se puede especificar solo ese hash
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
created: 2024-02-20 11:35
|
||||
updated: 2024-03-12 13:49
|
||||
---
|
||||
# Buscar cuando un bug se introdujo
|
||||
|
||||
## Utilizar `git bisect`
|
||||
|
||||
`git bisect` hará un _"binary search"_ entre 2 commits, dejandonos señalar si este commit es _"bueno"_ (no tiene el bug) o _"malo"_ (tiene el bug), permitiendo encontrar el commit que introdujo el bug y facilitar encontrar la causa de este.
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
---
|
||||
created: 2024-02-10T18:24:25-03:00
|
||||
modified: 2024-02-10T18:33:38-03:00
|
||||
updated: 2024-03-12 13:49
|
||||
---
|
||||
|
||||
# 12. Questions
|
||||
|
||||
1. ¿Cómo puedo automatizar una tarea tediosa y/o que consume mucho tiempo?
|
||||
2. ¿Cómo me puedo hacer la vida más sencilla?
|
||||
|
||||
|
||||
> ‘You have to keep a dozen of your favorite problems constantly present in your mind, although by and large they will lay in a dormant state. Every time you hear or read a new trick or a new result, test it against each of your twelve problems to see whether it helps. Every once in a while there will be a hit, and people will say, “How did he do it? He must be a genius!”’
|
||||
>
|
||||
source: Tiago Forte, “[[Building a Second Brain]]”, p. 62
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
created: 2024-02-21 10:39
|
||||
updated: 2024-03-12 13:49
|
||||
---
|
||||
An Archipelago of Ideas separates the two activities your brain has the most difficulty performing at the same time: _choosing_ ideas (known as selection) and _arranging_ them into a logical flow (known as sequencing).
|
||||
|
||||
The goal of an archipelago is that instead of sitting down to a blank page or screen and stressing out about where to begin, **you start with a series of small stepping-stones to guide your efforts**. First you select the points and ideas you want to include in your outline, and then in a separate step, you rearrange and sequence them into an order that flows logically. This makes both of those steps far more efficient, less taxing, and less vulnerable to interruption.
|
||||
|
||||
To create an Archipelago of _Ideas_, you divergently gather a group of ideas, sources, or points that will form the backbone of your essay, presentation, or deliverable. Once you have a critical mass of ideas to work with, you switch decisively into convergence mode and link them together in an order that makes sense.
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
created: 2024-02-21 12:33
|
||||
updated: 2024-03-12 13:49
|
||||
---
|
||||
## Examples:
|
||||
|
||||
- If you want to write a book, you could dial down the scope and write a series of online articles outlining your main ideas. If you don’t have time for that, you could dial it down even further and start with a social media post explaining the essence of your message.
|
||||
- If you want to deliver a workshop for paying clients, you could dial it down to a free workshop at a local meetup, or dial it down even further and start with a group exercise or book club for a handful of colleagues or friends.
|
||||
- If you’d like to make a short film, start with a YouTube video, or if that’s too intimidating, a livestream. If it’s still too much, record a rough cut on your phone and send it to a friend.
|
||||
- If you want to design a brand identity for a company, start with a mock-up of a single web page. Even easier, start with a few hand-drawn sketches with your ideas for a logo.
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
---
|
||||
created: 2024-02-20 11:14
|
||||
updated: 2024-03-12 13:49
|
||||
---
|
||||
# Habits to apply while notetaking process
|
||||
|
||||
In order to provide high quality work we need to be organized to be able to _go with the flow_ and have the less friction posible. But we cannot afford to stop everything in our life to organize our stuff, we need to continue delivering and taking care of the next _"important stuff"_ one after the other.
|
||||
|
||||
For this, we can borrow the _"mise en place"_ techniques of chef's:
|
||||
|
||||

|
||||
|
||||
So, the following are habits to keep the [[second brain]] tied up while we are using it:
|
||||
|
||||
- [Project checklists](Project%20checklists.md)
|
||||
- [Periodic reviews](Periodic%20reviews.md)
|
||||
- Noticing other habits:
|
||||
- Noticing that an idea you have in mind could potentially be valuable and capturing it instead of thinking, “Oh, it’s nothing.”
|
||||
- Noticing when an idea you’re reading about resonates with you and taking those extra few seconds to highlight it.
|
||||
- Noticing that a note could use a better title—and changing it so it’s easier for your future self to find it.
|
||||
- Noticing you could move or link a note to another project or area where it will be more useful.
|
||||
- Noticing opportunities to combine two or more Intermediate Packets into a new, larger work so you don’t have to start it from scratch.
|
||||
- Noticing a chance to merge similar content from different notes into the same note so it’s not spread around too many places.
|
||||
- Noticing when an IP that you already have could help someone else solve a problem, and sharing it with them, even if it’s not perfect.
|
||||
|
||||
## Some things to keep in mind:
|
||||
|
||||
- **There’s no need to capture every idea**; the best ones will always come back around eventually.
|
||||
- **There’s no need to clear your inbox frequently**; unlike your to-do list, there’s no negative consequence if you miss a given note.
|
||||
- **There’s no need to review or summarize notes on a strict timeline**; we’re not trying to memorize their contents or keep them top of mind.
|
||||
- When organizing notes or files within PARA, it’s a **very forgiving decision of where to put something**, since search is so effective as a backup option.
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
---
|
||||
created: 2024-02-20 19:52
|
||||
updated: 2024-03-12 13:49
|
||||
---
|
||||
# Intermediate Packages
|
||||
|
||||
> [...] there is a flaw in focusing only on the final results: all the intermediate work (the notes, the drafts, the outlines, the feedback) tends to be underappreciated and undervalued. The precious attention we invested in producing that in-between work gets thrown away, never to be used again.
|
||||
>
|
||||
> Source: Tiago Forte, “[[Building a Second Brain]]”, p. 150
|
||||
|
||||
intermediate packages can receive different names depending on who you ask:
|
||||
|
||||
- “Modules” or “features” in software development
|
||||
- “Betas” tested by start-ups
|
||||
- “Sketches” in architecture
|
||||
- “Pilots” for television series
|
||||
- “Prototypes” made by engineers
|
||||
- “Concept cars” in auto design
|
||||
- “Demos” in music recording
|
||||
|
||||
Each of these terms is the equivalent of a “rough draft” you create as part of the process of making something new.
|
||||
|
||||
Some kinds of intermediate packages are:
|
||||
|
||||
- **Distilled notes:** Books or articles you’ve read and distilled so it’s easy to get the gist of what they contain.
|
||||
- **Outtakes:** The material or ideas that didn’t make it into a past project but could be used in future ones.
|
||||
- **Work-in-process:** The documents, graphics, agendas, or plans you produced during past projects.
|
||||
- **Final deliverables:** Concrete pieces of work you’ve delivered as part of past projects, which could become components of something new.
|
||||
- **Documents created by others:** Knowledge assets created by people on your team, contractors or consultants, or even clients or customers, that you can reference and incorporate into your work.
|
||||
|
||||
These IP can be used to create others IP's or create a final product for a project.
|
||||
|
||||
## Benefits of working in IP's:
|
||||
|
||||
- You’ll become **interruption-proof** because you are focusing only on one small packet at a time.
|
||||
- You’ll be able to make **progress in any span of time**.
|
||||
- Intermediate Packets **increase the quality** of your work by allowing you to collect feedback more often.
|
||||
- Eventually you’ll have so many IP's at your disposal that you can execute entire projects just by **assembling [previously created](Reuse%20previous%20work.md) IP's**.
|
||||
|
||||
## IP's Examples:
|
||||
|
||||
- Favorites or bookmarks saved from the web or social media
|
||||
- Journal or diary entries with your personal reflections
|
||||
- Highlights or underlined passages in books or articles
|
||||
- Messages, photos, or videos posted on social media
|
||||
- Slides or charts included in presentations
|
||||
- Diagrams, mind maps, or other visuals on paper or in apps
|
||||
- Recordings of meetings, interviews, talks, or presentations
|
||||
- Answers to common questions you receive via email
|
||||
- Written works, such as blog posts or white papers
|
||||
- Documented plans and processes such as agendas, checklists, templates, or project retrospectives
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
created: 2024-02-10T18:26:45-03:00
|
||||
modified: 2024-02-10T18:32:53-03:00
|
||||
updated: 2024-03-12 13:49
|
||||
---
|
||||
|
||||
# North Start
|
||||
|
||||
TODO
|
||||
|
||||
## 12. Questions
|
||||
|
||||
## Objectives
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
---
|
||||
id: 9b7a4283-0523-4536-b562-4df99cd32037
|
||||
created: 2024-02-02T19:52:00-03:00
|
||||
updated: 2024-03-12 13:49
|
||||
---
|
||||
|
||||
El método PARA es para un sistema de organización transversal a cualquier herramienta, ya sea física o digital.
|
||||
|
||||
1. Projects: Short-term efforts in your work or life that your're working on right now.
|
||||
2. Areas: Long-term responsibilities you want to manage over time.
|
||||
3. Resources: Topics or interest that may be useful in the future.
|
||||
4. Archive: Inactive items from the other three categories.
|
||||
|
||||
The stuff inside each element can and should move between each category, and always should be put in the higher element because it's ordered by actionability.
|
||||
|
||||
This is an **organization method**, not a capture method. This mean we should not apply this when creating a note but at a later time (like a [[periodic reviews]]).
|
||||
## Techniques
|
||||
|
||||

|
||||
|
|
@ -1,57 +0,0 @@
|
|||
---
|
||||
created: 2024-02-21 17:49
|
||||
updated: 2024-03-12 13:49
|
||||
---
|
||||
## Periodic reviews
|
||||
|
||||
Periodic reviews ac as a way of _checkpoint_ in which we review how life and work is going and try to reset our minds to allow us to continue to work.
|
||||
|
||||
This should be forgiving, doesn't bad happens if we miss a review day.
|
||||
|
||||
The purpose of a review vary: depending how often is done, the scope of it increase or reduce, as well as it's certainty.
|
||||
## Weekly
|
||||
|
||||
The purpose of a weekly review is to provide a _reset point_: empty inboxes, glow up some notes and discard what's not relevant.
|
||||
|
||||
This are some actions to do on a weekly review:
|
||||
|
||||
- **Clear my email inbox**
|
||||
- Review unread emails.
|
||||
- Unsubscribe from spam emails.
|
||||
- Move wanted subscriptions to read-later email.
|
||||
- **Check my calendar**
|
||||
- Upcoming events to attend this week.
|
||||
- Following weeks events that I need to prepare to.
|
||||
- **Clear frequent folders**
|
||||
- Downloads
|
||||
- Documents
|
||||
- Drive
|
||||
- **Clear my notes inbox**
|
||||
- Batch process them all at once, making quick, intuitive decisions about which of the PARA folders each note might be relevant to. Don't think to hard about it.
|
||||
- Don't process or summarize them, this is taxing, is better to do when I work on a specific topic and I need the note.
|
||||
- **Choose my tasks for the week**
|
||||
- Clear the inbox of the task manager.
|
||||
- Choose the tasks I want/need to do this week.
|
||||
- This should be the last step, so we have the information gathered in the previous ones in consideration.
|
||||
|
||||
## Monthly
|
||||
|
||||
Since the scope of this review is a little more broad, it's recommended to review how are you going in a more general way instead of the granular approach of the weekly review.
|
||||
|
||||
> It’s a chance to evaluate the big picture and consider more fundamental changes to your goals, priorities, and systems that you might not have the chance to think about in the busyness of the day-to-day.
|
||||
>
|
||||
> Tiago Forte, “[[Building a Second Brain]]”, p. 215
|
||||
|
||||
This are some actions to do on a monthly review:
|
||||
|
||||
- **Review and update my goals**
|
||||
- What successes or accomplishments did I have?
|
||||
- What went unexpectedly and what can I learn from it?
|
||||
- **Review and update my project list**
|
||||
- Archiving any completed or canceled projects
|
||||
- Adding new projects
|
||||
- Updating active projects to reflect how they’ve changed
|
||||
- **Review my areas of responsibility**
|
||||
- Decide if there’s anything I want to change or take action on
|
||||
- **Review someday/maybe tasks**
|
||||
- **Re prioritize tasks**
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
---
|
||||
created: 2024-02-18 11:16
|
||||
updated: 2024-03-12 13:49
|
||||
---
|
||||
# Progresive Summarization
|
||||
|
||||
técnica para destilar notas y obtener la escencia sin perder el contenido original, permitiendo poder obtener tanto contexto como necesitemos en el momento de leerla.
|
||||
|
||||
Para aplicar esta técnica, debemos "destacar" multiples veces, y cada vez de manera más concisza el contenido de la nota, por ejemplo:
|
||||
|
||||
1. Conseguir las partes importantes de un articulo (usar read-later app)
|
||||
2. Marcar en negrita
|
||||
3. Destacar o poner en cursiva
|
||||
4. hacer un 2º resumen de un par de frases, con mis propias palabras
|
||||
|
||||
Es importante destacar que no es necesario aplicar todos estos pasos, ni aplicarlos de una sola vez. Esta es una tarea que requiere tiempo y esfuerzo que no siempre vale la pena invertir.
|
||||
|
||||
Además recordar que no hay que destacar todo, porque si todo está destacado, entonces nada lo está realmente.
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
---
|
||||
created: 2024-02-17 13:45
|
||||
updated: 2024-03-12 13:49
|
||||
---
|
||||
Para reutilizar trabajo previo desde el _second brain_ podemos utilizar las siguientes estrategias:
|
||||
|
||||
- Search notes by title or content
|
||||
- Manually browse the vault
|
||||
- Search through [[tags]]
|
||||
- [[Serendipity]] (connection between ideas & notes). for obsidian this means follow the links between notes.
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
---
|
||||
created: 2024-02-21 10:54
|
||||
updated: 2024-03-12 13:49
|
||||
aliases:
|
||||
- Motivation momentum
|
||||
---
|
||||
> [...] Hemingway was known for a particular writing strategy, which I call the “Hemingway Bridge.” He would always end a writing session only when he knew what came next in the story. Instead of exhausting every last idea and bit of energy, he would stop when the next plot point became clear. This meant that the next time he sat down to work on his story, he knew exactly where to start.
|
||||
>
|
||||
> Tiago Forte, “[[Building a Second Brain]]”, p. 186
|
||||
|
||||
You can think of a Hemingway Bridge as a bridge between the islands in your [Archipelago of Ideas](Archipelago%20of%20Ideas.md).
|
||||
|
||||
How do you create a Hemingway Bridge? Instead of burning through every last ounce of energy at the end of a work session, reserve the last few minutes to write down some of the following kinds of things in your digital notes:
|
||||
|
||||
- **Write down ideas for next steps:** At the end of a work session, write down what you think the next steps could be for the next one.
|
||||
- **Write down the current status:** This could include your current biggest challenge, most important open question, or future roadblocks you expect.
|
||||
- **Write down any details you have in mind that are likely to be forgotten once you step away:** Such as details about the characters in your story, the pitfalls of the event you’re planning, or the subtle considerations of the product you’re designing.
|
||||
- **Write out your intention for the next work session:** Set an intention for what you plan on tackling next, the problem you intend to solve, or a certain milestone you want to reach.
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
created: 2024-02-21 12:59
|
||||
updated: 2024-03-12 13:49
|
||||
---
|
||||
# Mise En Place
|
||||
|
||||
> [!cite]
|
||||
> The preparations to cook, having the ingredients ready, such as cuts of meat, relishes, sauces, par-cooked items, spices, freshly chopped vegetables, and other components that are required for the menu and recipes ingredients measured out, washed, chopped and placed in individual bowls; and equipment such as spatulas and blenders prepared, and oven preheated.
|
||||
|
||||
|
||||
Chefs can never afford to stop the whole kitchen just so they can clean up. They learn to keep their workspace clean and organized _in the flow of the meals they are preparing_. ^9aef88
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
---
|
||||
created: 2024-02-21 19:01
|
||||
updated: 2024-03-12 13:49
|
||||
---
|
||||
Tagging is an advance technique from ancient times where the search capabilities of modern notes app didn't exist. Because of this (and other reasons) is nearly imposible to create an universal taxonomy to catalogue all of our notes.
|
||||
|
||||
For this reasons we can use tags as an extensions of our mine organization and relations systems ([PARA method](PARA%20method.md) and linking).
|
||||
|
||||
There are three practical approaches to tagging you can use as your Second Brain grows and matures. Each one follows the principle of actionability and answers an important question about the purpose of a given note:
|
||||
|
||||
1. **Create personalized tags for your use cases**. (How will my notes be used?)
|
||||
2. **Use tags to track the progress of notes**. (How are my notes currently being used?)
|
||||
3. **Tag notes retroactively and only as needed**. (How have my notes been used?)
|
||||
|
||||
You can use as few or as many of these techniques as you find helpful, or use them only for specific projects or areas that demand a higher level of rigor. Each tag you create should answer a question about the past, present, or future status of a note so you always know where it’s been and where it’s going.
|
||||
|
||||
## Create personalized tags for your use cases
|
||||
|
||||
if you already know how your notes are likely to be used - such as for
|
||||
citations in a paper (_Source_), as evidence in a trial (_Evidence_), or as slides in a presentation (_Slides_) - it can be helpful to **tag your notes according to those uses cases**.
|
||||
|
||||
Ask yourself, _“What are the most common use cases for the content I capture?”_, here are a couple common examples:
|
||||
|
||||
- Tagging according to the final product a note will be used in: _Presentation_,
|
||||
_Essay_, _Report_, _Website_, _Project plan_, _Meeting agenda_, or _Budget_
|
||||
- Tagging according to the kind of information a note contains: _Arguments_,
|
||||
_Theories_, _Frameworks_, _Evidence_, _Claim_, _Counterpoint_, or _Question_
|
||||
## Use tags to track the progress of notes
|
||||
|
||||
As your collection of knowledge expands, at some point you may feel the need to **track their progress towards the outcomes you’re trying to create** in your life. You don’t need to remember the status of every note.
|
||||
|
||||
- Tagging according to its role in a project: _Meeting notes_, _Timeline_, _Budget_, _Decision_, _Action_, _Idea_, or _Objective_
|
||||
- Tagging according to the current stage of their workflow: _Planned_, _In process_, _Waiting for approval_, _Reviewed_, _Approved_, _On hold_, or _Finished_
|
||||
|
||||
## Tag notes retroactively and only as needed
|
||||
|
||||
Digital information is incredibly malleable, and it is often easier to organize your notes retroactively than to try and guess upfront all the projects, areas, and resources you might eventually need.
|
||||
|
||||
Tags are useful when you want a **different way of “viewing” your notes**, without having to undertake a massive reorganization of your entire system
|
||||
|
||||
When you apply tags with a specific use case in mind, the tags you come up with will be far more concrete and actionable.
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
---
|
||||
created: 2024-03-27 23:08
|
||||
updated: 2024-03-27 23:29
|
||||
---
|
||||
Time blocking is a time management method that asks you to **divide your day into blocks of time**. Each block is dedicated to accomplishing a **specific task or group of tasks**, and only those specific tasks.
|
||||
|
||||
With days that are time blocked in advance, you **won’t have to constantly make choices about what to focus on**.
|
||||
|
||||
## types of time Block
|
||||
|
||||
### Time Blocking or Calendar Block
|
||||
|
||||
Set a timeframe to work on a specific tasks, this doesn't mean you need to finish it then, just that you'll work in this timeframe on this task and this task alone.
|
||||
|
||||
## Tasks batching
|
||||
|
||||
Group a bunch of small and similar tasks and allocate a timeframe to work on them, this is usefull to reduce the context switching.
|
||||
|
||||
### Day theming
|
||||
|
||||
task batching at a bigger scale, dedicate a whole day to a specific area.
|
||||
|
||||
### Time boxing
|
||||
|
||||
Is the same as time blocking, but this time we'll have to end the task withing the timeframe. This is to force you to produce something finished, ether by being really efficient or by reducing the scope of the tasks to something archivable. the idea is not to produce a mediocre product, but to **finish stuff**
|
||||
|
||||
This will align with [The cult of done](The%20cult%20of%20done.md) idea and that 80% completion of the task will use the same time/effort as the reminding 20%.
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
---
|
||||
created: 2024-06-09 16:28
|
||||
updated: 2024-06-09 16:28
|
||||
status: Backlog
|
||||
---
|
||||
# Data Science
|
||||
|
||||
## Resources
|
||||
|
||||
- Item
|
||||
|
||||
## [Kickoff](Project%20checklists.md#Kickoff)
|
||||
|
||||
### Completion Criteria
|
||||
|
||||
This project will be completed when:
|
||||
|
||||
- [ ] #feat item
|
||||
|
||||
### Brainstorm
|
||||
|
||||
- Estudiar cálculo, matemática y estadística para poder entender del tema
|
||||
|
||||
## [Outtakes](Project%20checklists.md#Completion)
|
||||
|
||||
### Was the goal archived?
|
||||
|
||||
Yes/No, because of...
|
||||
|
||||
### What did go well?
|
||||
|
||||
- Item
|
||||
|
||||
### What did go wrong?
|
||||
|
||||
- Item
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
---
|
||||
created: 2024-06-22 12:15
|
||||
updated: 2024-06-22 12:15
|
||||
status: Backlog
|
||||
date_created: Saturday, June 22nd 2024, 12:15:12 pm
|
||||
date_modified: Saturday, June 22nd 2024, 12:16:41 pm
|
||||
---
|
||||
|
||||
# Frontend Framework
|
||||
|
||||
## Resources
|
||||
|
||||
- [A DIY guide to build your own React](https://github.com/pomber/didact)
|
||||
- [Frontend Framework](https://mfrachet.github.io/create-frontend-framework/)
|
||||
|
||||
## [Kickoff](Project%20checklists.md#Kickoff)
|
||||
|
||||
### Completion Criteria
|
||||
|
||||
This project will be completed when:
|
||||
|
||||
- [ ] #feat item
|
||||
|
||||
### Brainstorm
|
||||
|
||||
- Item
|
||||
|
||||
## [Outtakes](Project%20checklists.md#Completion)
|
||||
|
||||
### Was the Goal Archived?
|
||||
|
||||
Yes/No, because of…
|
||||
|
||||
### What Did Go Well?
|
||||
|
||||
- Item
|
||||
|
||||
### What Did Go Wrong?
|
||||
|
||||
- Item
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
---
|
||||
created: 2024-04-21 12:05
|
||||
updated: 2024-04-21 12:05
|
||||
status: Backlog
|
||||
---
|
||||
|
||||
# Frontmatter Query Language
|
||||
|
||||
## Resources
|
||||
|
||||
- Item
|
||||
|
||||
## [Kickoff](Project%20checklists.md#Kickoff)
|
||||
|
||||
### Completion Criteria
|
||||
|
||||
This project will be completed when:
|
||||
|
||||
- [ ] #feat item
|
||||
|
||||
### Brainstorm
|
||||
|
||||
- Item
|
||||
|
||||
## [Outtakes](Project%20checklists.md#Completion)
|
||||
|
||||
### Was the Goal Archived?
|
||||
|
||||
Yes/No, because of…
|
||||
|
||||
### What Did Go Well?
|
||||
|
||||
- Item
|
||||
|
||||
### What Did Go Wrong?
|
||||
|
||||
- Item
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
---
|
||||
created: 2024-05-07 14:49
|
||||
updated: 2024-05-07 14:49
|
||||
status: Backlog
|
||||
---
|
||||
# Fuuka desktop client
|
||||
|
||||
Hacer un cliente, y solo cliente, para Fuuka en tauri?
|
||||
|
||||
- Simple: solo reproducir el stream, y solicitar canciones (chat si es que tiene)
|
||||
- multi plataforma: con tauri podria hacer desktop + mobile (cuando salga de alpha)
|
||||
- Reproducir en segundo plano
|
||||
|
||||
## Resources
|
||||
|
||||
- Item
|
||||
|
||||
## [Kickoff](Project%20checklists.md#Kickoff)
|
||||
|
||||
### Completion Criteria
|
||||
|
||||
This project will be completed when:
|
||||
|
||||
- [ ] #feat item
|
||||
|
||||
### Brainstorm
|
||||
|
||||
- Item
|
||||
|
||||
## [Outtakes](Project%20checklists.md#Completion)
|
||||
|
||||
### Was the goal archived?
|
||||
|
||||
Yes/No, because of...
|
||||
|
||||
### What did go well?
|
||||
|
||||
- Item
|
||||
|
||||
### What did go wrong?
|
||||
|
||||
- Item
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
---
|
||||
created: 2024-04-14 12:37
|
||||
updated: 2024-04-15 20:56
|
||||
status: Backlog
|
||||
---
|
||||
|
||||
# Physics Engine
|
||||
|
||||
## Resources
|
||||
|
||||
- Item
|
||||
|
||||
## [Kickoff](Project%20checklists.md#Kickoff)
|
||||
|
||||
### Completion Criteria
|
||||
|
||||
This project will be completed when:
|
||||
|
||||
- [ ] #feat item
|
||||
|
||||
### Brainstorm
|
||||
|
||||
- Use [brilliant.org](http://brilliant.org) to lear physics for game dev
|
||||
|
||||
## [Outtakes](Project%20checklists.md#Completion)
|
||||
|
||||
### Was the Goal Archived?
|
||||
|
||||
Yes/No, because of…
|
||||
|
||||
### What Did Go Well?
|
||||
|
||||
- Item
|
||||
|
||||
### What Did Go Wrong?
|
||||
|
||||
- Item
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
---
|
||||
created: 2024-04-14 12:17
|
||||
updated: 2024-04-15 20:56
|
||||
status: Backlog
|
||||
---
|
||||
# Spotify Playlist Intersection
|
||||
|
||||
## Resources
|
||||
|
||||
- Item
|
||||
|
||||
## [Kickoff](Project%20checklists.md#Kickoff)
|
||||
|
||||
### Completion Criteria
|
||||
|
||||
This project will be completed when:
|
||||
|
||||
- [ ] #feat item
|
||||
|
||||
### Brainstorm
|
||||
|
||||
Repl que pregunte por 2 playlist en una lista (fzf???), luego encuentre las canciones que esten en ambas listas y prrguntar una por una
|
||||
|
||||
- mantener solo en playlist A
|
||||
- mantener solo en playlist B
|
||||
- Sacar de ambas
|
||||
- escuchar (para reconocer canciones en japo)
|
||||
|
||||
Buscar canciones repetidas (misma canción pero en distinto album)??
|
||||
## [Outtakes](Project%20checklists.md#Completion)
|
||||
|
||||
### Was the goal archived?
|
||||
|
||||
Yes/No, because of...
|
||||
|
||||
### What did go well?
|
||||
|
||||
- Item
|
||||
|
||||
### What did go wrong?
|
||||
|
||||
- Item
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
# 17-Year-Old Student Exposes Germany's 'Secret' Pirate Site Blocklist
|
||||
|
||||

|
||||
|
||||
## Metadata
|
||||
- Author: [[isaacfrond]]
|
||||
- Full Title: 17-Year-Old Student Exposes Germany's 'Secret' Pirate Site Blocklist
|
||||
- Category: #articles
|
||||
- URL: https://torrentfreak.com/17-year-old-student-exposes-germanys-secret-pirate-site-blocklist-240822/
|
||||
> [!tldr]
|
||||
> A 17-year-old student in Germany has created a website to reveal the blocked pirate sites that major internet providers do not disclose. This initiative aims to increase transparency and address concerns about censorship related to copyright enforcement. The site, CUIIliste.de, lists 275 blocked domains, allowing users to see which sites are restricted.
|
||||
|
||||
## Highlights
|
||||
watchdog - ([View Highlight](https://read.readwise.io/read/01j64wj1fy8b0dyhcdsjgv4vta))
|
||||
> [!note]
|
||||
> Watchdog: A term used to describe an individual or organization that monitors and oversees the actions of others, often to ensure accountability, transparency, and adherence to laws or regulations. Watchdogs play a critical role in various fields, including journalism, government, and environmental protection, by investigating misconduct, exposing corruption, and advocating for the public interest. Their function is essential in promoting ethical standards and fostering public trust in institutions.
|
||||
> In the context of Isaac Frond's article, the term "watchdog" refers to individuals or organizations that monitor and ensure accountability regarding governmental or institutional actions, particularly in relation to transparency and rights. The lack of public knowledge about the blocked pirate sites in Germany has led to frustration among journalists and advocates, highlighting the need for oversight. The 17-year-old student, along with his friends, embodies this watchdog role by exposing the secretive blocklist, thereby promoting transparency and challenging potential overreach in copyright enforcement.
|
||||
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
---
|
||||
id: 9f0419b3-2f89-4734-96b3-55aa984414ac
|
||||
title: |
|
||||
How to Learn Rust
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- Youtube
|
||||
- Youtube
|
||||
date_added: 2023-10-12 17:55:48
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/how-to-learn-rust-18b25ac93bb
|
||||
url_original: |
|
||||
https://www.youtube.com/watch?v=2hXNd6x9sZs
|
||||
---
|
||||
|
||||
# How to Learn Rust
|
||||
|
||||
## Original
|
||||
|
||||
<div class="page" id="readability-page-1">
|
||||
<iframe data-omnivore-anchor-idx="1" width="619.4690265486726" height="350" src="https://www.youtube.com/embed/2hXNd6x9sZs" title="How to Learn Rust" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
<p data-omnivore-anchor-idx="2"><a data-omnivore-anchor-idx="3" href="https://www.youtube.com/watch?v=2hXNd6x9sZs" target="_blank">How to Learn Rust</a></p>
|
||||
<p data-omnivore-anchor-idx="4" itemscope itemprop="author" itemtype="http://schema.org/Person">By <a data-omnivore-anchor-idx="5" href="https://www.youtube.com/@NoBoilerplate" target="_blank">No Boilerplate</a></p>
|
||||
</div>
|
||||
|
|
@ -1,272 +0,0 @@
|
|||
---
|
||||
id: 85f31880-6935-11ee-86f4-f7cb87ce263e
|
||||
title: |
|
||||
The Secret Power of ‘Read It Later’ Apps
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
date_added: 2023-10-12 16:28:29
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/the-secret-power-of-read-it-later-apps-18b255ca194
|
||||
url_original: |
|
||||
https://fortelabs.co/blog/the-secret-power-of-read-it-later-apps
|
||||
---
|
||||
|
||||
# The Secret Power of ‘Read It Later’ Apps
|
||||
|
||||
## Highlights
|
||||
|
||||
> People who cling to paradigms (which means just about all of us) take one look at the spacious possibility that everything they think is guaranteed to be nonsense and pedal rapidly in the opposite direction. Surely there is no power, no control, no understanding, not even a reason for being, much less acting, in the notion or experience that there is no certainty in any worldview. But, in fact, everyone who has managed to entertain that idea, for a moment or for a lifetime, has found it to be the basis for radical empowerment. **If no paradigm is right, you can choose whatever one will help to achieve your purpose.**
|
||||
|
||||
> It is in this space of mastery over paradigms that people throw off addictions, live in constant joy, bring down empires, get locked up or burned at the stake or crucified or shot, and **have impacts that last for millennia**.
|
||||
|
||||
> In the end, it seems that mastery has less to do with pushing leverage points than it does with **strategically, profoundly, madly letting go.**
|
||||
|
||||
> [!note]
|
||||
> Read again and understand it better
|
||||
|
||||
[source](https://omnivore.app/me/the-secret-power-of-read-it-later-apps-18b255ca194#42edb9e2-3799-430e-bbff-db1170ebbad1)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||
<DIV class="page" id="readability-page-1">
|
||||
<div>
|
||||
<div data-widget_type="theme-post-content.default" data-element_type="widget" data-id="5d9db16f">
|
||||
<figure>
|
||||
<figure>
|
||||
<img src="https://proxy-prod.omnivore-image-cache.app/900x380,sXXV7f9Au3y4tF2zoOnAQ1G8Xnf3Uh8IRqZcfVY3HoSY/https://i0.wp.com/cdn-images-1.medium.com/max/2000/1*rPXwIczUJRCE54v8FfAHGw.jpeg?resize=900%2C380&ssl=1" alt="" width="900" height="380" data-recalc-dims="1">
|
||||
<figcaption> Image via Nuno Cruz </figcaption>
|
||||
</figure>
|
||||
<figcaption></figcaption>
|
||||
</figure>
|
||||
<p>
|
||||
<em>By Tiago Forte of</em> <a href="http://fortelabs.co/" target="_blank" rel="noopener noreferrer"><em>Forte Labs</em></a>
|
||||
</p>
|
||||
<p> At the end of 2014 I received an email informing me that I had read over a million words in the ‘read it later’ app Pocket over the course of the year. </p>
|
||||
<p>
|
||||
<img loading="lazy" src="https://proxy-prod.omnivore-image-cache.app/358x377,ssfZXhGmomcxzcD-VkrtnzD-6vk-rI8GUuXk4JlRMX2s/https://i0.wp.com/cdn-images-1.medium.com/max/600/1*Hd7YIhMrS5lldl1gDU8iWQ.png?resize=358%2C377&ssl=1" width="358" height="377" data-src="https://i0.wp.com/cdn-images-1.medium.com/max/600/1*Hd7YIhMrS5lldl1gDU8iWQ.png?resize=358%2C377&ssl=1" data-recalc-dims="1">
|
||||
</p>
|
||||
<p> This number by itself isn’t impressive, considering our daily intake of information is equivalent to <a href="http://bits.blogs.nytimes.com/2009/12/09/the-american-diet-34-gigabytes-a-day/" target="_blank" rel="noopener noreferrer">34 gigabytes</a>, 100,000 words, or <a href="http://www.nytimes.com/2014/08/10/opinion/sunday/hit-the-reset-button-in-your-brain.html?smprod=nytcore-iphone&smid=nytcore-iphone-share" target="_blank" rel="noopener noreferrer">174 newspapers</a>, depending on who you ask. </p>
|
||||
<p> What makes this number significant (in my view) is that it represents 22 books’-worth of long-form reading that would not have happened without a system in place. </p>
|
||||
<p> We’ve made a habit of filling those hundred random spaces in our day with glances at Twitter, Instagram, and Facebook. But those glances have slowly become stares, and those stares have grown to encompass a major portion of our waking hours. </p>
|
||||
<p> The end result is the same person who spends 127 hours per year on Instagram (the <a href="http://www.businessinsider.com/people-spend-21-minutes-per-day-on-instagram-2014-10" target="_blank" rel="noopener noreferrer">global average</a>) complains that she has “no time” for reading. </p>
|
||||
<p> The fact is, <strong>the ability to read is becoming a source of competitive advantage in the world</strong>. </p>
|
||||
<p> I’m not talking about basic literacy. What has become exceedingly scarce (and therefore, valuable) is the physical, emotional, attentional, and mental capability to sit quietly and direct focused attention for sustained periods of time. </p>
|
||||
<p> A <a href="https://hbr.org/2005/01/overloaded-circuits-why-smart-people-underperform" target="_blank" rel="noopener noreferrer">recent article</a> in the Harvard Business Review puts a name to this new neurological phenomenon: Attention Deficit Trait. Basically, the terms ADD and ADHD are falling out of use because effectively the entire population fits the diagnostic criteria. It’s not a condition anymore, it’s a <em>trait</em> — the inherent and unavoidable experience of modern life characterized by “distractibility, inner frenzy, and impatience.” </p>
|
||||
<form action="https://app.convertkit.com/forms/1022733/subscriptions" method="post" data-sv-form="1022733" data-uid="308d24305b" data-format="inline" data-version="5" min-width="400 500 600 700">
|
||||
<div data-style="full">
|
||||
<p><img src="https://proxy-prod.omnivore-image-cache.app/0x0,sCKKsi_KsyhXjSRvn7hvFRJEjLKQkBiJU0agepFckkI4/https://embed.filekitcdn.com/e/oP2q5jihy5hj474ZFtvPjw/3edWskTMDwFhuVEtauLv5X"></p>
|
||||
<p> Start Building Your Second Brain </p>
|
||||
<p> Subscribe below to learn more about the next cohort of the Building a Second Brain course </p>
|
||||
</div>
|
||||
</form>
|
||||
<h3> Read It. Later. </h3>
|
||||
<p> Before I explain the massive, under-appreciated benefits these apps provide, and how to use them most effectively, a quick primer in case you’re unfamiliar. </p>
|
||||
<p> So-called “Read It Later” apps give you the ability to “save” content on the web for later consumption. They are essentially advanced bookmarking apps, pulling in the content from a page to be read or viewed in a cleaner, simpler visual layout. </p>
|
||||
<p> On top of that core function they add features like favoriting, tags, search, cross-platform syncing, recommended content, offline viewing, and archiving. The most popular options are: </p>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://www.instapaper.com/" target="_blank" rel="noopener noreferrer">Instapaper</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://getpocket.com/a/" target="_blank" rel="noopener noreferrer">Pocket</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://chrome.google.com/webstore/detail/send-to-kindle-for-google/cgdjpilhipecahhcilnafpblkieebhea?hl=en" target="_blank" rel="noopener noreferrer">Send to Kindle</a> (for sending articles to your Kindle)
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://feedly.com/i/welcome" target="_blank" rel="noopener noreferrer">Feedly</a> (for those RSS fans)
|
||||
</li>
|
||||
<li>and <a href="https://support.apple.com/en-us/HT200294" target="_blank" rel="noopener noreferrer">Safari’s built-in “Add to Reading List” feature</a>. </li>
|
||||
</ul>
|
||||
<p> The app I use, Pocket, adds a button to the Chrome toolbar that looks like this: </p>
|
||||
<figure>
|
||||
<img loading="lazy" src="https://proxy-prod.omnivore-image-cache.app/130x58,syYiQlMJ3hP3JyGS_AYz8D5Oq9FZ1QxR2ef29Fia7Ht0/https://i0.wp.com/cdn-images-1.medium.com/max/800/1*Lk-DPDFjLslM4h2GAv8KIA.png?resize=130%2C58&ssl=1" alt="" width="130" height="58" data-image-id="1*Lk-DPDFjLslM4h2GAv8KIA.png" data-width="130" data-height="58" data-recalc-dims="1">
|
||||
<figcaption> Chrome toolbar </figcaption>
|
||||
</figure>
|
||||
<p>
|
||||
<em>Note: at time of writing, I was using Pocket, but have recently switched to Instapaper because of Pocket’s “Share to Evernote” bug mentioned below.</em>
|
||||
</p>
|
||||
<p> Clicking the button while viewing a webpage turns the button pink, and saves the page to your “list.” Navigating to getpocket.com, or opening the Pocket app on your computer or mobile device shows you a list of everything you’ve saved: </p>
|
||||
<figure>
|
||||
<figure>
|
||||
<img loading="lazy" src="https://proxy-prod.omnivore-image-cache.app/800x507,smjUUrOduWv7T0bCSx9oh_Ag0Yasq_HyFfgAoDXryOcM/https://i0.wp.com/cdn-images-1.medium.com/max/800/1*wkKD4oP3-kWJERxmBBI2cA.png?resize=800%2C507&ssl=1" alt="" width="800" height="507" data-src="https://i0.wp.com/cdn-images-1.medium.com/max/800/1*wkKD4oP3-kWJERxmBBI2cA.png?resize=800%2C507&ssl=1" data-recalc-dims="1">
|
||||
<figcaption> Mac desktop client </figcaption>
|
||||
</figure>
|
||||
<p> You can also view your list in a “tile” layout on the web, making it into essentially a personalized magazine. Personalized, in this case, not by a cold, unfeeling algorithm, but by your past self: </p>
|
||||
</figure>
|
||||
<figure>
|
||||
<img loading="lazy" src="https://proxy-prod.omnivore-image-cache.app/800x478,sFjAZnzFiVzsVRlXF9QyD5dq_jzT69dsyyp3Bb-k5ZGU/https://i0.wp.com/cdn-images-1.medium.com/max/800/1*ug06oorCHGFpEzMyl9kfhg.png?resize=800%2C478&ssl=1" alt="" width="800" height="478" data-src="https://i0.wp.com/cdn-images-1.medium.com/max/800/1*ug06oorCHGFpEzMyl9kfhg.png?resize=800%2C478&ssl=1" data-recalc-dims="1">
|
||||
<figcaption> Web browser “tile” view </figcaption>
|
||||
</figure>
|
||||
<p> Marking an item as read in one version of the app will quickly sync across all platforms. It will also save your current progress on one device, so you can continue where you left off on a different device (for those longer pieces). </p>
|
||||
<h3> The highest leverage point in a system is in the intake — the initial assumptions and paradigms that inform its development </h3>
|
||||
<p> I’ve <a href="https://medium.com/forte-labs/how-to-use-evernote-for-your-creative-workflow-f048f0aa3ed1" target="_blank" rel="noopener noreferrer">written previously</a> about how to use Evernote as a general reference filing system, not only to stay organized but to inspire creativity. </p>
|
||||
<p> But I didn’t address a key question when creating any workflow: how and from where does information enter the system? The quality of a workflow’s outputs is fundamentally limited by the quality of its inputs. Garbage in, garbage out. </p>
|
||||
<p> There are A LOT of ways we could talk about to improve the quality of the information you consume. But I want to focus now on the two that Read It Later apps can help with: </p>
|
||||
<ol>
|
||||
<li>Increasing consumption of long-form content (which is presumably more substantive) </li>
|
||||
<li>Better filtering </li>
|
||||
</ol>
|
||||
<h3> #1 | Increasing Consumption of Long-Form Content </h3>
|
||||
<p> In order to consume good ideas, first you have to consume many ideas. </p>
|
||||
<p> This is the fundamental flaw in the “information diet” advice from Tim Ferriss and others: strong filters work best on a larger initial flow. Using your friends as your primary filter for new ideas ensures you remain the dumbest person in the room, and contribute nothing to the conversation. </p>
|
||||
<p> The problem is that our entire digital world is geared toward snackable chunks of low-grade information — photos, tweets, statuses, snaps, feeds, cards, etc. To fight the tide you have to redesign your environment — you have to create affordances. </p>
|
||||
<blockquote>
|
||||
<p> Affordance (n.): a relation between an object and an organism that, through a collection of stimuli, <strong>affords the opportunity for that organism to perform an action.</strong>
|
||||
</p>
|
||||
</blockquote>
|
||||
<p> Let’s look at the 4 main barriers to consuming long-form content, and the affordances that Read It Later apps use to overcome them: </p>
|
||||
<h4> 1. App performance </h4>
|
||||
<p> We know that the most infinitesimal delays in the loading time of a webpage will dramatically impact how many people stay on the page. <a href="https://blog.kissmetrics.com/speed-is-a-killer/" target="_blank" rel="noopener noreferrer">Google found</a> that increasing the number of results per page from 10 to 30 took only half a second longer, but <strong>caused 20% of people to drop off</strong>. </p>
|
||||
<p> If you think your behavior is not affected by such trivialities, think again. Even on a subconscious level, you will resist even opening apps that don’t reward you with snappy response times. Which is a problem because the apps most people turn to for reading are either ebook apps like iBooks and Kindle, or web browsers like Chrome and Safari. I’m not sure which category is slower, but they’re both abysmal. </p>
|
||||
<p> Meanwhile, your snaps and instas refresh at precog-like speeds. </p>
|
||||
<p> Read It Later apps, by slurping in content (articles, videos, slideshows) into a clean interface, eliminate the culprits — ads, site analytics, popups — all the stuff you don’t care about. </p>
|
||||
<p> A <a href="http://www.nytimes.com/2015/10/01/technology/personaltech/ad-blockers-mobile-iphone-browsers.html" target="_blank" rel="noopener noreferrer">recent analysis</a> by The New York Times of 3 leading ad-blockers (which have the same effect) measured a <strong>21% increase in battery life</strong>, and in the most egregious case of Boston.com, a drop in loading time <strong>from 33 seconds to 7 seconds</strong>. Many other leading sites were not that far off. </p>
|
||||
<figure>
|
||||
<img loading="lazy" src="https://proxy-prod.omnivore-image-cache.app/563x365,sFABKoLfIzSHIwYCEllG7t2i-uxewZOlI9ALe6-KJLSs/https://i0.wp.com/cdn-images-1.medium.com/max/800/1*vfmR5LKEjfx-0Lx-kWb4bw.png?resize=563%2C365&ssl=1" alt="" width="563" height="365" data-src="https://i0.wp.com/cdn-images-1.medium.com/max/800/1*vfmR5LKEjfx-0Lx-kWb4bw.png?resize=563%2C365&ssl=1" data-recalc-dims="1">
|
||||
<figcaption> Effect of ad-blocker on loading times of Boston.com, via <a href="http://www.nytimes.com/2015/10/01/technology/personaltech/ad-blockers-mobile-iphone-browsers.html" target="_blank" rel="noopener noreferrer">NYT</a>
|
||||
</figcaption>
|
||||
</figure>
|
||||
<p> Yeah that’s pretty much an eternity in mobile behavior land. </p>
|
||||
<h4> 2. Matching content with your context </h4>
|
||||
<figure>
|
||||
<figure>
|
||||
<img loading="lazy" src="https://proxy-prod.omnivore-image-cache.app/507x676,sxG7LpsFKxnoEDDIOpwI06zJ3e8CoE30WZseOtRT8u6s/https://i0.wp.com/cdn-images-1.medium.com/max/600/1*N15BlTDGq8kTc7HdGUmShA.png?resize=507%2C676&ssl=1" alt="" width="507" height="676" data-src="https://i0.wp.com/cdn-images-1.medium.com/max/600/1*N15BlTDGq8kTc7HdGUmShA.png?resize=507%2C676&ssl=1" data-recalc-dims="1">
|
||||
<figcaption> My Pocket list on iPad </figcaption>
|
||||
</figure>
|
||||
</figure>
|
||||
<p> Much of the time when we pull out our phone, we’re looking for something to match our mood (or energy, or time available, or other context). We use our constellation of shiny apps as mood regulators and self-soothers, as time-fillers and boredom-suppressors, for better or worse. </p>
|
||||
<p> So you need a little entertainment, and you open…an ebook? Yeah right. Monochrome pages don’t attract you. They don’t draw you in. </p>
|
||||
<p> Pocket gives reading some of this stimulatory pleasure by laying out your list in a pleasing, magazine-style layout (at left). Not only is it generally attractive, but it gives you that same magazine-flipping pleasure of engaging with something that interests you <em>right in that moment</em>. </p>
|
||||
<p> David Allen puts it this way: </p>
|
||||
<blockquote>
|
||||
<p> “It’s practical to have organized reading material at hand when you’re on your way to a meeting that may be starting late, a seminar that may have a window of time when nothing is going on, a dentist appointment that may keep you waiting, or, of course, if you’re going to have some time on a train or plane. Those are all great opportunities to browse and work through that kind of reading. People who don’t have their Read/Review material organized can waste a lot of time, since <strong>life is full of weird little windows when it could be used.</strong>” </p>
|
||||
</blockquote>
|
||||
<p> You’re not fighting your impulses forcing yourself to read a dense tome after a long work day. Willpower preserved ✓ </p>
|
||||
<h4> 3. Asynchronous reading </h4>
|
||||
<p> This is one of the least understood barriers to reading in our fragmented timescape. </p>
|
||||
<p> There is something deeply, deeply unsatisfying about repeatedly starting something and not finishing it. This is what we experience all day at work, being continuously interrupted by a stream of “emergencies.” The last thing we want after a stressful day starved of wins is to fail even at reading an article. </p>
|
||||
<p> The <a href="https://www.amazon.com/Getting-Things-Done-Stress-Free-Productivity-ebook/dp/B00KWG9M2E/ref=as_li_ss_tl?ie=UTF8&linkCode=ll1&tag=fortelabs07-20&linkId=fe6db72d8e5bbb38b1ea43241924f7e9&language=en_US" target="_blank" rel="noopener noreferrer">2015 revised edition (affiliate link)</a> of <em>Getting Things Done</em> <a href="http://users.wfu.edu/masicaej/MasicampoBaumeister2011JPSP.pdf" target="_blank" rel="noopener noreferrer">cites the work</a> of Dr. Roy Baumeister, who has shown that “uncompleted tasks take up room in the mind, which then limits clarity and focus.” The risk of cognitive dissonance at not being able to finish a long article (much less a book) keep us from even beginning it. </p>
|
||||
<p> Read It Later apps address this by simply saving your progress in a given article, allowing you to pick back up at a different time, or on a different device, and clearly marking items as “read” once you’re finished. </p>
|
||||
<h4> 4. Focus </h4>
|
||||
<p> A common response when I recommend people adopt <em>yet another</em> category of apps is “Why don’t I just use Evernote?” Or whatever app they’re using for general reference or task management. Evernote even makes a Chrome extension called <a href="https://evernote.com/clearly/" target="_blank" rel="noopener noreferrer">Clearly</a> for reading online content and <a href="https://evernote.com/webclipper/?downloaded" target="_blank" rel="noopener noreferrer">Web Clipper</a> for saving it. </p>
|
||||
<p> It is a question of focus. Why don’t you use your task manager to keep track of content (i.e. “Read this article”)? Because the last thing you want to see when you cuddle up with your hot cocoa for some light reading is the hundreds of tasks you’re not doing. </p>
|
||||
<p> Likewise, the last thing you want to see when you (finally!) have time to read is the thousands of notes you’ve collected from every corner of the universe, only some of which you haven’t read, only some of which you <em>want</em> to read, only some of which are <em>meant</em> to be read. </p>
|
||||
<blockquote>
|
||||
<p> Actionable info ≠ Reference info ≠ To Read pile </p>
|
||||
</blockquote>
|
||||
<p> Ergo, </p>
|
||||
<blockquote>
|
||||
<p> Task manager ≠ Evernote ≠ Pocket </p>
|
||||
</blockquote>
|
||||
<h3> #2 | Better filtering </h3>
|
||||
<p> Now you’ve got the funnel filled. It’s time to narrow it. </p>
|
||||
<p> Most advice on this topic focuses on being more selective about your sources. Cutting out the email digests that just throw you off track, unfollowing people posting crap, or even <a href="https://chrome.google.com/webstore/detail/ad-replacer-turn-spammy-a/eckeeomlpacfhejaameopnmgipghaoam" target="_blank" rel="noopener noreferrer">directly replacing ads with quality sources</a>. </p>
|
||||
<p> The problem is that this assumes you are always at your best, always at 100% self-discipline, totally aligned with your life values, priorities ship shape. </p>
|
||||
<p> Yeah. </p>
|
||||
<p> In the moment, with your blood sugar at a negative value and every fiber of your being screaming for a dopamine hit, <em>of course</em> that Buzzfeed article seems like the best conceivable use of your time. If you think you can permanently seal off your life from the celebrity news, content marketing, and spammy friends that dominate the web, the NSA has a job for you. </p>
|
||||
<p> Procrastination is the most powerful force in the universe. <em>It will find a way.</em>
|
||||
</p>
|
||||
<p> I have a different approach: <strong>waiting periods</strong>. Every time I come across something I may want to read/watch, I’m totally allowed to. No limits! The only requirement is I have to save it to Pocket, and then choose to consume it at a later time. </p>
|
||||
<p> I’ve found that even just clicking a link to open the URL, in order to save it to Pocket, is too much of a temptation. The first glimpse of a cute GIF and I’m off to Reddit, completely forgetting my morning email session. </p>
|
||||
<p> So instead I just <strong>command-click</strong> every link I’m interested in (or <strong>right-click > Open link in new tab</strong>), which opens each link in a separate tab <em>without taking me to that tab</em>. </p>
|
||||
<p> Here’s what a typical Monday morning link-fest looks like, just from email: </p>
|
||||
<p>
|
||||
<img src="https://proxy-prod.omnivore-image-cache.app/0x0,s6KkWg-OdGcQNuvOShcztrmaslDz3Cm5o9rD1eDOxxRc/https://i0.wp.com/cdn-images-1.medium.com/max/2000/1*cLy09F0SPJJmi0WfazXi3Q.png?w=900&ssl=1" data-src="https://i0.wp.com/cdn-images-1.medium.com/max/2000/1*cLy09F0SPJJmi0WfazXi3Q.png?w=900&ssl=1" data-recalc-dims="1">
|
||||
</p>
|
||||
<p> Then, because I’m still in <strong>collection mode</strong>, not in read mode, I cycle through each tab one at a time (<strong>shift-command-}</strong> or <strong>control-tab</strong>), saving each one to Pocket using the shortcut I set up: <strong>command-p</strong> (chosen for irony and to avoid inadvertent printing). </p>
|
||||
<p> There’s only one rule: <strong>NO READING OR WATCHING!</strong>
|
||||
</p>
|
||||
<p> Bringing this back to filtering, not only am I saving time and preserving focus by batch processing both the collection and the consumption of new content, I’m <strong>time-shifting the curation process</strong> to a time better suited for reading, and (most critically) removed from the temptations, stresses, and biopsychosocial hooks that first lured me in. </p>
|
||||
<p> I am always amazed by what happens: no matter how stringent I was in the original collecting, no matter how certain I was that this thing was worthwhile, I <strong>regularly eliminate 1/3 of my list before reading</strong>. The post that looked SO INTERESTING when compared to that one task I’d been procrastinating on, in retrospect isn’t even something I care about. </p>
|
||||
<p> What I’m essentially doing is creating a buffer. Instead of pushing a new piece of info through from intake to processing to consumption without any scrutiny, I’m creating a pool of options drawn from a longer time period, which allows me to make decisions from a higher perspective, where those decisions are much better aligned with what truly matters to me. </p>
|
||||
<blockquote>
|
||||
<p> Remove any feature, process, or effort that does not directly contribute to the learning you seek. — Eric Ries, The Leader’s Guide </p>
|
||||
</blockquote>
|
||||
<p> Here’s a visual of how this works, from my Pocket analytics: </p>
|
||||
<p>
|
||||
<img src="https://proxy-prod.omnivore-image-cache.app/0x0,stGbUueP6GB86OSUIreA-v1CvD10SF4A-ecLznSBpGQc/https://i0.wp.com/cdn-images-1.medium.com/max/800/1*YRExWXbhPma8-AcWP_KSrw.png?w=900&ssl=1" data-src="https://i0.wp.com/cdn-images-1.medium.com/max/800/1*YRExWXbhPma8-AcWP_KSrw.png?w=900&ssl=1" data-recalc-dims="1">
|
||||
</p>
|
||||
<p> You can see that I save more things toward the beginning of the week and the weekend, and then draw down the buffer more towards the end of the week. </p>
|
||||
<p>
|
||||
<strong><em>/sidebar</em></strong>
|
||||
</p>
|
||||
<p> Imagine for a second if we could do this with everything. On Saturday morning, well-rested and wise, you retroactively decide everything you <em>want to have done</em> during the previous week. Anything you decide was not worthwhile, you <em>get that time back</em>. </p>
|
||||
<p> I experienced this recently with email — after returning from a 10-day meditation course during which I was completely off the grid, I was surprised to notice it took only 1.9 hours to process almost 2 weeks’ worth of email (I track these things). I normally spend on average 2.19 hours on email <strong>per week</strong> —<em> what happened to those extra 2.48 hours?!</em> Besides the gains from batch processing such a large quantity of emails at once, I believe the main factor was that I evaluated my emails from a longer time horizon and higher perspective, more correctly judging whether something was worth responding to or acting on. </p>
|
||||
<p> If only this method would scale. </p>
|
||||
<p>
|
||||
<strong>/end_sidebar</strong>
|
||||
</p>
|
||||
<h3> Mo’ apps, mo’ problems </h3>
|
||||
<p> There are drawbacks, which I’ve glossed over until now. The two main ones: </p>
|
||||
<h4> 1. Formatting issues </h4>
|
||||
<p> Many sites, including popular ones, aren’t presented correctly within the Pocket app (and I imagine others). There’s always the option of opening the link in a web browser, but this eliminates all the positive affordances and then some. If there wasn’t so much value provided otherwise, this would be a deal breaker. </p>
|
||||
<p> The worst part is that, sometimes, the article is cut off or links don’t appear <em>without any indication that something is amiss</em>. On Tim Ferriss’ blog, for example, links (of which there are many) are simply removed. </p>
|
||||
<p> One solution is to tag problematic items with “desktop” so you know that these need to be read/viewed on your computer. </p>
|
||||
<h4> 2. Dependence </h4>
|
||||
<p> Every productivity tool eventually becomes a victim of its own success. In this case, I’ve become so dependent on Pocket that bugs really affect me. </p>
|
||||
<p> For example, the Share to Evernote feature, which I use to highlight and save key passages, has been broken for at least a month. My hysterical tweets to Pocket Support have been answered but not resolved. </p>
|
||||
<p> You wouldn’t think such a minor feature within one app could be so disruptive, but it has been massively so. This simple workflow: </p>
|
||||
<p>
|
||||
<em>Highlight > Share > Share to Evernote > Save</em>
|
||||
</p>
|
||||
<p> …has been replaced with this: </p>
|
||||
<p>
|
||||
<em>Highlight > Copy > Switch to Evernote > New note > Paste > Switch back to Pocket > Share > More > Copy URL > Switch back to Evernote > Paste URL > Switch back to Pocket</em>
|
||||
</p>
|
||||
<p> Worse, I often forget to go back and grab the URL, so I have to hunt it down at some later date. </p>
|
||||
<p>
|
||||
<strong>/rant_over</strong>
|
||||
</p>
|
||||
<h3> Progress Traps and Paradigms </h3>
|
||||
<p> The amount of information in the world is a <a href="https://en.wikipedia.org/wiki/Progress_trap" target="_blank" rel="noopener noreferrer">progress trap</a>. Too much stuff to read is just as limiting as too little. </p>
|
||||
<p> As the inimitable Venkatesh Rao <a href="http://breakingsmart.com/season-1/" target="_blank" rel="noopener noreferrer">has written</a>, we’re moving from a world of <strong>containers</strong> (companies, departments, semesters, packages, silos) to a world of <strong>streams</strong> (social networks, info feeds, main streets of thriving cities, Twitter). Problems and opportunities alike resist having neat little boxes drawn around them. There’s way too much to absorb. Way too much to even guess what you don’t know. </p>
|
||||
<p> As the pace of change in the world accelerates, we double down on all the methods that created the problems in the first place — more planning, more forecasting, more control and risk management. We’re left with massive institutions that nobody trusts, that are simultaneously brittle and too-big-to-fail, creating precarity at every level of the socioeconomic pyramid. </p>
|
||||
<p> What would it look like instead to solve problems (and explore opportunities) in a way that gets better the faster we go? </p>
|
||||
<p> I can’t do justice to Rao’s blog series linked above (it’s in 20 parts — may want to save it for later ;), but the first step he proposes is “exposing yourself to as many different diverse streams as possible.” </p>
|
||||
<p> When you’re immersed in a stream, the faster it goes, the more novel perspectives and ideas you’re exposed to. You develop an <a href="http://rogerlmartin.com/lets-read/the-opposable-mind" target="_blank" rel="noopener noreferrer">opposable mind</a> — the ability to juggle and play around with different perspectives on any issue, instead of seeing it through one lens. </p>
|
||||
<p> Increasingly, the only metric that will matter in your journey of personal growth will be <strong>ROL: Rate-of-Learning</strong>. We’ve heard a lot in recent years about the importance of hands-on learning and practical experimentation. We get it. Burying your head in a book by itself gets you nowhere. </p>
|
||||
<p> But the pendulum is swinging too far in that direction. Yes, you can be <em>too</em> action-oriented. Ideas, while cheap when compared to effective execution, are still more valuable than many of the other things we spend time on. </p>
|
||||
<p> There’s another way to learn faster: assimilate and build on the ideas of others. Sure, you won’t understand every tacit lesson their experience gave them, but you can incorporate many of them, and in a fraction of the time it would take you to make every mistake yourself. </p>
|
||||
<p> Ideas are high leverage agents. They become more so when arranged in highly cross-referenced networks. The only tool we have available that is capable of both creating and accessing these networks on demand is the human brain. </p>
|
||||
<p> I lied before. There is one form of leverage even more powerful than the initial assumptions and paradigms that inform a system’s development: the <strong>ability to transcend paradigms</strong>. </p>
|
||||
<p> I can’t put it any better than Donella Meadows, in her <a href="http://www.donellameadows.org/archives/leverage-points-places-to-intervene-in-a-system/" target="_blank" rel="noopener noreferrer">seminal piece</a> on complex systems: </p>
|
||||
<blockquote>
|
||||
<p> People who cling to paradigms (which means just about all of us) take one look at the spacious possibility that everything they think is guaranteed to be nonsense and pedal rapidly in the opposite direction. Surely there is no power, no control, no understanding, not even a reason for being, much less acting, in the notion or experience that there is no certainty in any worldview. But, in fact, everyone who has managed to entertain that idea, for a moment or for a lifetime, has found it to be the basis for radical empowerment. <strong>If no paradigm is right, you can choose whatever one will help to achieve your purpose.</strong>
|
||||
</p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p> It is in this space of mastery over paradigms that people throw off addictions, live in constant joy, bring down empires, get locked up or burned at the stake or crucified or shot, and <strong>have impacts that last for millennia</strong>. </p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p> In the end, it seems that mastery has less to do with pushing leverage points than it does with <strong>strategically, profoundly, madly letting go.</strong>
|
||||
</p>
|
||||
</blockquote>
|
||||
<p> Reading is the closest thing we have to thinking another’s thoughts. It’s long and sometimes ponderous, but that work is required to wrap yourself in another person’s paradigm. Which is the first step in madly letting go of your own. </p>
|
||||
<p> The amazing thing about ideas is that it takes zero time for one to change your paradigm. It happens in time, but takes no time, like an inter-dimensional wormhole, one entangled particle in your brain mirroring its twin across a chasm even more vast than the universe — the chasm between two minds. </p>
|
||||
<p> And that is the secret power of Read It Later apps. </p>
|
||||
<p>
|
||||
<strong>P.S.</strong> <em>My latest setup has 2 parts: 1) using</em> <a href="https://ifttt.com/recipes/182352-instpaper-to-evernote" target="_blank" rel="noopener noreferrer"><em>this IFTTT recipe</em></a> <em>to automatically send “liked” articles in Instapaper to an Evernotebook called “Instapaper favorites” (for things I want to save in general but don’t have any particular notes on), and 2)</em> <a href="https://ifttt.com/recipes/368728-send-instapaper-highlights-to-evernote-default-notebook" target="_blank" rel="noopener noreferrer"><em>this recipe</em></a> <em>that saves anything I highlight in Instapaper to a new note, and sends it to the Evernote default notebook where I can decide where it belongs later (for when I have specific passages I want to extract)</em>
|
||||
</p>
|
||||
<hr>
|
||||
<p><em><strong>Subscribe below to receive free weekly emails with our best new content, or follow us on <a href="https://twitter.com/fortelabs/">Twitter</a>, <a href="https://www.facebook.com/fortelabs/">Facebook</a>, <a href="https://www.instagram.com/fortelabsco/">Instagram</a>, <a href="https://www.linkedin.com/in/tiagoforte/">LinkedIn</a>, or <a href="https://www.youtube.com/user/simulacrumsquared/">YouTube</a>. Or become a <a href="https://fortelabs.co/about-praxis/">Praxis member</a> to receive instant access to our full collection of members-only posts.</strong></em></p>
|
||||
<form action="https://app.convertkit.com/forms/1022693/subscriptions" method="post" data-sv-form="1022693" data-uid="c4407a2f08" data-format="inline" data-version="5" min-width="400 500 600 700">
|
||||
<div data-style="full">
|
||||
<p><img src="https://proxy-prod.omnivore-image-cache.app/0x0,sqWznQTJOu8MLbN_KvWQgeSkhwNPdvLRWTom32MHspAE/https://embed.filekitcdn.com/e/oP2q5jihy5hj474ZFtvPjw/pkwszL6w2hsV41vY6MLfdR"></p>
|
||||
<p> Join the Forte Labs Newsletter </p>
|
||||
<p> Join 50,000+ people receiving my best ideas on learning, productivity & knowledge management every Tuesday. I'll send you my Top 10 All-Time Articles right away as a thank you. </p>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div data-widget_type="post-info.default" data-element_type="section" data-id="60a66d24">
|
||||
<ul>
|
||||
<li itemprop="about">
|
||||
<span><span>POSTED IN:</span> <span><a href="https://fortelabs.co/blog/category/topics/building-a-second-brain/">Building a Second Brain</a>, <a href="https://fortelabs.co/blog/category/topics/curation/">Curation</a>, <a href="https://fortelabs.co/blog/category/types/free/">Free</a>, <a href="https://fortelabs.co/blog/category/topics/note-taking/">Note-taking</a>, <a href="https://fortelabs.co/blog/category/topics/technology/">Technology</a>, <a href="https://fortelabs.co/blog/category/topics/workflow/">Workflow</a></span></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</DIV>
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
---
|
||||
id: 23360258-5e55-4f51-ae84-83f073539aef
|
||||
title: |
|
||||
Using CSS custom properties like this is a waste - YouTube
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- Youtube
|
||||
date_added: 2023-10-14 20:11:15
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/using-css-custom-properties-like-this-is-a-waste-you-tube-18b30754bdc
|
||||
url_original: |
|
||||
https://m.youtube.com/watch?index=12&list=WL&pp=gAQBiAQB&v=_2LwjfYc1x8
|
||||
---
|
||||
|
||||
# Using CSS custom properties like this is a waste - YouTube
|
||||
|
||||
## Notes
|
||||
|
||||
Definir _"variables locales"_ en la clase más alta de un _componente_ (Ej: ˋ.cardˋ), esta variable se puede utilizar para hacer variantes del componente de manera más rápida y limpia y se puede utilizar en los decendientes de la clase.
|
||||
|
||||
Esto tiene la ventaja de:
|
||||
1. Para crear una variante de nuestro componente solo debemos crear una nueva clase y añadirla junto a la clase más alta (ˋ.card-successˋ), y ya solo debemos sobre escribir las variables en vez de tener que actualizar cada parte del componente (ˋ.card.card-success .buttonˋ & ˋ.card.card-success .card-header h3ˋ).
|
||||
2. Si tenemos propiedades complejas o animaciones donde solo varia una parte de ellas (Ej: ˋdrop-shadowˋ) no tenemos que re-escribir en cada variante la propiedad completa.
|
||||
|
||||
## Original
|
||||
|
||||

|
||||
|
||||
0:02 / 16:11•Watch full video
|
||||
|
||||
[](https://m.youtube.com/@KevinPowell)
|
||||
|
||||
45K views 2 days ago [#css](https://m.youtube.com/hashtag/css)
|
||||
|
||||
If you're interested in checking out ICodeThis, you can find it here: [https://icodethis.com/?ref=kevin](https://www.youtube.com/redirect?event=video%5Fdescription&redir%5Ftoken=QUFFLUhqbVZsbWpVZ3M1NUdacFdJSVZha3BFQ0ZIaTNoZ3xBQ3Jtc0ttWG5nU0ltOTdzSE9YSDQ3aWlsUVFGcEVoMlRFaVhLb0hrczRKRVgta3N0bXBIeC1Sc1ZtTWJHY2MycUpfdVN6OE5pWDlfTG9WQlhTMlRzcW1YX2p1MTY4bjVybTd1ZG02RV9zM1l0QkFWeTNybjBtcw&q=https%3A%2F%2Ficodethis.com%2F%3Fref%3Dkevin&v=%5F2LwjfYc1x8) and if you want to sign up for one of their premium plans, use KEVIN at checkout for an extra 10% off. Custom properties are amazing, but a lot of people don’t take advantage of how awesome they are. They set them up in the :root and that’s it, but they can be so much more useful than that! So, in this …
|
||||
|
||||
...more
|
||||
|
||||
...more
|
||||
|
||||
45,645 views • Oct 12, 2023 • #css
|
||||
|
||||
#### License
|
||||
|
||||
Shop the Kevin Powell store
|
||||
|
|
@ -1,349 +0,0 @@
|
|||
---
|
||||
id: 512f7bbc-6ba0-11ee-be2a-83432433f852
|
||||
title: |
|
||||
Highlighting fold text, community fork of null-ls, leetcode integration, reduce ram usage of LSP servers, svelte inspector integration
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- RSS
|
||||
date_added: 2023-10-15 16:10:23
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/highlighting-fold-text-community-fork-of-null-ls-leetcode-integr-18b3533f57b
|
||||
url_original: |
|
||||
https://dotfyle.com/this-week-in-neovim/55
|
||||
---
|
||||
|
||||
# Highlighting fold text, community fork of null-ls, leetcode integration, reduce ram usage of LSP servers, svelte inspector integration
|
||||
|
||||
## Highlights
|
||||
|
||||
hinell/duplicate.nvim
|
||||
|
||||
> [!note]
|
||||
> Add to nvim config
|
||||
|
||||
[source](https://omnivore.app/me/highlighting-fold-text-community-fork-of-null-ls-leetcode-integr-18b3533f57b#5de369b4-f406-446f-b59a-358d59dd9eb1) #Todo
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||
## Introduction
|
||||
|
||||
This week we have new features in Neovim Core, new plugins and new releases. Some new Neovim features include `:fclose` to close floating windows, support spaces in in directory names, treesitter highlighting in folds and NVIM\_APPNAME supports relative paths.
|
||||
|
||||
We have several new plugins, e.g. you can now grind LeetCode inside Neovim, mini.pick a new fuzzy finder + selector added to the mini.nvim library, and a plugin to start/stop LSP servers upon demand to keep RAM usage low etc..
|
||||
|
||||
Hope you enjoy!
|
||||
|
||||
## Neovim core
|
||||
|
||||
> Updates of Neovim itself, which are available on Neovim nightly.
|
||||
|
||||
> * [@neovim](https://twitter.com/neovim) on Twitter
|
||||
> * [Neovim news](https://neovim.io/doc/user/news.html)
|
||||
> * `:h news.txt` updates in Neovim directly
|
||||
> * [PR's on GitHub](https://github.com/neovim/neovim/pulls)
|
||||
|
||||
* [:fclose to close floating window](https://github.com/neovim/neovim/commit/fd39f5ce8c9bbda1b77ff6c03553148fadac5d57)
|
||||
* [Spaces can be used to separate directory names. To have a space in a directory name, precede it with an extra backslash, and escape the space](https://github.com/neovim/neovim/commit/f5eabaa9407ae3d1ccf6592337453c423eff3d9a)
|
||||
* [Ignore swapfile for running Nvim processes](https://github.com/neovim/neovim/commit/29fe883aa9166bdbcae3f935523c75a8aa56fe45)
|
||||
* [vim.lsp.util.parse\_snippet() will now strictly follow the snippet grammar defined by LSP, and hence previously parsed snippets might now be considered invalid input.](https://github.com/neovim/neovim/commit/eb1f0e8fcca756a00d287e23bf87554e0e7f6dfd)
|
||||
* [vim.treesitter.foldtext() applies treesitter highlighting to foldtext.](https://github.com/neovim/neovim/commit/9ce1623837a817c3f4f5deff9c8ba862578b6009)
|
||||
* [Better cmdline completion for string option value](https://github.com/neovim/neovim/commit/01c51a491330bd10202c73aff92c0978984c0692)
|
||||
* [Support toggling showing of float window](https://github.com/neovim/neovim/commit/4200a0f1678c06c6da4e4cfb0184c29c1174ed21)
|
||||
* [NVIM\_APPNAME now supports relative paths](https://github.com/neovim/neovim/commit/a66b0fdfaa35715c832b98b8941cc5673505e0c2)
|
||||
|
||||
### Highlighted folds on Neovim Nightly
|
||||
|
||||

|
||||
|
||||
* [PR](https://github.com/neovim/neovim/pull/25209)
|
||||
* [Reddit](https://www.reddit.com/r/neovim/comments/16sqyjz/finally%5Fwe%5Fcan%5Fhave%5Fhighlighted%5Ffolds/)
|
||||
|
||||
## Neovim Plugin Community
|
||||
|
||||
> Neovim is full of active plugins. This section is about the community and what is going on.
|
||||
|
||||
---
|
||||
|
||||
### Resources & articles
|
||||
|
||||
#### Open Neovim From Your Browser - Integrating nvim with Svelte’s Inspector
|
||||
|
||||
* [Blog](https://theosteiner.de/open-neovim-from-your-browser-integrating-nvim-with-sveltes-inspector)
|
||||
* [Reddit](https://www.reddit.com/r/neovim/comments/177p9fj/open%5Fneovim%5Ffrom%5Fyour%5Fbrowser%5Fintegrating%5Fnvim/)
|
||||
|
||||
---
|
||||
|
||||
### New plugins
|
||||
|
||||
#### none-ls.nvim is a community fork of null-ls.nvim
|
||||
|
||||
> null-ls.nvim reloaded / Use Neovim as a language server to inject LSP diagnostics, code actions, and more via Lua.
|
||||
|
||||
null-ls.nvim fork, maintained by the community. Only the repository name has changed for compatibility reasons. All the API's will stay as is.
|
||||
|
||||
Migrate by replacing `jose-elias-alvarez/null-ls.nvim` with `nvimtools/none-ls.nvim` in your package manager.
|
||||
|
||||
* [GitHub](https://github.com/nvimtools/none-ls.nvim)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/nvimtools/none-ls.nvim)
|
||||
* [Reddit](https://www.reddit.com/r/neovim/comments/16wystn/nonelsnvim%5Fis%5Fa%5Fcommunity%5Ffork%5Fof%5Fnulllsnvim/)
|
||||
|
||||
#### kawre/leetcode.nvim
|
||||
|
||||

|
||||
|
||||
> A Neovim plugin enabling you to solve LeetCode problems within Neovim.
|
||||
|
||||
* [GitHub](https://github.com/kawre/leetcode.nvim)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/kawre/leetcode.nvim)
|
||||
* [Reddit](https://www.reddit.com/r/neovim/comments/173ctlz/leetcodenvim%5Fsolve%5Fleetcode%5Fproblems%5Fwithin%5Fneovim/)
|
||||
|
||||
#### echasnovski/mini.pick
|
||||
|
||||

|
||||
|
||||
> pick anything. Interactive non-blocking picker with one window design, toggleable preview, fast default matching, built-in pickers, and more
|
||||
|
||||
* [GitHub](https://github.com/echasnovski/mini.pick)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/echasnovski/mini.pick)
|
||||
* [Reddit](https://www.reddit.com/r/neovim/comments/176yv8g/minipick%5Fpick%5Fanything%5Finteractive%5Fnonblocking/)
|
||||
|
||||
#### hinell/lsp-timeout.nvim
|
||||
|
||||

|
||||
|
||||
> Start/stop LSP servers upon demand; keeps RAM usage low
|
||||
|
||||
Some LSP servers are terribly inefficient at memory management and can easily take up gigabytes of RAM MBs if left unattended (just like VS Code huh?!). This plugin prevents excessive memory usage by stopping and restarting LSP servers automatically upon gaining or loosing window focus, keeping neovim fast.
|
||||
|
||||
* [GitHub](https://github.com/hinell/lsp-timeout.nvim)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/hinell/lsp-timeout.nvim)
|
||||
* [Reddit](https://www.reddit.com/r/neovim/comments/16vkkj8/lsptimeoutnvim/)
|
||||
|
||||
---
|
||||
|
||||
#### luckasRanarison/clear-action.nvim
|
||||
|
||||

|
||||
|
||||
> Predictable LSP code actions
|
||||
|
||||
A simple Neovim plugin that enhances LSP code actions with fully customizable signs, personalized actions, and server-specific mappings, making code actions more predictable.
|
||||
|
||||
* [GitHub](https://github.com/luckasRanarison/clear-action.nvim)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/luckasRanarison/clear-action.nvim)
|
||||
* [Reddit](https://www.reddit.com/r/neovim/comments/16v32p5/clearactionnvim%5Fmakes%5Flsp%5Fcode%5Factions/)
|
||||
|
||||
---
|
||||
|
||||
#### JMarkin/gentags.lua
|
||||
|
||||
> autogenerate tags for neovim
|
||||
|
||||
* [GitHub](https://github.com/JMarkin/gentags.lua)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/JMarkin/gentags.lua)
|
||||
|
||||
---
|
||||
|
||||
#### roobert/palette.nvim
|
||||
|
||||

|
||||
|
||||
> 🎨 Palette - A beautiful, versatile, systematic, Neovim theme system
|
||||
|
||||
Palette is a Neovim theme system to make creating and customizing themes easy.
|
||||
|
||||
Highlight groups are logically arranged to strike a harmonious balance between clarity and aesthetic appeal.
|
||||
|
||||
Caching ensures themes are performant.
|
||||
|
||||
Build easily distributable themes using the provided build script.
|
||||
|
||||
Generate application color schemes, such as for LS\_COLORS and iterm2 for matching terminal feel.
|
||||
|
||||
* [GitHub](https://github.com/roobert/palette.nvim)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/roobert/palette.nvim)
|
||||
* [Reddit](https://www.reddit.com/r/neovim/comments/16smdr6/introducing%5Froobertpalettenvim%5Fa%5Fbeautiful/)
|
||||
|
||||
---
|
||||
|
||||
#### MunifTanjim/nougat.nvim
|
||||
|
||||
  
|
||||
|
||||
> 🍫 Hyperextensible Statusline / Tabline / Winbar for Neovim 🚀
|
||||
|
||||
* [GitHub](https://github.com/MunifTanjim/nougat.nvim)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/MunifTanjim/nougat.nvim)
|
||||
|
||||
---
|
||||
|
||||
#### trimclain/builder.nvim
|
||||
|
||||

|
||||
|
||||
> Simple building plugin for neovim
|
||||
|
||||
* [GitHub](https://github.com/trimclain/builder.nvim)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/trimclain/builder.nvim)
|
||||
* [Reddit](https://www.reddit.com/r/neovim/comments/16qwcl7/buildernvim%5Fsimple%5Fbuild%5Fplugin%5Ffor%5Fneovim/)
|
||||
|
||||
---
|
||||
|
||||
#### niuiic/git-log.nvim
|
||||
|
||||

|
||||
|
||||
> Check git log of the selected code.
|
||||
|
||||
* [GitHub](https://github.com/niuiic/git-log.nvim)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/niuiic/git-log.nvim)
|
||||
|
||||
---
|
||||
|
||||
#### 2KAbhishek/nerdy.nvim
|
||||
|
||||

|
||||
|
||||
> Find Nerd Glyphs Easily 🤓🔭
|
||||
|
||||
Do you like Nerd fonts, but don't like going over to the site just to find a glyph? nerdy.nvim, is a super handy plugin that lets you easily search, preview and insert any nerd font glyph from Neovim!
|
||||
|
||||
* [GitHub](https://github.com/2KAbhishek/nerdy.nvim)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/2KAbhishek/nerdy.nvim)
|
||||
* [Reddit](https://www.reddit.com/r/neovim/comments/16qr135/nerdynvim%5Feasily%5Ffind%5Fand%5Finsert%5Fnerd%5Ffont%5Fglyphs/)
|
||||
|
||||
---
|
||||
|
||||
#### David-Kunz/gen.nvim
|
||||
|
||||

|
||||
|
||||
> Neovim plugin to generate text using LLMs with customizable prompts
|
||||
|
||||
* [GitHub](https://github.com/David-Kunz/gen.nvim)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/David-Kunz/gen.nvim)
|
||||
* [Reddit](https://www.reddit.com/r/neovim/comments/16x1zf7/local%5Fllms%5Fin%5Fneovim%5Fgennvim/)
|
||||
* [Youtube](https://www.youtube.com/watch?v=FIZt7MinpMY)
|
||||
|
||||
---
|
||||
|
||||
#### VidocqH/data-viewer.nvim
|
||||
|
||||

|
||||
|
||||
> Table view for data files, csv, tsv
|
||||
|
||||
Lightweight neovim plugin provides a table view for inspect data files such as csv, tsv
|
||||
|
||||
* [GitHub](https://github.com/VidocqH/data-viewer.nvim)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/VidocqH/data-viewer.nvim)
|
||||
|
||||
---
|
||||
|
||||
#### ==hinell/duplicate.nvim==
|
||||
|
||||

|
||||
|
||||
> Duplicate visual selection, lines, and textobjects
|
||||
|
||||
Duplicate lines in different directions (up/down) by specified offset Duplicate visual selection & line-wise blocks
|
||||
|
||||
* [GitHub](https://github.com/hinell/duplicate.nvim)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/hinell/duplicate.nvim)
|
||||
* [Reddit](https://www.reddit.com/r/neovim/comments/16vkd4x/duplicatenvim/)
|
||||
|
||||
---
|
||||
|
||||
#### niuiic/remote.nvim
|
||||
|
||||

|
||||
|
||||
> Edit remote files locally.
|
||||
|
||||
Edit remote files with local neovim configuration.
|
||||
|
||||
Edit them as local directories.
|
||||
|
||||
No other dependencies required for remote machine except ssh.
|
||||
|
||||
* [GitHub](https://github.com/niuiic/remote.nvim)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/niuiic/remote.nvim)
|
||||
|
||||
---
|
||||
|
||||
#### niuiic/typst-preview.nvim
|
||||
|
||||

|
||||
|
||||
> Neovim plugin to preview typst document.
|
||||
|
||||
Generate pdf files by typst compile. Respond to subsequent file changes with typst-lsp. Redirect these pdf files to a fixed path when you switch buffer. Preview this pdf by a pdf viewer with the ability to respond to the file changes.
|
||||
|
||||
* [GitHub](https://github.com/niuiic/typst-preview.nvim)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/niuiic/typst-preview.nvim)
|
||||
|
||||
---
|
||||
|
||||
#### SalOrak/whaler.nvim
|
||||
|
||||

|
||||
|
||||
> Telescope extension to change between directories blazingly fast
|
||||
|
||||
Whaler is a Telescope extension to move between directories. It is based on the concept of [tmux-windowizer](https://github.com/ThePrimeagen/.dotfiles/blob/master/bin/.local/scripts/tmux-windowizer) which uses a set of directories and fzf to move to another directory whilst creating a new tmux session.
|
||||
|
||||
* [GitHub](https://github.com/SalOrak/whaler.nvim)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/SalOrak/whaler.nvim)
|
||||
* [Reddit](https://www.reddit.com/r/neovim/comments/16wgw0b/whalernvim/)
|
||||
|
||||
---
|
||||
|
||||
#### gsuuon/note.nvim
|
||||
|
||||

|
||||
|
||||
> Notes in neovim
|
||||
|
||||
A simple Neovim note taking plugin with daily notes, task tracking and syntax highlighting.
|
||||
|
||||
note.nvim makes it easy to take working notes and track tasks. It adds commands to help manipulate task items, create daily notes, and navigate within (and between) notes.
|
||||
|
||||
* [GitHub](https://github.com/gsuuon/note.nvim)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/gsuuon/note.nvim)
|
||||
|
||||
---
|
||||
|
||||
#### A retrospective on why Nyoom is archived
|
||||
|
||||
* [Reddit](https://www.reddit.com/r/neovim/comments/16sk266/nyoom%5Fwhy%5Fim%5Fultimately%5Farchiving%5Fit%5Fa%5Fshort/)
|
||||
|
||||
#### indent-blankline.nvim v3 is released
|
||||
|
||||
* [GitHub](https://github.com/lukas-reineke/indent-blankline.nvim)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/lukas-reineke/indent-blankline.nvim)
|
||||
* [Migration guide](https://github.com/lukas-reineke/indent-blankline.nvim/wiki/Migrate-to-version-3)
|
||||
* [Reddit](https://www.reddit.com/r/neovim/comments/16u5abl/indent%5Fblankline%5Fv3%5Fis%5Freleased/)
|
||||
|
||||
#### LazyVim 10.0.0 has been released!
|
||||
|
||||
* [GitHub](https://github.com/LazyVim/LazyVim)
|
||||
* [Dotfyle](https://dotfyle.com/plugins/LazyVim/LazyVim)
|
||||
* [Changelog](https://github.com/LazyVim/LazyVim/blob/main/CHANGELOG.md)
|
||||
* [Reddit](https://www.reddit.com/r/neovim/comments/1766fl1/lazyvim%5F1000%5Fhas%5Fbeen%5Freleased/)
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
Add your the plugin in either of the following to be featured in This Week in Neovim and Dotfyle:
|
||||
|
||||
* [rockerBOO/awesome-neovim](https://github.com/rockerBOO/awesome-neovim)
|
||||
* [SUBMITTED\_PLUGINS.md](https://github.com/codicocodes/dotfyle/blob/main/SUBMITTED-PLUGINS.md)
|
||||
|
||||
Contribute to the development of Dotfyle:
|
||||
|
||||
* File issues and submit pull requests on [GitHub](https://github.com/codicocodes/dotfyle)
|
||||
* Discuss ideas on [Discord](https://discord.gg/AMbnnN5eep)
|
||||
|
|
@ -1,592 +0,0 @@
|
|||
---
|
||||
id: 07f91eda-1940-4aaa-8e27-78b0bf176193
|
||||
title: |
|
||||
The Unreasonable Effectiveness Of Plain Text
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
date_added: 2023-10-18 10:01:51
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/noboilerplate-scripts-34-plain-text-team-md-at-main-0-atman-nobo-18b42e0d185
|
||||
url_original: |
|
||||
https://github.com/0atman/noboilerplate/blob/main/scripts/34-Plain-Text-Team.md
|
||||
---
|
||||
|
||||
# The Unreasonable Effectiveness Of Plain Text
|
||||
|
||||
## Highlights
|
||||
|
||||
## [Tie Yourself to the Mast](#tie-yourself-to-the-mast)
|
||||
|
||||
%%pron. oh diss e us%% In the Odyssey, Odysseus (confusingly called Ulysses in English literature) had to travel through siren-infested waters.
|
||||
|
||||
This was a well-understood problem in his world. Sailors would simply solve this by putting wax in their ears, so the sirens' tempting song wouldn't lure them to their deaths.
|
||||
|
||||
But Odysseus had a challenge: He WANTED to hear the Sirens' beautiful song. He certainly didn't want to drown, so he ordered his crew to tie him to the mast of the ship, and to ignore any of his pleas to let him go, until safety.
|
||||
|
||||
This way, he was able to guard against future bad decisions he knew he would make by setting up a framework to control his future self.
|
||||
|
||||
This is the Ulysses pact, and it's a very common trick:
|
||||
|
||||
* Leaving your credit card or car keys at home when going out drinking is a Ulysses pact.
|
||||
* Publishing a warrant canary on your company's website is a Ulysses pact,
|
||||
* and standardising all your tools on plain text is a Ulysses pact.
|
||||
|
||||
> [!note]
|
||||
> El pacto de Ulysses es una estrategia (o framework) en donde tomamos medidas tempranamente para prevenir malas desiciones en un futuro.
|
||||
|
||||
[source](https://omnivore.app/me/noboilerplate-scripts-34-plain-text-team-md-at-main-0-atman-nobo-18b42e0d185#7466a699-a115-4b9f-99fc-416852b5aef2) #frameworks
|
||||
|
||||
---
|
||||
|
||||
"The difference between science and screwing around is _writing it down_."
|
||||
|
||||
## [— Adam Savage](#-adam-savage)
|
||||
|
||||
> [!note]
|
||||
> This was just a cool quote...
|
||||
|
||||
[source](https://omnivore.app/me/noboilerplate-scripts-34-plain-text-team-md-at-main-0-atman-nobo-18b42e0d185#9a030eb7-6269-4863-8e5e-61b59a1704b6) #quote
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||
<style> :root {--r-code-font: "FiraCode Nerd Font";} .reveal .hljs {min-height: 50%;} </style>
|
||||
|
||||
!\[\[git-logo.png|500\]\]
|
||||
|
||||
## [Plain-Text Team](#plain-text-team)
|
||||
|
||||
notes: %%
|
||||
|
||||
* Tell them what you're going to tell them
|
||||
* Tell them
|
||||
* Tell them what you told them %% Hi friends my name is Tris and this is No Boilerplate, focusing on fast, technical videos.
|
||||
|
||||
All good teams are alike; each bad team is bad in its own way. %% to paraphrase Tolstoy %%
|
||||
|
||||
Software is an incredible thing, isn't it? Combined with the internet, a small team of friends can change the world overnight.
|
||||
|
||||
Every company, no matter what their industry, must now run a tech team, even if only to maintain their website.
|
||||
|
||||
So why are they all so bad at it?
|
||||
|
||||
---
|
||||
|
||||
!\[\[cc-logo.png\]\]
|
||||
|
||||
## [Public Domain Videos](#public-domain-videos)
|
||||
|
||||
<https://github.com/0atman/noboilerplate/>
|
||||
|
||||
notes: Everything you see in this video: script, links, and images are part of a plain-text markdown document available freely on GitHub under a public domain licence.
|
||||
|
||||
---
|
||||
|
||||
## [First World Problems](#first-world-problems)
|
||||
|
||||
notes: If you've worked in a web team, tech team or any digital creative team, you've likely felt the pain.
|
||||
|
||||
* Bad software,
|
||||
* constantly changing processes,
|
||||
* and lots and lots of meetings.
|
||||
|
||||
I discussed some of these problems in my Agile video that made me a lot of friends. But today, I want to go bigger. You can solve all these problems in a single blow.
|
||||
|
||||
The secret is, in order to do more, you must have the discipline to do LESS.
|
||||
|
||||
---
|
||||
|
||||
!\[\[rework-book.png|400\]\]
|
||||
|
||||
!\[\[remote-book.png|400\]\]
|
||||
|
||||
notes:
|
||||
|
||||
A lot of the ideas that I will mention today are not new. They've been well-understood in the startup and digital world for a long time.
|
||||
|
||||
But regression to the mean is prevalent.
|
||||
|
||||
It's not just enough to argue for good tools today, you must stop the future churn of new apps and processes that solve the same things in different, but equivalent ways.
|
||||
|
||||
And you do this with a Ulysses pact.
|
||||
|
||||
---
|
||||
|
||||
!\[\[ulysses-and-the-sirens-waterhouse.jpg\]\]
|
||||
|
||||
_"Ulysses and the Sirens"_ [John William Waterhouse](https://en.wikipedia.org/wiki/John%5FWilliam%5FWaterhouse)
|
||||
|
||||
notes:
|
||||
|
||||
## ==[Tie Yourself to the Mast](#tie-yourself-to-the-mast)==
|
||||
|
||||
==%%pron. oh diss e us%%
|
||||
In the Odyssey, Odysseus (confusingly called Ulysses in English literature) had to travel through siren-infested waters.==
|
||||
|
||||
==This was a well-understood problem in his world.
|
||||
Sailors would simply solve this by putting wax in their ears, so the sirens' tempting song wouldn't lure them to their deaths.==
|
||||
|
||||
==But Odysseus had a challenge: He WANTED to hear the Sirens' beautiful song. He certainly didn't want to drown, so he ordered his crew to tie him to the mast of the ship, and to ignore any of his pleas to let him go, until safety.==
|
||||
|
||||
==This way, he was able to guard against future bad decisions he knew he would make by setting up a framework to control his future self.==
|
||||
|
||||
==This is the Ulysses pact, and it's a very common trick:==
|
||||
|
||||
* ==Leaving your credit card or car keys at home when going out drinking is a Ulysses pact.==
|
||||
* ==Publishing a warrant canary on your company's website is a Ulysses pact,==
|
||||
* ==and standardising all your tools on plain text is a Ulysses pact.==
|
||||
|
||||
---
|
||||
|
||||
!\[\[the-fbi-has-not-been-here.png\]\]
|
||||
|
||||
An example of a warrant canary
|
||||
|
||||
notes:
|
||||
|
||||
In the future, you, or your successor, or your team might well be tempted to try the latest hot project management software, or documentation tool or scrum system.
|
||||
|
||||
While it might be good for a while, the act of changing tools constantly is an enormous overhead for your team, and one that gives the lasting impression that anything we write is likely to be legacy very soon, trapped in a deprecated app that "we just don't use any more", so why bother writing anything down.
|
||||
|
||||
Tying yourself to the mast by standardising on one tool, and not only that, but a plain text tool, means your data will live forever, and the network effect can make it more and more valuable over time, instead of less and less.
|
||||
|
||||
---
|
||||
|
||||
"The greatest problem in communication is the _illusion_ that it has been achieved."
|
||||
|
||||
## [— William H. Whyte](#-william-h-whyte)
|
||||
|
||||
[(not George Bernard Shaw, apparently)](https://quoteinvestigator.com/2014/08/31/illusion/)
|
||||
|
||||
notes:
|
||||
|
||||
## [Decoupled Organisation Through Plain Text](#decoupled-organisation-through-plain-text)
|
||||
|
||||
Teams of people need to be on the same page. Both literally and figuratively.
|
||||
|
||||
The natural way to do this is by talking to one another. But talking does not scale, and is extremely impermanent. After the sound waves have bounced off the walls and reverberated for a second... the words are gone, and what is left is our memory of them.
|
||||
|
||||
---
|
||||
|
||||
=="The difference between science and screwing around is== _==writing it down==_==."==
|
||||
|
||||
## ==[— Adam Savage](#-adam-savage)==
|
||||
|
||||
notes:
|
||||
|
||||
Human memory is extremely unreliable, subjective, and the root cause of many problems.
|
||||
|
||||
After a discussion, it is not apparent that everyone has agreed upon exactly the same thing. And you now need another meeting to double-check that.
|
||||
|
||||
The solution is documentation.
|
||||
|
||||
---
|
||||
|
||||
## [Documentation-First Teams](#documentation-first-teams)
|
||||
|
||||
notes: Communication is most reliable when it is in black and white.
|
||||
|
||||
Everyone understands this, from 10,000-page government specifications to an email sign-off from the client you're making a 3-minute track for.
|
||||
|
||||
Yes, have more immediate conversations, by video, or chat, but write down what you concluded, and get the other person to confirm it.
|
||||
|
||||
---
|
||||
|
||||
## [](#documenting-architecture-decisions)["Documenting Architecture Decisions"](https://cognitect.com/blog/2011/11/15/documenting-architecture-decisions)
|
||||
|
||||
(aka the _ADR_ process)
|
||||
|
||||
— [Michael Nygard](https://cognitect.com/authors/MichaelNygard.html)
|
||||
|
||||
notes: You can improve every part of your team, business, or organisation by recording what decisions you have made, and WHY, in a system that allows for asynchronous discussion and improvements.
|
||||
|
||||
The ADR process is excellent for this, for example.
|
||||
|
||||
There are a thousand competing apps that claim to solve these problems for you.
|
||||
|
||||
---
|
||||
|
||||
!\[\[gdocs-screenshot.png|200\]\]
|
||||
|
||||
!\[\[jamboard-photo.png|200\]\]
|
||||
|
||||
!\[\[confluence-screenshot.png|200\]\]
|
||||
|
||||
!\[\[pivotal-tracker-screenshot.png|200\]\]
|
||||
|
||||
!\[\[notion-screenshot.png|200\]\]
|
||||
|
||||
!\[\[trello-screenshot.png|200\]\]
|
||||
|
||||
notes: These apps all re-invent the wheel in their own way, and new ones are being released every week. I've used most of them, perhaps you have too, and they're all rubbish.
|
||||
|
||||
But there is a group of people who are extremely practised at managing enormous distributed, concurrent, text projects:
|
||||
|
||||
_Programmers!_
|
||||
|
||||
As an example, if you use Google Docs, your small team can collaborate on a few files a day, in a drive of perhaps a hundred or two hundred. And just like in most other documentation systems, that won't scale.
|
||||
|
||||
Programmers simultaneously edit thousands of files a day, across repositories of data so numerous that we don't keep count.
|
||||
|
||||
What are programmers using, and can non-programmers use it too?
|
||||
|
||||
---
|
||||
|
||||
## [Enter Git](#enter-git)
|
||||
|
||||
* GitHub
|
||||
* GitLab
|
||||
* Bitbucket
|
||||
* SourceForge
|
||||
* Etc.
|
||||
|
||||
notes:
|
||||
|
||||
The answer is yes, yes we can.
|
||||
|
||||
I recommend you use the most popular distributed version control system on the planet: Git.
|
||||
|
||||
You'll use this through one of the many git web hosts, the largest of which is GitHub, which I recommend for most people.
|
||||
|
||||
---
|
||||
|
||||
## [Popularity Matters](#popularity-matters)
|
||||
|
||||
notes:
|
||||
|
||||
Though I mention GitHub primarily in this video, I'm not sponsored by them, or anything like that, I just acknowledge that popularity matters. Support, experience, and integrations with other services will all be far, far easier if you use the standard.
|
||||
|
||||
All these tools started as a web interface around the incredible tool: Git.
|
||||
|
||||
---
|
||||
|
||||
## [Aside:](#aside)
|
||||
|
||||
## [Linux & Git](#linux--git)
|
||||
|
||||
notes: By the way, the creator of Linux, Linus Torvalds, also later created git, to solve the problem that he created: that the Linux project had become SO LARGE that existing plain text collaboration tools were not scaling.
|
||||
|
||||
He jokes that he named his first project, Linux, after himself, and so it was natural to name the second one after himself too!
|
||||
|
||||
---
|
||||
|
||||
## [Github Et Al. Are Greater Than the Sum of Their Parts](#github-et-al-are-greater-than-the-sum-of-their-parts)
|
||||
|
||||
notes: From simple code-hosting beginnings, these git services have grown to be so much more than that, trusted by the largest projects in the world, built by the largest companies in the world.
|
||||
|
||||
The foundation of my ideal team uses the raw materials that GitHub has given us.
|
||||
|
||||
What are the raw materials?
|
||||
|
||||
I'll show you this with a demo: We're going to build a GitHub organisation for No Boilerplate.
|
||||
|
||||
This video is not sponsored by GitHub, my work is possible, thanks to viewers like you.
|
||||
|
||||
---
|
||||
|
||||
!\[\[nb-patreon-aug-23.png|700\]\]
|
||||
|
||||
<https://www.patreon.com/noboilerplate>
|
||||
|
||||
notes:
|
||||
|
||||
If you'd like to see and give feedback on my videos up to a week early, as well as get discord perks, and even your name in the credits, it would be very kind of you to check my Patreon.
|
||||
|
||||
I'm also offering a limited number of mentoring slots. If you'd like 1:1 tuition on Rust, Python, Web tech, Personal organisation, or anything that I talk about in my videos, do sign up and let's chat!
|
||||
|
||||
It's just me running this channel, and I'm so grateful to everyone for supporting me on this wild adventure.
|
||||
|
||||
Let's make our plain text team:
|
||||
|
||||
---
|
||||
|
||||
!\[\[repo.png\]\]
|
||||
|
||||
## [Repos](#repos)
|
||||
|
||||
notes: The foundational unit with any git host is the repo. This doesn't just correspond with one git repository, but one logical project or subproject. Organisational tools like the Wiki (for documentation), Projects (for project management) and more can sit here, right next to your project's files, right where you need them.
|
||||
|
||||
---
|
||||
|
||||
!\[\[wiki2.png\]\]
|
||||
|
||||
## [Wikis](#wikis)
|
||||
|
||||
notes: Each GitHub repository has a wiki, a folder of linked markdown files that anyone with access can edit, either in the friendly web editor, or, by cloning the wiki with git, on their own computer with whatever editor they like.
|
||||
|
||||
This is the minimum viable documentation tool, and it's useful for when git's full collaboration system isn't needed, and you just want to throw some linked markdown files together quickly.
|
||||
|
||||
---
|
||||
|
||||
## [\# This is a Heading](#-this-is-a-heading)
|
||||
|
||||
### [\### This is a Sub Heading](#-this-is-a-sub-heading)
|
||||
|
||||
_\_this is italic text\__
|
||||
|
||||
**\*\*this is bold\*\***
|
||||
|
||||
\[[this is a link](https://github.com/0atman/noboilerplate/blob/main/scripts)\]([http://example.com](http://example.com/))
|
||||
|
||||
_(learn more: [markdownguide.org/basic-syntax/](https://www.markdownguide.org/basic-syntax/))_
|
||||
|
||||
notes:
|
||||
|
||||
## [Aside: Markdown is Great](#aside-markdown-is-great)
|
||||
|
||||
Github, GitLab, and most of the Internet have standardised on Markdown. Just like Slack, Discord, many websites, and sometimes Facebook depending on the phase of the moon, they all format text using this lightweight standard called Markdown.
|
||||
|
||||
Markdown is my favourite text format, it's really simple to use, and is designed to look good both in plain text and rendered as rich text, unlike HTML, which is unreadable by most people unless rendered in a browser.
|
||||
|
||||
Here we've got a heading, denoted by the hash symbol, italic with underscores, bold with double asterisks, and links using this bracket pairing syntax.
|
||||
|
||||
There are a few more options available, which you can look up at markdownguide.org, but this is the overwhelming majority of formatting you'll need on a day-to-day basis.
|
||||
|
||||
---
|
||||
|
||||
!\[\[obsidian-kanban-paint.png\]\]
|
||||
|
||||
notes:
|
||||
|
||||
The genius of storing your data in this universal plain-text format is that should you wish to migrate from GitHub to another similar platform, your data is portable and under your control.
|
||||
|
||||
GitHub formats Markdown very nicely, but you can export it in any format you like, and edit it with any tool you like, present and future.
|
||||
|
||||
Including my favourite tool here, Obsidian.
|
||||
|
||||
Markdown keeps your team focussed on what is important by allowing you just enough formatting, but no rich customisation options. You're not making a beautiful client brochure, so you shouldn't use 90s desktop publishing tools to make your company's critical documentation.
|
||||
|
||||
Back to GitHub's features:
|
||||
|
||||
---
|
||||
|
||||
!\[\[issues.png\]\]
|
||||
|
||||
## [Issues](#issues)
|
||||
|
||||
notes:
|
||||
|
||||
Though not part of the git system, Issues are a natural addition that all git hosts have implemented: A simple task system for capturing work that needs doing. These could be new features, customer requests, bug reports, or ideas. They have a rich comment thread for discussion, can be assigned to team members, and tagged with custom tags.
|
||||
|
||||
This minimum viable project management system could be all you need. Certainly, for a solo or small team, capturing requirements in Issues might be enough.
|
||||
|
||||
But if you need more, you need Milestones.
|
||||
|
||||
---
|
||||
|
||||
!\[\[milestones.png\]\]
|
||||
|
||||
## [Milestones](#milestones)
|
||||
|
||||
notes: GH milestones are a grouping of issues with a deadline.
|
||||
|
||||
They typically represent a target, a release, or something the team is working towards. Milestones just have a title, a description, and a date. No burndown charts, no swim lanes, no complex statistics, just a progress bar.
|
||||
|
||||
This might be enough project management for you. If not, it is time for GH Projects.
|
||||
|
||||
---
|
||||
|
||||
!\[\[projects.png\]\]
|
||||
|
||||
## [Projects](#projects)
|
||||
|
||||
notes:
|
||||
|
||||
Each GitHub repo, team, and organisation can have a project board, a lightweight kanban board with customisable columns, allowing you to group your issues together, and observe their progress through your current iteration.
|
||||
|
||||
This represents the information radiator for your team, a bird's-eye view of what is happening with the project, and something you might gather around for your morning catchup meeting.
|
||||
|
||||
You don't need all the features of Trello, JIRA, or anything like that. You need the minimum viable board.
|
||||
|
||||
This bare-bones tool completely side-steps 'the JIRA effect', which is if you have a tool that is packed full of time tracking, velocity points, and so on, the temptation is to use all these features, even if they give no value, and complicate your processes.
|
||||
|
||||
---
|
||||
|
||||
## [Aside:](#aside-1)
|
||||
|
||||
## [Standups Are Great](#standups-are-great)
|
||||
|
||||
notes:
|
||||
|
||||
If you have one meeting a day, it should be a standup. Good standups replace other meetings and accelerate your project dramatically.
|
||||
|
||||
The way I like to do standups is not by asking everyone what they did yesterday and what they intend to do today.
|
||||
|
||||
That's a great way to find out at length what Dave did on his day off, but not a good way to find out what's happening with the project specifically.
|
||||
|
||||
I recommend walking your board, backwards, from right to left. Everyone is timeboxed, keeping the meeting tight. If you don't have an issue on the board, you don't speak yet. Perhaps you could write or pick up a task from the backlog and talk about it tomorrow.
|
||||
|
||||
At the end, the team member who is facilitating the meeting asks if anyone has any blockers, and we're done.
|
||||
|
||||
The most important part of this most important meeting is asking if you have any blockers. A good standup means that no-one can get lost or delayed by more than 24 hours.
|
||||
|
||||
Note I didn't say the PM or DM or scrum master or whoever facilitates. That person doesn't exist in my team. These are not roles, they are hats.
|
||||
|
||||
I don't know if your team needs any other meetings, but it is vital that you do a standup.
|
||||
|
||||
Back to GitHub.
|
||||
|
||||
---
|
||||
|
||||
!\[\[org-public.png\]\]
|
||||
|
||||
## [Organisations](#organisations)
|
||||
|
||||
notes: GitHub provides an umbrella group of users called an organisation. This is your company, and if you're building your products in the open, as I recommend you do, you won't pay GitHub a thing. Most git hosts provide their services for free for open-source companies. If you have too much money, you can pay GitHub for a plan to make your data closed.
|
||||
|
||||
If you require more subdivision, Organisations are divided into Teams.
|
||||
|
||||
---
|
||||
|
||||
!\[\[teams.png\]\]
|
||||
|
||||
## [Teams](#teams)
|
||||
|
||||
notes:
|
||||
|
||||
Teams on GitHub allow you to granularly scope repo, project, wiki, and other permissions to the different teams in your organisation.
|
||||
|
||||
I recommend allowing everyone to write and contribute to all projects, you want the network effect and low admin overhead. This pattern is called "internal open source".
|
||||
|
||||
But if you wish, perhaps for regulatory reasons, read and write access to repos can be restricted by team.
|
||||
|
||||
---
|
||||
|
||||
!\[\[PR.png\]\]
|
||||
|
||||
## [Pull Requests](#pull-requests)
|
||||
|
||||
notes:
|
||||
|
||||
Now we're getting into the detail of GitHub. I adore pull requests, sometimes called merge requests in other systems. PRs represent a change to the files in a repo, with an explanation of what you did, some links, and a discussion.
|
||||
|
||||
---
|
||||
|
||||
!\[\[PR diff.png\]\]
|
||||
|
||||
## [Pull Requests (diffs)](#pull-requests-diffs)
|
||||
|
||||
notes:
|
||||
|
||||
After the discussion is satisfied, perhaps as simply as a colleague saying "LGTM" or as heavy weight as a full change review with an audit trail that would satisfy a bank, the changes are merged into the repo.
|
||||
|
||||
PRs can have powerful automation, called Actions
|
||||
|
||||
---
|
||||
|
||||
!\[\[action.png\]\]
|
||||
|
||||
## [Github Actions](#github-actions)
|
||||
|
||||
notes:
|
||||
|
||||
PRs and actions can run your company for you if you let them. Though Actions were built for running tests on source code, with a little imagination, they can be used for anything:
|
||||
|
||||
* If you're uploading vector images, an action can build all the rasterised resolutions the client wants.
|
||||
* If you're uploading video or audio clips, an action can run them through plugins to remove noise, add a music track, and upload the draft to YouTube.
|
||||
* If you're checking in company documents, an action can simply spellcheck it.
|
||||
|
||||
Actions can run hundreds of times an hour, always adhere to best practice, and never make mistakes.
|
||||
|
||||
Automating your company gives you an enormous competitive speed and quality advantage.
|
||||
|
||||
---
|
||||
|
||||
!\[\[language-tool-on-premise.png\]\]
|
||||
|
||||
notes: You could also, for example, set up style guide enforcement, blocking the PR if the phrase "on premise" has been found.
|
||||
|
||||
---
|
||||
|
||||
!\[\[nvme.png\]\] notes:
|
||||
|
||||
## [Offline Work](#offline-work)
|
||||
|
||||
When your company's code, visual assets, and administration, are all in git repositories, you gain another huge superpower.
|
||||
|
||||
All of this becomes accessible offline. Every file, every photo, every design, and document can be on your computer. The magic of offline isn't necessarily that you don't need the internet (though that is a handy feature on a plane) But that it's FAST, the data is RIGHT HERE on your computer, and you can do ANYTHING with it. If you need to change the company's name across 10,000 files, it's trivial. It's find and replace.
|
||||
|
||||
If you, instead, had 5-15 different web services that you scattered all your team's data across, you'd have to log in to each one, and hope they had the feature to find and replace within their own walled garden.
|
||||
|
||||
Most, somehow, don't have this basic feature.
|
||||
|
||||
---
|
||||
|
||||
## [Who is flying this thing?](#who-is-flying-this-thing)
|
||||
|
||||
notes:
|
||||
|
||||
GOOGLE DOCS doesn't have this basic feature: you can't find and replace across a drive of files!?
|
||||
|
||||
And the reason for this, I suspect, is that would be TERRIFYING, wouldn't it? What if a new hire accidentally did that, you'd have to roll back all those files manually, that could take days!
|
||||
|
||||
But with git, it would be a PR, clearly showing what was happening, and mistakes are trivial to fix.
|
||||
|
||||
Plain-text files, with just enough Markdown syntax to convey meaning, allow you and your team to work with this data in the way that they want, not the way that google or Atlassian or WHOEVER thinks is best.
|
||||
|
||||
Doesn't this take up a lot of space on your disk? Not plain text. But even if you're storing large files, storage is cheap if you're smart. A topic for another video, perhaps.
|
||||
|
||||
---
|
||||
|
||||
## [Future-Proofing](#future-proofing)
|
||||
|
||||
notes: The benefits of git, especially for teams already using it for code and text collaboration, are that
|
||||
|
||||
1. you're already paying for it, and
|
||||
2. It's never going away.
|
||||
|
||||
It is impossible to imagine a management reshuffle that might decide on another tool just because it is the flavour of the month. Git and GitHub dominate the coding world, and I recommend GitHub not only because it is the biggest but also the most featureful.
|
||||
|
||||
---
|
||||
|
||||
!\[\[killed-by-google-10-23.png\]\]
|
||||
|
||||
[https://killedbygoogle.com](https://killedbygoogle.com/)
|
||||
|
||||
notes:
|
||||
|
||||
Even if you don't think git and plain text are the best option, I still suggest you use them because stability is far, far better than a constantly churning tool choice, as staff come, and go and fashions change, and Google decommission ANOTHER product.
|
||||
|
||||
RIP Jamboard :-(
|
||||
|
||||
---
|
||||
|
||||
## [Conclusion](#conclusion)
|
||||
|
||||
Click around my demo organisation for yourself:<https://github.com/noboilerplate>
|
||||
|
||||
notes:
|
||||
|
||||
You can't do all these utopian things in most companies, I'm painfully aware.
|
||||
|
||||
But you CAN do SOME of these things, even just in your immediate team, or only for yourself.
|
||||
|
||||
I'd be interested to know what other ways good teams buck the hype cycle in favour of sane, evidence-based improvements.
|
||||
|
||||
Thank you.
|
||||
|
||||
---
|
||||
|
||||
!\[\[tri-hex-moon-white-transparent.png|300\]\]
|
||||
|
||||
## [Thank You](#thank-you)
|
||||
|
||||
## [](#patreoncomnoboilerplate)[Patreon.com/NoBoilerplate](http://www.patreon.com/noboilerplate)
|
||||
|
||||
notes:
|
||||
|
||||
## [OUTRO](#outro)
|
||||
|
||||
If you would like to support my channel, get early ad-free and tracking-free videos, vip discord access or 1:1 mentoring, head to patreon.com/noboilerplate.
|
||||
|
||||
If you're interested in transhumanism and hopepunk stories, please check out my weekly sci-fi podcast, Lost Terminal.
|
||||
|
||||
Or if urban fantasy is more your bag, do listen to a strange and beautiful podcast I produce every full moon called Modem Prometheus.
|
||||
|
||||
Transcripts and compile-checked markdown source code are available on GitHub, links in the description, and corrections are in the pinned ERRATA comment.
|
||||
|
||||
Thank you so much for watching, talk to you on Discord.
|
||||
|
||||
%% NOW READ THE INTRO AGAIN %%
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
---
|
||||
id: f07b145f-4fc5-4acf-99a4-4e3201c009b9
|
||||
title: |
|
||||
How Game Reviews Actually Affect You
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- Youtube
|
||||
date_added: 2023-10-21 16:01:08
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/how-game-reviews-actually-affect-you-18b539cd3a3
|
||||
url_original: |
|
||||
https://youtu.be/8LbLvi9llCI?si=7MMwTZTpCb-mHDH5
|
||||
---
|
||||
|
||||
# How Game Reviews Actually Affect You
|
||||
|
||||
## Notes
|
||||
|
||||
Según estudios, los jugadores se ven afectados por reviews que leen/ven, ya sean por críticos o por otros jugadores. Destacar que en ambos casos, pero principalmente en otros jugadores hay opiniones que pueden decir lo mismo pero con una altas carga emocional, lo que amplifica su impacto.
|
||||
|
||||
Estas críticas tienen un impacto inconciente en el jugador en forma de _"self fulfilling prophecy"_ ó _"probar lo contrario"_.
|
||||
|
||||
Esto nos afecta queramos o no, por lo que es mejor evitar opiniones lo más posible y solo disfrutar el juego por lo que es, podemos validar nuestras opiniones luego de terminar el juego.
|
||||
## Original
|
||||
|
||||
[How Game Reviews Actually Affect You](https://youtu.be/8LbLvi9llCI?si=7MMwTZTpCb-mHDH5)
|
||||
|
||||
By [Daryl Talks Games](https://www.youtube.com/@DarylTalksGames)
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
---
|
||||
id: bcb6f4ba-cb8e-4e8d-847f-911cda184b83
|
||||
title: |
|
||||
Study shows stronger brain activity after writing on paper than on tablet or smartphone | ScienceDaily
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
date_added: 2023-10-23 10:56:32
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/study-shows-stronger-brain-activity-after-writing-on-paper-than--18b5cd2abed
|
||||
url_original: |
|
||||
https://www.sciencedaily.com/releases/2021/03/210319080820.htm
|
||||
---
|
||||
|
||||
# Study shows stronger brain activity after writing on paper than on tablet or smartphone | ScienceDaily
|
||||
|
||||
## Highlights
|
||||
|
||||
"Our take-home message is to use paper notebooks for information we need to learn or memorize," said Sakai.
|
||||
|
||||
[source](https://omnivore.app/me/study-shows-stronger-brain-activity-after-writing-on-paper-than--18b5cd2abed#1c9a0a5a-c3a9-40d8-a6de-9e986dd27aec)
|
||||
|
||||
---
|
||||
|
||||
Researchers say that personalizing digital documents by highlighting, underlining, circling, drawing arrows, handwriting color-coded notes in the margins, adding virtual sticky notes, or other types of unique mark-ups can mimic analog-style spatial enrichment that may enhance memory.
|
||||
|
||||
[source](https://omnivore.app/me/study-shows-stronger-brain-activity-after-writing-on-paper-than--18b5cd2abed#85a6ad74-1b87-4f32-95b3-f0a549d32089)
|
||||
|
||||
---
|
||||
|
||||
Although the current research focused on learning and memorization, the researchers encourage using paper for creative pursuits as well.
|
||||
|
||||
"It is reasonable that one's creativity will likely become more fruitful if prior knowledge is stored with stronger learning and more precisely retrieved from memory. For art, composing music, or other creative works, I would emphasize the use of paper instead of digital methods," said Sakai.
|
||||
|
||||
[source](https://omnivore.app/me/study-shows-stronger-brain-activity-after-writing-on-paper-than--18b5cd2abed#aeb79efa-7582-4493-94e1-6a7004b5ed80)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||
FULL STORY
|
||||
|
||||
---
|
||||
|
||||
A study of Japanese university students and recent graduates has revealed that writing on physical paper can lead to more brain activity when remembering the information an hour later. Researchers say that the unique, complex, spatial and tactile information associated with writing by hand on physical paper is likely what leads to improved memory.
|
||||
|
||||
"Actually, paper is more advanced and useful compared to electronic documents because paper contains more one-of-a-kind information for stronger memory recall," said Professor Kuniyoshi L. Sakai, a neuroscientist at the University of Tokyo and corresponding author of the research recently published in _Frontiers in Behavioral Neuroscience_. The research was completed with collaborators from the NTT Data Institute of Management Consulting.
|
||||
|
||||
Contrary to the popular belief that digital tools increase efficiency, volunteers who used paper completed the note-taking task about 25% faster than those who used digital tablets or smartphones.
|
||||
|
||||
Although volunteers wrote by hand both with pen and paper or stylus and digital tablet, researchers say paper notebooks contain more complex spatial information than digital paper. Physical paper allows for tangible permanence, irregular strokes, and uneven shape, like folded corners. In contrast, digital paper is uniform, has no fixed position when scrolling, and disappears when you close the app.
|
||||
|
||||
=="Our take-home message is to use paper notebooks for information we need to learn or memorize," said Sakai.==
|
||||
|
||||
In the study, a total of 48 volunteers read a fictional conversation between characters discussing their plans for two months in the near future, including 14 different class times, assignment due dates and personal appointments. Researchers performed pre-test analyses to ensure that the volunteers, all 18-29 years old and recruited from university campuses or NTT offices, were equally sorted into three groups based on memory skills, personal preference for digital or analog methods, gender, age and other aspects.
|
||||
|
||||
Volunteers then recorded the fictional schedule using a paper datebook and pen, a calendar app on a digital tablet and a stylus, or a calendar app on a large smartphone and a touch-screen keyboard. There was no time limit and volunteers were asked to record the fictional events in the same way as they would for their real-life schedules, without spending extra time to memorize the schedule.
|
||||
|
||||
After one hour, including a break and an interference task to distract them from thinking about the calendar, volunteers answered a range of simple (When is the assignment due?) and complex (Which is the earlier due date for the assignments?) multiple choice questions to test their memory of the schedule. While they completed the test, volunteers were inside a magnetic resonance imaging (MRI) scanner, which measures blood flow around the brain. This is a technique called functional MRI (fMRI), and increased blood flow observed in a specific region of the brain is a sign of increased neuronal activity in that area.
|
||||
|
||||
Participants who used a paper datebook filled in the calendar within about 11 minutes. Tablet users took 14 minutes and smartphone users took about 16 minutes. Volunteers who used analog methods in their personal life were just as slow at using the devices as volunteers who regularly use digital tools, so researchers are confident that the difference in speed was related to memorization or associated encoding in the brain, not just differences in the habitual use of the tools.
|
||||
|
||||
Volunteers who used analog methods scored better than other volunteers only on simple test questions. However, researchers say that the brain activation data revealed significant differences.
|
||||
|
||||
Volunteers who used paper had more brain activity in areas associated with language, imaginary visualization, and in the hippocampus -- an area known to be important for memory and navigation. Researchers say that the activation of the hippocampus indicates that analog methods contain richer spatial details that can be recalled and navigated in the mind's eye.
|
||||
|
||||
"Digital tools have uniform scrolling up and down and standardized arrangement of text and picture size, like on a webpage. But if you remember a physical textbook printed on paper, you can close your eyes and visualize the photo one-third of the way down on the left-side page, as well as the notes you added in the bottom margin," Sakai explained.
|
||||
|
||||
Researchers say that personalizing digital documents by highlighting, underlining, circling, drawing arrows, handwriting color-coded notes in the margins, adding virtual sticky notes, or other types of unique mark-ups can mimic analog-style spatial enrichment that may enhance memory.
|
||||
|
||||
Although they have no data from younger volunteers, researchers suspect that the difference in brain activation between analog and digital methods is likely to be stronger in younger people.
|
||||
|
||||
"High school students' brains are still developing and are so much more sensitive than adult brains," said Sakai.
|
||||
|
||||
Although the current research focused on learning and memorization, the researchers encourage using paper for creative pursuits as well.
|
||||
|
||||
"It is reasonable that one's creativity will likely become more fruitful if prior knowledge is stored with stronger learning and more precisely retrieved from memory. For art, composing music, or other creative works, I would emphasize the use of paper instead of digital methods," said Sakai.
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
---
|
||||
id: 6f1925bb-b86c-40d2-9363-6784aa2d402f
|
||||
title: |
|
||||
Train Your Brain to Be More Creative
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
date_added: 2023-10-23 10:56:30
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/train-your-brain-to-be-more-creative-18b5cd2a390
|
||||
url_original: |
|
||||
https://hbr.org/2021/06/train-your-brain-to-be-more-creative
|
||||
---
|
||||
|
||||
# Train Your Brain to Be More Creative
|
||||
|
||||
## Highlights
|
||||
|
||||
## **Engage with nature**
|
||||
|
||||
It’s been proven that [spending time in nature](https://greatergood.berkeley.edu/article/item/how%5Fnature%5Fmakes%5Fyou%5Fkinder%5Fhappier%5Fmore%5Fcreative) makes us more creative. Looking at trees and leaves — instead of our electronic devices — reduces our anxiety, lowers our heart rates, soothes us, and allows our brains to make [connections more easily](https://bjsm.bmj.com/content/49/4/272.abstract?sid=56b97a4c-0e75-46d0-a6ba-41c7f41a089c).
|
||||
|
||||
By spending time in nature, I’m not referring to a trek in the wilderness either. Walking in an urban green space for just 25 minutes can quiet our brains and help us switch into autopilot node. According to the [_British Journal of Sports Medicine_](https://bjsm.bmj.com/content/49/4/272?sid=56b97a4c-0e75-46d0-a6ba-41c7f41a089c), this state sparks our present awareness and fuels imagination. We are more easily able to connect existing notions, thoughts, and images to form a new, relevant, and useable concept.
|
||||
|
||||
[source](https://omnivore.app/me/train-your-brain-to-be-more-creative-18b5cd2a390#9190b653-c9fe-4438-b02d-10ac2095ecd1)
|
||||
|
||||
---
|
||||
|
||||
You may have heard that creativity uses your right brain while your left brain is triggered during more analytical tasks. Well, [neuroscientists have found](https://www.livescience.com/39671-roots-of-creativity-found-in-brain.html) that creativity actually draws on your _entire_ brain — and meditation can you give you access to it.
|
||||
|
||||
[source](https://omnivore.app/me/train-your-brain-to-be-more-creative-18b5cd2a390#6b9b547e-2d87-4b4e-8fb5-76c0fe82be37)
|
||||
|
||||
---
|
||||
|
||||
Try to add workout time on your calendar and make sure not to skip it. If you feel you don’t have time for a dedicated workout, block 20 minutes on your calendar and spend that time doing stretches at your desk.
|
||||
|
||||
[source](https://omnivore.app/me/train-your-brain-to-be-more-creative-18b5cd2a390#339a25cd-d9b8-4c5c-90bb-34f31965dea8)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||
[  ](https://hbr.org/ascend)
|
||||
|
||||
Where your work meets your life.
|
||||
|
||||

|
||||
|
||||
Anastasia Usenko/Getty Images
|
||||
|
||||
Creativity isn’t inherent. You have to hone it. Here are a few ways to do that, based on neuroscience. Engage with nature: Looking at trees and leaves, instead of our electronic devices, reduces our anxiety, lowers our heart rates, soothes us, and allows our brains to...
|
||||
|
||||
[](https://hbr.org/insight-center/ascend)
|
||||
|
||||
Where your work meets your life. See more from Ascend [here](https://hbr.org/insight-center/ascend).
|
||||
|
||||
I don’t do ruts.
|
||||
|
||||
Not because I’m some brilliant creative, but because I’ve learned how my brain works. Your brain needs fuel, and it needs to be stretched to create those “OMG!” moments on demand.
|
||||
|
||||
Think about it. Great athletes train their bodies for days, weeks, and years to whip them into peak performance. Why, then, wouldn’t a creator do the same with their brain?
|
||||
|
||||
I’ve spent more than two decades (and counting) in the advertising industry, and contrary to popular belief, creativity isn’t inherent. You have to hone it. Over time, I’ve figured out what I need to do to get ideas flowing freely, and a lot of that insight comes from my interest in neuroscience. The more we learn about the workings of our gray matter, the better we can train it, control it, and make it do what we want.
|
||||
|
||||
Here a few things that have worked for me over the years.
|
||||
|
||||
## **==Engage with nature==**
|
||||
|
||||
==It’s been proven that== ==[spending time in nature](https://greatergood.berkeley.edu/article/item/how%5Fnature%5Fmakes%5Fyou%5Fkinder%5Fhappier%5Fmore%5Fcreative)== ==makes us more creative. Looking at trees and leaves — instead of our electronic devices — reduces our anxiety, lowers our heart rates, soothes us, and allows our brains to make== ==[connections more easily](https://bjsm.bmj.com/content/49/4/272.abstract?sid=56b97a4c-0e75-46d0-a6ba-41c7f41a089c)====.==
|
||||
|
||||
==By spending time in nature, I’m not referring to a trek in the wilderness either. Walking in an urban green space for just 25 minutes can quiet our brains and help us switch into autopilot node. According to the== [_British Journal of Sports Medicine_](https://bjsm.bmj.com/content/49/4/272?sid=56b97a4c-0e75-46d0-a6ba-41c7f41a089c)==, this state sparks our present awareness and fuels imagination. We are more easily able to connect existing notions, thoughts, and images to form a new, relevant, and useable concept.==
|
||||
|
||||
So make disconnecting a priority. Take a walk in your neighborhood park, stroll along the beach, or just add plants to your balcony and spend some time out there. For me, walking my dog — even when my name is not on the family schedule — works. You’ll feel the benefits of moving away from screens almost immediately.
|
||||
|
||||
## **Meditate**
|
||||
|
||||
I know, I know, you’ve heard this a million times: [Meditation](https://www.frontiersin.org/articles/10.3389/fpsyg.2013.01020/full) clears our minds of jumbled thoughts, and gives our brains the space to observe and reflect, improving task concentration and enhancing our ability to make smart decisions.
|
||||
|
||||
But did you know that meditation also puts the entire brain to work?
|
||||
|
||||
==You may have heard that creativity uses your right brain while your left brain is triggered during more analytical tasks. Well,== ==[neuroscientists have found](https://www.livescience.com/39671-roots-of-creativity-found-in-brain.html)== ==that creativity actually draws on your== _==entire==_ ==brain — and meditation can you give you access to it.==
|
||||
|
||||
This intentional practice can be as simple as closing your eyes and focusing on your breath. Headspace, the popular meditation app, even has guided meditations for inspiring creativity. The idea is that when we intentionally pause in awareness, [we allow our minds the freedom and space to be still and creative](https://www.headspace.com/meditation/creativity). I practice this between meetings. I find a quiet space, focus on my breathing, and get my brain into an alpha state, or a wakeful state of relaxation. This allows me to disconnect from my initial ideas (after all, the human brain is hardwired to take the path of least resistance) and create new pathways in my mind.
|
||||
|
||||
## **Get moving**
|
||||
|
||||
[Steve Jobs](https://financialpost.com/executive/c-suite/steve-jobs-was-right-about-walking) was a big advocate for walking meetings for a reason. Moving around [has been linked to increased performance](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC1332529/pdf/brjsmed00003-0076.pdf) on creative tests. Exercising releases endorphins — chemicals our bodies produce to relieve stress and pain. When we are less stressed, our brains venture into more fruitful territory.
|
||||
|
||||
In fact, [a recent article](https://www.irishexaminer.com/lifestyle/healthandwellbeing/arid-40251431.html) compared the chemical that our brain releases during physical activity to Miracle-Gro, the water-soluble plant food that helps grow bigger, healthier plants. The good part is moving around is super simple to do, especially when you’re working at home. I often attend meetings while cycling on a stationary bike or plan short walks in between (and this can be done in an office too).
|
||||
|
||||
==Try to add workout time on your calendar and make sure not to skip it. If you feel you don’t have time for a dedicated workout, block 20 minutes on your calendar and spend that time doing stretches at your desk.==
|
||||
|
||||
Find a routine that works for you.
|
||||
|
||||
Ascend
|
||||
|
||||
Career and life advice for young professionals.
|
||||
|
||||
## **Connect with different kinds of people**
|
||||
|
||||
When consciously seeking inspiration, not enough can be said about diversity. Remember the brain and its predisposition to take the lazy way out? Diversity makes the brain work harder [by challenging stereotypes.](https://www.theguardian.com/lifeandstyle/2015/nov/01/diversity-good-for-your-brain-mind-multicultural) In addition, researchers at Johns Hopkins University [found](https://muse.jhu.edu/article/536530/summary) that “exposure to diversity experiences might foster the development of more complex forms of thought, including the ability to think critically.”
|
||||
|
||||
I make it a point to surround myself with people who come from different backgrounds than I do because their perspectives are a catalyst for creative thinking. Contrasting opinions sparks new possibilities, and allow us to make connections we hadn’t seen before, leading to better decisions. There was something to be said about Abraham Lincoln filling his cabinet with [a “team of rivals.”](https://bigthink.com/in-their-own-words/you-can-be-your-own-team-of-rivals) Productive discussions, brainstorms, and debates often result in wiser outcomes. At my agency, we’ve set up an “inspiration council,” which brings together our people from various regions, cultures, genders, and more, to initiate these kind of discussions.
|
||||
|
||||
Today, the distributed working model born out of the pandemic has made it even easier to bring people together. I recommend using social media channels like LinkedIn and Instagram to follow and connect with people who have backgrounds and experiences that diverge from your own. Don’t limit yourself by geography when you’re reaching out to someone or expanding your network. We are much better at creative problem-solving when we don’t have the comfort of knowing what to expect, which can happen if we only surround ourselves with people just like us.
|
||||
|
||||
Use these principles of neuroscience to give your brain the exercise that it needs. It will get you out of any rut. Or prevent you from getting into one in the first place.
|
||||
|
||||
#### Readers Also Viewed These Items
|
||||
|
||||
* [Bas Korsten](https://hbr.org/search?term=bas%20korsten&search%5Ftype=search-all) is the Global Chief Creative Officer at Wunderman Thompson.
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
---
|
||||
id: 46eadaec-733a-11ee-aae2-4b1c5b8d8405
|
||||
title: |
|
||||
Let's Get Webby! 🦀 🕸️
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- Newsletter
|
||||
date_added: 2023-10-25 10:27:43
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/let-s-get-webby-18b6705008a
|
||||
url_original: |
|
||||
https://omnivore.app/no_url?q=bec70357-3199-44e0-9c84-40dd5a7bf774
|
||||
---
|
||||
|
||||
# Let's Get Webby! 🦀 🕸️
|
||||
|
||||
## Highlights
|
||||
|
||||
...and front-end frameworks like [Yew](https://letsgetrusty.krtra.com/c/y9r3LFJzeRCp/OQKy) and [Seed](https://letsgetrusty.krtra.com/c/mN30voJhWLXc/OQKy) letting you write web apps in Rust!
|
||||
|
||||
> [!note]
|
||||
> I can create front end web apps with this libraries
|
||||
|
||||
[source](https://omnivore.app/me/let-s-get-webby-18b6705008a#7065ade5-765c-4d60-bd89-1ecb0d919389)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||

|
||||
|
||||
Hey Alexander,
|
||||
|
||||
JavaScript isn't the fastest language out there.
|
||||
|
||||
In fact, it's **pretty dang slow** compared to C/C++!
|
||||
|
||||
Unfortunately, this limits the type of web apps we could build.
|
||||
|
||||
How great would it be if we could write code that runs **at native speeds** in the browser?
|
||||
|
||||
This would allow computationally intensive apps like video editors, AAA games, and IDEs to be run in the browser!
|
||||
|
||||
Great news... **this is possible today** with the help of WebAssembly.
|
||||
|
||||
WebAssembly or WASM for short, is a technology that allows code written in languages such as C/C++, Java, Swift, and Rust to run in the browser at native speeds!
|
||||
|
||||
**And Rust has first-class support for WASM!**
|
||||
|
||||
With crates such as [wasm-bindgen ](https://letsgetrusty.krtra.com/c/Fv1n9JiwhxdT/OQKy)facilitating high-level interactions between Rust and JavaScript...
|
||||
|
||||
==...and front-end frameworks like== ==[Yew](https://letsgetrusty.krtra.com/c/y9r3LFJzeRCp/OQKy)== ==and== ==[Seed](https://letsgetrusty.krtra.com/c/mN30voJhWLXc/OQKy)== ==letting you write web apps in Rust!==
|
||||
|
||||
Are you ready to give Rust + WASM a try?
|
||||
|
||||
Check out this video I made: **[\>> Building a Rust App with Yew! <<](https://letsgetrusty.krtra.com/c/6AUVThScIsa4/OQKy)**
|
||||
|
||||
Have you built any WASM projects in Rust? Let me know!
|
||||
|
||||
Stay Rusty my friend!
|
||||
|
||||
Bogdan, Let's Get Rusty
|
||||
|
||||
**[Website](https://letsgetrusty.krtra.com/c/FBKvcPOtTzlF/OQKy)** | **[YouTube](https://letsgetrusty.krtra.com/c/4KIGD3ocszdT/OQKy)**
|
||||
|
||||
© Copyrights by Let's Get Rusty. All Rights Reserved.
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
---
|
||||
id: ad8a0732-733a-11ee-b2ab-13f1d6012322
|
||||
title: |
|
||||
What the Rust Book didn't tell you about testing...
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- Newsletter
|
||||
date_added: 2023-10-25 10:30:35
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/what-the-rust-book-didn-t-tell-you-about-testing-18b6707a120
|
||||
url_original: |
|
||||
https://omnivore.app/no_url?q=1fed5fd7-7706-46cf-9947-927b26a77112
|
||||
---
|
||||
|
||||
# What the Rust Book didn't tell you about testing...
|
||||
|
||||
## Highlights
|
||||
|
||||
We want to test _get\_user_ without making real database queries.
|
||||
|
||||
The solution is to mock the _Database_ trait and assert _execute\_query_ is called with the correct query. But how?
|
||||
|
||||
We can use the [mockall crate](https://letsgetrusty.us6.list-manage.com/track/click?u=9f28b35c1658c447f3b962a54&id=00a07042b3&e=d0eb971086)!
|
||||
|
||||
[source](https://omnivore.app/me/what-the-rust-book-didn-t-tell-you-about-testing-18b6707a120#f9650419-c778-4974-9da2-aabce209609f)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||
|
||||
The Rust Book has an [entire chapter dedicated to testing](https://letsgetrusty.us6.list-manage.com/track/click?u=9f28b35c1658c447f3b962a54&id=a95a715235&e=d0eb971086), but it's missing a critical piece…
|
||||
|
||||
What happens when your code needs to make API calls or database queries?
|
||||
|
||||
Unit tests should be be fast, reliable, and deterministic.
|
||||
|
||||
We don't want to make expensive calls that might fail for various reasons.
|
||||
|
||||
|
||||
Well here is some good news… we don't have to!
|
||||
|
||||
We can use mocking to substitute real objects for mock objects and assert certain expectations…
|
||||
|
||||
What's that? You want an example? Consider the following code…
|
||||
|
||||
trait Database {
|
||||
fn execute_query(&self, query: String);
|
||||
}
|
||||
|
||||
fn get_user(db: impl Database, id: i32) {
|
||||
let query = format!("SELECT * from Users where id={}", id);
|
||||
db.execute_query(query);
|
||||
}
|
||||
We want to test _get\_user_ without making real database queries.
|
||||
|
||||
The solution is to mock the _Database_ trait and assert _execute\_query_ is called with the correct query. But how?
|
||||
|
||||
We can use the [mockall crate](https://letsgetrusty.us6.list-manage.com/track/click?u=9f28b35c1658c447f3b962a54&id=00a07042b3&e=d0eb971086)!
|
||||
|
||||
Here is how we would test _get\_user_…
|
||||
|
||||
#[cfg(test)]
|
||||
use mockall::{automock, predicate::*};
|
||||
|
||||
#[cfg_attr(test, automock)]
|
||||
trait Database {
|
||||
fn execute_query(&self, query: String);
|
||||
}
|
||||
|
||||
fn get_user(db: impl Database, id: i32) {
|
||||
let query = format!("SELECT * from Users where id={}", id);
|
||||
db.execute_query(query);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn get_user_executes_correct_query() {
|
||||
let mut mock_database = MockDatabase::new();
|
||||
mock_database.expect_execute_query()
|
||||
.with(eq("SELECT * from Users where id=22".to_owned()))
|
||||
.once()
|
||||
.returning(|_x| ());
|
||||
|
||||
get_user(mock_database, 22);
|
||||
}
|
||||
}
|
||||
Boom! Now we have a unit test that's fast, reliable, and deterministic!
|
||||
|
||||
If you haven't seen my [intro to testing in Rust video](https://letsgetrusty.us6.list-manage.com/track/click?u=9f28b35c1658c447f3b962a54&id=90d4167901&e=d0eb971086) make sure to check it out!
|
||||
|
||||
|
||||
Happy testing, and stay Rusty!
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
---
|
||||
id: 7b7ae540-77ef-11ee-9aed-e318464fef5a
|
||||
title: |
|
||||
Use cases for Rust
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- Newsletter
|
||||
date_added: 2023-10-31 10:14:54
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/use-cases-for-rust-18b85df6f3a
|
||||
url_original: |
|
||||
https://omnivore.app/no_url?q=9e2f3a10-e4fd-4c33-85a3-ff3609f3c4d6
|
||||
---
|
||||
|
||||
# Use cases for Rust
|
||||
|
||||
## Highlights
|
||||
|
||||
Some popular server-side web frameworks written in Rust include Actix Web, Warp, and Axum.
|
||||
|
||||
[source](https://omnivore.app/me/use-cases-for-rust-18b85df6f3a#64793bd7-d3bd-4597-9f2c-9b4697217661)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||

|
||||
|
||||
Hi Rustaceans,
|
||||
|
||||
Rust is fast, safe and hip.
|
||||
|
||||
But, what can you actually build with Rust?
|
||||
|
||||
…whether you want to use Rust professionally or as a hobbyist.
|
||||
|
||||
Here are a few common types of applications built using Rust:
|
||||
|
||||
**Blockchain**
|
||||
|
||||
* Rust is a great choice for blockchain applications because it is fast and secure.
|
||||
* You can write both smart contracts and entire blockchains using Rust.
|
||||
* Some popular blockchain projects written in Rust include Solana, Polkadot, and Near.
|
||||
|
||||
**Embedded programs**
|
||||
|
||||
* Rust is also well-suited for embedded programs, such as those used in cars, airplanes, and other devices.
|
||||
* This is because Rust is memory-safe, memory-efficient and can be compiled to run on a variety of platforms.
|
||||
|
||||
**Server-side applications / Microservices**
|
||||
|
||||
* Rust is a great choice for server-side applications and microservices because it is fast and efficient.
|
||||
* ==Some popular server-side web frameworks written in Rust include Actix Web, Warp, and Axum.==
|
||||
* Many companies are migrating their critical microservices to Rust because of its safety and performance guarantees.
|
||||
|
||||
**WebAssembly**
|
||||
|
||||
* Rust can be compiled to WebAssembly, which means that you can use Rust to build web applications.
|
||||
* Rust’s small runtime and first-class support for WebAssembly often make it the first contender for any WebAssembly projects.
|
||||
|
||||
This is only a small sample of what you can build in Rust.
|
||||
|
||||
In general, Rust is a great choice if you are looking for speed, safety and versatility.
|
||||
|
||||
If you want more details, here’s a YouTube video I made on the same topic.
|
||||
|
||||
**[\>>> What can you build in Rust?!](https://letsgetrusty.krtra.com/c/BgXaOx7YGua4/OQKy)**
|
||||
|
||||
Have fun building!
|
||||
|
||||
Bogdan
|
||||
|
||||
\---
|
||||
|
||||
PS - Looking for a Rust job? Apply here - [https://letsgetrusty.com/jobs](https://letsgetrusty.krtra.com/c/ysWbInNFr59c/OQKy)
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
---
|
||||
id: e41b4086-963e-45e7-9ef7-2cfee7061047
|
||||
title: |
|
||||
Why Signals Are Better Than React Hooks
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
date_added: 2023-11-01 14:16:42
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/https-youtu-be-so-8-l-bvwf-2-y-8-si-zy-gl-ie-hl-ai-pg-w-5-xo-18b8be328e5
|
||||
url_original: |
|
||||
https://youtu.be/SO8lBVWF2Y8?si=zyGlIeHlAiPgW5Xo
|
||||
---
|
||||
|
||||
# Why Signals Are Better Than React Hooks
|
||||
|
||||
## Notes
|
||||
|
||||
Signals ayuda a la performance y legibilidad de una aplicación haciendo que la funcionalidades que normalmente se realizarían con los hooks `useState` y `useEffect` se realizen dentro de `signals`.
|
||||
|
||||
Esto permite compartir este _"estado"_ entre componentes pero solo actualizar los involucrados y no todos los desendientes del componente mayor.
|
||||
|
||||
Además, podemos extraer toda la lógica del estado a un archivo aparte que solo tenga código relevante, y en los componentes se mantiene solo la implementación.
|
||||
|
||||
Es obviamente más rápido de implementar y más limpio que hacer custom hooks, pero es añadir otra dependencia, habrá otras ventajas y desventajas??
|
||||
## Original
|
||||
|
||||
[Why Signals Are Better Than React Hooks](https://youtu.be/SO8lBVWF2Y8?si=zyGlIeHlAiPgW5Xo)
|
||||
|
||||
By [Web Dev Simplified](https://www.youtube.com/@WebDevSimplified)
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
---
|
||||
id: 24bd8d1e-b118-4930-a86d-3929f2dad34c
|
||||
title: |
|
||||
The First Rule of Comments in Code
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
date_added: 2023-11-02 23:25:19
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/https-youtu-be-hxsx-3-vbf-qq-si-c-5-qy-m-mg-8-j-yhc-bbq-18b92ffccf6
|
||||
url_original: |
|
||||
https://youtu.be/hxsx3vbf-QQ?si=-C5QyMMg8JYhcBBQ
|
||||
---
|
||||
|
||||
# The First Rule of Comments in Code
|
||||
|
||||
## Notes
|
||||
|
||||
Comments are bad by nature:
|
||||
- They get outdated pretty quickly, and you don't know if the comments is updated with the code.
|
||||
- A comments is most probably noise, because it's not gonna provide more information than the code itself.
|
||||
- Commented code is broken code, because it's probably outdated compared to it's context.
|
||||
|
||||
Some rules to evade writing comments:
|
||||
|
||||
**Code that needs a comment, needs to be rewritten**. Always try to put the information in the code. if it needs a comment, it's not good enough.
|
||||
|
||||
**Move information somewhere else**. this is similar to the previous, move to a variable name, or to a documentation file in the worst case.
|
||||
|
||||
**How quickly the information will goes out of date**. It's so simple that a comments goes out of sync with the code, to prevent that transform the comment in code.
|
||||
|
||||
**If a comment gives no more information than the code, delete it**.
|
||||
|
||||
**"I need to explain the complexity"**. No, you need to fix the complexity. If the complexity is so big, put in the documentation instead. A comment cannot fix complexity, and will require hard work to change that code.
|
||||
|
||||
**Don't comment out code, delete it**. Commented code goes quickly out of sync with it's context, is not tested in any way and the effort of updating it is almost the same if not higher that writing it over with better knowledge, so it's better to just delete it. If we need this code back, we can recover it with git.
|
||||
## Original
|
||||
|
||||
[The First Rule of Comments in Code](https://youtu.be/hxsx3vbf-QQ?si=-C5QyMMg8JYhcBBQ)
|
||||
|
||||
By [Bran van der Meer](https://www.youtube.com/@branvandermeer)
|
||||
|
|
@ -1,266 +0,0 @@
|
|||
---
|
||||
id: 88b1e080-79be-11ee-b19c-971f00999697
|
||||
title: |
|
||||
Web Accessibility Tips for Developers – A11y Principles Explained
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- RSS
|
||||
date_added: 2023-11-02 11:17:51
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/web-accessibility-tips-for-developers-a-11-y-principles-explaine-18b91ba16e5
|
||||
url_original: |
|
||||
https://www.freecodecamp.org/news/web-accessibility-for-devs/
|
||||
---
|
||||
|
||||
# Web Accessibility Tips for Developers – A11y Principles Explained
|
||||
|
||||
## Highlights
|
||||
|
||||
you can provide captions for audio and video materials.
|
||||
|
||||
[source](https://omnivore.app/me/web-accessibility-tips-for-developers-a-11-y-principles-explaine-18b91ba16e5#a243f9e5-2cf7-437b-afdb-725d69408fa5)
|
||||
|
||||
---
|
||||
|
||||
color contrast for text and background
|
||||
|
||||
[source](https://omnivore.app/me/web-accessibility-tips-for-developers-a-11-y-principles-explaine-18b91ba16e5#7da331b9-d92c-40b1-b9ff-03cd350b19e0)
|
||||
|
||||
---
|
||||
|
||||
it's a good idea to include descriptive alternative text (alt text) for images, explaining what they depict and their purpose.
|
||||
|
||||
[source](https://omnivore.app/me/web-accessibility-tips-for-developers-a-11-y-principles-explaine-18b91ba16e5#c2a6ebd3-44b3-4bac-b723-be08ec3191d3)
|
||||
|
||||
---
|
||||
|
||||
You should also describe your icon buttons.
|
||||
|
||||
[source](https://omnivore.app/me/web-accessibility-tips-for-developers-a-11-y-principles-explaine-18b91ba16e5#644def06-75fc-41b3-ad64-8b0eb34eb055)
|
||||
|
||||
---
|
||||
|
||||
First, make sure you use clear and consistent headings.
|
||||
|
||||
[source](https://omnivore.app/me/web-accessibility-tips-for-developers-a-11-y-principles-explaine-18b91ba16e5#5d22dea1-4451-4052-a211-ffbc432cb3be)
|
||||
|
||||
---
|
||||
|
||||
And make sure you think about [keyboard accessibility](https://www.freecodecamp.org/news/designing-keyboard-accessibility-for-complex-react-experiences/) so users can navigate and communicate using the keyboard, and not exclusively using a mouse.
|
||||
|
||||
[source](https://omnivore.app/me/web-accessibility-tips-for-developers-a-11-y-principles-explaine-18b91ba16e5#a6f33320-f395-41f2-92e4-7e5c70337377)
|
||||
|
||||
---
|
||||
|
||||
Organize content using headings, subheadings, and bullet points to enhance readability.
|
||||
|
||||
> [!note]
|
||||
> Use semantic HTML
|
||||
|
||||
[source](https://omnivore.app/me/web-accessibility-tips-for-developers-a-11-y-principles-explaine-18b91ba16e5#d6c8b9dc-b9e7-4ab7-8b53-0057246fea9a)
|
||||
|
||||
---
|
||||
|
||||
* Use [HTML5 semantic elements](https://www.freecodecamp.org/news/semantic-html-alternatives-to-using-divs/) like ``, ``, ``, and `` to enhance the document's structure.
|
||||
* Ensure that your [JavaScript code is efficient](https://www.freecodecamp.org/news/javascript-performance-async-defer/) and doesn't block the rendering process.
|
||||
* Utilize [browser developer tools](https://www.freecodecamp.org/news/learn-how-to-use-the-chrome-devtools-to-troubleshoot-websites/) and online testing services to identify and fix compatibility issues.
|
||||
* Conduct [usability testing](https://www.freecodecamp.org/news/10-best-ux-testing-software-tools/) with a diverse group of users, including those who rely on assistive technologies, to gather feedback and make improvements.
|
||||
* Optimize your website for fast loading times and low data usage using techniques like [caching](https://www.freecodecamp.org/news/a-detailed-guide-to-pre-caching/) and [tools like CDNs](https://www.freecodecamp.org/news/cdns-speed-up-performance-by-reducing-latency/) to reduce latency. This benefits both accessibility and user experience.
|
||||
* Document your code and accessibility features for future maintainers.
|
||||
* Test [website compatibility across various browsers](https://www.freecodecamp.org/news/cross-browser-compatibility-testing-best-practices-for-web-developers/). Testing website compatibility involves ensuring that your website functions correctly and looks good on a variety of devices, browsers, and assistive technologies.
|
||||
|
||||
[source](https://omnivore.app/me/web-accessibility-tips-for-developers-a-11-y-principles-explaine-18b91ba16e5#ade773c1-f3e3-499b-8b34-c9d8a2c084e3)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||

|
||||
|
||||
Accessibility isn't just something you check off as done when you're building websites and web apps. It's a basic part of making the online world a better and fairer place for everyone.
|
||||
|
||||
In this article, you'll learn what accessibility means, and why it's important to make accessibility a part of your regular workflow. I'll also give you practical tips with examples to make your websites more accessible.
|
||||
|
||||
Let's explore the key parts of web accessibility together and help you make a website that includes everyone.
|
||||
|
||||
## What is Web Accessibility?
|
||||
|
||||
[Web accessibility](https://www.freecodecamp.org/news/accessibility-best-practices-to-make-web-apps-accessible/) refers to the practice of designing and developing websites, applications, and digital content in a way that ensures people with disabilities can perceive, understand, navigate, and interact with them effectively.
|
||||
|
||||
## Principles of Web Accessibility
|
||||
|
||||
To effectively enhance the accessibility of your websites and apps, you'll want to follow these fundamental principles outlined by the Web Content Accessibility Guidelines ([WCAG](https://www.w3.org/WAI/WCAG21/quickref/?versions=2.0)):
|
||||
|
||||
### Is it Perceivable?
|
||||
|
||||
Content should be displayed in a manner that all users can understand, regardless of their sensory abilities. Here are some ways you can make your content more perceivable:
|
||||
|
||||
First, ==you can provide captions for audio and video materials.== Adding captions to your website or application allows those with hearing disabilities to understand the information being shared, and make the content more accessible to everyone.
|
||||
|
||||
You can see an example of adding captions to a video in the image below:
|
||||
|
||||

|
||||
|
||||
Image of a video illustrating the use of captions.
|
||||
|
||||
Next, make sure you use proper ==color contrast for text and background== elements.
|
||||
|
||||
Colors are an important part of a website, and we can describe them in terms of hue, lightness, and saturation.
|
||||
|
||||
There are several categories of colors which include warm colors, cool colors, and neutral colors
|
||||
|
||||
**Warm Colors:** Warm colors include red, orange, and yellow, and variations of
|
||||
those three colors. These are the colors of fire, fall leaves, sunsets, and sunrises, and are generally energizing, passionate, and positive.
|
||||
|
||||
**Cool Colors:** Cool colors include green, blue, and purple, are often more
|
||||
subdued than warm colors. They are the colors of night, water, of nature, and are usually calming, relaxing, and somewhat reserved.
|
||||
|
||||
**Neutral Colors:** Neutral colors often serve as the backdrop in design. They’re
|
||||
commonly combined with brighter accent colors. But they can also be used on their own in designs and can create very sophisticated layouts. Neutral colors include black, white, gray, cream, and beige.
|
||||
|
||||
Examples of colors that will make good contrast are white and blue, purple and white, yellow and white, light purple and black, green and white, black and white, and so on – basically any colors that are different enough from each other to create that contrast.
|
||||
|
||||
Examples of colors that will make a bad contrast are gray and white, brown and orange, red and purple, and so on.
|
||||
|
||||
Here is an example that shows good color contrast that's easy to read:
|
||||
|
||||

|
||||
|
||||
Image illustrating good contrast using a dark blue background with white text
|
||||
|
||||
And here's an image with poor color contrast that's hard to read:
|
||||
|
||||

|
||||
|
||||
Image Illustrating bad contrast using a white background with light grey text
|
||||
|
||||
Also, ==it's a good idea to include descriptive alternative text (alt text) for images, explaining what they depict and their purpose.==
|
||||
|
||||
So for example, when you want to add an image to your website, you can add alt text to it explaining what it depicts.
|
||||
|
||||
Here is a markup description of how to add alt text to an image:
|
||||
|
||||
```routeros
|
||||
<img src="Dog.png" alt="Image of a dog">
|
||||
|
||||
```
|
||||
|
||||
Here is an example that shows an image of two (2) dogs:
|
||||
|
||||

|
||||
|
||||
Image of two dogs
|
||||
|
||||
And here's an example of an image that illustrates the use of alt text:
|
||||
|
||||

|
||||
|
||||
Image of dog with alt text displayed
|
||||
|
||||
==You should also describe your icon buttons.==
|
||||
|
||||
Icons can be easily understood most of the time. It's widely recognized that an x symbol, like this ❌, typically closes a window, a check mark ✅ signifies completion, a forward arrow ▶ signifies send (or play), and a plus sign ➕ represents addition.
|
||||
|
||||
But this is clear only for individuals with visual capabilities. For people who aren't able to see the buttons, you'll need to provide a description so they know what that button does.
|
||||
|
||||
Let's take a look at this HTML and CSS code that shows how to make buttons access:
|
||||
|
||||
Document
|
||||
|
||||
Here's the result of the code implemented above:
|
||||
|
||||

|
||||
|
||||
### Is it Operable?
|
||||
|
||||
Users should be able to navigate and interact with the interface quickly. Consider the following factors:
|
||||
|
||||
==First, make sure you use clear and consistent headings.==
|
||||
|
||||
This is what clear and consistent headings look like:
|
||||
|
||||
## I am a Title
|
||||
|
||||
## I am a Subtitle
|
||||
|
||||
### This is heading 3
|
||||
|
||||
#### This is Heading 4
|
||||
|
||||
##### This is Heading 5
|
||||
|
||||
###### This is heading 6
|
||||
|
||||
As you can see, these headings go from largest to smallest in order. We have an H1 heading first, followed by H2, H3, and so on.
|
||||
|
||||
Here are some headings that don't follow the proper hierarchy:
|
||||
|
||||
###### This is heading 6
|
||||
|
||||
##### This is Heading 5
|
||||
|
||||
#### This is Heading 4
|
||||
|
||||
### This is heading 3
|
||||
|
||||
## I am a Subtitle
|
||||
|
||||
## I am a Title
|
||||
|
||||
In this example, the headings go in reverse order, starting from H6 and moving up through H5, H4, and so on.
|
||||
|
||||
Just remember to use proper heading hierarchy – don't use an H2 and then jump straight to H4 for a subheading, for example, as this is visually jarring and doesn't convey the proper importance or hierarchy of the text.
|
||||
|
||||
Here's why heading hierarchy is important:
|
||||
|
||||
* A clear heading hierarchy helps readers easily navigate and understand the content of a document.
|
||||
* Heading hierarchy is crucial for accessibility, as it helps screen readers and assistive technologies interpret the structure of the content. This is important for individuals with visual impairments who rely on such tools to access information.
|
||||
* A well-organized heading hierarchy implement a logical flow of information, ensuring that topics are presented in a coherent order.
|
||||
|
||||
Also, refrain from using elements that might trigger physical discomfort, like bright flashing lights.
|
||||
|
||||
==And make sure you think about== ==[keyboard accessibility](https://www.freecodecamp.org/news/designing-keyboard-accessibility-for-complex-react-experiences/)== ==so users can navigate and communicate using the keyboard, and not exclusively using a mouse.==
|
||||
|
||||
### Is it Understandable?
|
||||
|
||||
Content and functionality should be presented clearly and understandably. Consider the following factors:
|
||||
|
||||
* ==Organize content using headings, subheadings, and bullet points to enhance readability.==
|
||||
* Provide instructions and error messages that are easy to understand.
|
||||
* Use simple and concise language, avoid complex terms.
|
||||
|
||||
### Is it Robust?
|
||||
|
||||
Websites should be built using robust and widely supported technologies to enable compatibility across devices and assistive technologies.
|
||||
|
||||
You'll want to maximize compatibility with current and future user agents, including assistive technologies.
|
||||
|
||||
Here are some of the ways you can maximize compatibility with current and future agents, including assistive tools:
|
||||
|
||||
* ==Use== ==[HTML5 semantic elements](https://www.freecodecamp.org/news/semantic-html-alternatives-to-using-divs/)== ==like== `==<====header====>==`==,== `==<====nav====>==`==,== `==<====main====>==`==, and== `==<====footer====>==` ==to enhance the document's structure.==
|
||||
* ==Ensure that your== ==[JavaScript code is efficient](https://www.freecodecamp.org/news/javascript-performance-async-defer/)== ==and doesn't block the rendering process.==
|
||||
* ==Utilize== ==[browser developer tools](https://www.freecodecamp.org/news/learn-how-to-use-the-chrome-devtools-to-troubleshoot-websites/)== ==and online testing services to identify and fix compatibility issues.==
|
||||
* ==Conduct== ==[usability testing](https://www.freecodecamp.org/news/10-best-ux-testing-software-tools/)== ==with a diverse group of users, including those who rely on assistive technologies, to gather feedback and make improvements.==
|
||||
* ==Optimize your website for fast loading times and low data usage using techniques like== ==[caching](https://www.freecodecamp.org/news/a-detailed-guide-to-pre-caching/)== ==and== ==[tools like CDNs](https://www.freecodecamp.org/news/cdns-speed-up-performance-by-reducing-latency/)== ==to reduce latency. This benefits both accessibility and user experience.==
|
||||
* ==Document your code and accessibility features for future maintainers.==
|
||||
* ==Test== ==[website compatibility across various browsers](https://www.freecodecamp.org/news/cross-browser-compatibility-testing-best-practices-for-web-developers/)====. Testing website compatibility involves ensuring that your website functions correctly and looks good on a variety of devices, browsers, and assistive technologies.==
|
||||
|
||||
Here are the steps you can follow to test website compatibility effectively:
|
||||
|
||||
1. **Device Testing**: Test your website on various devices, such as desktop computers, laptops, tablets, and smartphones. This includes both iOS and Android devices.
|
||||
2. **Browser Testing**: Check your website's performance and appearance on multiple browsers, including but not limited to Google Chrome, Mozilla Firefox, Apple Safari, and Microsoft Edge.
|
||||
3. **User Testing**: Conduct usability testing with real users. Ask them to use your website on different devices and browsers and collect feedback on compatibility issues.
|
||||
4. **Performance Testing**: Assess website loading times, and optimize for speed using tools like Google PageSpeed Insights, GTmetrix, or Lighthouse. Check for compatibility with slow internet connections.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Understanding web accessibility can enhance the user experience by creating a smooth and seamless interaction with websites and web applications.
|
||||
|
||||
Implementing these tips can improve the overall user-friendliness and navigability of your app. It'll help create a more enjoyable experience for all users, and will also allow people with disabilities to perceive, understand, navigate, and interact with your sites effectively.
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
Learn to code for free. freeCodeCamp's open source curriculum has helped more than 40,000 people get jobs as developers. [Get started](https://www.freecodecamp.org/learn/)
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
---
|
||||
id: fc51bf82-66d3-451f-8f64-17d6add50f92
|
||||
title: |
|
||||
Git Merge vs Rebase vs Squash ¿Qué estrategia debemos elegir?
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- Youtube
|
||||
date_added: 2023-11-04 14:14:49
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/https-www-youtube-com-watch-pp-yg-ukz-2-l-0-ih-nxd-w-fza-a-253-d-18b9b548407
|
||||
url_original: |
|
||||
https://www.youtube.com/watch?pp=ygUKZ2l0IHNxdWFzaA%253D%253D&v=HlmZLXMOpEM
|
||||
---
|
||||
|
||||
# Git Merge vs Rebase vs Squash ¿Qué estrategia debemos elegir?
|
||||
|
||||
## Notes
|
||||
|
||||
- Merge commit: Se crea un commit que tiene 2 padres, el último commit de main y la feature branch, se mantiene la trazabilidad hacia la feature branch pero el historial queda visualmente más complejo
|
||||
- Rebase: Se copian los commits de la feature branch a main como nuevos commits, se pierde la trazabilidad hacia la feature branch pero queda un historial lineal en main
|
||||
- Squash commit: Se juntan todos los commits en uno solo con un squash que queda en main, se pierde la trazabilidad hacia la feature branch pero queda un historial lineal en main
|
||||
## Original
|
||||
|
||||
[Git Merge vs Rebase vs Squash ¿Qué estrategia debemos elegir?](https://www.youtube.com/watch?pp=ygUKZ2l0IHNxdWFzaA%253D%253D&v=HlmZLXMOpEM)
|
||||
|
||||
By [CodelyTV - Redescubre la programación](https://www.youtube.com/@CodelyTV)
|
||||
|
|
@ -1,402 +0,0 @@
|
|||
---
|
||||
id: 616d5d08-7d04-11ee-8eaa-9f56108b78ec
|
||||
title: |
|
||||
How to Write Components that Work in Any Framework
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- RSS
|
||||
date_added: 2023-11-06 17:25:12
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/how-to-write-components-that-work-in-any-framework-18ba72d0079
|
||||
url_original: |
|
||||
https://www.freecodecamp.org/news/write-components-that-work-in-any-framework/
|
||||
---
|
||||
|
||||
# How to Write Components that Work in Any Framework
|
||||
|
||||
## Highlights
|
||||
|
||||
With Custom Elements you can author your own custom HTML elements that you can reuse across your site. They can be as simple as text, images, or visual decorations. You can push them further and build interactive components, complex widgets, or entire web applications.
|
||||
|
||||
[source](https://omnivore.app/me/how-to-write-components-that-work-in-any-framework-18ba72d0079#bceef8c0-728e-422a-aed6-b047736cb395)
|
||||
|
||||
---
|
||||
|
||||
### Writing a web component requires understanding all of its underlying technologies
|
||||
|
||||
As we saw above, web components are made up of three technologies. You can also see in the hello world code snippet, that we explicitly need to know and understand these three technologies.
|
||||
|
||||
1. We’re creating a **template element** and setting its inner HTML
|
||||
2. We’re creating a **shadow root**, and explicitly setting its mode to ‘open’.
|
||||
3. We’re cloning our **template** and appending it to our **shadow root**
|
||||
4. We’re registering a new **custom element** to the document
|
||||
|
||||
[source](https://omnivore.app/me/how-to-write-components-that-work-in-any-framework-18ba72d0079#46fc130a-1549-40c8-b950-42035c227bc4)
|
||||
|
||||
---
|
||||
|
||||
As web component authors, we need to consider a lot of things:
|
||||
|
||||
* Setting up the shadow DOM
|
||||
* Setting up the HTML templates
|
||||
* Cleaning up event listeners
|
||||
* Defining properties that we want to observe
|
||||
* Reacting to properties when they change
|
||||
* Handling type conversions for attributes
|
||||
|
||||
[source](https://omnivore.app/me/how-to-write-components-that-work-in-any-framework-18ba72d0079#855f444c-49f1-4176-9537-aaeeb6a01355)
|
||||
|
||||
---
|
||||
|
||||
One such tool is called Lit, which is developed by a team at Google. [Lit](https://lit.dev/) is a lightweight library designed to make writing web components simple, by removing the need for the boilerplate we’ve already seen above.
|
||||
|
||||
[source](https://omnivore.app/me/how-to-write-components-that-work-in-any-framework-18ba72d0079#385d9ef8-13fb-4799-bff5-ef767b3df67f)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||

|
||||
|
||||
The browser has a built-in way of writing reusable components in the form of **web components**. They’re an excellent choice for building interactive and reusable components that work in any frontend framework.
|
||||
|
||||
With that said, writing highly interactive and robust web components isn’t simple. They require a lot of boilerplate and feel much less intuitive than the components you may have written in frameworks like React, Svelte, or Vue.
|
||||
|
||||
In this tutorial, I’ll give you an example of an interactive component written as a web component, and then refactor it using a library that softens the edges and removes heaps of boilerplate.
|
||||
|
||||
Don’t sweat it if you’re not familiar with web components. In the next section, I’ll do a (brief) overview of what web components are, and what they’re made out of. If you have some basic experience with them, you can skip the next section.
|
||||
|
||||
## What are Web Components?
|
||||
|
||||
Before web components, the browser didn’t have a standard way of writing reusable components. Many libraries solve this problem, but they often run into limitations like performance, interoperability, and issues with web standards.
|
||||
|
||||
Web components are a technology made up of 3 different browser features:
|
||||
|
||||
* Custom elements
|
||||
* Shadow DOM
|
||||
* HTML Templates
|
||||
|
||||
We’ll do a quick crash course covering these technologies, but it’s by no means a comprehensive breakdown.
|
||||
|
||||
### What are Custom Elements?
|
||||
|
||||
==With Custom Elements you can author your own custom HTML elements that you can reuse across your site. They can be as simple as text, images, or visual decorations. You can push them further and build interactive components, complex widgets, or entire web applications.==
|
||||
|
||||
You’re not just limited to using them in your projects, but you can publish them and allow other developers to use them on their sites.
|
||||
|
||||
Here are some of the reusable components from my library [A2K](https://a2000-docs.netlify.app/). You can see that they come in all shapes and sizes, and have a range of different functionalities. Using them in your projects is similar to using any old HTML element.
|
||||
|
||||

|
||||
|
||||
A small collection of web components from the A2K library
|
||||
|
||||
Here’s how you’d use the progress element in your project:
|
||||
|
||||
```xml
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Quick Start</title>
|
||||
<meta charset="UTF-8" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- Use web components in your HTML like regular built-in elements. -->
|
||||
<a2k-progress progress="50" />
|
||||
|
||||
<!-- a2k web components use standard JavaScript modules. -->
|
||||
<script type="module">
|
||||
import 'https://cdn.jsdelivr.net/npm/@a2000/progress@0.0.5/lib/src/a2k-progress.js';
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
Once you’ve imported the third-party scripts, you can start using the component, `a2k-progress` in this case, just like any other HTML element.
|
||||
|
||||
If you’re building your own web components, there’s virtually no limit to how complex you can make your custom elements.
|
||||
|
||||
I recently created a web component that renders a CodeSandbox code editor in the browser. And because it’s a web component, you can use it in any framework you like! If you’d like to learn a little more about that, [you can read more here](https://component-odyssey.com/articles/00-sandpack-lit-universal).
|
||||
|
||||
### What is the Shadow DOM?
|
||||
|
||||
If you have a working knowledge of CSS, you’ll know that vanilla CSS is scoped globally. Writing something like this in your global.css:
|
||||
|
||||
```css
|
||||
p {
|
||||
color: tomato;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
will give all `p` elements a nice orange/red color, assuming that no other, more specific CSS selectors are applied to a `p` element.
|
||||
|
||||
Take this select menu, for example:
|
||||
|
||||

|
||||
|
||||
It has a distinct character which is driven by the visual design. You might want to use this component, but if your global styles affect things like the font family, the color, or the font size, it could cause issues with the appearance of the component:
|
||||
|
||||
```xml
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
color: blue;
|
||||
font-size: 12px;
|
||||
font-family: system-ui;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<a2k-select></a2k-select>
|
||||
</body>
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
This is where the Shadow DOM comes in. The Shadow DOM is an encapsulation mechanism that prevents the rest of the DOM from interfering with your web components. It ensures that the global styles of the web application don’t interfere with any components that you consume. It also means that component library developers can author their components with the confidence that they’ll look and behave as expected across different web applications.
|
||||
|
||||
There’s a lot more nuance when it comes to the Shadow DOM, as well as other features that we’re not going to touch on in this article. If you’d like to learn more about web components though, I have an entire course ([Component Odyssey](https://component-odyssey.com/)) dedicated to teaching you how to build reusable components that work in any framework.
|
||||
|
||||
### HTML Templates
|
||||
|
||||
The last feature in our whistle-stop tour of web component features is HTML Templates.
|
||||
|
||||
What makes this HTML element different from other elements, is that the browser doesn’t render its content to the page. If you were to write the following HTML you wouldn’t see the text “I’m a header” displayed on the page:
|
||||
|
||||
```xml
|
||||
<body>
|
||||
<template>
|
||||
<h1>I'm a header</h1>
|
||||
</template>
|
||||
</body>
|
||||
|
||||
```
|
||||
|
||||
Instead of being used to render the content directly, the content of the template is designed to be copied. The copied template can then be used to render content to the page.
|
||||
|
||||
You can think of the template element much like the template for a 3D print. The template isn’t a physical entity, but it’s used to create real-life clones.
|
||||
|
||||
You would then reference the template element in your web component, clone it, and render the clone as the markup for your component.
|
||||
|
||||
I won’t spend any more time on these web component features, but you’ve probably already noticed that to write vanilla web components, there are a lot of new browser features that you need to know and understand.
|
||||
|
||||
You’ll see in the next section that the mental model for building web components doesn’t feel as streamlined as it does for other component frameworks.
|
||||
|
||||
## How to Build a Basic Web Component
|
||||
|
||||
Now that we’ve briefly covered the fundamental technologies powering a web component, here’s how to build a _hello world_ component:
|
||||
|
||||
```scala
|
||||
const template = document.createElement('template');
|
||||
template.innerHTML = `<p>Hello World</p>`;
|
||||
|
||||
class HelloWorld extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.attachShadow({ mode: 'open' });
|
||||
this.shadowRoot.append(template.content.cloneNode(true));
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('hello-world', HelloWorld);
|
||||
|
||||
```
|
||||
|
||||
This is the most simple component you can write, but there’s already so much going on. For someone completely new to web components, and without the background knowledge I provided above, they’re going to be left with a lot of questions, and a lot of confusion.
|
||||
|
||||
For me, there are at least two key reasons why web components can be challenging to write, at least within the context of the hello world examples.
|
||||
|
||||
### The markup is decoupled from the component logic
|
||||
|
||||
In many frameworks, the markup of the component is often treated as a first-class citizen. It’s often the content that gets returned from the component function, or has direct access to the component’s state, or has built-in utilities to help manipulate markup (like loops, conditionals, and so on).
|
||||
|
||||
This isn’t the case for web components. In fact, the markup is often defined outside of the component’s class. There’s also no built-in way for the template to reference the current state of the component. This becomes a cumbersome limitation as the complexity of a component grows.
|
||||
|
||||
In the world of frontend, components are designed to help developers reuse markup in several pages. As a result, the markup and the component logic are inextricably linked, and so they should be colocated with one another.
|
||||
|
||||
### ==Writing a web component requires understanding all of its underlying technologies==
|
||||
|
||||
==As we saw above, web components are made up of three technologies. You can also see in the hello world code snippet, that we explicitly need to know and understand these three technologies.==
|
||||
|
||||
1. ==We’re creating a== **==template element==** ==and setting its inner HTML==
|
||||
2. ==We’re creating a== **==shadow root==**==, and explicitly setting its mode to ‘open’.==
|
||||
3. ==We’re cloning our== **==template==** ==and appending it to our== **==shadow root==**
|
||||
4. ==We’re registering a new== **==custom element==** ==to the document==
|
||||
|
||||
There’s nothing inherently wrong with this, since web components are supposed to be a “lower-level” browser API, making them prime for building abstractions on top of. But for a developer coming from a React or a Svelte background, having to understand these new browser features, and then having to write components with them can feel like too much friction.
|
||||
|
||||
## More Advanced Web Components
|
||||
|
||||
Let’s take a look at a more advanced web component, a counter button.
|
||||
|
||||

|
||||
|
||||
You click the button, and the counter increments.
|
||||
|
||||
The following example contains a few extra web component concepts, like lifecycle functions and observable attributes. You don’t need to understand everything going on in the code snippet. This example is really only used to illustrate how much boilerplate is required for the most basic of interactive interfaces, a counter button:
|
||||
|
||||
```kotlin
|
||||
const templateEl = document.createElement("template");
|
||||
|
||||
templateEl.innerHTML = `
|
||||
<button>Press me!</button>
|
||||
<p>You pressed me 0 times.</p>
|
||||
`;
|
||||
|
||||
export class OdysseyButton extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.attachShadow({ mode: "open" });
|
||||
this.shadowRoot.appendChild(templateEl.content.cloneNode(true));
|
||||
this.button = this.shadowRoot.querySelector("button");
|
||||
this.p = this.shadowRoot.querySelector("p");
|
||||
this.setAttribute("count", "0");
|
||||
}
|
||||
|
||||
// Note: Web components have lifecycle methods,
|
||||
// If we're setting event listeners when the component is added to the DOM, it's our job to clean
|
||||
// them up when it gets removed from the DOM
|
||||
connectedCallback() {
|
||||
this.button.addEventListener("click", this.handleClick);
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.button.removeEventListener("click", this.handleClick);
|
||||
}
|
||||
|
||||
// Unlike frameworks like React, Web Components don't automatically rerender when a prop (or attribute)
|
||||
// changes. Instead, we need to explicitly define which attributes we want to observe.
|
||||
static get observedAttributes() {
|
||||
return ["disabled", "count"];
|
||||
}
|
||||
|
||||
// When one of the above attributes changes, this lifecycle method runs, and we can
|
||||
// react to the new attribute's value accordingly.
|
||||
attributeChangedCallback(name, _, newVal) {
|
||||
if (name === "count") {
|
||||
this.p.innerHTML = `You pressed me ${newVal} times.`;
|
||||
}
|
||||
if (name === "disabled") {
|
||||
this.button.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
// In HTML, attribute values are always strings. This means that it's our job to
|
||||
// convert types. You can see below that we're converting a string -> number, and then back to a string
|
||||
handleClick = () => {
|
||||
const counter = Number(this.getAttribute("count"));
|
||||
this.setAttribute("count", `${counter + 1}`);
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
==As web component authors, we need to consider a lot of things:==
|
||||
|
||||
* ==Setting up the shadow DOM==
|
||||
* ==Setting up the HTML templates==
|
||||
* ==Cleaning up event listeners==
|
||||
* ==Defining properties that we want to observe==
|
||||
* ==Reacting to properties when they change==
|
||||
* ==Handling type conversions for attributes==
|
||||
|
||||
And there are still so many other things to consider that I haven’t touched on in this article.
|
||||
|
||||
That isn’t to say that web components are bad and that you shouldn’t write them. In fact, I’d argue that you learn so much about the browser platform by building with them.
|
||||
|
||||
But I feel that there are better ways to write components if your priority is to write interoperable components in a much more streamlined and ergonomic way.
|
||||
|
||||
## How to Write Web Components with Less Boilerplate
|
||||
|
||||
As I mentioned earlier, there are a lot of tools out there to help make writing web components much easier.
|
||||
|
||||
==One such tool is called Lit, which is developed by a team at Google.== ==[Lit](https://lit.dev/)== ==is a lightweight library designed to make writing web components simple, by removing the need for the boilerplate we’ve already seen above.==
|
||||
|
||||
As we’ll see, Lit does a lot of heavy lifting under-the-hood to help cut down the total lines of code by nearly half! And because Lit is a wrapper around web components and other native browser features, all your existing knowledge about web components is transferable.
|
||||
|
||||
To start seeing how Lit simplifies your web components. Here’s the **hello world** example from earlier, but refactored to use Lit instead of a vanilla web component:
|
||||
|
||||
```scala
|
||||
import { LitElement, html } from "lit";
|
||||
|
||||
export class HelloWorld extends LitElement {
|
||||
render() {
|
||||
return html`<p>Hello World!</p>`;
|
||||
}
|
||||
}`
|
||||
|
||||
customElements.define('hello-world', HelloWorld);
|
||||
|
||||
```
|
||||
|
||||
There’s a lot less boilerplate with the Lit component, and Lit handles the two problems I mentioned earlier, a little bit differently. Let’s see how:
|
||||
|
||||
1. The markup is directly defined from within the component class. While you can define your templates outside of the class, it’s common practice to return the template from the `render` function. This is more in line with the mental model presented in other UI frameworks, where the UI is a function of the state.
|
||||
2. Lit also doesn’t require developers to attach the shadow DOM, or create templates and clone template elements. While having an understanding of the underlying web component features will help when developing Lit components, they’re not required for getting started, so the barrier for entry is much lower.
|
||||
|
||||
So now for the big finale, what does the counter component look like once we’ve migrated it over to Lit?
|
||||
|
||||
```typescript
|
||||
import { LitElement, html } from "lit";
|
||||
|
||||
export class OdysseyCounter extends LitElement {
|
||||
static properties = {
|
||||
// We define the component's properties as well as their type.
|
||||
// These properties will trigger the component to re-render when their values change.
|
||||
// While they're not the same, you can think of these "properties" as being
|
||||
// Lit's alternatives to "observed attributes"
|
||||
// If the value is passed down as an attribute, Lit converts the value
|
||||
// to the correct type
|
||||
count: { type: Number },
|
||||
disabled: { type: Boolean },
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
// There's no need to create a shadow DOM, clone the template,
|
||||
// or store references to our DOM nodes.
|
||||
this.count = 0;
|
||||
}
|
||||
|
||||
onCount() {
|
||||
this.count = this.count + 1;
|
||||
}
|
||||
|
||||
render() {
|
||||
// Instead of using the attributeChangedCallback lifecycle, the
|
||||
// render function has access to all of the component's properties,
|
||||
// which simplifies the process of manipulating our templates.
|
||||
return html`
|
||||
<button ?disabled=${this.disabled} @click=${this.onCount}>
|
||||
Press me!
|
||||
</button>
|
||||
<p>You pressed me ${this.count} times.</p>
|
||||
`;
|
||||
}
|
||||
}`
|
||||
|
||||
```
|
||||
|
||||
The amount of code we’re writing is cut down by almost half! And this difference becomes more noticeable when creating more complex user interfaces.
|
||||
|
||||
## Why am I going on about Lit?
|
||||
|
||||
I’m a big believer in web components, but I recognise that the barrier to entry is high for many developers. Writing complex web components requires understanding heaps of browser features and the education around web components isn’t as comprehensive as other technologies, like React or Vue.
|
||||
|
||||
This is why I think it’s important to use tools like Lit can make writing performant and interoperable web components much easier. This is great if you want your components to work within any frontend framework.
|
||||
|
||||
If you’d like to learn even more, this is the approach I teach in my upcoming course [Component Odyssey](https://component-odyssey.com/). This course is excellent for anyone who wants to understand how to write components that work in any framework.
|
||||
|
||||
I do this by covering the absolute basics of web components, before moving on to tools like Lit that simplify the process of writing web components without complicating your development environment. By the end, you’ll learn how to build and publish a component library that works across any frontend framework.
|
||||
|
||||
If you want early-bird discount codes for Component Odyssey, then head on [over to the site to get notified](https://component-odyssey.com/subscribe).
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
Learn to code for free. freeCodeCamp's open source curriculum has helped more than 40,000 people get jobs as developers. [Get started](https://www.freecodecamp.org/learn/)
|
||||
|
|
@ -1,479 +0,0 @@
|
|||
---
|
||||
id: aceac380-7e10-11ee-992a-432064e77190
|
||||
title: |
|
||||
How to Avoid Prop Drilling in React
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- RSS
|
||||
- react
|
||||
date_added: 2023-11-07 19:58:39
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2
|
||||
url_original: |
|
||||
https://www.freecodecamp.org/news/avoid-prop-drilling-in-react/
|
||||
---
|
||||
|
||||
# How to Avoid Prop Drilling in React
|
||||
|
||||
## Highlights
|
||||
|
||||
Prop drilling occurs when a parent component generates its state and passes it down as `props` to its children components that do not consume the props – instead, they only pass it down to another component that finally consumes it.
|
||||
|
||||
[source](https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2#05db3def-4e59-4cfe-b8dd-1044ce91a9d5)
|
||||
|
||||
---
|
||||
|
||||
First of all, **grouping static elements and dependent components** together to achieve an appealing UI design is the major cause of prop drilling. You can't avoid prop drilling when your UI groups static elements and dependent components together in a parent. The parent component clearly won't use the `prop`, as everything within it is a static element – except the component that needs a prop.
|
||||
|
||||
[source](https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2#fa2c28c0-1b7e-4416-8553-c1b5c7a59637)
|
||||
|
||||
---
|
||||
|
||||
Second of all, when a **component accepts `props` that it doesn't use but merely passes it down to its children**, this is a sign that you have prop drilling in your component:
|
||||
|
||||
[source](https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2#6749a89e-a38c-4f4f-aa3f-c6455e6daf85)
|
||||
|
||||
---
|
||||
|
||||
Third, when a component that represents an independent section of a page is **forced to take props from its parent**, prop drilling is inevitable. It should ideally be self-contained with its state and operations.
|
||||
|
||||
[source](https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2#751d81de-62b7-444b-a2f0-a0b374f6ce45)
|
||||
|
||||
---
|
||||
|
||||
And finally, **the presence of elongated `props`** is a sure sign of prop drilling. Since an elongated prop is a fundamental element that's consistently present in every case of prop drilling, grasping this concept allows you to instinctively avoid prop drilling.
|
||||
|
||||
[source](https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2#90f807ca-03a3-4804-bcf1-c5df4e53a997)
|
||||
|
||||
---
|
||||
|
||||
Component composition is a good approach to fix prop drilling. If you ever find yourself in a situation where a component passes down a prop it neither creates nor consumes, you can use component composition to fix it.
|
||||
|
||||
[source](https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2#0112181f-34b7-4ca3-b941-f1c16303c6c0)
|
||||
|
||||
---
|
||||
|
||||
To avoid prop drilling in this case, any grandchildren components that require access to the same `props`, especially when their parent don't consume the data, should be passed as children ensuring that the data remains within the `App` context.
|
||||
|
||||
[source](https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2#c17f1d4e-8f5c-45d1-9078-fe8ab740e11e)
|
||||
|
||||
---
|
||||
|
||||
Prop drilling can also be fixed by moving state to where it is consumed. The example of prop drilling in this article has a component named `Content`. But the component is forced to receive a `prop` from its parent instead of having a state and be an independent component – and so we have prop drilling.
|
||||
|
||||
[source](https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2#9f94fd13-9558-4bd3-a60c-60074b3495d2)
|
||||
|
||||
---
|
||||
|
||||
It's essential to highlight what to avoid when dealing with prop drilling to prevent unnecessary challenges.
|
||||
|
||||
* **Avoid React Context, if possible, to fix prop drilling.** This approach ties your component to a specific context, restricting its usability outside of that context and hindering composition and reusability.
|
||||
* **Steer clear of redundant components by employing a children-parent replacement approach.** This approach naturally incorporates [component composition](https://www.codementor.io/@dinerismail/the-power-of-component-composition-in-react-21goassg4m) without introducing redundant components or states when resolving prop drilling.
|
||||
|
||||
[source](https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2#8ff7b79b-5503-4e1a-b7fe-1a07a46c578c)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||

|
||||
|
||||
In order to write scalable, reusable, and maintainable applications with React, you'll need to go beyond the surface of using React components, useEffect, useContext, useState, and the like. It involves learning in detail how React works in more depth.
|
||||
|
||||
And if you don't properly understand these key React concepts, you can run into various issues, like [prop drilling](https://www.quora.com/What-is-prop-drilling-in-ReactJS).
|
||||
|
||||
In this tutorial, you'll learn what prop drilling is. I'll also teach you how to intuitively avoid it without relying on React context. In the end, you'll understand how to identify prop drilling without thinking and fix it with precision.
|
||||
|
||||
If you prefer a visual guide, here's a video version of this tutorial on my [YouTube channel](https://youtu.be/KZnQ5R8Kd4I) (approximately 15 minutes).
|
||||
|
||||
[](https://www.youtube.com/embed/ELZZnqHJhlw)
|
||||
|
||||
## What is Prop Drilling?
|
||||
|
||||
==Prop drilling occurs when a parent component generates its state and passes it down as== `==props==` ==to its children components that do not consume the props – instead, they only pass it down to another component that finally consumes it.==
|
||||
|
||||
Below is an example of prop drilling in React:
|
||||
|
||||
```xquery
|
||||
function App() {
|
||||
const [profile, setProfile] = useState({ame: 'John'});
|
||||
return (
|
||||
<div> <Header profile={profile} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Header({ profile }) {
|
||||
return (
|
||||
<header>
|
||||
<h1>This is the header</h1>
|
||||
<Content profile={profile} />
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
function Content({ profile }) {
|
||||
return (
|
||||
<main>
|
||||
<h2>Content Component</h2>
|
||||
<p>{profile.name}</p>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
If you check out the example above, you'll notice that `profile` is passed from the `App` component through the `Header` to the `Content` component, which eventually makes use of the `props`. This is commonly referred to as prop drilling as the `Header` component doesn't consume the `prop` but only passes it down to the `Content` component that finally consumes it.
|
||||
|
||||
Now that you understand what prop drilling is, the next challenge is to figure out how to avoid it because it's not always an intuitive process.
|
||||
|
||||
You'll need to start exploring methods to address it. While you can use component composition and React context to resolve it, the challenge lies in not always recognizing the issue until later.
|
||||
|
||||
To truly master the art of handling prop drilling intuitively, you must learn how to identify elongated props and contexts.
|
||||
|
||||
## What is an Elongated Prop?
|
||||
|
||||

|
||||
|
||||
Photo by [Emily Morter](https://unsplash.com/@emilymorter?utm%5Fsource=ghost&utm%5Fmedium=referral&utm%5Fcampaign=api-credit) / [Unsplash](https://unsplash.com/?utm%5Fsource=ghost&utm%5Fmedium=referral&utm%5Fcampaign=api-credit)
|
||||
|
||||
An elongated prop is a `prop` that is not consumed but it is only passed down to another component. When a component receives a `prop` from its parent and doesn't consume the `prop`, it passes the prop down to another component. This prop is called elongated prop because it has been extended.
|
||||
|
||||
Whenever you see a `prop` being passed down by components that neither creates nor consumes the `prop`, you have an an elongated prop (as well as prop drilling) in your code. The code snippet below is an example:
|
||||
|
||||
```javascript
|
||||
function Profile({ user }) {
|
||||
return (
|
||||
<header>
|
||||
<h1>This is the header</h1>
|
||||
<Content user={user} />
|
||||
</header>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
`user`, in this example, is an elongated `prop` as it is neither created nor consumed by the `Profile` component. Instead, it is only passed down to the `Content` component. And that means we have extended `user` through a component that doesn't need it so that it can get to the one that does.
|
||||
|
||||
Now, let's revisit the example we used to illustrate prop drilling. Wait, are you thinking what I'm thinking? The `prop` that's being passed down in the prop drilling example is indeed an elongated prop, right? Yes, you've got it.
|
||||
|
||||
```xquery
|
||||
function App() {
|
||||
const [profile, setProfile] = useState({ame: 'John'});
|
||||
return (
|
||||
<div>
|
||||
<Header profile={profile} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Header({ profile }) {
|
||||
return (
|
||||
<header>
|
||||
<h1>This is the header</h1>
|
||||
<Content profile={profile} />
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
function Content({ profile }) {
|
||||
return (
|
||||
<main>
|
||||
<h2>Content Component</h2>
|
||||
<p>{profile.name}</p>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
In the code above, you can observe that the `prop` passed to `Header` is created in the `App` component. Then, `Header` passes it down to its child component named `Content`. As a result, the `profile` being passed down can be considered elongated because it is passed through a component (`Header`) that neither creates nor consumes it down to the one that does.
|
||||
|
||||
The `Header` component passing down the `prop` it doesn't create or need is unnecessarily stretching the context of the `prop`.
|
||||
|
||||
Now, the question is, how do elongated props help to intuitively avoid prop drilling in React? They make it easy for you to spot `props` being used where they're are neither created nor consumed.
|
||||
|
||||
Rather than focusing on how to solve prop drilling, elongated props enable you to avoid it. This is because it's intuitive to recognize when a component neither creates nor consumes `props`, and that helps you to know the component is irrelevant.
|
||||
|
||||
But before you learn how to quickly avoid prop drilling with your understanding of elongated props, it is important that you know the main causes of prop drilling. Then you'll truly know how to avoid it without thinking about it.
|
||||
|
||||
## What Causes Prop Drilling?
|
||||
|
||||

|
||||
|
||||
Photo by [Etienne Girardet](https://unsplash.com/@etiennegirardet?utm%5Fsource=ghost&utm%5Fmedium=referral&utm%5Fcampaign=api-credit) / [Unsplash](https://unsplash.com/?utm%5Fsource=ghost&utm%5Fmedium=referral&utm%5Fcampaign=api-credit)
|
||||
|
||||
Prop drilling doesn't occur out of thin air. It's a consequence of inadequate component organization, and it is not a React problem. It is a thinking or design problem.
|
||||
|
||||
You won't encounter an instance of prop drilling without observing one of the following layout mistakes:
|
||||
|
||||
==First of all,== **==grouping static elements and dependent components==** ==together to achieve an appealing UI design is the major cause of prop drilling. You can't avoid prop drilling when your UI groups static elements and dependent components together in a parent. The parent component clearly won't use the== `==prop==`==, as everything within it is a static element – except the component that needs a prop.==
|
||||
|
||||
Here's an example:
|
||||
|
||||
```javascript
|
||||
function Header({ profile }) {
|
||||
return (
|
||||
<header>
|
||||
<h1>This is the header</h1>
|
||||
<Content profile={profile} />
|
||||
</header>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
In this case, static elements `<header> and <h1>` are grouped with a dependent component `Content` – and that's why we have prop drilling therein.
|
||||
|
||||
Provided that the `Content` component is independent or takes no `props`, it won't need `profile` and there won't be prop drilling in the first place. This is why forcing a component that should be independent to take `props` from its parent is a recipe for prop drilling in React.
|
||||
|
||||
==Second of all, when a== **==component accepts== `==props==` ==that it doesn't use but merely passes it down to its children==**==, this is a sign that you have prop drilling in your component:==
|
||||
|
||||
```php
|
||||
function App () {
|
||||
const [profile, setProfile] = useState({name: "Ayobami"})
|
||||
return (
|
||||
<>
|
||||
<Parent profile={profile} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
function Parent({ profile }) {
|
||||
return (
|
||||
<div>
|
||||
<Hero profile={profile} />
|
||||
<Features profile={profile} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
In this case there is prop drilling because the `Parent` component takes `profile` and it doesn't use it though it passes it down to its children.
|
||||
|
||||
==Third, when a component that represents an independent section of a page is== **==forced to take props from its parent==**==, prop drilling is inevitable. It should ideally be self-contained with its state and operations.==
|
||||
|
||||
The exception would be if it's intentionally tied to its parent for specific reasons. In such cases, prop drilling becomes a necessary trade-off.
|
||||
|
||||
If you revisit the example of prop drilling cited in this article, you will realize it has a prop drilling issue because the `Content` component which could have been an independent component by having a state is forced to receive props from its parent.
|
||||
|
||||
==And finally,== **==the presence of elongated== `==props==`** ==is a sure sign of prop drilling. Since an elongated prop is a fundamental element that's consistently present in every case of prop drilling, grasping this concept allows you to instinctively avoid prop drilling.==
|
||||
|
||||
When you spot an elongated prop, you can be certain that one of the other three mistakes is also in play. In short, an elongated prop is a prop that is not consumed and is also passed down to another component.
|
||||
|
||||
So grouping static elements with dependent components, forcing components to take props, elongated props, and receiving a prop without consuming it are the signs to recognize prop drilling in React.
|
||||
|
||||
## How to Fix Prop Drilling with Component Composition
|
||||
|
||||
==Component composition is a good approach to fix prop drilling. If you ever find yourself in a situation where a component passes down a prop it neither creates nor consumes, you can use component composition to fix it.==
|
||||
|
||||
But to use component composition, you need to understand a component context.
|
||||
|
||||
### What is a component context?
|
||||
|
||||
The context of a component encompasses everything that is visible within it, including state, props, and children. The following code further illustrates this concept:
|
||||
|
||||
```javascript
|
||||
function App() {
|
||||
const [profile, setProfile] = useState({name: 'Ayobami'});
|
||||
return (
|
||||
<div>
|
||||
<Header profile={profile} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
In this scenario, the context of `App` refers to everything we can see within the `App` component – including the `profile` prop, the `Header`, and other `App` content. Therefore, any data created in the `App` component should ideally be utilized within the `App` component itself, either as its own data or as `props` to its children.
|
||||
|
||||
Prop drilling always emerges when the children receiving the `props` doesn't consume it but only passes it down to its children.
|
||||
|
||||
==To avoid prop drilling in this case, any grandchildren components that require access to the same== `==props==`==, especially when their parent don't consume the data, should be passed as children ensuring that the data remains within the== `==App==` ==context.==
|
||||
|
||||
```javascript
|
||||
export function App() {
|
||||
const [profile, setProfile] = useState({name: 'Ayobami'});
|
||||
return (
|
||||
<div>
|
||||
<Header>
|
||||
<Content profile={profile} />
|
||||
</Header>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
**`Or`**
|
||||
|
||||
```javascript
|
||||
export function App() {
|
||||
const [profile, setProfile] = useState({name: 'Ayobami'});
|
||||
return (
|
||||
<div>
|
||||
<Header children={<Content profile={profile} />} >
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, we have resolved the prop drilling issue in the previous example, even though we still have a redundant component, `<Header>`, right? We've successfully addressed prop drilling through component composition.
|
||||
|
||||
This process is quite straightforward because we concentrate on recognizing elongated props and repositioning them within appropriate contexts.
|
||||
|
||||
The concept of prop drilling is problem-focused, but prop elongation is solution-driven. When dealing with elongated props, our primary goal is to identify props that are not consumed but only passed down to another components.
|
||||
|
||||
## How to Fix Prop Drilling by Moving State to the Consumer
|
||||
|
||||
==Prop drilling can also be fixed by moving state to where it is consumed. The example of prop drilling in this article has a component named== `==Content==`==. But the component is forced to receive a== `==prop==` ==from its parent instead of having a state and be an independent component – and so we have prop drilling.==
|
||||
|
||||
We can fix the prop drilling in this case by moving the profile state to where it is consumed.
|
||||
|
||||
Let's revisit the example:
|
||||
|
||||
```xquery
|
||||
function App() {
|
||||
const [profile, setProfile] = useState({ame: 'John'});
|
||||
return (
|
||||
<div>
|
||||
<Header profile={profile} />
|
||||
<Footer profile={profile />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Header({ profile }) {
|
||||
return (
|
||||
<header>
|
||||
<h1>This is the header</h1>
|
||||
<Content profile={profile} />
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
function Content({ profile }) {
|
||||
return (
|
||||
<main>
|
||||
<h2>Content Component</h2>
|
||||
<p>{profile.name}</p>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
We can fix prop drilling in this case by moving `profile` to where it is consumed:
|
||||
|
||||
```javascript
|
||||
function App() {
|
||||
return (
|
||||
<div>
|
||||
<Header />
|
||||
<Footer profile={profile />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Header() {
|
||||
return (
|
||||
<header>
|
||||
<h1>This is the header</h1>
|
||||
<Content />
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
function Content({ profile }) {
|
||||
const [profile, setProfile] = useState({ame: 'John'});
|
||||
return (
|
||||
<main>
|
||||
<h2>Content Component</h2>
|
||||
<p>{profile.name}</p>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
Now that we have lifted the profile to the `Content` component where it is consumed, the `App` component doesn't have a state, while the `Header` component doesn't receive a prop again as the `Content` component has its state.
|
||||
|
||||
But wait! There is a problem. The `Footer` component needs the state we moved away from `App`. There you are! That is the problem with lifting or moving state to where we think it is needed. In this case, if the `Footer` component doesn't need it, we won't have any issue – but `Footer` also needs the prop.
|
||||
|
||||
Now that `Footer` needs `profile` as a prop, we need to solve prop drilling with another method.
|
||||
|
||||
## How to Fix Prop Drilling with a Children-Replacing-Parent Strategy
|
||||
|
||||
Earlier in this article, we talked about how to use component composition and moving state to its consumer to solve prop drilling. But as you saw, they have some issues – duplicated components or states.
|
||||
|
||||
But using this children-replacing-parent approach fixes the problem effectively:
|
||||
|
||||
****Working but could be better:**
|
||||
|
||||
```xquery
|
||||
export function App() {
|
||||
const [profile, setProfile] = useState({name: 'Ayobami'});
|
||||
return (
|
||||
<div>
|
||||
<Header>
|
||||
<Content profile={profile} />
|
||||
</Header>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Header({ profile }) {
|
||||
return (
|
||||
<header>
|
||||
<h1>This is the header</h1>
|
||||
<Content profile={profile} />
|
||||
</header>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
The example above shows a solution to the prop drilling example in this article. But as you can see, it has a redundant component, as `Header` does nothing.
|
||||
|
||||
**Here's a better version:**
|
||||
|
||||
```javascript
|
||||
export function App() {
|
||||
const [profile, setProfile] = useState({name: 'Ayobami'});
|
||||
return (
|
||||
<header>
|
||||
<h1>This is the header</h1>
|
||||
<Content profile={profile} />
|
||||
</header>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
In the above code, we enhance the component composition solution we previously implemented for the prop drilling example by replacing the redundant `Header` component with its content in its parent (`App`).
|
||||
|
||||
## What to Avoid
|
||||
|
||||

|
||||
|
||||
Photo by [Edwin Hooper](https://unsplash.com/@edwinhooper?utm%5Fsource=ghost&utm%5Fmedium=referral&utm%5Fcampaign=api-credit) / [Unsplash](https://unsplash.com/?utm%5Fsource=ghost&utm%5Fmedium=referral&utm%5Fcampaign=api-credit)
|
||||
|
||||
==It's essential to highlight what to avoid when dealing with prop drilling to prevent unnecessary challenges.==
|
||||
|
||||
* **==Avoid React Context, if possible, to fix prop drilling.==** ==This approach ties your component to a specific context, restricting its usability outside of that context and hindering composition and reusability.==
|
||||
* **==Steer clear of redundant components by employing a children-parent replacement approach.==** ==This approach naturally incorporates== ==[component composition](https://www.codementor.io/@dinerismail/the-power-of-component-composition-in-react-21goassg4m)== ==without introducing redundant components or states when resolving prop drilling.==
|
||||
|
||||
By avoiding elongated props, you pave the way for crafting maintainable, high-performing, reusable, and scalable React components. It simplifies the process of lifting states and components by removing the struggle of deciding where to place them.
|
||||
|
||||
With your understanding of elongated props, you can confidently position props and components within the right context without undue stress.
|
||||
|
||||
In short, you can now discover prop drilling intuitively by paying attention to any component that takes `props` it doesn't consume and only passes it down to another component.
|
||||
|
||||
Thanks for reading – cheers!
|
||||
|
||||
Hey wait! I am [Ayobami Ogundiran](https://twitter.com/codingnninja) and I am about to start showing how to build your own React, Redux, TypeScript, Zod or Ecommerce websites on my YouTube channel. [Click to subscribe](https://youtube.com/youtoocancode) to stay connected.
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
Learn to code for free. freeCodeCamp's open source curriculum has helped more than 40,000 people get jobs as developers. [Get started](https://www.freecodecamp.org/learn/)
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
---
|
||||
id: b453f3fe-d74e-4a3a-b778-8e4f6450da30
|
||||
title: |
|
||||
The one thing you need to finish your game
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
date_added: 2023-11-14 22:58:47
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/https-youtu-be-b-6-au-n-gi-ue-m-si-ixu-ds-nh-t-2-k-5-b-3-jf-s-18bd0b3d045
|
||||
url_original: |
|
||||
https://youtu.be/B6auN-GIUeM?si=ixuDsNhT2k5b3JfS
|
||||
---
|
||||
|
||||
# The one thing you need to finish your game
|
||||
|
||||
## Notes
|
||||
|
||||
What you need... is a **plan**...
|
||||
|
||||
Because it makes the game feasible, realizable and gives it a scope, to see how "big" it's going to be. Also prevents burn out by all the stuff you _"need to do"_.
|
||||
|
||||
A plan is not a immovable wall, you can tweak it if you need to adjust to new discoveries or new inputs, this is better than wandering without a goal. But try to not increment the scope so you don't end up with an interminable project.
|
||||
|
||||
> The code is more of a guide than law...
|
||||
> Jack Sparrow
|
||||
## Original
|
||||
|
||||
[The one thing you need to finish your game](https://youtu.be/B6auN-GIUeM?si=ixuDsNhT2k5b3JfS)
|
||||
|
||||
By [Game Maker's Toolkit](https://www.youtube.com/@GMTK)
|
||||
|
|
@ -1,313 +0,0 @@
|
|||
---
|
||||
id: 49d7bfb2-8911-11ee-9b49-a315c7dbc2d7
|
||||
title: |
|
||||
Career Mistakes to Avoid as a Developer
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- RSS
|
||||
date_added: 2023-11-21 21:04:22
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/career-mistakes-to-avoid-as-a-developer-18bf626412f
|
||||
url_original: |
|
||||
https://www.freecodecamp.org/news/career-mistakes-to-avoid-as-a-dev/
|
||||
---
|
||||
|
||||
# Career Mistakes to Avoid as a Developer
|
||||
|
||||
## Highlights
|
||||
|
||||
Build authentic connections to get the best out of it. Then once you're connected, here are a few things you can do:
|
||||
|
||||
* Show interest in their posts.
|
||||
* Engage with discussions by commenting or sharing posts.
|
||||
* Repost with your thoughts
|
||||
* Exchange ideas, or even build things together!
|
||||
|
||||
A strong social connection may help you in getting information faster. You may learn about a new release of a library/framework/product, how an industry is moving, how certain technologies might impact your work, and so on.
|
||||
|
||||
[source](https://omnivore.app/me/career-mistakes-to-avoid-as-a-developer-18bf626412f#3d561a03-61e0-4ca6-8e70-81651abe90c1)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||

|
||||
|
||||
What does the word `career` mean to you? To me, it is a roller coaster journey during which we find opportunities, progress, and growth in life. The journey involves learning objectives, work, and other personal and professional aspects.
|
||||
|
||||
A promising career is one where you enjoy most (if not all) of your daily work. You see your personal, professional, and financial growth and gradually define what success means to you.
|
||||
|
||||
A lousy career is just the opposite. It may pay your bills, but you need more work satisfaction, and measuring your progress and growth becomes hard.
|
||||
|
||||
Several factors define a career: promising versus lousy, good versus bad, and successful versus failed. A few of them we can not control – but, we can avoid some career mistakes to build a better career path.
|
||||
|
||||
I have spent more than 18 years in Software Engineering and have seen a lot of ups and downs, including in my own career and those of my colleagues. In this article, I will discuss ten career mistakes you should avoid.
|
||||
|
||||
Usually, I [share knowledge](https://www.freecodecamp.org/news/author/tapas/) on technical topics like JavaScript, web development, React, Node, Next.js, and so on. But this time, let's connect on essential tips for our Career Development.
|
||||
|
||||
If you like to learn from video content as well, this article is also available as a video tutorial here: 🙂
|
||||
|
||||
## A Few Things Before We Start
|
||||
|
||||
You may or may not agree with all the points. That's fine with me, because what I'm planning to share here is based on my own experiences.
|
||||
|
||||
You may strongly agree or disagree with my conclusions, but if there are any additional points that you think I still need to include, please let me know. You can contact me on the social handles I mention at the end of this article.
|
||||
|
||||
Also, this article is not only meant for working professionals. All these mistakes we will discuss are relevant for everyone, including students, people seeking jobs, or anyone getting ready for tomorrow in the software industry or any industry.
|
||||
|
||||
All set? Let's get started.
|
||||
|
||||
## 1\. You Don't Set Realistic Goals
|
||||
|
||||

|
||||
|
||||
One of the biggest mistakes most of us make in our careers is not having a goal. What exactly is a goal? It is something like a target.
|
||||
|
||||
Let's take an example. Let's say you're going shopping to buy something. You usually have a list of items that you want to get. You don't randomly pick things and come home and feel like, "Oh, it was a complete waste of time and money". So, if that list is your shopping goal, why not have something like this for your career?
|
||||
|
||||
Usually, we have a lot of short-term goals, for example,
|
||||
|
||||
* I have to fix this bug today.
|
||||
* I have to build this project this week.
|
||||
* I have to get a promotion this year.
|
||||
|
||||
These are great goals to have. But we need to have long-term goals as well. Like, what do you want to be in the long-term in your career. How do you plan every steps to achieve that goal?
|
||||
|
||||
Say you are in mechanical engineering, but your heart is in software engineering (mechanical engineering is excellent – I'm just taking this as an example). In that case, you should have a goal for the next few years to translate yourself into a software developer and try to seek more roles more opportunities in the software industry.
|
||||
|
||||
I can tell you my story, as I think it'll help give you some perspective. I set myself a long term career goal to transition from my regular multi-national corporation job and start my career full time as an independent teacher and content creator. It took me four years to realize it, but without that goal it would have been impossible for me to chase my passion.
|
||||
|
||||
You may ask, will I be able to fulfill all the goals in my life? Well, maybe not. Still, it's important to have some and prioritize the most important ones. That way, even if you can't achieve some, you may identify a few more new goals along the way.
|
||||
|
||||
You may have a different way of going about it. But, if you don't have a starting point, you do not have anything to work toward and chase. Your career may become stagnant.
|
||||
|
||||
If you don't have any career goals for yourself right now, take some time to come up with a couple realistic goals. Here's some advice on [how to set SMART goals you can actually achieve](https://www.freecodecamp.org/news/how-to-set-smart-goals-you-can-achieve/).
|
||||
|
||||
## 2\. You Fail to Recognize Your Potential
|
||||
|
||||

|
||||
|
||||
> **Human potential** is the capacity for humans to **improve** themselves through **studying**, **training**, and **practice**, to reach the limit of their ability to develop **aptitudes** and **skills**. – Definition of Human Potential from Wikipedia.
|
||||
|
||||
For us, the software developers, is about improving ourselves through practice, training, and study to reach the heights of our ability. But many of us do not know our potential at the start our careers. We figure it out gradually, and when we become aware of it, this helps us improve our careers.
|
||||
|
||||
When you know your potential, someone else will not dictate how to shape your career. Instead, you will be able to identify what would be good for you based on your strengths and where you need to bridge the gaps.
|
||||
|
||||
But you may ask, "How do I know my potential?". That's where having a goal and working towards it helps. Say you have a goal of mastering machine learning and data science to have a career as a data scientist. As you work towards this goal, you will find the areas where you excel, and other areas where you need to work especially hard. You figure out your potential as you work towards this goal.
|
||||
|
||||
Also, try not to settle for unimportant things. Constantly challenge yourself to produce better and more significant outcomes. When you do so, you discover your true potential in a much better way.
|
||||
|
||||
## 3\. You Don't Take the Time to Network
|
||||
|
||||

|
||||
|
||||
Hey, we're gonna talk about something other than computer networking here. We will focus on human-to-human networking. We are going to talk about socializing. But why?
|
||||
|
||||
Networking or socializing with like-minded people, talking to them, and getting inspired by their work are as important as learning to code in programming. You might be a great programmer and fantastic coder. But suppose you do it in a silo. In that case, no one knows you or what you're capable of, so you will most likely lose out on more significant opportunities in your career.
|
||||
|
||||
When you socialize and network with others in the tech space, you may find a meaningful community to join. You'll be able to discuss important topics with like-minded people who have interests similar to yours – and this can help you multiply your growth by many times.
|
||||
|
||||
This is one mistake I made in my career for several years, as I was unaware of its vast potential. Be active on platforms like LinkedIn, follow people you'd like to connect with on tech Twitter (now X), and make authentic connections with them. Spending mindful time on these platforms, and at in-person events as you're able, can really help boost your career.
|
||||
|
||||
Check out the `You Miss Out on Learning Opportunities` section below for some real-life tips on how to reach out and connect with people.
|
||||
|
||||
## 4\. You Waste Your Precious Time
|
||||
|
||||

|
||||
|
||||
"Wasting time" means not effectively utilizing your time. Would you agree that time is precious? Using and managing your time properly will help your career and life in general.
|
||||
|
||||
To clarify, watching a movie, going out with your friends and family, participating in festive activities, and so are not wasting time. You need these to balance out the time you spend working.
|
||||
|
||||
Rather, I'm more concerned about the tasks you may have to perform that take away from your "focus time" at work.
|
||||
|
||||
Let me walk you through a few situations:
|
||||
|
||||
You are working on a task, and here comes some notifications on your phone. You pause whatever you are doing and jump on your phone to see what's happening on that side of the world. The notification may take you 10-15 seconds to read, but you then spend 10 minutes browsing the phone.
|
||||
|
||||
This is a habit many of us have built in recent times. And then when you get back to your work, your brain has to recalculate and bring you back to the topic at hand – where you were, and what you were doing – and get you started with the task gain. This context switching is costly, and the same amount of focus may not be possible.
|
||||
|
||||
The best way of tackle a situation like this is,
|
||||
|
||||
* Switch off the phone's internet while you're working if you do not need it. You can switch it on when you take breaks, maybe at lunch time.
|
||||
* You can also set your phone in "Do Not Disturb" mode while your work needs your utmost attention. Just make sure you add some of your family and friend's contacts as emergency contacts so that only a limited set of people can reach out to you during those times in case of any emergencies.
|
||||
|
||||
Let's talk about another situation. Suppose you need to prepare and send a design doc to a senior dev for review. But instead, you spend time on something low priority or some little luxury that delayed preparing the doc. You keep postponing until it's become an urgent thing that you'll have to do within a limited time.
|
||||
|
||||
This act of delaying something knowingly is called `procrastination`, an ultimate way to kill time. There are some well-known and proven methods to tackle procrastination.
|
||||
|
||||
* The first step is to realize and admit to yourself that you procrastinate.
|
||||
* Then list out your distractors. This list may vary from person to person. Remove these distractors. It could be your phone, TV, novels, anything.
|
||||
* Break down your deliverables into smaller tasks. Achieve them one by one and give yourself a pat on your back once you've finished each small task.
|
||||
* Take small breaks and come back to the point where you left off on your task to continue with a fresh brain.
|
||||
|
||||
Instead of finding yourself in these types of situations, use your time wisely. If you have to get something done, get it done. When you're procrastinating, something that depends on one task may also get delayed, creating a cycle of time waste, frustrations, and complicated situations.
|
||||
|
||||
## 5\. You Neglect Upskilling
|
||||
|
||||

|
||||
|
||||
`Upskilling` means getting better at your current skill or acquiring relevant new skills. It is essential to upskill at any and all stages of your career.
|
||||
|
||||
One of the common mistakes we make is that we stop upskilling after a few years in our professional life. We get used to the projects, domains, technologies, and environments that create a comfort zone around us. Upskilling is always about coming out of that comfort zone.
|
||||
|
||||
Here are a few common excuses we give to ourselves when it comes to upskilling:
|
||||
|
||||
* I already have a lot of work at the office or assignments in university.
|
||||
* I need to have a personal life.
|
||||
* I am happy with whatever I know now, and my work only demands so much.
|
||||
* There is so much to learn and it is never ending (sigh!).
|
||||
|
||||
But you really don't need that much time in a week to up-skill. You just need to have a plan and to stay consistent in executing it. Set just 1 hour aside in your day. Fork it out from any non-urgent activities and plan your learning schedule in that one hour.
|
||||
|
||||
In this one hour, here are some things you can do:
|
||||
|
||||
* Assess the gaps, weaknesses, and strengths in your technical and non technical abilities.
|
||||
* List them out in a place where you can easily get back to them and make modifications.
|
||||
* Prioritize them based on your current needs and near future goals.
|
||||
* Time-box each of the items so that you can get something tangible within a specified duration. For example, you want to do a certification on cloud computing within a month, or the Responsive Web Design course from freeCodeCamp over the next few weeks, and so on.
|
||||
* Start working on these defined tasks. You may find many resources on internet. Glance over them to create an index of resources that you can understand easily and relate to well.
|
||||
* Read and watch tutorials, but also practice hard.
|
||||
* Finally, recognize your progress.
|
||||
|
||||
You may ask, is that one hour really enough? And I will tell you – it works like magic if you keep it up. Upskilling is not a race or sprint. It needs time, consistency, and perseverance to get from the one end to other.
|
||||
|
||||
Have you heard about the power of tiny gains?
|
||||
|
||||

|
||||
|
||||
Credit: James Clear
|
||||
|
||||
It is a strategy of being just 1% better every day. If you continue to do that for a year, you get almost 38% better at the end of the year. Being 1% worse does the opposite. The strategy was represented in mathematical graphs by James Clear in explanation of [Continuous improvements and how it works](https://jamesclear.com/continuous-improvement).
|
||||
|
||||
Upskilling can also help you out a lot if you're preparing for the job search. The way the tech industry is moving, we may not be able to avoid layoffs – but we can be better prepared to get our next job faster. And that becomes much more attainable when you stay relevant and continue learning new things.
|
||||
|
||||
## 6\. You Don't Ask for What You Want
|
||||
|
||||

|
||||
|
||||
Let me start by sharing an experience of mine. Back in the early 2000s when I was a fresher, I had to attend a meeting with some of the project leads and the manager. We were discussing how to modernize our product with HTML5 features.
|
||||
|
||||
I was aware of HTML5, and every time a discussion point was raised, I thought of adding to it, but I didn't. I thought of asking some valuable questions, but I didn't. I felt that in order to ask something in a meeting, I needed a lot of guts! I was wrong.
|
||||
|
||||
Oftentimes in your career journey, if you do not ask, you simply won't get what you want or deserve. If someone has some knowledge and you lack it, ask about it. If you have a questiona bout something, ask before you commit to the work. Ask about your promotion, a salary hike, career growth, and anything that is related to your career. There is no such thing as a silly question when it comes to your career growth.
|
||||
|
||||
## 7\. You Only Focus on the Money
|
||||
|
||||

|
||||
|
||||
Come on, money is important. But is it the only important thing, especially in the context of switching jobs or working towards your career goals? No, certainly not.
|
||||
|
||||
When you plan to switch jobs, you also need to look into other factors like work culture, the amount of time you need to spend at the office working, whether it's going to be more stressful compared to the compensation you'll be getting, and so on.
|
||||
|
||||
I would certainly look into the following factors along with the compensation (the money part) to make an informed decision about my job switching:
|
||||
|
||||
* What will be my technical growth and learning opportunities?
|
||||
* What will the work environment be like? Remote/Work From Office/Hybrid? How will that impact me?
|
||||
* What skills (both tech and soft) will I be able to learn in the new position?
|
||||
* What kind of employee benefits will I get compared to my current organization?
|
||||
* Will my work-life balance be impacted positively?
|
||||
* What are the company's vision, culture, and values?
|
||||
|
||||
Then when you're considering the salary, be careful and make sure you understand the breakdown. What percentage of the CTC comes from any bonus? Is it inclusive or exclusive of CTC? How does the bonus payout happen? If the company doesn't do well in a fiscal year, will you get paid less? Are there stock options or other benefits they pay out instead of cash? All this matters.
|
||||
|
||||
The mistake people often make is that they see only the `money` figure as the most important part of a job offer. Make sure you talk to someone from the company, do your research, and learn about what else they're offering as we mentioned above.
|
||||
|
||||
## 8\. You Neglect Work-Life Balance
|
||||
|
||||

|
||||
|
||||
Another mistake you might make is not balancing your work and life. The last thing you want is to `burn out` at the cost of things you love the most, like your friends, family, and long-term career.
|
||||
|
||||
We must learn to prioritize things, and this includes both work and personal life. Your priority list for the day should not have only work related items. While it's important to ship a bug fix, it is also essential to accompany your kids to their soccer games or school plays, or make time to go on a date with your partner, or do something nice for yourself.
|
||||
|
||||
Do not be afraid to say "No". At the same time, don't be arrogant when you accept or decline tasks. This is important to keep a healthy work-life balance. When you already have plenty on your plate, trying to accommodate more or do more will only spill over and negatively affect your work-life balance.
|
||||
|
||||
So say no when you need to, communicate your intentions ahead of time when possible, and proactively ask for what tasks you'd like to work on when your plate has room for more.
|
||||
|
||||
For a long time in my career, I attended meetings late at night to match the timezones of my customers and other colleagues. Then, slowly, it started affecting my health and productivity.
|
||||
|
||||
When I thought about it more carefully, I discovered a couple of things. First, I realized that I didn't have to attend all the meetings, and that I could request that they take place in my clients' evenings sometimes. That way we'd both be taking turns compromising. And it worked.
|
||||
|
||||
At times, our habits drive us towards the work-life imbalance. For example, staying late at office while the same work can wait till the next morning is a classic example of a habit that may lead to health issues and frustrations in a long run.
|
||||
|
||||
We all need to find a way to sustain both work and life. So plan ahead, and stick to your schedule as much as possible. There might be exceptions where you have to give one thing priority above another – but do not allow the exception to become the norm.
|
||||
|
||||
## 9\. You Miss Out on Learning Opportunities
|
||||
|
||||

|
||||
|
||||
If you have the opportunity to learn from a person who specializes in a particular field, grab it. If you use social media platforms like LinkedIn and X/Twitter wisely, it can lead you to the people who share great insights about subjects you're interested in.
|
||||
|
||||
A quick tip for you:
|
||||
|
||||
When you send someone a connection request on LinkedIn/X, take some time to introduce yourself. Things that you can mention briefly:
|
||||
|
||||
* What did you find unique about the person you want to connect to?
|
||||
* A bit about yourself, introducing some of your uniqueness, too.
|
||||
* Why do you want to connect?
|
||||
|
||||
==Build authentic connections to get the best out of it. Then once you're connected, here are a few things you can do:==
|
||||
|
||||
* ==Show interest in their posts.==
|
||||
* ==Engage with discussions by commenting or sharing posts.==
|
||||
* ==Repost with your thoughts==
|
||||
* ==Exchange ideas, or even build things together!==
|
||||
|
||||
==A strong social connection may help you in getting information faster. You may learn about a new release of a library/framework/product, how an industry is moving, how certain technologies might impact your work, and so on.==
|
||||
|
||||
Apart from learning a lot, you may also get to know about job openings, hirings, and references. After all, companies have also started recruiting talent from social media pages.
|
||||
|
||||
Also, being part of a forum like the [freeCodeCamp forum](https://forum.freecodecamp.org/) can be helpful for networking and learning as well. It is also a place for you to share solutions to a problem, talk about what you've learned, and make yourself visible gradually.
|
||||
|
||||
When we learn from someone, we not only come to understand what they've achieved or how they did it, but we also learn about the struggles, failures, and how they made the turnaround. Learning from someone else's experience can help accelerate your career journey. Don't make the mistake of living in a silo and missing out on these opportunities.
|
||||
|
||||
## 10\. You Can't See the Bigger Picture
|
||||
|
||||

|
||||
|
||||
By `Big Picture`(or Bigger Picture), I mean understanding and developing a wider perspective on your career as a whole. It is about your ability to consider and assess many different aspects of a situation, rather than focusing on just the minute details.
|
||||
|
||||
As developers, we're supposed to implement features, do bug fixes, maintain code, and deliver quality software to our end-users. That's great!
|
||||
|
||||
But, we need to think beyond the individual tasks assigned to us. Our understanding of the overall project goals, the user acceptance criteria, delivery mechanisms, and perspectives of other engineers is key. And so is judging the impact of our work, as it will help us get the big picture of a project.
|
||||
|
||||
Suppose your product manager wants your team to build user interfaces that also cater to the needs of specially-abled and visually challenged users. In this case, you and your team members must see the bigger picture around `Accessibility`.
|
||||
|
||||
If your designer doesn't define the site's colors accordingly, or the developers do not implement keyboard accessibility along with ARIA roles and attributes, then they're missing the bigger picture.
|
||||
|
||||
Another example could be over-optimizing performance while your users do not care about it. Your users may be waiting to get a feature ASAP so it can help them achieve their business goals. But by addressing unnecessary optimizations, you may be delaying that release and missing crucial deadlines.
|
||||
|
||||
Missing the bigger picture may lead to a lack of synergy in your organization. It can also result in software products that need multiple iterations to meet customer needs because those needs weren't understood at the beginning. This can cause you to miss deadlines and do more work, and can greatly increase the cost to your client.
|
||||
|
||||
Along with understanding "what" tasks you need to perform, also ask "why" your tasks are important and how they will impact the rest of the project or other people's work.
|
||||
|
||||
Irrespective of what you build, how big or small it is, how glorified or dull is the outcome, you need to know the impact of it on end users and your internal customers (like product/project managers, quality assurance team, documentation team, whoever).
|
||||
|
||||
Once you look at the bigger picture and act accordingly, your margin of error reduces automatically.
|
||||
|
||||
## Some More Advice and Wrapping Up
|
||||
|
||||
I wanted to share all this career advice with you because I have been on the other side and learned the hard way. Before I move on to write my next article or record my next video, one more quick tip for you: make sure you work to build up your finances.
|
||||
|
||||
Financial independence brings peace and the mental stability to think wildly about things you want to pursue in your career. But getting to the point of financial stability is not an overnight thing. You need to plan, save, and invest wisely such that your money grows faster than your age.
|
||||
|
||||
I am not a finance expert, but I relied on some good ones and took their suggestions early on. If you have the opportunity and mindset to build your finances for the future, the time is now.
|
||||
|
||||
That's all for now. I hope you found this article informative and insightful. I regularly publish meaningful posts on my [GreenRoots Blog](https://blog.greenroots.info/), you may find them helpful, too.
|
||||
|
||||
Let's connect.
|
||||
|
||||
* I am an educator on my YouTube channel, `tapaScript`. Please [SUBSCRIBE](https://www.youtube.com/tapasadhikary?sub%5Fconfirmation=1) to the channel if you want to learn JavaScript, ReactJS, Next.js, Node.js, Git, and all about Web Development in the fundamental way.
|
||||
* [Follow me on X (Twitter](https://twitter.com/tapasadhikary)) or [LinkedIn](https://www.linkedin.com/in/tapasadhikary/) if you don't want to miss the daily dose of Web Development and Programming Tips.
|
||||
* Find all my public speaking talks [here](https://www.tapasadhikary.com/talks).
|
||||
* Check out and follow my Open Source work on [GitHub](https://github.com/atapas).
|
||||
|
||||
See you soon with my next article. Until then, please take care of yourself, and stay happy.
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
Learn to code for free. freeCodeCamp's open source curriculum has helped more than 40,000 people get jobs as developers. [Get started](https://www.freecodecamp.org/learn/)
|
||||
|
|
@ -1,265 +0,0 @@
|
|||
---
|
||||
id: 2a685647-d920-4ba6-b837-3ee29a2f7f10
|
||||
title: |
|
||||
Conventional Commits
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
date_added: 2023-11-21 16:36:37
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/https-www-conventionalcommits-org-en-v-1-0-0-18bf36268eb
|
||||
url_original: |
|
||||
https://www.conventionalcommits.org/en/v1.0.0/
|
||||
---
|
||||
|
||||
# Conventional Commits
|
||||
|
||||
## Highlights
|
||||
|
||||
The commit message should be structured as follows:
|
||||
|
||||
---
|
||||
|
||||
```fortran
|
||||
[optional scope]:
|
||||
|
||||
[optional body]
|
||||
|
||||
[optional footer(s)]
|
||||
```
|
||||
|
||||
[source](https://omnivore.app/me/https-www-conventionalcommits-org-en-v-1-0-0-18bf36268eb#0a71a3f4-0b81-4ccf-849b-f45c65951d5b)
|
||||
|
||||
---
|
||||
|
||||
## Specification
|
||||
|
||||
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt).
|
||||
|
||||
1. Commits MUST be prefixed with a type, which consists of a noun, `feat`, `fix`, etc., followed by the OPTIONAL scope, OPTIONAL `!`, and REQUIRED terminal colon and space.
|
||||
2. The type `feat` MUST be used when a commit adds a new feature to your application or library.
|
||||
3. The type `fix` MUST be used when a commit represents a bug fix for your application.
|
||||
4. A scope MAY be provided after a type. A scope MUST consist of a noun describing a section of the codebase surrounded by parenthesis, e.g., `fix(parser):`
|
||||
5. A description MUST immediately follow the colon and space after the type/scope prefix. The description is a short summary of the code changes, e.g., _fix: array parsing issue when multiple spaces were contained in string_.
|
||||
6. A longer commit body MAY be provided after the short description, providing additional contextual information about the code changes. The body MUST begin one blank line after the description.
|
||||
7. A commit body is free-form and MAY consist of any number of newline separated paragraphs.
|
||||
8. One or more footers MAY be provided one blank line after the body. Each footer MUST consist of a word token, followed by either a `:` or `#` separator, followed by a string value (this is inspired by the[git trailer convention](https://git-scm.com/docs/git-interpret-trailers)).
|
||||
9. A footer’s token MUST use `-` in place of whitespace characters, e.g., `Acked-by` (this helps differentiate the footer section from a multi-paragraph body). An exception is made for `BREAKING CHANGE`, which MAY also be used as a token.
|
||||
10. A footer’s value MAY contain spaces and newlines, and parsing MUST terminate when the next valid footer token/separator pair is observed.
|
||||
11. Breaking changes MUST be indicated in the type/scope prefix of a commit, or as an entry in the footer.
|
||||
12. If included as a footer, a breaking change MUST consist of the uppercase text BREAKING CHANGE, followed by a colon, space, and description, e.g.,_BREAKING CHANGE: environment variables now take precedence over config files_.
|
||||
13. If included in the type/scope prefix, breaking changes MUST be indicated by a`!` immediately before the `:`. If `!` is used, `BREAKING CHANGE:` MAY be omitted from the footer section, and the commit description SHALL be used to describe the breaking change.
|
||||
14. Types other than `feat` and `fix` MAY be used in your commit messages, e.g., _docs: update ref docs._
|
||||
15. The units of information that make up Conventional Commits MUST NOT be treated as case sensitive by implementors, with the exception of BREAKING CHANGE which MUST be uppercase.
|
||||
16. BREAKING-CHANGE MUST be synonymous with BREAKING CHANGE, when used as a token in a footer.
|
||||
|
||||
[source](https://omnivore.app/me/https-www-conventionalcommits-org-en-v-1-0-0-18bf36268eb#5670099d-60fe-4b9c-82b9-814e423c0e61)
|
||||
|
||||
---
|
||||
|
||||
### What do I do if the commit conforms to more than one of the commit types?
|
||||
|
||||
Go back and make multiple commits whenever possible. Part of the benefit of Conventional Commits is its ability to drive us to make more organized commits and PRs.
|
||||
|
||||
[source](https://omnivore.app/me/https-www-conventionalcommits-org-en-v-1-0-0-18bf36268eb#6ae81ced-efe6-464a-8026-c2f286faf4b7)
|
||||
|
||||
---
|
||||
|
||||
### How does this relate to SemVer?
|
||||
|
||||
`fix` type commits should be translated to `PATCH` releases. `feat` type commits should be translated to `MINOR` releases. Commits with `BREAKING CHANGE` in the commits, regardless of type, should be translated to `MAJOR` releases.
|
||||
|
||||
[source](https://omnivore.app/me/https-www-conventionalcommits-org-en-v-1-0-0-18bf36268eb#6876934a-5761-49f8-8905-3153e5d667b7)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||
## [](#summary)Summary
|
||||
|
||||
The Conventional Commits specification is a lightweight convention on top of commit messages. It provides an easy set of rules for creating an explicit commit history; which makes it easier to write automated tools on top of. This convention dovetails with [SemVer](http://semver.org/), by describing the features, fixes, and breaking changes made in commit messages.
|
||||
|
||||
==The commit message should be structured as follows:==
|
||||
|
||||
---
|
||||
|
||||
```fortran
|
||||
<type>[optional scope]: <description>
|
||||
|
||||
[optional body]
|
||||
|
||||
[optional footer(s)]
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
The commit contains the following structural elements, to communicate intent to the consumers of your library:
|
||||
|
||||
1. **fix:** a commit of the _type_ `fix` patches a bug in your codebase (this correlates with [PATCH](http://semver.org/#summary) in Semantic Versioning).
|
||||
2. **feat:** a commit of the _type_ `feat` introduces a new feature to the codebase (this correlates with [MINOR](http://semver.org/#summary) in Semantic Versioning).
|
||||
3. **BREAKING CHANGE:** a commit that has a footer `BREAKING CHANGE:`, or appends a `!` after the type/scope, introduces a breaking API change (correlating with [MAJOR](http://semver.org/#summary) in Semantic Versioning). A BREAKING CHANGE can be part of commits of any _type_.
|
||||
4. _types_ other than `fix:` and `feat:` are allowed, for example [@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional) (based on the [Angular convention](https://github.com/angular/angular/blob/22b96b9/CONTRIBUTING.md#-commit-message-guidelines)) recommends `build:`, `chore:`,`ci:`, `docs:`, `style:`, `refactor:`, `perf:`, `test:`, and others.
|
||||
5. _footers_ other than `BREAKING CHANGE: <description>` may be provided and follow a convention similar to[git trailer format](https://git-scm.com/docs/git-interpret-trailers).
|
||||
|
||||
Additional types are not mandated by the Conventional Commits specification, and have no implicit effect in Semantic Versioning (unless they include a BREAKING CHANGE).A scope may be provided to a commit’s type, to provide additional contextual information and is contained within parenthesis, e.g., `feat(parser): add ability to parse arrays`.
|
||||
|
||||
## [](#examples)Examples
|
||||
|
||||
### [](#commit-message-with-description-and-breaking-change-footer)Commit message with description and breaking change footer
|
||||
|
||||
```routeros
|
||||
feat: allow provided config object to extend other configs
|
||||
|
||||
BREAKING CHANGE: `extends` key in config file is now used for extending other config files
|
||||
|
||||
```
|
||||
|
||||
### [](#commit-message-with--to-draw-attention-to-breaking-change)Commit message with `!` to draw attention to breaking change
|
||||
|
||||
```routeros
|
||||
feat!: send an email to the customer when a product is shipped
|
||||
|
||||
```
|
||||
|
||||
### [](#commit-message-with-scope-and--to-draw-attention-to-breaking-change)Commit message with scope and `!` to draw attention to breaking change
|
||||
|
||||
```routeros
|
||||
feat(api)!: send an email to the customer when a product is shipped
|
||||
|
||||
```
|
||||
|
||||
### [](#commit-message-with-both--and-breaking-change-footer)Commit message with both `!` and BREAKING CHANGE footer
|
||||
|
||||
```crmsh
|
||||
chore!: drop support for Node 6
|
||||
|
||||
BREAKING CHANGE: use JavaScript features not available in Node 6.
|
||||
|
||||
```
|
||||
|
||||
### [](#commit-message-with-no-body)Commit message with no body
|
||||
|
||||
```avrasm
|
||||
docs: correct spelling of CHANGELOG
|
||||
|
||||
```
|
||||
|
||||
### [](#commit-message-with-scope)Commit message with scope
|
||||
|
||||
```stylus
|
||||
feat(lang): add Polish language
|
||||
|
||||
```
|
||||
|
||||
### [](#commit-message-with-multi-paragraph-body-and-multiple-footers)Commit message with multi-paragraph body and multiple footers
|
||||
|
||||
```http
|
||||
fix: prevent racing of requests
|
||||
|
||||
Introduce a request id and a reference to latest request. Dismiss
|
||||
incoming responses other than from latest request.
|
||||
|
||||
Remove timeouts which were used to mitigate the racing issue but are
|
||||
obsolete now.
|
||||
|
||||
Reviewed-by: Z
|
||||
Refs: #123
|
||||
|
||||
```
|
||||
|
||||
## [](#specification)==Specification==
|
||||
|
||||
==The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in== ==[RFC 2119](https://www.ietf.org/rfc/rfc2119.txt)====.==
|
||||
|
||||
1. ==Commits MUST be prefixed with a type, which consists of a noun,== `==feat==`==,== `==fix==`==, etc., followed
|
||||
by the OPTIONAL scope, OPTIONAL== `==!==`==, and REQUIRED terminal colon and space.==
|
||||
2. ==The type== `==feat==` ==MUST be used when a commit adds a new feature to your application or library.==
|
||||
3. ==The type== `==fix==` ==MUST be used when a commit represents a bug fix for your application.==
|
||||
4. ==A scope MAY be provided after a type. A scope MUST consist of a noun describing a
|
||||
section of the codebase surrounded by parenthesis, e.g.,== `==fix====(parser)====:==`
|
||||
5. ==A description MUST immediately follow the colon and space after the type/scope prefix.
|
||||
The description is a short summary of the code changes, e.g.,== _==fix: array parsing issue when multiple spaces were contained in string==_==.==
|
||||
6. ==A longer commit body MAY be provided after the short description, providing additional contextual information about the code changes. The body MUST begin one blank line after the description.==
|
||||
7. ==A commit body is free-form and MAY consist of any number of newline separated paragraphs.==
|
||||
8. ==One or more footers MAY be provided one blank line after the body. Each footer MUST consist of
|
||||
a word token, followed by either a== `==:====<====space====>==` ==or== `==<====space====>====#==` ==separator, followed by a string value (this is inspired by the====[git trailer convention](https://git-scm.com/docs/git-interpret-trailers)====).==
|
||||
9. ==A footer’s token MUST use== `==-==` ==in place of whitespace characters, e.g.,== `==Acked-====by==` ==(this helps differentiate
|
||||
the footer section from a multi-paragraph body). An exception is made for== `==BREAKING== ==CHANGE==`==, which MAY also be used as a token.==
|
||||
10. ==A footer’s value MAY contain spaces and newlines, and parsing MUST terminate when the next valid footer
|
||||
token/separator pair is observed.==
|
||||
11. ==Breaking changes MUST be indicated in the type/scope prefix of a commit, or as an entry in the
|
||||
footer.==
|
||||
12. ==If included as a footer, a breaking change MUST consist of the uppercase text BREAKING CHANGE, followed by a colon, space, and description, e.g.,==_==BREAKING CHANGE: environment variables now take precedence over config files==_==.==
|
||||
13. ==If included in the type/scope prefix, breaking changes MUST be indicated by a==`==!==` ==immediately before the== `==:==`==. If== `==!==` ==is used,== `==BREAKING== ==CHANGE:==` ==MAY be omitted from the footer section,
|
||||
and the commit description SHALL be used to describe the breaking change.==
|
||||
14. ==Types other than== `==feat==` ==and== `==fix==` ==MAY be used in your commit messages, e.g.,== _==docs: update ref docs.==_
|
||||
15. ==The units of information that make up Conventional Commits MUST NOT be treated as case sensitive by implementors, with the exception of BREAKING CHANGE which MUST be uppercase.==
|
||||
16. ==BREAKING-CHANGE MUST be synonymous with BREAKING CHANGE, when used as a token in a footer.==
|
||||
|
||||
## [](#why-use-conventional-commits)Why Use Conventional Commits
|
||||
|
||||
* Automatically generating CHANGELOGs.
|
||||
* Automatically determining a semantic version bump (based on the types of commits landed).
|
||||
* Communicating the nature of changes to teammates, the public, and other stakeholders.
|
||||
* Triggering build and publish processes.
|
||||
* Making it easier for people to contribute to your projects, by allowing them to explore a more structured commit history.
|
||||
|
||||
## [](#faq)FAQ
|
||||
|
||||
### [](#how-should-i-deal-with-commit-messages-in-the-initial-development-phase)How should I deal with commit messages in the initial development phase?
|
||||
|
||||
We recommend that you proceed as if you’ve already released the product. Typically _somebody_, even if it’s your fellow software developers, is using your software. They’ll want to know what’s fixed, what breaks etc.
|
||||
|
||||
### [](#are-the-types-in-the-commit-title-uppercase-or-lowercase)Are the types in the commit title uppercase or lowercase?
|
||||
|
||||
Any casing may be used, but it’s best to be consistent.
|
||||
|
||||
### [](#what-do-i-do-if-the-commit-conforms-to-more-than-one-of-the-commit-types)==What do I do if the commit conforms to more than one of the commit types?==
|
||||
|
||||
==Go back and make multiple commits whenever possible. Part of the benefit of Conventional Commits is its ability to drive us to make more organized commits and PRs.==
|
||||
|
||||
### [](#doesnt-this-discourage-rapid-development-and-fast-iteration)Doesn’t this discourage rapid development and fast iteration?
|
||||
|
||||
It discourages moving fast in a disorganized way. It helps you be able to move fast long term across multiple projects with varied contributors.
|
||||
|
||||
### [](#might-conventional-commits-lead-developers-to-limit-the-type-of-commits-they-make-because-theyll-be-thinking-in-the-types-provided)Might Conventional Commits lead developers to limit the type of commits they make because they’ll be thinking in the types provided?
|
||||
|
||||
Conventional Commits encourages us to make more of certain types of commits such as fixes. Other than that, the flexibility of Conventional Commits allows your team to come up with their own types and change those types over time.
|
||||
|
||||
### [](#how-does-this-relate-to-semver)==How does this relate to SemVer?==
|
||||
|
||||
`==fix==` ==type commits should be translated to== `==PATCH==` ==releases.== `==feat==` ==type commits should be translated to== `==MINOR==` ==releases. Commits with== `==BREAKING== ==CHANGE==` ==in the commits, regardless of type, should be translated to== `==MAJOR==` ==releases.==
|
||||
|
||||
### [](#how-should-i-version-my-extensions-to-the-conventional-commits-specification-eg-jameswomackconventional-commit-spec)How should I version my extensions to the Conventional Commits Specification, e.g. `@jameswomack/conventional-commit-spec`?
|
||||
|
||||
We recommend using SemVer to release your own extensions to this specification (and encourage you to make these extensions!)
|
||||
|
||||
### [](#what-do-i-do-if-i-accidentally-use-the-wrong-commit-type)What do I do if I accidentally use the wrong commit type?
|
||||
|
||||
#### [](#when-you-used-a-type-thats-of-the-spec-but-not-the-correct-type-eg-fix-instead-of-feat)When you used a type that’s of the spec but not the correct type, e.g. `fix` instead of `feat`
|
||||
|
||||
Prior to merging or releasing the mistake, we recommend using `git rebase -i` to edit the commit history. After release, the cleanup will be different according to what tools and processes you use.
|
||||
|
||||
#### [](#when-you-used-a-type-not-of-the-spec-eg-feet-instead-of-feat)When you used a type _not_ of the spec, e.g. `feet` instead of `feat`
|
||||
|
||||
In a worst case scenario, it’s not the end of the world if a commit lands that does not meet the Conventional Commits specification. It simply means that commit will be missed by tools that are based on the spec.
|
||||
|
||||
### [](#do-all-my-contributors-need-to-use-the-conventional-commits-specification)Do all my contributors need to use the Conventional Commits specification?
|
||||
|
||||
No! If you use a squash based workflow on Git lead maintainers can clean up the commit messages as they’re merged—adding no workload to casual committers. A common workflow for this is to have your git system automatically squash commits from a pull request and present a form for the lead maintainer to enter the proper git commit message for the merge.
|
||||
|
||||
### [](#how-does-conventional-commits-handle-revert-commits)How does Conventional Commits handle revert commits?
|
||||
|
||||
Reverting code can be complicated: are you reverting multiple commits? if you revert a feature, should the next release instead be a patch?
|
||||
|
||||
Conventional Commits does not make an explicit effort to define revert behavior. Instead we leave it to tooling authors to use the flexibility of _types_ and _footers_ to develop their logic for handling reverts.
|
||||
|
||||
One recommendation is to use the `revert` type, and a footer that references the commit SHAs that are being reverted:
|
||||
|
||||
```http
|
||||
revert: let us never again speak of the noodle incident
|
||||
|
||||
Refs: 676104e, a215868
|
||||
|
||||
```
|
||||
|
|
@ -1,253 +0,0 @@
|
|||
---
|
||||
id: 1996b6ce-9449-415d-8c18-609ddb9cd580
|
||||
title: |
|
||||
How to Write Better Git Commit Messages – A Step-By-Step Guide
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
date_added: 2023-11-21 12:10:32
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/https-www-freecodecamp-org-news-how-to-write-better-git-commit-m-18bf26ec55f
|
||||
url_original: |
|
||||
https://www.freecodecamp.org/news/how-to-write-better-git-commit-messages/
|
||||
---
|
||||
|
||||
# How to Write Better Git Commit Messages – A Step-By-Step Guide
|
||||
|
||||
## Highlights
|
||||
|
||||
To come up with thoughtful commits, consider the following:
|
||||
|
||||
* Why have I made these changes?
|
||||
* What effect have my changes made?
|
||||
* Why was the change needed?
|
||||
* What are the changes in reference to?
|
||||
|
||||
[source](https://omnivore.app/me/https-www-freecodecamp-org-news-how-to-write-better-git-commit-m-18bf26ec55f#b1693951-0a92-44f4-804d-7c5008bf3113)
|
||||
|
||||
---
|
||||
|
||||
See the differences below:
|
||||
|
||||
1. `git commit -m 'Add margin'`
|
||||
2. `git commit -m 'Add margin to nav items to prevent them from overlapping the logo'`
|
||||
|
||||
[source](https://omnivore.app/me/https-www-freecodecamp-org-news-how-to-write-better-git-commit-m-18bf26ec55f#a3c842a2-18b0-46b9-8131-c37ecd867c19)
|
||||
|
||||
---
|
||||
|
||||
Conventional Commit is a formatting convention that provides a set of rules to formulate a consistent commit message structure like so:
|
||||
|
||||
```fortran
|
||||
[optional scope]:
|
||||
|
||||
[optional body]
|
||||
|
||||
[optional footer(s)]
|
||||
```
|
||||
|
||||
The commit type can include the following:
|
||||
|
||||
* `feat` – a new feature is introduced with the changes
|
||||
* `fix` – a bug fix has occurred
|
||||
* `chore` – changes that do not relate to a fix or feature and don't modify src or test files (for example updating dependencies)
|
||||
* `refactor` – refactored code that neither fixes a bug nor adds a feature
|
||||
* `docs` – updates to documentation such as a the README or other markdown files
|
||||
* `style` – changes that do not affect the meaning of the code, likely related to code formatting such as white-space, missing semi-colons, and so on.
|
||||
* `test` – including new or correcting previous tests
|
||||
* `perf` – performance improvements
|
||||
* `ci` – continuous integration related
|
||||
* `build` – changes that affect the build system or external dependencies
|
||||
* `revert` – reverts a previous commit
|
||||
|
||||
[source](https://omnivore.app/me/https-www-freecodecamp-org-news-how-to-write-better-git-commit-m-18bf26ec55f#f3ea8f19-6480-43ac-a72f-2856ee003fb6)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||

|
||||
|
||||
When first introduced to Git, it's typical for developers to feel uncomfortable with the process.
|
||||
|
||||
You might feel uncertainty when encountering the Git commit message, unsure how to properly summarize the changes you've made and why you've made them. But the earlier in your career you can develop good committing habits, the better.
|
||||
|
||||
Have you ever wondered how you can improve your Git commit messages? This guide outlines steps to elevate your commit messages that you can start implementing today.
|
||||
|
||||
This article assumes you already understand basic Git workflow. If not, I suggest reading through the [Git Handbook](https://guides.github.com/introduction/git-handbook/).
|
||||
|
||||
It is also important to note that you should follow your team's conventions first and foremost. These tips are based on suggestions based upon research and general consensus from the community. But by the end of this article you may have some implementations to suggest that may help your team's workflow.
|
||||
|
||||
> I think git enters a whole other realm the moment you start working in teams -- there are so many cool different flows and ways that people can commit code, share code, and add code to your repo open-source or closed-source-wise. — [Scott Tolinski, Syntax.fm](https://syntax.fm/).
|
||||
|
||||
## Why should you write better commit messages?
|
||||
|
||||
I challenge you to open up a personal project or any repository for that matter and run `git log` to view a list of old commit messages. The vast majority of us who have run through tutorials or made quick fixes will say "Yep... I have absolutely no idea what I meant by 'Fix style' 6 months ago."
|
||||
|
||||
Perhaps you have encountered code in a professional environment where you had no idea what it was doing or meant for. You've been left in the dark without code comments or a traceable history, and even wondering "what are the odds this will break everything if I remove this line?"
|
||||
|
||||
### Back to the Future
|
||||
|
||||
By writing good commits, you are simply future-proofing yourself. You could save yourself and/or coworkers hours of digging around while troubleshooting by providing that helpful description.
|
||||
|
||||
The extra time it takes to write a thoughtful commit message as a letter to your potential future self is extremely worthwhile. On large scale projects, documentation is imperative for maintenance.
|
||||
|
||||
Collaboration and communication are of utmost importance within engineering teams. The Git commit message is a prime example of this. I highly suggest setting up a convention for commit messages on your team if you do not already have one in place.
|
||||
|
||||
## The Anatomy of a Commit Message
|
||||
|
||||
#### Basic:
|
||||
|
||||
`git commit -m <message>`
|
||||
|
||||
#### Detailed:
|
||||
|
||||
`git commit -m <title> -m <description>`
|
||||
|
||||

|
||||
|
||||
## 5 Steps to Write Better Commit Messages
|
||||
|
||||
Let's summarize the suggested guidelines:
|
||||
|
||||
1. Capitalization and Punctuation: Capitalize the first word and do not end in punctuation. If using Conventional Commits, remember to use all lowercase.
|
||||
2. Mood: Use imperative mood in the subject line. Example – `Add fix for dark mode toggle state`. Imperative mood gives the tone you are giving an order or request.
|
||||
3. Type of Commit: Specify the type of commit. It is recommended and can be even more beneficial to have a consistent set of words to describe your changes. Example: Bugfix, Update, Refactor, Bump, and so on. See the section on Conventional Commits below for additional information.
|
||||
4. Length: The first line should ideally be no longer than 50 characters, and the body should be restricted to 72 characters.
|
||||
5. Content: Be direct, try to eliminate filler words and phrases in these sentences (examples: though, maybe, I think, kind of). Think like a journalist.
|
||||
|
||||
### How to Find Your Inner Journalist
|
||||
|
||||
I never quite thought my Journalism minor would benefit my future career as a Software Engineer, but here we are!
|
||||
|
||||
Journalists and writers ask themselves questions to ensure their article is detailed, straightforward, and answers all of the reader's questions.
|
||||
|
||||
When writing an article they look to answer _who_, _what_, _where_, _when_, _why_ and _how._ For committing purposes, it is most important to answer the what and why for our commit messages.
|
||||
|
||||
==To come up with thoughtful commits, consider the following:==
|
||||
|
||||
* ==Why have I made these changes?==
|
||||
* ==What effect have my changes made?==
|
||||
* ==Why was the change needed?==
|
||||
* ==What are the changes in reference to?==
|
||||
|
||||
Assume the reader does not understand what the commit is addressing. They may not have access to the story addressing the detailed background of the change.
|
||||
|
||||
Don't expect the code to be self-explanatory. This is similar to the point above.
|
||||
|
||||
It might seem obvious to you, the programmer, if you're updating something like CSS styles since it is visual. You may have intimate knowledge on why these changes were needed at the time, but it's unlikely you will recall why you did that hundreds of pull requests later.
|
||||
|
||||
Make it clear _why_ that change was made, and note if it may be crucial for the functionality or not.
|
||||
|
||||
==See the differences below:==
|
||||
|
||||
1. `==git== ==commit -m== =='Add margin'==`
|
||||
2. `==git commit -m 'Add margin== ==to== ==nav items== ==to== ==prevent them== ==from== ==overlapping== ==the== ==logo'==`
|
||||
|
||||
It is clear which of these would be more useful to future readers.
|
||||
|
||||
Pretend you're writing an important newsworthy article. Give the headline that will sum up what happened and what is important. Then, provide further details in the body in an organized fashion.
|
||||
|
||||
In filmmaking, it is often quoted "show, don't tell" using visuals as the communication medium compared to a verbal explanation of what is happening.
|
||||
|
||||
In our case, "**tell**, don't \[just\] show" – though we have some visuals at our disposal such as the browser, most of the specifics come from reading the physical code.
|
||||
|
||||
If you're a VSCode user, download the [Git Blame](https://marketplace.visualstudio.com/items?itemName=waderyan.gitblame) extension. This is a prime example of when useful commit messages are helpful to future developers.
|
||||
|
||||
This plugin will list the person who made the change, the date of the changes, as well as the commit message commented inline.
|
||||
|
||||
Imagine how useful this could be in troubleshooting a bug or back-tracing changes made. Other honorable mentions to see Git historical information are [Git History](https://marketplace.visualstudio.com/items?itemName=donjayamanne.githistory) and [GitLens](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens).
|
||||
|
||||

|
||||
|
||||
## Conventional Commits
|
||||
|
||||
Now that we've covered basic commit structure of a good commit message, I'd like to introduce Conventional Commits to help provide some detail on creating solid commit messages.
|
||||
|
||||
At D2iQ, we use Conventional Commit which is a great practice among engineering teams. ==Conventional Commit is a formatting convention that provides a set of rules to formulate a consistent commit message structure like so:==
|
||||
|
||||
```fortran
|
||||
<type>[optional scope]: <description>
|
||||
|
||||
[optional body]
|
||||
|
||||
[optional footer(s)]
|
||||
```
|
||||
|
||||
==The commit type can include the following:==
|
||||
|
||||
* `==feat==` ==– a new feature is introduced with the changes==
|
||||
* `==fix==` ==– a bug fix has occurred==
|
||||
* `==chore==` ==– changes that do not relate to a fix or feature and don't modify src or test files (for example updating dependencies)==
|
||||
* `==ref====actor==` ==– refactored code that neither fixes a bug nor adds a feature==
|
||||
* `==docs==` ==– updates to documentation such as a the README or other markdown files==
|
||||
* `==style==` ==– changes that do not affect the meaning of the code, likely related to code formatting such as white-space, missing semi-colons, and so on.==
|
||||
* `==test==` ==– including new or correcting previous tests==
|
||||
* `==perf==` ==– performance improvements==
|
||||
* `==ci==` ==– continuous integration related==
|
||||
* `==build==` ==– changes that affect the build system or external dependencies==
|
||||
* `==revert==` ==– reverts a previous commit==
|
||||
|
||||
The commit type subject line should be all lowercase with a character limit to encourage succinct descriptions.
|
||||
|
||||
The optional commit body should be used to provide further detail that cannot fit within the character limitations of the subject line description.
|
||||
|
||||
It is also a good location to utilize `BREAKING CHANGE: <description>` to note the reason for a breaking change within the commit.
|
||||
|
||||
The footer is also optional. We use the footer to link the JIRA story that would be closed with these changes for example: `Closes D2IQ-<JIRA #>` .
|
||||
|
||||
#### Full Conventional Commit Example
|
||||
|
||||
```http
|
||||
fix: fix foo to enable bar
|
||||
|
||||
This fixes the broken behavior of the component by doing xyz.
|
||||
|
||||
BREAKING CHANGE
|
||||
Before this fix foo wasn't enabled at all, behavior changes from <old> to <new>
|
||||
|
||||
Closes D2IQ-12345
|
||||
```
|
||||
|
||||
To ensure that these committing conventions remain consistent across developers, commit message linting can be configured before changes are able to be pushed up. [Commitizen](https://commitizen-tools.github.io/commitizen/) is a great tool to enforce standards, sync up semantic versioning, along with other helpful features.
|
||||
|
||||
To aid in adoption of these conventions, it's helpful to include guidelines for commits in a contributing or README markdown file within your projects.
|
||||
|
||||
Conventional Commit works particularly well with semantic versioning (learn more at [SemVer.org](https://semver.org/)) where commit types can update the appropriate version to release. You can also [read more about Conventional Commits here](https://www.conventionalcommits.org/en/v1.0.0/).
|
||||
|
||||
## Commit Message Comparisons
|
||||
|
||||
Review the following messages and see how many of the suggested guidelines they check off in each category.
|
||||
|
||||
#### Good
|
||||
|
||||
* `feat: improve performance with lazy load implementation for images`
|
||||
* `chore: update npm dependency to latest version`
|
||||
* `Fix bug preventing users from submitting the subscribe form`
|
||||
* `Update incorrect client phone number within footer body per client request`
|
||||
|
||||
#### Bad
|
||||
|
||||
* `fixed bug on landing page`
|
||||
* `Changed style`
|
||||
* `oops`
|
||||
* `I think I fixed it this time?`
|
||||
* empty commit messages
|
||||
|
||||
## Conclusion
|
||||
|
||||
Writing good commit messages is an extremely beneficial skill to develop, and it helps you communicate and collaborate with your team. Commits serve as an archive of changes. They can become an ancient manuscript to help us decipher the past, and make reasoned decisions in the future.
|
||||
|
||||
There is an existing set of agreed-upon standards we can follow, but as long as your team agrees upon a convention that is descriptive with future readers in mind, there will undoubtedly be long-term benefits.
|
||||
|
||||
In this article, we've learned some tactics to level up our commit messages. How do you think these techniques can improve your commits?
|
||||
|
||||
I hope you've learned something new, thanks for reading!
|
||||
|
||||
Connect with me on Twitter [@ui\_natalie](https://twitter.com/ui%5Fnatalie).
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
Learn to code for free. freeCodeCamp's open source curriculum has helped more than 40,000 people get jobs as developers. [Get started](https://www.freecodecamp.org/learn/)
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
---
|
||||
id: f5956559-3eb2-4717-93bd-3f3a2f0c5549
|
||||
title: |
|
||||
The Life-Changing Magic of Tidying Up Your To-Do List
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
date_added: 2023-11-21 08:05:01
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/https-todoist-com-inspiration-life-changing-magic-tidying-todois-18bf18e00a2
|
||||
url_original: |
|
||||
https://todoist.com/inspiration/life-changing-magic-tidying-todoist
|
||||
---
|
||||
|
||||
# The Life-Changing Magic of Tidying Up Your To-Do List
|
||||
|
||||
## Notes
|
||||
|
||||
Before you even start looking at your tasks, write down what having a neatly organized and prioritized to-do list would mean for your life. Maybe you want to run a successful business, get in shape, be more present with your family, have closer relationships with friends, or lead a more adventurous life.
|
||||
|
||||
Find a medium that lets you truly envision the details. You can describe it in words, mind map it, draw it out, create a Pinterest board, collect YouTube videos, or brainstorm in whatever form suits you.
|
||||
|
||||
Why do you want to get in shape? The answer might be "to have more energy and feel more confident." Why do you want to have more energy and feel more confident? Maybe the answer is "to be more fully yourself and stop worrying about what other people think of you." Ask yourself "why" 3-5 times for every item in your vision.
|
||||
## Original
|
||||
|
||||
---
|
||||
|
||||
## Other readers also enjoyed...
|
||||
|
||||

|
||||
|
||||
## How to Vanquish Busywork and Spend More Time on What Matters
|
||||
|
||||
These tips for improving your focus and productivity will help you avoid getting sucked into busywork.
|
||||
|
||||
[Read more](https://todoist.com/inspiration/busywork-productivity-focus)
|
||||
* [Productivity](https://todoist.com/inspiration/category/productivity)
|
||||
|
||||

|
||||
|
||||
## How to Ask to Work From Home (With Exact Scripts & Email Templates to Aid Your Negotiation)
|
||||
|
||||
Follow these 9 steps to secure a remote work arrangement even in the most skeptical of organizations
|
||||
|
||||
[Read more](https://todoist.com/inspiration/how-to-ask-to-work-from-home)
|
||||
* [Remote Work](https://todoist.com/inspiration/category/remote-work)
|
||||
|
||||

|
||||
|
||||
## How to Complete Your Own Annual Review
|
||||
|
||||
Reflect on work, health, finances, and more with a personal year in review
|
||||
|
||||
[Read more](https://todoist.com/inspiration/annual-review)
|
||||
* [Goals](https://todoist.com/inspiration/category/goals)
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
---
|
||||
id: 01b3b6c1-27ae-40a4-99fa-d297febc1e7c
|
||||
title: |
|
||||
tbaggery - A Note About Git Commit Messages
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
date_added: 2023-11-21 11:59:10
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/https-tbaggery-com-2008-04-19-a-note-about-git-commit-messages-h-18bf2646727
|
||||
url_original: |
|
||||
https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
|
||||
---
|
||||
|
||||
# tbaggery - A Note About Git Commit Messages
|
||||
|
||||
## Notes
|
||||
|
||||
- Tratar de mantener el limite que muestra Treesitter
|
||||
- Utilizar la primera linea como "el asunto de un correo"
|
||||
- Escribir el cuerpo con una separación de una linea en blanco
|
||||
- Usar lenguaje imperativo, _"Fix bug"_ en vez de _"Fixes bug."_.
|
||||
## Original
|
||||
|
||||
I want to take a moment to elaborate on what makes a well formed commit message. I think the best practices for commit message formatting is one of the little details that makes Git great. Understandably, some of the first commits to rails.git have messages of the really-long-line variety, and I want to expand on why this is a poor practice.
|
||||
|
||||
Here’s a model Git commit message:
|
||||
|
||||
```livecodeserver
|
||||
Capitalized, short (50 chars or less) summary
|
||||
|
||||
More detailed explanatory text, if necessary. Wrap it to about 72
|
||||
characters or so. In some contexts, the first line is treated as the
|
||||
subject of an email and the rest of the text as the body. The blank
|
||||
line separating the summary from the body is critical (unless you omit
|
||||
the body entirely); tools like rebase can get confused if you run the
|
||||
two together.
|
||||
|
||||
Write your commit message in the imperative: "Fix bug" and not "Fixed bug"
|
||||
or "Fixes bug." This convention matches up with commit messages generated
|
||||
by commands like git merge and git revert.
|
||||
|
||||
Further paragraphs come after blank lines.
|
||||
|
||||
- Bullet points are okay, too
|
||||
|
||||
- Typically a hyphen or asterisk is used for the bullet, followed by a
|
||||
single space, with blank lines in between, but conventions vary here
|
||||
|
||||
- Use a hanging indent
|
||||
|
||||
```
|
||||
|
||||
Let’s start with a few of the reasons why wrapping your commit messages to 72 columns is a good thing.
|
||||
|
||||
* `git log` doesn’t do any special special wrapping of the commit messages. With the default pager of `less -S`, this means your paragraphs flow far off the edge of the screen, making them difficult to read. On an 80 column terminal, if we subtract 4 columns for the indent on the left and 4 more for symmetry on the right, we’re left with 72 columns.
|
||||
* `git format-patch --stdout` converts a series of commits to a series of emails, using the messages for the message body. Good email netiquette dictates we wrap our plain text emails such that there’s room for a few levels of nested reply indicators without overflow in an 80 column terminal. (The current rails.git workflow doesn’t include email, but who knows what the future will bring.)
|
||||
|
||||
Vim users can meet this requirement by installing my [vim-git runtime files](http://github.com/tpope/vim-git), or by simply setting the following option in your git commit message file:
|
||||
|
||||
For Textmate, you can adjust the “Wrap Column” option under the view menu, then use `^Q` to rewrap paragraphs (be sure there’s a blank line afterwards to avoid mixing in the comments). Here’s a shell command to add 72 to the menu so you don’t have to drag to select each time:
|
||||
|
||||
```lsl
|
||||
$ defaults write com.macromates.textmate OakWrapColumns '( 40, 72, 78 )'
|
||||
|
||||
```
|
||||
|
||||
More important than the mechanics of formatting the body is the practice of having a subject line. As the example indicates, you should shoot for about 50 characters (though this isn’t a hard maximum) and always, always follow it with a blank line. This first line should be a concise summary of the changes introduced by the commit; if there are any technical details that cannot be expressed in these strict size constraints, put them in the body instead. The subject line is used all over Git, oftentimes in truncated form if too long of a message was used. The following are just a handful of examples of where it ends up:
|
||||
|
||||
* `git log --pretty=oneline` shows a terse history mapping containing the commit id and the summary
|
||||
* `git rebase --interactive` provides the summary for each commit in the editor it invokes
|
||||
* if the config option `merge.summary` is set, the summaries from all merged commits will make their way into the merge commit message
|
||||
* `git shortlog` uses summary lines in the changelog-like output it produces
|
||||
* `git format-patch`, `git send-email`, and related tools use it as the subject for emails
|
||||
* reflogs, a local history accessible with `git reflog` intended to help you recover from stupid mistakes, get a copy of the summary
|
||||
* `gitk` has a column for the summary
|
||||
* GitHub uses the summary in various places in their user interface
|
||||
|
||||
The subject/body distinction may seem unimportant but it’s one of many subtle factors that makes Git history so much more pleasant to work with than Subversion.
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
---
|
||||
id: a82f2e4b-829e-48a5-9e5c-c152860743a7
|
||||
title: |
|
||||
Historias de usuario | Ejemplos y plantilla | Atlassian
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
date_added: 2023-12-24 18:35:22
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/https-www-atlassian-com-es-agile-project-management-user-stories-18c9dc0ecd1
|
||||
url_original: |
|
||||
https://www.atlassian.com/es/agile/project-management/user-stories
|
||||
---
|
||||
|
||||
# Historias de usuario | Ejemplos y plantilla | Atlassian
|
||||
|
||||
## Highlights
|
||||
|
||||
una historia de usuario es una explicación general e informal de una función de software escrita desde la perspectiva del usuario final. Su propósito es articular cómo proporcionará una función de software valor al cliente.
|
||||
|
||||
[source](https://omnivore.app/me/https-www-atlassian-com-es-agile-project-management-user-stories-18c9dc0ecd1#d1988eb3-4939-4bf3-b932-44aad141c065)
|
||||
|
||||
---
|
||||
|
||||
Las historias encajan perfectamente en marcos ágiles como [scrum](https://www.atlassian.com/es/agile/scrum) y [kanban](https://www.atlassian.com/es/agile/kanban). En el scrum, las historias de los usuarios se añaden a los sprints y se van realizando a lo largo del sprint. Los equipos de kanban incorporan las historias de usuario en su backlog y las ejecutan siguiendo su flujo de trabajo.
|
||||
|
||||
[source](https://omnivore.app/me/https-www-atlassian-com-es-agile-project-management-user-stories-18c9dc0ecd1#3e9e29ab-43db-4c8f-b517-c2f3b8892432)
|
||||
|
||||
---
|
||||
|
||||
Las historias de usuario son también los componentes básicos de los marcos ágiles más grandes, como los epics y las iniciativas. Los epics son grandes elementos de trabajo divididos en un conjunto de historias, y varios epics constituyen una iniciativa.
|
||||
|
||||
[source](https://omnivore.app/me/https-www-atlassian-com-es-agile-project-management-user-stories-18c9dc0ecd1#8f41f654-4b72-4789-b848-b46c2d185291)
|
||||
|
||||
---
|
||||
|
||||
## Cómo escribir historias de usuario
|
||||
|
||||
Piensa en lo siguiente cuando escribas historias de usuario:
|
||||
|
||||
* **Definición de “Listo”**: la historia suele estar “lista” cuando el usuario puede completar la tarea descrita, pero debes asegurarte de definir lo que representa completarla.
|
||||
* **Describe tareas o subtareas**: decide qué pasos específicos deben completarse y quién es responsable de cada uno de ellos.
|
||||
* **Perfiles de usuario**: ¿para quién? Si hay varios usuarios finales, considera crear varias historias.
|
||||
* **Pasos ordenados**: escribe una historia para cada paso en un proceso más grande.
|
||||
* **Escucha el feedback**: habla con los usuarios y capta sus problemas o necesidades en lo que dicen. No es necesario tener que estar adivinando las historias cuando puedes obtenerlas de tus clientes.
|
||||
* **Tiempo**: el tiempo es un tema delicado. Muchos equipos de desarrollo evitan hablar sobre el tiempo, y en su lugar confían en sus marcos de trabajo de estimación. Dado que las historias deberían completarse en un sprint, aquellas que puedan necesitar semanas o meses deberían dividirse en historias más pequeñas o considerarse un epic independiente.
|
||||
|
||||
[source](https://omnivore.app/me/https-www-atlassian-com-es-agile-project-management-user-stories-18c9dc0ecd1#536ca974-d30c-4d48-a02f-a9c16c469e01)
|
||||
|
||||
---
|
||||
|
||||
Las historias de usuario suelen expresarse con una frase simple con la siguiente estructura:
|
||||
|
||||
**“Como \[perfil\], \[quiero\] \[para\].”**
|
||||
|
||||
Desglosemos esta estructura:
|
||||
|
||||
* “Como \[perfil\]”: ¿para quién desarrollamos esto? No solo buscamos un puesto, buscamos el perfil de la persona. Max. Nuestro equipo debería comprender quién es Max. Con suerte hemos entrevistado a muchos Max. Comprendemos cómo trabaja esa persona, cómo piensa y cómo se siente. Sentimos empatía por Max.
|
||||
* “Quiere”: aquí describimos su intención, no las funciones que usan. ¿Qué es lo que están intentando lograr realmente? Esta descripción debería realizarse con independencia de las implementaciones; si describes algún elemento de la IU y no el objetivo del usuario, estás cometiendo un error.
|
||||
* “Para”: ¿cómo encaja su deseo inmediato de hacer algo en la perspectiva general? ¿Cuál es el beneficio general que intentan lograr? ¿Cuál es el gran problema que debe resolverse?
|
||||
|
||||
[source](https://omnivore.app/me/https-www-atlassian-com-es-agile-project-management-user-stories-18c9dc0ecd1#74f6051c-6394-4c99-94c9-176857d9caf2)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||
* [DevOps](#)
|
||||
* [Entrega continua](https://www.atlassian.com/es/continuous-delivery)
|
||||
* [Git](https://www.atlassian.com/es/git)
|
||||
* [Agile](https://www.atlassian.com/es/agile)
|
||||
* [Microservicios](https://www.atlassian.com/es/microservices)
|
||||
|
||||
Las historias de usuario son tareas de desarrollo que se suelen expresar como "persona + necesidad + propósito".
|
||||
|
||||
Resumen: _==una historia de usuario es una explicación general e informal de una función de software escrita desde la perspectiva del usuario final. Su propósito es articular cómo proporcionará una función de software valor al cliente.==_
|
||||
|
||||
Es tentador pensar que las historias de usuario son, en pocas palabras, requisitos del sistema de software. Pero no lo son.
|
||||
|
||||
Un componente clave del desarrollo de software ágil es poner a las personas en primer lugar, y las historias de usuarios ponen a los usuarios finales reales en el centro de la conversación. Las historias utilizan un lenguaje no técnico para ofrecer contexto al equipo de desarrollo y sus esfuerzos. Después de leer una historia de usuario, el equipo sabe por qué está compilando lo que está compilando y qué valor crea.
|
||||
|
||||
Las historias de usuario son uno de los componentes centrales de un programa ágil. Ayudan a proporcionar un marco centrado en el usuario para el trabajo diario, lo que impulsa la colaboración y la creatividad y mejora el producto en general.
|
||||
|
||||
## ¿Qué son las historias de usuario ágiles?
|
||||
|
||||
Una historia de usuario es la unidad de trabajo más pequeña en un marco ágil. Es un objetivo final, no una función, expresado desde la perspectiva del usuario del software.
|
||||
|
||||
Una historia de usuario es una explicación general e informal de una función de software escrita desde la perspectiva del usuario final o cliente.
|
||||
|
||||
El propósito de una historia de usuario es articular cómo un elemento de trabajo entregará un valor particular al cliente. Ten en cuenta que los "clientes" no tienen por qué ser usuarios finales externos en el sentido tradicional, también pueden ser clientes internos o colegas dentro de tu organización que dependen de tu equipo.
|
||||
|
||||
Las historias de usuario son unas pocas frases en lenguaje sencillo que describen el resultado deseado. No entran en detalles, ya que los requisitos se añaden más tarde, una vez acordados por el equipo.
|
||||
|
||||
==Las historias encajan perfectamente en marcos ágiles como== ==[scrum](https://www.atlassian.com/es/agile/scrum)== ==y== ==[kanban](https://www.atlassian.com/es/agile/kanban)====. En el scrum, las historias de los usuarios se añaden a los sprints y se van realizando a lo largo del sprint. Los equipos de kanban incorporan las historias de usuario en su backlog y las ejecutan siguiendo su flujo de trabajo.== Es este trabajo sobre las historias de usuario lo que ayuda a los equipos de scrum a mejorar en la [estimación](https://www.atlassian.com/es/agile/project-management/estimation) y planificación de sprints, lo que conduce a un pronóstico más preciso y a una mayor agilidad. Gracias a las historias, los equipos de kanban aprenden a gestionar el trabajo en curso (WIP) y pueden perfeccionar aún más sus flujos de trabajo.
|
||||
|
||||
==Las historias de usuario son también los componentes básicos de los marcos ágiles más grandes, como los epics y las iniciativas. Los epics son grandes elementos de trabajo divididos en un conjunto de historias, y varios epics constituyen una iniciativa.== Estas estructuras más grandes garantizan que el trabajo diario del equipo de desarrollo contribuya a los objetivos de la organización incorporados en los epics y las iniciativas.
|
||||
|
||||
[Más información sobre epics e iniciativas](https://www.atlassian.com/es/agile/project-management/epics-stories-themes)
|
||||
|
||||

|
||||
|
||||
## ¿Por qué crear historias de usuario?
|
||||
|
||||
Para los equipos de desarrollo nuevos en la metodología ágil, las historias de usuario a veces parecen un paso más. ¿Por qué no dividir el gran proyecto ([el epic](https://www.atlassian.com/es/agile/project-management/epics)) en una serie de pasos y seguir adelante? Pero las historias dan al equipo un contexto importante y asocian las tareas con el valor que estas aportan.
|
||||
|
||||
Las historias de usuario tienen varios beneficios clave:
|
||||
|
||||
* **Las historias centran la atención en el usuario.** Una lista de tareas pendientes mantiene al equipo centrado en tareas que deben completarse, pero un conjunto de historias lo mantiene centrado en solucionar problemas para usuarios reales.
|
||||
* **Las historias permiten la colaboración.** Con el objetivo definido, el equipo puede colaborar para decidir cómo ofrecer un mejor servicio al usuario y cumplir con dicho objetivo.
|
||||
* **Las historias impulsan soluciones creativas.** Las historias fomentan que el equipo piense de forma crítica y creativa sobre cómo lograr mejor un objetivo.
|
||||
* **Las historias motivan.** Con cada historia el equipo de desarrollo disfruta de un pequeño reto y una pequeña victoria, lo que aumenta la motivación.
|
||||
|
||||
## Trabajar con historias de usuario
|
||||
|
||||
Una vez que se ha escrito una historia, es hora de integrarla en tu flujo de trabajo. Por lo general, una historia la escribe el propietario del producto, el gestor del producto o el gestor del programa, y la envía para su revisión.
|
||||
|
||||
Durante una reunión de planificación de sprint o iteración, el equipo decide qué historias afrontará en ese sprint. Los equipos discuten los requisitos y la funcionalidad que requiere cada historia de usuario. Esta es una oportunidad para ponerse técnico y creativo en la implementación de la historia por parte del equipo. Una vez acordados, estos requisitos se añaden a la historia.
|
||||
|
||||
Otro paso común en esta reunión es calificar las historias en función de su complejidad o tiempo hasta su finalización. Los equipos usan las tallas de las camisetas, la secuencia de Fibonacci o el Planning Poker para hacer las estimaciones adecuadas. Una historia debe ser de un tamaño que pueda completarse en un sprint; por lo tanto, cuando el equipo establezca las especificaciones de cada historia, se deben asegurar de dividir las historias que superen ese horizonte de finalización.
|
||||
|
||||
## ==Cómo escribir historias de usuario==
|
||||
|
||||
==Piensa en lo siguiente cuando escribas historias de usuario:==
|
||||
|
||||
* **==Definición de “Listo”==**==: la historia suele estar “lista” cuando el usuario puede completar la tarea descrita, pero debes asegurarte de definir lo que representa completarla.==
|
||||
* **==Describe tareas o subtareas==**==: decide qué pasos específicos deben completarse y quién es responsable de cada uno de ellos.==
|
||||
* **==Perfiles de usuario==**==: ¿para quién? Si hay varios usuarios finales, considera crear varias historias.==
|
||||
* **==Pasos ordenados==**==: escribe una historia para cada paso en un proceso más grande.==
|
||||
* **==Escucha el feedback==**==: habla con los usuarios y capta sus problemas o necesidades en lo que dicen. No es necesario tener que estar adivinando las historias cuando puedes obtenerlas de tus clientes.==
|
||||
* **==Tiempo==**==: el tiempo es un tema delicado. Muchos equipos de desarrollo evitan hablar sobre el tiempo, y en su lugar confían en sus marcos de trabajo de estimación. Dado que las historias deberían completarse en un sprint, aquellas que puedan necesitar semanas o meses deberían dividirse en historias más pequeñas o considerarse un epic independiente.==
|
||||
|
||||
Una vez que las historias de usuario estén definidas de forma clara, debes asegurarte de que todo el equipo pueda verlas.
|
||||
|
||||
==Las historias de usuario suelen expresarse con una frase simple con la siguiente estructura:==
|
||||
|
||||
**==“Como [perfil], [quiero] [para].”==**
|
||||
|
||||
==Desglosemos esta estructura:==
|
||||
|
||||
* ==“Como [perfil]”: ¿para quién desarrollamos esto? No solo buscamos un puesto, buscamos el perfil de la persona. Max. Nuestro equipo debería comprender quién es Max. Con suerte hemos entrevistado a muchos Max. Comprendemos cómo trabaja esa persona, cómo piensa y cómo se siente. Sentimos empatía por Max.==
|
||||
* ==“Quiere”: aquí describimos su intención, no las funciones que usan. ¿Qué es lo que están intentando lograr realmente? Esta descripción debería realizarse con independencia de las implementaciones; si describes algún elemento de la IU y no el objetivo del usuario, estás cometiendo un error.==
|
||||
* ==“Para”: ¿cómo encaja su deseo inmediato de hacer algo en la perspectiva general? ¿Cuál es el beneficio general que intentan lograr? ¿Cuál es el gran problema que debe resolverse?==
|
||||
|
||||
Por ejemplo, las historias de usuario pueden tener este aspecto:
|
||||
|
||||
* Como Max, quiero invitar a mis amigos, para que podamos disfrutar de este servicio juntos.
|
||||
* Como Sascha, quiero organizar mi trabajo, para poder sentir que tengo un mayor control.
|
||||
* Como gestor, quiero poder comprender el progreso de mis compañeros, para poder informar sobre nuestros éxitos y fallos.
|
||||
|
||||
Esta estructura no es obligatoria, pero resulta de ayuda para establecer una definición de "hecho". Cuando ese perfil puede alcanzar su valor deseado, la historia está completa. Recomendamos a nuestros equipos definir su propia estructura, y que no se desvíen de ella.
|
||||
|
||||
## Introducción a las historias de usuario ágiles
|
||||
|
||||
Las historias de los usuarios describen el por qué y el qué que hay detrás del trabajo diario de los miembros del equipo de desarrollo; a menudo las historias de usuario se expresan de la siguiente manera: _perfil + necesidad + propósito_. Entender su papel como fuente de verdad para lo que el equipo está entregando, pero también el por qué, es clave para un proceso sin problemas.
|
||||
|
||||
Empieza por evaluar el siguiente gran proyecto o el más apremiante (por ejemplo, un epic). Divídelo en historias de usuario más pequeñas y trabaja con el equipo de desarrollo para mejorarlo. Una vez que tus historias están fuera, donde todo el equipo puede verlas, ya tienes todo listo para empezar a trabajar.
|
||||
|
||||
.jpg?cdnVersion=1373)
|
||||
|
||||
Max Rehkopf
|
||||
|
||||
Como persona caótica que soy, confío en las prácticas de la metodología ágil y en los principios optimizados para poner orden en mi día a día. Me alegra compartir estas lecciones con otras personas a través de los muchos artículos, ponencias y vídeos que hago para Atlassian.
|
||||
|
||||

|
||||
|
||||
tutorial
|
||||
|
||||
#### Cómo crear historias de usuario en Jira Software
|
||||
|
||||
Descubre cómo los equipos pueden utilizar los tiques para realizar un seguimiento del trabajo que debe completarse.
|
||||
|
||||
[Probar el tutorial ](https://www.atlassian.com/es/agile/tutorials/issues)
|
||||
|
||||

|
||||
|
||||
artículo
|
||||
|
||||
#### ¿Qué son los puntos de historia y cómo se estiman?
|
||||
|
||||
Conoce por dentro los secretos de la estimación ágil y los puntos de historia. Una buena estimación ágil permite a los propietarios del producto optimizar sus procesos en términos de eficiencia e impacto.
|
||||
|
||||
[Leer el artículo ](https://www.atlassian.com/es/agile/project-management/estimation)
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
---
|
||||
id: 22bb5f59-fddb-4ab4-89dd-bb28fe723f4f
|
||||
title: |
|
||||
¿Qué son los puntos de historia en la metodología ágil y cómo se estiman?
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
date_added: 2023-12-24 18:36:25
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/https-www-atlassian-com-es-agile-project-management-estimation-18c9dc1e48a
|
||||
url_original: |
|
||||
https://www.atlassian.com/es/agile/project-management/estimation
|
||||
---
|
||||
|
||||
# ¿Qué son los puntos de historia en la metodología ágil y cómo se estiman?
|
||||
|
||||
## Highlights
|
||||
|
||||
Se trata de unidades de medida que permiten expresar una estimación del esfuerzo total que deberá hacer el equipo para implementar íntegramente un elemento del backlog del producto o cualquier otro trabajo. Los equipos asignan puntos de historia en función de la complejidad y del volumen del trabajo, así como del riesgo o de la incertidumbre.
|
||||
|
||||
[source](https://omnivore.app/me/https-www-atlassian-com-es-agile-project-management-estimation-18c9dc1e48a#4ddb962e-4ff6-44fa-8e72-b74db4a9b7a2)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||
* [DevOps](#)
|
||||
* [Entrega continua](https://www.atlassian.com/es/continuous-delivery)
|
||||
* [Git](https://www.atlassian.com/es/git)
|
||||
* [Agile](https://www.atlassian.com/es/agile)
|
||||
* [Microservicios](https://www.atlassian.com/es/microservices)
|
||||
|
||||
## Puntos de historia y estimación
|
||||
|
||||
Una buena estimación ayuda a los propietarios de los productos a optimizar sus procesos en términos de eficiencia e impacto. Por eso es tan importante.
|
||||
|
||||
Hacer estimaciones es complicado. Para los desarrolladores de software, es uno de los aspectos más difíciles de su trabajo, por no decir el más difícil. Conlleva tener en cuenta un montón de factores que ayudan a los propietarios de los productos a tomar decisiones que afectan a todo el equipo, así como a la empresa. Con todo eso en juego, no es de extrañar que todos, desde los desarrolladores hasta la alta dirección, tiendan a perder los estribos sobre este tema. Craso error. La estimación ágil de los puntos de historia no es más que eso, un cálculo: no es un pacto de sangre.
|
||||
|
||||
No es obligatorio trabajar los fines de semana para compensar el tiempo de más que nos lleva un trabajo que habíamos subestimado. Dicho eso, veamos algunas maneras de realizar estimaciones con la mayor precisión posible.
|
||||
|
||||
## Colaboración con el propietario del producto
|
||||
|
||||
En un desarrollo ágil, el [propietario del producto](https://www.atlassian.com/es/agile/product-management) se encarga de priorizar el [backlog](https://www.atlassian.com/es/agile/scrum/backlogs), es decir, la lista ordenada de trabajo que contiene descripciones breves de todas las funciones y correcciones de un producto. Los propietarios del producto capturan los [requisitos](https://www.atlassian.com/es/agile/product-management/requirements) empresariales, pero no siempre entienden los detalles de la implementación. Por ello, una buena estimación puede informar al propietario del producto sobre el nivel de esfuerzo de cada elemento de trabajo, que a su vez sirve para evaluar la prioridad relativa de cada elemento.
|
||||
|
||||
Cuando el equipo de ingeniería empieza su proceso de estimación, normalmente surgen preguntas sobre los requisitos y las historias de usuario. Esto es algo positivo: las preguntas ayudan a todo el equipo a entender el trabajo mejor. Específicamente en el caso de los propietarios de los productos, la división granular de los elementos de trabajo y las estimaciones les ayudan a priorizar todas las áreas del trabajo, incluidas las que pueden estar ocultas. Con las estimaciones del equipo de desarrollo en la mano, no es extraño que un propietario del producto reordene los elementos del backlog.
|
||||
|
||||
## La estimación ágil de los puntos de historia es un trabajo en equipo
|
||||
|
||||
Involucrar a todo el mundo (desarrolladores, diseñadores, testers, deployers... todos) en el equipo es clave. Cada miembro del equipo aporta una perspectiva diferente sobre el producto y el trabajo necesario para entregar una historia de usuario. Por ejemplo, si la gestión de productos quiere hacer algo que parece sencillo, como admitir un nuevo navegador web, el desarrollo y el control de calidad deben dar su opinión también, ya que su experiencia les ha enseñado qué dragones pueden estar al acecho bajo la superficie.
|
||||
|
||||
Asimismo, los cambios de diseño requieren no sólo la aportación del equipo de diseño, sino también la del de desarrollo y la del de QA. Dejar a parte del equipo de producto más amplio fuera del proceso de estimación crea estimaciones de menor calidad, baja la moral porque los contribuyentes clave no se sienten incluidos y compromete la calidad del software.
|
||||
|
||||
No dejes que tu equipo sea víctima de las estimaciones poco precisas. Es un camino seguro al fracaso.
|
||||
|
||||
## Puntos de historia frente a horas
|
||||
|
||||
Los equipos de software tradicionales proporcionan estimaciones en un formato de tiempo concreto: pueden ser días, semanas o meses. Sin embargo, muchos equipos ágiles han decidido pasarse a los puntos de historia. ==Se trata de unidades de medida que permiten expresar una estimación del esfuerzo total que deberá hacer el equipo para implementar íntegramente un elemento del backlog del producto o cualquier otro trabajo. Los equipos asignan puntos de historia en función de la complejidad y del volumen del trabajo, así como del riesgo o de la incertidumbre.== Los valores se asignan para desglosar el trabajo de forma más eficaz en partes más pequeñas. De esta manera, se puede gestionar la incertidumbre. Con el tiempo, esto ayuda a los equipos a ser conscientes de lo que pueden llegar a conseguir en un período de tiempo concreto y genera un sentimiento de consenso y compromiso con la solución. Aunque pueda parecer contradictorio, esta abstracción es realmente útil, ya que obliga al equipo a tomar decisiones más complejas sobre la dificultad del trabajo. A continuación, se indican algunos motivos por los cuales es recomendable utilizar puntos de historia:
|
||||
|
||||
* Las fechas no tienen en cuenta el trabajo no relacionado con el proyecto que inevitablemente surge en nuestro día a día, como correos electrónicos, reuniones y entrevistas en las que un miembro del equipo puede participar.
|
||||
* Las fechas tienen una connotación emocional. La estimación relativa elimina este componente.
|
||||
* Cada equipo estima el trabajo en una escala ligeramente diferente, lo cual significa que su velocidad (medida en puntos) será diferente, como es natural. Asimismo, esto imposibilita que se politiquee usando la velocidad como arma.
|
||||
* Una vez que se llegue a un acuerdo sobre el esfuerzo relativo del valor de cada punto de historia, podrás asignar puntos rápidamente sin que haya lugar a demasiado debate.
|
||||
* Los puntos de historia recompensan a los miembros del equipo por resolver incidencias basándose en la dificultad, y no en el tiempo empleado. De esta forma, los miembros del equipo se mantienen centrados en entregar valor, no en el tiempo dedicado.
|
||||
|
||||
Lamentablemente, los puntos de historia se suelen utilizar de forma incorrecta; por ejemplo, cuando se emplean para juzgar a las personas o para asignar cronogramas y recursos detallados, o bien cuando se confunden con una medida de productividad. La auténtica función de los puntos de historia es que los equipos puedan hacerse una idea del volumen de trabajo y saber qué partes tienen prioridad. Para ver un debate en profundidad sobre los puntos de historia y las prácticas relacionadas con las estimaciones, échale un vistazo a esta [mesa redonda con expertos del sector](https://community.atlassian.com/t5/Agile-articles/Six-experts-sound-off-on-story-points-the-evolution-of-agile/ba-p/1553590). Si quieres más consejos sobre la estimación ágil, sigue leyendo.
|
||||
|
||||
[ ](https://www.youtube.com/watch?v=%5FN5gj9gzOjg)
|
||||
|
||||
## Puntos de historia y póker de planificación
|
||||
|
||||
Los equipos que se están iniciando en los puntos de historia usan un ejercicio llamado [Planning Poker](https://www.atlassian.com/blog/platform/a-brief-overview-of-planning-poker). En Atlassian, el Planning Poker es una práctica habitual en toda la empresa. Los miembros del equipo toman un elemento del backlog, hablan sobre él brevemente y cada uno fórmula mentalmente una estimación. A continuación, todos levantan una tarjeta con el número que refleje su estimación. Si todo el mundo está de acuerdo, ¡estupendo! De lo contrario, dedica algo de tiempo (no mucho, tan solo un par de minutos) para entender el motivo de las distintas estimaciones. Recuerda, sin embargo, que la estimación debe ser una actividad bastante general. Si el equipo se va por las ramas, respira hondo y deriva el debate a un superior.
|
||||
|
||||
**¿Listo para intentarlo?**
|
||||
|
||||
* Instala esta [Aplicación de póker de planificación](https://marketplace.atlassian.com/apps/1212495/planning-poker?hosting=cloud&tab=overview)
|
||||
* Obtén más información sobre el [póker de planificación](https://www.atlassian.com/blog/agile/planning-poker-sane-healthy)
|
||||
|
||||
## Estima con mayor inteligencia, no con mayor esfuerzo
|
||||
|
||||
Ninguna tarea individual debe superar las 16 horas de trabajo. (Si usas puntos de historia, puedes decidir que 20 puntos es el límite superior, por ejemplo). Sencillamente, es demasiado complicado estimar elementos de trabajo individuales de mayor duración con confianza. Esa confianza es especialmente importante para los elementos en la parte superior del backlog. Cuando algo se estima por encima del límite de 16 horas (o 20 puntos) del equipo, será una señal para dividirlo granularmente y volver a estimarlo.
|
||||
|
||||
Para los elementos que se encuentren más abajo en el backlog, basta con una estimación aproximada. Cuando el equipo empiece a trabajar en esos elementos, los requisitos podrían haber cambiado y la aplicación seguramente habrá cambiado también, de modo que las estimaciones no serán tan precisas. No pierdas tiempo estimando trabajo que posiblemente cambiará. Da al propietario del producto una cifra aproximada que pueda utilizar para priorizar la hoja de ruta del producto adecuadamente.
|
||||
|
||||
## Aprende de las estimaciones anteriores
|
||||
|
||||
Las retrospectivas constituyen un momento para que el equipo incorpore ideas de iteraciones anteriores, incluida la precisión de sus estimaciones. Hay muchas herramientas ágiles (como [Jira Software](https://www.atlassian.com/es/software/jira)) que realizan el seguimiento de los puntos de historia, cosa que facilita en gran medida el análisis y el recalibrado de las estimaciones. Prueba, por ejemplo, a comparar las cinco últimas historias de usuario que haya entregado el equipo con un valor de 8 puntos de historia. Estudia si cada uno de estos elementos de trabajo tuvo un nivel de esfuerzo similar. Si no, analizad por qué. Utilizad esta información en los siguientes debates de estimaciones.
|
||||
|
||||
Al igual que [el resto de los aspectos de un proceso ágil](https://www.atlassian.com/es/agile/project-management), la estimación es una cuestión de práctica. Irás mejorando con el tiempo.
|
||||
|
||||

|
||||
|
||||
Dan Radigan
|
||||
|
||||
La metodología ágil ha influido mucho en mí, tanto en el aspecto profesional como en el personal: he aprendido que las mejores experiencias se basan en el modelo ágil, tanto al programar como en la vida real. Mis intereses suelen moverse entre la tecnología, la fotografía y el motociclismo.
|
||||
|
||||

|
||||
|
||||
tutorial
|
||||
|
||||
#### Aprender a usar diagramas de trabajo pendiente con Jira Software
|
||||
|
||||
La guía completa sobre diagramas de evolución en Jira Software. Aprende a supervisar epics y sprints con diagramas de evolución.
|
||||
|
||||
[Probar el tutorial ](https://www.atlassian.com/es/agile/tutorials/burndown-charts)
|
||||
|
||||

|
||||
|
||||
artículo
|
||||
|
||||
#### Cinco métricas ágiles que no odiarás
|
||||
|
||||
¿Cómo usar métricas ágiles? Descubre las gráficas de trabajo pendiente de sprints, epics y publicaciones, los gráficos de control y velocidad, y el diagrama de flujo acumulado.
|
||||
|
||||
[Leer el artículo ](https://www.atlassian.com/es/agile/project-management/metrics)
|
||||
|
|
@ -1,412 +0,0 @@
|
|||
---
|
||||
id: d529f41a-ca28-11ee-97f3-f78c291f6623
|
||||
title: |
|
||||
Debouncing in JavaScript – Explained by Building Auto-Complete Functionality in React
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- RSS
|
||||
date_added: 2024-02-12 20:23:30
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/debouncing-in-java-script-explained-by-building-auto-complete-fu-18da0bc7510
|
||||
url_original: |
|
||||
https://www.freecodecamp.org/news/deboucing-in-react-autocomplete-example/
|
||||
---
|
||||
|
||||
# Debouncing in JavaScript – Explained by Building Auto-Complete Functionality in React
|
||||
|
||||
## Highlights
|
||||
|
||||
Debouncing accepts a function and transforms it in to an updated (debounced) function so that the code inside the original function is executed after a certain period of time.
|
||||
|
||||
[source](https://omnivore.app/me/debouncing-in-java-script-explained-by-building-auto-complete-fu-18da0bc7510#2c8f31bd-f011-49bd-99bc-36192f7fd823)
|
||||
|
||||
---
|
||||
|
||||
function debounce(func, delay) {let timeout=null return (...args) => {if(timeout) clearTimeout(timeout) timeout=setTimeout(() \=> { func(...args) timeout=null }, delay) } }
|
||||
|
||||
[source](https://omnivore.app/me/debouncing-in-java-script-explained-by-building-auto-complete-fu-18da0bc7510#5a57c802-520a-409a-a51c-e554a6ec8bd5)
|
||||
|
||||
---
|
||||
|
||||
const useDebounce = (func, delay) => { let timeout\=null return (...args) => {if(timeout) clearTimeout(timeout)timeout\=setTimeout(() => { func(...args) }, delay) } }export default useDebounce
|
||||
|
||||
[source](https://omnivore.app/me/debouncing-in-java-script-explained-by-building-auto-complete-fu-18da0bc7510#226d8c7b-6900-4b2f-a705-5f5b6e10afc5)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||

|
||||
|
||||
Hi readers, I hope you are doing great! I am back with another tutorial on web development. If you are someone who enjoys developing web apps with JavaScript and React, then this post is for you.
|
||||
|
||||
When you roll out a new app into production, you want to make sure that it's user friendly. A website's performance is a key part of the user experience. Every user wants the website and its contents to load quickly. Each and every second is valuable and could result into a user never visiting your website again.
|
||||
|
||||
In this guide, we are going to understand a very important technique in JavaScript known as debouncing. Then, I will show you how to implement the autocomplete functionality in React with debouncing.
|
||||
|
||||
Now, in order to get the most out of this tutorial, I am assuming you have a basic knowledge of JavaScript. If you need to get started or review, here are a couple resources for you:
|
||||
|
||||
* Learn JavaScript basics – [handbook for beginners](https://www.freecodecamp.org/news/learn-javascript-for-beginners/)
|
||||
* The freeCodeCamp [JavaScript Algorithms and Data Structures certification](https://www.freecodecamp.org/news/learn-javascript-with-new-data-structures-and-algorithms-certification-projects/)
|
||||
|
||||
## **Table of Contents:**
|
||||
|
||||
* [What is Debouncing?](#what-is-debouncing)
|
||||
* [How to Implement Debouncing in JavaScript](#how-to-implement-debouncing-in-javascript)
|
||||
* [Use Case of Debouncing](#use-case-of-debouncing)
|
||||
* [Conclusion](#conclusion)
|
||||
|
||||
## What is Debouncing?
|
||||
|
||||
Debouncing is a strategy used to improve the performance of a feature by controlling the time at which a function should be executed.
|
||||
|
||||
==Debouncing accepts a function and transforms it in to an updated (debounced) function so that the code inside the original function is executed after a certain period of time.==
|
||||
|
||||
If the debounced function is called again within that period, the previous timer is reset and a new timer is started for this function call. The process repeats for each function call.
|
||||
|
||||
An example will help you understand better. Let's take a function `fun()`. We want this function to execute after 500ms.
|
||||
|
||||
```crystal
|
||||
function fun() {
|
||||
console.log('This is a function')
|
||||
}
|
||||
```
|
||||
|
||||
After debouncing, a new function `debouncedFun()` is returned. Now, whenever you call `debouncedFun()`, it will be called after 500ms.
|
||||
|
||||
If you call it again within the next 500ms after first calling it, the previous timer is reset and a new timer is started for the second function call. The process repeats if you keep calling the function within 500ms.
|
||||
|
||||
## How to Implement Debouncing in JavaScript
|
||||
|
||||
Let's understand how to implement debouncing in JavaScript. First, we'll go over our requirements. What behavior do we want from the debounced function?
|
||||
|
||||
* Delay the function execution by a certain time, `delay`.
|
||||
* Reset the timer if the function is called again.
|
||||
|
||||
To debounce a function, we'll have a separate function that accepts the function reference and the delay as parameters, and returns a debounced function.
|
||||
|
||||
```ada
|
||||
function debounce(func, delay) {
|
||||
return () => {} // return debounced function
|
||||
}
|
||||
```
|
||||
|
||||
This function will only be called once to return a debounced function and that, in turn, will be used in the subsequent code.
|
||||
|
||||
To delay a function by some milliseconds, we can simply use the `setTimeout` function in JavaScript.
|
||||
|
||||
```arcade
|
||||
function debounce(func, delay) {
|
||||
return () => {
|
||||
setTimeout(() => {
|
||||
func()
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This delays the function call by `delay` milliseconds. But this is incomplete as it only satisfies the first requirement. How do we achieve the second behaviour?
|
||||
|
||||
Let's create a variable `timeout` and assign it to the return value of `setTimeout` method. The `setTimeout` method returns a unique identifier to the timeout, which is held by `timeout` variable.
|
||||
|
||||
```javascript
|
||||
function debounce(func, delay) {
|
||||
let timeout=null
|
||||
return () => {
|
||||
timeout=setTimeout(() => {
|
||||
func()
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Each time you invoke `setTimeout`, the ID is different. We will use this `timeout` variable to reset the timer.
|
||||
|
||||
But how do we get access to `timeout` from outside the `debounce()` method? As mentioned before, `debounce()` is only used once to return a debounced function. This, in turn, performs the debouncing logic.
|
||||
|
||||
Then, how does the debounced function have access to `timeout` even if it is used outside the `debounce()` function? Well, it uses a concept called closure.
|
||||
|
||||
### What's a closure in JavaScript?
|
||||
|
||||
In JavaScript, an inner function always has access to the local variables of the outer function. In our case, the inner function has access to `timeout` that has function level scope in the `debounce()` method.
|
||||
|
||||
But when the outer function returns this inner function, the inner function still holds a reference to the local variables of the outer function long after the outer function has finished execution. This is the concept of a closure.
|
||||
|
||||
Let's understand closures with an example.
|
||||
|
||||
```javascript
|
||||
function outerFunction() {
|
||||
const x = 5;
|
||||
|
||||
return () => {
|
||||
console.log(x);
|
||||
}
|
||||
}
|
||||
|
||||
const inner = outerFunction();
|
||||
|
||||
inner(); // prints 5
|
||||
|
||||
// console.log(x) Throws reference error
|
||||
```
|
||||
|
||||
Here, if we call `inner()`, the code runs without any errors and prints 5\. But, if we try to access `x` directly, JavaScript throws a reference error.
|
||||
|
||||

|
||||
|
||||
JavaScript Reference Error
|
||||
|
||||
Here, `inner()` closes over `x` and only this function can use the variable and no one other one can. We cannot access the variable explicitly.
|
||||
|
||||
You can check out [this beginner-friendly tutorial](https://www.freecodecamp.org/news/closures-in-javascript/) to learn more about closures.
|
||||
|
||||
### Back to Debouncing
|
||||
|
||||
Let's get back to where we left off:
|
||||
|
||||
```javascript
|
||||
function debounce(func, delay) {
|
||||
let timeout=null
|
||||
return () => {
|
||||
timeout=setTimeout(() => {
|
||||
func()
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here, JavaScript uses a closure to hold access to `timeout` every time we use the debounced function.
|
||||
|
||||
Let's use this to our advantage. Since `debouncedFun()` has access to the same `timeout` variable in every function call, we can add a condition to check whether a previous timeout exists. We can simply do this with a null check, `if(timeout !== null)` or `if(timeout)`.
|
||||
|
||||
Then, we use the `clearTimeout()` method to cancel the previous timeout, thus resetting the timer.
|
||||
|
||||
Add the following statement before starting a new timeout:
|
||||
|
||||
```lisp
|
||||
if(timeout)
|
||||
clearTimeout(timeout)
|
||||
|
||||
```
|
||||
|
||||
Once the timeout is reset, a new timeout is started for the current function call, whose ID is then assigned to `timeout`. The process is repeated for the subsequent function calls who have access to the same `timeout` due to closures.
|
||||
|
||||
```javascript
|
||||
function debounce(func, delay) {
|
||||
let timeout=null
|
||||
return () => {
|
||||
if(timeout) clearTimeout(timeout)
|
||||
|
||||
timeout=setTimeout(() => {
|
||||
func()
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
With this, we have satisfied our second requirement – that is, resetting the timer and starting a new one. It's time to use this debounced function.
|
||||
|
||||
Let's pass `fun()` to the `debounce()` method with a delay of 500ms.
|
||||
|
||||
```kotlin
|
||||
const debouncedFun = debounce(fun, 500)
|
||||
|
||||
```
|
||||
|
||||
`debouncedFun()` is basically `fun()` with debouncing behaviour. Let's call this function at different time intervals to test our functionality.
|
||||
|
||||
```stylus
|
||||
debouncedFun()
|
||||
|
||||
setTimeout(debouncedFun, 300)
|
||||
|
||||
setTimeout(debouncedFun, 900)
|
||||
```
|
||||
|
||||
The first function call is made instantly. The other two are made after 300ms and 900ms respectively. Can you guess the output?
|
||||
|
||||
The code prints `This is a function` two times. Let's understand why. Here, after the first call is made, `fun()` is scheduled to execute after 500ms. But the second one is made in 300ms which resets the timer and starts a new one.
|
||||
|
||||
500ms have passed and the `fun()` method executes. Then, at 900ms, another function call is made. This again executes `fun()` after 500ms.
|
||||
|
||||
There is still a small improvement we should make. Our logic does not consider function arguments. Let's replace `fun()` with `fun(a, b)`.
|
||||
|
||||
```javascript
|
||||
function fun(a, b) {
|
||||
console.log(`This is a function with arguments ${a} and ${b}`)
|
||||
}
|
||||
```
|
||||
|
||||
To incorporate arguments while debouncing, return a debounced function that accepts arguments.
|
||||
|
||||
```javascript
|
||||
function debounce(func, delay) {
|
||||
let timeout=null
|
||||
return (...args) => {
|
||||
if(timeout) clearTimeout(timeout)
|
||||
|
||||
timeout=setTimeout(() => {
|
||||
func(...args)
|
||||
timeout=null
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
By using the spread operator, any arguments passed to the debounced function will be stored as an array in the `args` variable. Then, spread out the same `args` array to call the actual function with the arguments passed.
|
||||
|
||||
```kotlin
|
||||
const debouncedFun=debounce(fun, 500)
|
||||
debouncedFun(2,3)
|
||||
```
|
||||
|
||||
The above code prints `This is a function with arguments 2 and 3` after 500ms.
|
||||
|
||||
## Use Case of Debouncing
|
||||
|
||||
Let's see how debouncing is used in practical applications. The most common use case of debouncing is the autocomplete functionality. You must have seen many websites where you type into an input field and it shows a list of results as you type them.
|
||||
|
||||
Here's an example from Google Search:
|
||||
|
||||

|
||||
|
||||
Google Search Autocomplete after typing in "Top 10"
|
||||
|
||||
Google search shows the most recent and commonly searched terms. The information is mostly fetched from the browser cache. But, several websites make API calls to backend server to fetch the data from a database.
|
||||
|
||||
This can easily be implemented by adding an `onchange` event to the `input` element and implementing the fetch logic in the event handler. But there's a slight issue with this.
|
||||
|
||||
Consider the following example:
|
||||
|
||||

|
||||
|
||||
API Request made for each input value
|
||||
|
||||
When I type the word _absolute_, an API request is made every time the value of the input field changes. We are making 8 API requests in very few milliseconds which puts a lot of load on the backend server and could cause performance issues.
|
||||
|
||||
Ideally, we want to show the auto-complete results some time after the user has finished typing. Here, the user has typed _absolute_ in one go, so instead of showing results every time the input changes, we could show them once the user has finished typing – that is, we could add some delay between the input change and the results being displayed.
|
||||
|
||||
So, we only make the API calls when the user finishes typing their word and not on every input change. This reduces the number of API calls and improves performance. We can achieve this behavior with debouncing.
|
||||
|
||||
Let's understand how to implement the autocomplete functionality in React.
|
||||
|
||||
### Auto-complete example
|
||||
|
||||
Use `create-react-app` (or a modern build tool like Vite) to create the project. Remove the existing boilerplate code. There is no need to install any additional dependencies. Run `npm start` command to start the project. You can find the complete code on [GitHub](https://github.com/KunalN25/react-debouncing).
|
||||
|
||||
I have set up a Node server to fetch data for the app. You can find it in the Git repo. Run the `node server` command to start it. I am not going to show the Node.js code as it's out of the scope of this tutorial.
|
||||
|
||||
Let's get started with the implementation. We will write a simple autocomplete functionality. The app should show a list of cities that contain an input string typed by the user.
|
||||
|
||||
#### App Component
|
||||
|
||||
We'll first need an `input` element to accept user input and a _results container_ for the search results. Attach an event handler to the `input` element which is an `async` function since it will include the fetching logic.
|
||||
|
||||
```javascript
|
||||
function App() {
|
||||
const [data, setData] = useState(null)
|
||||
|
||||
const loadData = async (event) => {
|
||||
|
||||
}
|
||||
return (
|
||||
<div className="App">
|
||||
<input type="text" onChange={(e) => loadData(e)}/>
|
||||
{data && data.length !== 0 &&
|
||||
<div className="results-container">
|
||||
{data.map(item => (
|
||||
<div key={item.id} className="result-item">
|
||||
<p> {item.city} </p>
|
||||
</div>
|
||||
))}
|
||||
</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
The data will be stored as state and the results will only be shown if the data is non-empty. I'll skip over the CSS for this tutorial, you can find it in the [Git Repo](https://github.com/KunalN25/react-debouncing).
|
||||
|
||||
#### Event Handler
|
||||
|
||||
The `loadData()` function fetches our data and stores the response as state.
|
||||
|
||||
```cs
|
||||
const loadData = async (event) => {
|
||||
const value=event.target.value
|
||||
if(value === '') {
|
||||
setData(null)
|
||||
return
|
||||
}
|
||||
const response=await fetch(`http://localhost:8000/data/${value}`)
|
||||
const res=await response.json()
|
||||
setData(res)
|
||||
}
|
||||
```
|
||||
|
||||
If no value is entered, simply exit the function. Else, make the request to the node server endpoint. This function is called every time the input changes, so we will debounce this function.
|
||||
|
||||
#### Debounce Implementation using a Custom Hook
|
||||
|
||||
We will write the debouncing logic inside a custom hook. The advantage of custom hooks is that you can re-use the same logic throughout your application. It is highly advisable to do so.
|
||||
|
||||
Create a new folder `custom-hooks` and inside it, create a file `useDebounce.js`. As explained before, the `useDebounce()` method should take a function and delay as parameters and return the debounced function.
|
||||
|
||||
```routeros
|
||||
const useDebounce = (func, delay) => {
|
||||
let timeout=null
|
||||
|
||||
return (...args) => {
|
||||
if(timeout) clearTimeout(timeout)
|
||||
|
||||
timeout=setTimeout(() => {
|
||||
func(...args)
|
||||
}, delay)
|
||||
}
|
||||
}
|
||||
|
||||
export default useDebounce
|
||||
```
|
||||
|
||||
Now, inside the app component, call this method once to get `loadDataDebounced()`.
|
||||
|
||||
```angelscript
|
||||
const loadDataDebounced = useDebounce(loadData, 400)
|
||||
|
||||
```
|
||||
|
||||
We'll use this new method as the event handler for the `input` element.
|
||||
|
||||
```reasonml
|
||||
<input type="text" onChange={(e) => loadDataDebounced(e)}/>
|
||||
|
||||
```
|
||||
|
||||
#### Output
|
||||
|
||||
Enter a search string inside the `input` element to test our code.
|
||||
|
||||

|
||||
|
||||
On-screen output
|
||||
|
||||

|
||||
|
||||
As you can see in the Network tab, only one request is getting sent instead of three. This makes the search performance much better.
|
||||
|
||||
## Conclusion
|
||||
|
||||
In this tutorial, you learned what debouncing is and how it is implemented. Debouncing delays the function execution by a certain time and resets the previous timer if the function is called again.
|
||||
|
||||
Debouncing uses the important concept of closures. I took a slight detour from the implementation to explain what closure is. It can be a confusing concept for beginners, so take your time understanding it. Closures allow you to work with local variables even after a function has finished execution.
|
||||
|
||||
After that, I showed you a popular use case of debouncing, the auto-complete functionality. The performance of the feature can be improved with debouncing. I also showed you how to implement auto-complete in React and use debouncing with custom hooks. I hope this helps you in future projects.
|
||||
|
||||
If you are unable to understand the content or find the explanation unsatisfactory, let me know. New ideas are always appreciated! Feel free to connect with me on Twitter. Till then, Goodbye!
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
Learn to code for free. freeCodeCamp's open source curriculum has helped more than 40,000 people get jobs as developers. [Get started](https://www.freecodecamp.org/learn/)
|
||||
|
|
@ -1,764 +0,0 @@
|
|||
---
|
||||
id: c4ab379e-cc84-11ee-b3d0-afc69cc1061d
|
||||
title: |
|
||||
React Optimization Techniques to Help You Write More Performant Code
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- RSS
|
||||
date_added: 2024-02-15 21:57:28
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/react-optimization-techniques-to-help-you-write-more-performant--18db03268c2
|
||||
url_original: |
|
||||
https://www.freecodecamp.org/news/react-performance-optimization-techniques/
|
||||
---
|
||||
|
||||
# React Optimization Techniques to Help You Write More Performant Code
|
||||
|
||||
## Highlights
|
||||
|
||||
List visualization, or windowing, involves rendering only the items currently visible on the screen.
|
||||
|
||||
[source](https://omnivore.app/me/react-optimization-techniques-to-help-you-write-more-performant--18db03268c2#9fb355ed-811d-44e7-aa61-12c0b18db7e2)
|
||||
|
||||
---
|
||||
|
||||
Lazy loading allows you to defer or delay the loading of images until they are needed or visible to the user instead of loading all the images on page load.
|
||||
|
||||
[source](https://omnivore.app/me/react-optimization-techniques-to-help-you-write-more-performant--18db03268c2#f9c0a23a-9d66-4a80-bb4c-a4f2806ed1aa)
|
||||
|
||||
---
|
||||
|
||||
Another approach is to use the [intersection observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection%5FObserver%5FAPI), which is a web API that allows you to detect when an element enters or exists the viewport efficiently.
|
||||
|
||||
[source](https://omnivore.app/me/react-optimization-techniques-to-help-you-write-more-performant--18db03268c2#a44706c9-5cce-4765-ac78-77efdca40a30)
|
||||
|
||||
---
|
||||
|
||||
Memoization in React is a technique used to optimize the performance of functional components by caching the results of expensive computations or function calls. It's particularly useful when dealing with computationally intensive or frequently called functions with the same input values, as it helps avoid redundant calculations and improves the overall efficiency of the application.
|
||||
|
||||
[source](https://omnivore.app/me/react-optimization-techniques-to-help-you-write-more-performant--18db03268c2#051f1544-65d2-4eae-87c6-bb7f226c4fa7)
|
||||
|
||||
---
|
||||
|
||||
Below is an example on how to use the `React.memo` with a functional component:
|
||||
|
||||
```javascript
|
||||
import React from 'react';
|
||||
|
||||
const Post = ({ signedIn, post }) => {
|
||||
console.log('Rendering Post');
|
||||
return (
|
||||
|
||||
{post.title}
|
||||
{post.content}
|
||||
{signedIn && Edit Post}
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(Post);
|
||||
|
||||
```
|
||||
|
||||
In the code above, `Post` (functional component) depends on the `signedIn` and `post` props. By wrapping it with `React.memo()`, React will only re-render the `Post` component if either `signedIn` or `post` changes.
|
||||
|
||||
> [!note]
|
||||
> You can memoize complete components to prevent re-renders if the props doesn't change, this use `React.memo()`, not the `useMemo()` hook
|
||||
|
||||
[source](https://omnivore.app/me/react-optimization-techniques-to-help-you-write-more-performant--18db03268c2#f0735f25-7bdf-4562-84cb-6f93f3a0b5a6)
|
||||
|
||||
---
|
||||
|
||||
The `useMemo()` hook optimizes performance by memoizing the result of a function call or an expensive computation. It caches the result and recalculates it only when the input values change.
|
||||
|
||||
[source](https://omnivore.app/me/react-optimization-techniques-to-help-you-write-more-performant--18db03268c2#360c5717-251f-40d7-9dd8-24bccb26a59b)
|
||||
|
||||
---
|
||||
|
||||
The `useCallback()` hook in React is used to memoize a function instead of memoizing the function result. It is particularly useful when passing events as props to child components to prevent unnecessary re-renders.
|
||||
|
||||
`useCallback()` memoizes the function, ensuring it remains the same across re-renders as long as the dependencies haven't changed.
|
||||
|
||||
This is especially beneficial when passing functions as props to child components, preventing unnecessary re-renders.
|
||||
|
||||
[source](https://omnivore.app/me/react-optimization-techniques-to-help-you-write-more-performant--18db03268c2#c01f0766-7401-44ae-9888-ee1da6d10ca7)
|
||||
|
||||
---
|
||||
|
||||
It's important to note that `useCallback` should be used sparingly and only for performance-critical parts of your application. Overusing `useCallback` can actually lead to worse performance due to the overhead of memoization itself. Always measure the performance impact before and after using `useCallback` to ensure it's having the desired effect.
|
||||
|
||||
[source](https://omnivore.app/me/react-optimization-techniques-to-help-you-write-more-performant--18db03268c2#4292a582-b6cb-44e9-baff-3be6a127ed14)
|
||||
|
||||
---
|
||||
|
||||
Throttling in React is a technique used to limit the number of times a function or an event handler is invoked. It ensures that the function is called at a specified interval, preventing it from being executed too frequently.
|
||||
|
||||
[source](https://omnivore.app/me/react-optimization-techniques-to-help-you-write-more-performant--18db03268c2#5e73fc50-7717-449d-a27f-f3bb87fd100f)
|
||||
|
||||
---
|
||||
|
||||
Debouncing, on the other hand, is also used to limit the number of times a function or an event handler is invoked. It ensures that the function is called only after a certain period of inactivity. Debouncing allows you to postpone the function call until the user has finished typing or a specific time has elapsed since the last event.
|
||||
|
||||
[source](https://omnivore.app/me/react-optimization-techniques-to-help-you-write-more-performant--18db03268c2#2926578f-0a36-4acc-8c03-5d740981bb04)
|
||||
|
||||
---
|
||||
|
||||
// Debounce function to delay the searchAPI call const debounce = (func, delay) => {let timeoutId;return function (...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() \=> { func(...args); }, delay); }; };
|
||||
|
||||
[source](https://omnivore.app/me/react-optimization-techniques-to-help-you-write-more-performant--18db03268c2#131255d3-029e-43c9-8c5e-0489e786e425)
|
||||
|
||||
---
|
||||
|
||||
Code splitting in React is a technique used to split a large JavaScript bundle into smaller, manageable chunks. It helps improve performance by loading only the necessary code for a specific part of an application rather than loading the entire bundle upfront.
|
||||
|
||||
[source](https://omnivore.app/me/react-optimization-techniques-to-help-you-write-more-performant--18db03268c2#9f66f0bf-2185-499a-a4f1-591e5af60182)
|
||||
|
||||
---
|
||||
|
||||
In this example, `AsyncComponent` is a component that uses `lazy` and `Suspense` to perform code splitting. The `DynamicComponent` is dynamically imported using the import() syntax.
|
||||
|
||||
[source](https://omnivore.app/me/react-optimization-techniques-to-help-you-write-more-performant--18db03268c2#aff44dd9-50f2-4ad2-8f93-d52e6ab0988d)
|
||||
|
||||
---
|
||||
|
||||
Web Workers serve as a solution to alleviate the burden on the main thread. They allow the execution of scripts in the background on a separate thread, distinct from the main JavaScript thread.
|
||||
|
||||
[source](https://omnivore.app/me/react-optimization-techniques-to-help-you-write-more-performant--18db03268c2#16416227-0870-4503-a67d-76418223953a)
|
||||
|
||||
---
|
||||
|
||||
The `useTransition` hook in React plays a pivotal role in improving the performance of applications by allowing the marking of state updates as non-blocking transitions. This capability enables React to defer rendering for these updates, preventing UI blocking and enhancing overall responsiveness.
|
||||
|
||||
[source](https://omnivore.app/me/react-optimization-techniques-to-help-you-write-more-performant--18db03268c2#0622edf4-fa98-4848-aeee-174fa1cbde22)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||

|
||||
|
||||
Performance optimization is a critical aspect of developing web applications. Users expect applications to load quickly and respond to their interactions smoothly.
|
||||
|
||||
In the React ecosystem, performance optimization techniques can significantly enhance the user experience by reducing load times and improving responsiveness.
|
||||
|
||||
In this article, we will discuss eight effective techniques for optimizing the performance of your React application.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Why Performance Optimization is Important](#why-performance-optimization-is-important)
|
||||
2. [List visualization](#list-visualization)
|
||||
3. [Lazy Loading Images](#lazy-loading-images)
|
||||
4. [Memoization](#memoization)
|
||||
5. [Throttling and Debouncing Events](#throttling-and-debouncing-events)
|
||||
6. [Code Splitting](#code-splitting)
|
||||
7. [React Fragments](#react-fragments)
|
||||
8. [Web Workers](#web-workers)
|
||||
9. [UseTransition Hook](#usetransition-hook)
|
||||
10. [Conclusion](#conclusion)
|
||||
|
||||
## Why Performance Optimization is Important
|
||||
|
||||
Optimizing the performance of your React application is crucial for several reasons:
|
||||
|
||||
* **Better User Experience:** A slow-loading or laggy application can lead to a poor user experience, negatively impacting your business. Users expect fast and responsive interactions, and performance optimization helps deliver that.
|
||||
* **Improved SEO:** Search engines like Google consider page load times and overall performance when ranking websites. A well-optimized application will rank higher in search results, making it more visible to potential users.
|
||||
* **Reduced Bounce Rates:** If your application takes too long to load or respond, users will likely leave and never return. By optimizing performance, you can reduce bounce rates and increase engagement.
|
||||
* **Cost Savings** A performant application requires fewer resources (like servers and memory) to handle the same workload. This means lower hosting costs and reduced infrastructure needs.
|
||||
* **Competitive Advantage:** A fast and efficient application sets you apart from competitors whose applications may be slower or less optimized. According to research by [Portent](https://www.portent.com/blog/analytics/research-site-speed-hurting-everyones-revenue.htm), a website that loads within one second has a conversion rate five times higher than a site that takes ten seconds to load. Therefore, ensuring your React applications perform well is crucial for retaining users and maintaining a competitive edge.
|
||||
|
||||
## 8 React Performance Optimization Techniques
|
||||
|
||||
Below are eight React performance optimization techniques you can use to speed up your applications.
|
||||
|
||||
### List visualization
|
||||
|
||||
==List visualization, or windowing, involves rendering only the items currently visible on the screen.==
|
||||
|
||||
When dealing with a large number of items in a list, rendering all the items at once can lead to slow performance and consume a significant amount of memory. List virtualization tackles this issue by rendering only a subset of the list items currently visible within the view, which conserves resources as the users scroll through the list.
|
||||
|
||||
The virtualization technique dynamically replaces rendered items with new ones, keeping the visible portion of the list updated and responsive. It efficiently allows you to render large lists or tabular data by only rendering the visible portion, recycling components as needed, and optimizing scroll performance.
|
||||
|
||||
There are different approaches to implementing list visualization in React, and one is using a popular library called [React Virtualized](https://www.npmjs.com/package/react-virtualized).
|
||||
|
||||
To install `react-virtualized`, you can use the following command:
|
||||
|
||||
```sql
|
||||
npm install react-virtualized --save
|
||||
```
|
||||
|
||||
After installing `react-virtualized`, you can import the required components and styles. Below is an example of how to use the `List` component to create a virtualized list:
|
||||
|
||||
```javascript
|
||||
import React from 'react';
|
||||
import { List } from 'react-virtualized';
|
||||
import 'react-virtualized/styles.css'; // Import styles
|
||||
|
||||
// Your list data
|
||||
const list = Array(5000).fill().map((_, index) => ({
|
||||
id: index,
|
||||
name: `Item ${index}`
|
||||
}));
|
||||
|
||||
// Function to render each row
|
||||
function rowRenderer({ index, key, style }) {
|
||||
return (
|
||||
<div key={key} style={style}>
|
||||
{list[index].name}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Main component
|
||||
function MyVirtualizedList() {
|
||||
return (
|
||||
<List
|
||||
width={300}
|
||||
height={300}
|
||||
rowCount={list.length}
|
||||
rowHeight={20}
|
||||
rowRenderer={rowRenderer}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default MyVirtualizedList;
|
||||
|
||||
```
|
||||
|
||||
In this example, `List` is the main component provided by `react-virtualized`. The `rowRenderer` function defines how each row should be rendered. The `width`, `height`, `rowCount`, `rowHeight`, and `rowRenderer` props are essential for configuring the list's behavior and appearance.
|
||||
|
||||
React applications can handle massive amounts of data by leveraging list virtualization without sacrificing performance or user experience.
|
||||
|
||||
### Lazy Loading Images
|
||||
|
||||
Similar to the list virtualization technique, lazy loading images prevents the creation of unnecessary DOM nodes, thereby boosting performance. Lazy loading allows you to defer or delay the loading of images until they are needed or visible to the user instead of loading all the images on page load.
|
||||
|
||||
The concept behind lazy loading is to initiate the load of a placeholder or a small low-resolution version of the image, typically a small-sized thumbnail or a blurred placeholder. As the user scrolls or interacts with the page, the actual image is loaded dynamically, replacing the placeholder when the user enters the viewport or when it becomes visible.
|
||||
|
||||
Lazy loading in React can be achieved using various libraries and techniques. One of the popular libraries is the [react-lazyload](https://www.npmjs.com/package/react-lazyload).
|
||||
|
||||
To install `react-lazyload`, you can use the following command:
|
||||
|
||||
```sql
|
||||
npm install --save react-lazyload
|
||||
```
|
||||
|
||||
Below is an example of a simple React component that uses `react-lazyload` to implement lazy loading for images:
|
||||
|
||||
```javascript
|
||||
import React from 'react';
|
||||
import LazyLoad from 'react-lazyload';
|
||||
|
||||
const MyLazyLoadedImage = ({ src, alt }) => {
|
||||
return (
|
||||
<LazyLoad height={200} offset={100}>
|
||||
{/* The height and offset props control when the image should start loading */}
|
||||
<img src={src} alt={alt} />
|
||||
</LazyLoad>
|
||||
);
|
||||
};
|
||||
|
||||
export default MyLazyLoadedImage;
|
||||
|
||||
```
|
||||
|
||||
In this example, `MyLazyLoadedImage` uses the `LazyLoad` component from `react-lazyload`. The `height` prop specifies the height of the placeholder, and the `offset` prop determines how far below the viewport the placeholder should start loading.
|
||||
|
||||
==Another approach is to use the== ==[intersection observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection%5FObserver%5FAPI)====, which is a web API that allows you to detect when an element enters or exists the viewport efficiently.== Here's how we can use the Intersection Observer API along with the `useEffect` hook in React:
|
||||
|
||||
```javascript
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
|
||||
const IntersectionLazyLoad = ({ src, alt }) => {
|
||||
const imageRef = useRef();
|
||||
|
||||
useEffect(() => {
|
||||
const options = {
|
||||
root: null, // Use the viewport as the root
|
||||
rootMargin: '0px', // No margin around the root
|
||||
threshold: 0.5, // 50% of the image should be visible
|
||||
};
|
||||
|
||||
const observer = new IntersectionObserver(handleIntersection, options);
|
||||
|
||||
if (imageRef.current) {
|
||||
observer.observe(imageRef.current);
|
||||
}
|
||||
|
||||
return () => {
|
||||
// Cleanup the observer when the component is unmounted
|
||||
observer.disconnect();
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleIntersection = (entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
// Load the image when it becomes visible
|
||||
imageRef.current.src = src;
|
||||
imageRef.current.alt = alt;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return <img ref={imageRef} style={{ height: '200px' }} alt="Placeholder" />;
|
||||
};
|
||||
|
||||
export default IntersectionLazyLoad;
|
||||
|
||||
```
|
||||
|
||||
In this example, `IntersectionLazyLoad` uses the Intersection Observer API to determine when the image becomes visible in the viewport.
|
||||
|
||||
By utilizing this API along with React `useEffect` hook, you can implement your custom lazy loading solution for images in React.
|
||||
|
||||
### Memoization
|
||||
|
||||
Memoization in React is a technique used to optimize the performance of functional components by caching the results of expensive computations or function calls. It's particularly useful when dealing with computationally intensive or frequently called functions with the same input values, as it helps avoid redundant calculations and improves the overall efficiency of the application.
|
||||
|
||||
In React, there are three techniques for memoization: `React.memo()`, `useMemo(),` and `useCallback().` Let's delve into the details for each:
|
||||
|
||||
#### How to use `React.memo()`
|
||||
|
||||
This higher-order component wraps purely functional components to prevent re-rendering if the received props remain unchanged.
|
||||
|
||||
By using `React.memo()`, the rendering result is cached based on props. If the props haven't changed since the last render, React reuses the previously rendered result instead of redoing the rendering process. This saves time and resources.
|
||||
|
||||
==Below is an example on how to use the== `==React====.====memo==` ==with a functional component:==
|
||||
|
||||
```javascript
|
||||
import React from 'react';
|
||||
|
||||
const Post = ({ signedIn, post }) => {
|
||||
console.log('Rendering Post');
|
||||
return (
|
||||
<div>
|
||||
<h2>{post.title}</h2>
|
||||
<p>{post.content}</p>
|
||||
{signedIn && <button>Edit Post</button>}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(Post);
|
||||
|
||||
```
|
||||
|
||||
==In the code above,== `==Post==` ==(functional component) depends on the== `==signedIn==` ==and== `==post==` ==props. By wrapping it with== `==React====.====memo====()==`==, React will only re-render the== `==Post==` ==component if either== `==signedIn==` ==or== `==post==` ==changes.==
|
||||
|
||||
You can now use the memoized component like any other component in your application:
|
||||
|
||||
```javascript
|
||||
import React, { useState } from 'react';
|
||||
import Post from './Post';
|
||||
|
||||
const App = () => {
|
||||
const [signedIn, setSignedIn] = useState(false);
|
||||
const post = { title: 'Hello World', content: 'Welcome to my blog!' };
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Post signedIn={signedIn} post={post} />
|
||||
<button onClick={() => setSignedIn(!signedIn)}>
|
||||
Toggle Signed In
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
|
||||
```
|
||||
|
||||
When you click the `Toggle Signed In` button, it will toggle the `signedIn` state. Since `Post` is wrapped with `React.memo()`, it will only re-render when the `signedIn` prop changes, thus saving rendering time and resources
|
||||
|
||||
#### How to use `useMemo()`
|
||||
|
||||
The `useMemo()` hook optimizes performance by memoizing the result of a function call or an expensive computation. It caches the result and recalculates it only when the input values change. Below is an example on how to use the `useMemo` hook in functional component:
|
||||
|
||||
```javascript
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
function App() {
|
||||
const [count, setCount] = React.useState(0);
|
||||
const [otherState, setOtherState] = React.useState('');
|
||||
|
||||
const expensiveComputation = (num) => {
|
||||
let i = 0;
|
||||
while (i < 1000000000) i++;
|
||||
return num * num;
|
||||
};
|
||||
|
||||
const memoizedValue = useMemo(() => expensiveComputation(count), [count]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>Count: {count}</p>
|
||||
<p>Square: {memoizedValue}</p>
|
||||
<button onClick={() => setCount(count + 1)}>Increase Count</button>
|
||||
<input type="text" onChange={(e) => setOtherState(e.target.value)} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
||||
```
|
||||
|
||||
In the code above, the `expensiveComputation` function simulates a resource-intensive operation, like squaring a number.
|
||||
|
||||
The `useMemo` hook is utilized to cache the result of this computation. The memoized value, stored in `memoizedValue`, is only recalculated when the `count` state changes, as `count` is specified as a dependency in the `useMemo` dependency array. Consequently, clicking the `Increase Count` button increments the `count` state, triggering a recalculation of the memoized value.
|
||||
|
||||
Conversely, changing the `otherState` via the input field does not prompt a recalculation, as `otherState` is not included in the `useMemo` dependency array.
|
||||
|
||||
#### How to use `useCallback()`
|
||||
|
||||
The `useCallback()` hook in React is used to memoize a function instead of memoizing the function result. It is particularly useful when passing events as props to child components to prevent unnecessary re-renders.
|
||||
|
||||
`useCallback()` memoizes the function, ensuring it remains the same across re-renders as long as the dependencies haven't changed.
|
||||
|
||||
This is especially beneficial when passing functions as props to child components, preventing unnecessary re-renders. It is often used with `React.memo()` to ensure child components do not re-render when unnecessary. Below is an exmple of how to use the `useCallback()` hook:
|
||||
|
||||
```javascript
|
||||
import React, { useState, useCallback } from 'react';
|
||||
|
||||
const ParentComponent = () => {
|
||||
const [count, setCount] = useState(0);
|
||||
|
||||
// Define a function that increments the count state
|
||||
const incrementCount = () => {
|
||||
setCount(count + 1);
|
||||
};
|
||||
|
||||
// Memoize the incrementCount function using useCallback
|
||||
const memoizedIncrement = useCallback(incrementCount, [count]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>Count: {count}</p>
|
||||
<ChildComponent onIncrement={memoizedIncrement} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ChildComponent = React.memo(({ onIncrement }) => {
|
||||
console.log('Child component rendered');
|
||||
return (
|
||||
<div>
|
||||
<button onClick={onIncrement}>Increment Count</button>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default ParentComponent;
|
||||
|
||||
```
|
||||
|
||||
In the code above, the `ParentComponent` is responsible for managing a state variable named `count` and introduces a function called `incrementCount`, which handles the incrementation of the count. Utilizing the `useCallback` hook, the `incrementCount` function is memoized, guaranteeing its stability across renders unless any of its dependencies, in this case, `count`, undergo changes.
|
||||
|
||||
On the other hand, the `ChildComponent` is a component nested within the parent. It receives the memoized `onIncrement` function from the parent as a prop.
|
||||
|
||||
To optimize performance and prevent unnecessary re-renders when the props remain constant, the `ChildComponent` is wrapped with `React.memo()`. This ensures that the child component will only re-render when its props, specifically the memoized function, experience changes, contributing to a more efficient rendering process.
|
||||
|
||||
==It's important to note that== `==useCallback==` ==should be used sparingly and only for performance-critical parts of your application. Overusing== `==useCallback==` ==can actually lead to worse performance due to the overhead of memoization itself. Always measure the performance impact before and after using== `==useCallback==` ==to ensure it's having the desired effect.==
|
||||
|
||||
### Throttling and Debouncing Events
|
||||
|
||||
Throttling in React is a technique used to limit the number of times a function or an event handler is invoked. It ensures that the function is called at a specified interval, preventing it from being executed too frequently.
|
||||
|
||||
Throttling allows you to control the rate at which the function is called by setting up a minimum time interval between each function invocation. If the function is called multiple times within that interval, only the first invocation is executed, and subsequent invocations are ignored until the interval elapses
|
||||
|
||||
Now, let's illustrate throttling with a code example. First, without t==hrottling:==
|
||||
|
||||
```javascript
|
||||
// Without throttling, this function will be called every time the event is triggered
|
||||
function handleResize() {
|
||||
console.log('Window resized');
|
||||
}
|
||||
|
||||
window.addEventListener('resize', handleResize);
|
||||
|
||||
```
|
||||
|
||||
==With throttling, we can limit how often the== `==handleResize==` ==function is called:==
|
||||
|
||||
```actionscript
|
||||
// Throttling function
|
||||
function throttle(func, delay) {
|
||||
let lastCall = 0;
|
||||
return function(...args) {
|
||||
const now = new Date().getTime();
|
||||
if (now - lastCall < delay) {
|
||||
return;
|
||||
}
|
||||
lastCall = now;
|
||||
func(...args);
|
||||
};
|
||||
}
|
||||
|
||||
// Throttled event handler
|
||||
const throttledHandleResize = throttle(handleResize, 200);
|
||||
|
||||
window.addEventListener('resize', throttledHandleResize)
|
||||
|
||||
```
|
||||
|
||||
In this example, the `throttle` function wraps `handleResize` and ensures it's not called more often than every 200 milliseconds. If the `resize` event fires more frequently than that, the `handleResize` function will only be executed once every 200 milliseconds, reducing the potential for performance issues caused by rapid, repeated function calls
|
||||
|
||||
==Debouncing, on the other hand, is also used to limit the number of times a function or an event handler is invoked. It ensures that the function is called only after a certain period of inactivity. Debouncing allows you to postpone the function call until the user has finished typing or a specific time has elapsed since the last event.==
|
||||
|
||||
For example, imagine you have a search input field and want to trigger a search API request only when the user has finished typing for a certain duration, like `300ms`.
|
||||
|
||||
With debouncing, the search function will only be invoked after the user stops typing for` 300ms`. If the user continues typing within that interval, the function call will be delayed until the pause occurs. Without debouncing, the function will be called for every keystroke, potentially leading to excessive function calls and unnecessary computation. let's demonstrate with a code example:
|
||||
|
||||
```javascript
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
const SearchComponent = () => {
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
|
||||
// Function to simulate a search API request
|
||||
const searchAPI = (query) => {
|
||||
console.log(`Searching for: ${query}`);
|
||||
// In a real application, you would make an API request here
|
||||
};
|
||||
|
||||
// Debounce function to delay the searchAPI call
|
||||
const debounce = (func, delay) => {
|
||||
let timeoutId;
|
||||
return function (...args) {
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = setTimeout(() => {
|
||||
func(...args);
|
||||
}, delay);
|
||||
};
|
||||
};
|
||||
|
||||
// Debounced search function
|
||||
const debouncedSearch = debounce(searchAPI, 300);
|
||||
|
||||
// useEffect to watch for changes in searchTerm and trigger debouncedSearch
|
||||
useEffect(() => {
|
||||
debouncedSearch(searchTerm);
|
||||
}, [searchTerm, debouncedSearch]);
|
||||
|
||||
// Event handler for the search input
|
||||
const handleSearchChange = (event) => {
|
||||
setSearchTerm(event.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<label htmlFor="search">Search:</label>
|
||||
<input
|
||||
type="text"
|
||||
id="search"
|
||||
value={searchTerm}
|
||||
onChange={handleSearchChange}
|
||||
placeholder="Type to search..."
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SearchComponent;
|
||||
|
||||
```
|
||||
|
||||
With this setup, the `searchAPI` function will only be invoked after the user stops typing for 300ms, preventing excessive API requests and improving the overall performance of the search functionality.
|
||||
|
||||
### Code Splitting
|
||||
|
||||
Code splitting in React is a technique used to split a large JavaScript bundle into smaller, manageable chunks. It helps improve performance by loading only the necessary code for a specific part of an application rather than loading the entire bundle upfront.
|
||||
|
||||
When you develop a new React application, all your JavaScript code is typically bundled together into a single file. This file contains all the components, libraries, and other code required for your application to function. But as your application grows, the bundle size can become quite large, resulting in slow initial load times for your users.
|
||||
|
||||
Code splitting ==allows you to divide a single bundle into multiple chunks, which can be loaded selectively based on the current needs of your application. Instead of downloading the entire bundle upfront,== only the necessary code is fetched and executed when a user visits a particular page or triggers a specific action.
|
||||
|
||||
Below is a basic example of code splitting:
|
||||
|
||||
```javascript
|
||||
// AsyncComponent.js
|
||||
import React, { lazy, Suspense } from 'react';
|
||||
|
||||
const DynamicComponent = lazy(() => import('./DynamicComponent'));
|
||||
|
||||
const AsyncComponent = () => (
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<DynamicComponent />
|
||||
</Suspense>
|
||||
);
|
||||
|
||||
export default AsyncComponent;
|
||||
|
||||
|
||||
// DynamicComponent.js
|
||||
import React from 'react';
|
||||
|
||||
const DynamicComponent = () => (
|
||||
<div>
|
||||
<p>This is a dynamically loaded component!</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default DynamicComponent;
|
||||
|
||||
```
|
||||
|
||||
==In this example,== `==AsyncComponent==` ==is a component that uses== `==lazy==` ==and== `==Suspense==` ==to perform code splitting. The== `==DynamicComponent==` ==is dynamically imported using the import() syntax.==
|
||||
|
||||
When `AsyncComponent` is rendered, React will load `DynamicComponent` only when it is needed, reducing the initial bundle size and improving the application's performance. The fallback prop in Suspense specifies what to render while waiting for the dynamic import to resolve, providing a better user experience during the loading process.
|
||||
|
||||
### React Fragments
|
||||
|
||||
React Fragments are a feature introduced in [React 16.2](https://legacy.reactjs.org/blog/2017/11/28/react-v16.2.0-fragment-support.html) that allows you to group multiple elements together without adding an additional DOM node. This is particularly useful when you need to return multiple elements from a component's render method, but you don't want to introduce unnecessary DOM elements that could affect the layout or styles of your application.
|
||||
|
||||
Imagine you are arranging books on a bookshelf. Each book represents a React component, and the bookshelf represents the DOM.
|
||||
|
||||
Normally, if you have multiple books, you might want to group them together under a category label (analogous to a DOM element like a `<div>`). But sometimes you just want to place the books side by side without a label because the label itself doesn't hold any value and only takes up physical space.
|
||||
|
||||
React Fragments are like the option to arrange the books without a label, saving space and making the arrangement cleaner.
|
||||
|
||||
Here's an example of how to utilize React fragments:
|
||||
|
||||
```actionscript
|
||||
import React from 'react';
|
||||
|
||||
function BookShelf() {
|
||||
return (
|
||||
<>
|
||||
<Book title="React for Beginners" />
|
||||
<Book title="Mastering Redux" />
|
||||
<Book title="JavaScript Essentials" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Book({ title }) {
|
||||
return <li>{title}</li>;
|
||||
}
|
||||
|
||||
export default BookShelf;
|
||||
|
||||
```
|
||||
|
||||
In this example, the `BookShelf` component returns a list of `Book` components without wrapping them in a `<div>` or other unnecessary DOM element. Instead, it uses the `<>` shorthand syntax for React Fragments.
|
||||
|
||||
This results in a cleaner DOM structure, which can improve the performance of your React application by reducing the number of elements that the browser has to process and render. Using fragments can also reduce unnecessary markup and contribute to a cleaner and more efficient render tree.
|
||||
|
||||
### Web Workers
|
||||
|
||||
JavaScript operates as a single-threaded application designed to handle synchronous tasks.
|
||||
|
||||
When a web page is being rendered, JavaScript executes multiple tasks, including manipulating DOM elements, managing UI interactions, handling API response data, and enabling CSS animations, all within a single thread. Despite its efficiency in managing these tasks, executing them in a single thread can sometimes lead to performance bottlenecks.
|
||||
|
||||
==Web Workers serve as a solution to alleviate the burden on the main thread. They allow the execution of scripts in the background on a separate thread, distinct from the main JavaScript thread.==
|
||||
|
||||
This separation enables the handling of computationally intensive tasks, execution of long-running operations, or management of tasks that might otherwise block the main thread. By doing so, Web Workers contribute to maintaining user interface responsiveness and overall application performance.
|
||||
|
||||
To use web worker in React, create a new JavaScript file that will contain the code for the worker thread:
|
||||
|
||||
```php
|
||||
// worker.js
|
||||
self.onmessage = function(event) {
|
||||
var input = event.data;
|
||||
var result = performHeavyComputation(input);
|
||||
postMessage(result);
|
||||
};
|
||||
|
||||
function performHeavyComputation(input) {
|
||||
// Insert your heavy computation logic here
|
||||
return input * 2; // Just a placeholder operation
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In your React component, instantiate the Web Worker and establish a communication channel with it:
|
||||
|
||||
```javascript
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
|
||||
function MyComponent() {
|
||||
const workerRef = useRef();
|
||||
|
||||
useEffect(() => {
|
||||
// Initialize the worker
|
||||
workerRef.current = new Worker('path-to-your-worker-file.js');
|
||||
|
||||
// Handle incoming messages from the worker
|
||||
workerRef.current.onmessage = (event) => {
|
||||
console.log('Message received from worker:', event.data);
|
||||
};
|
||||
|
||||
// Cleanup the worker when the component unmounts
|
||||
return () => {
|
||||
workerRef.current.terminate();
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Function to send a message to the worker
|
||||
const sendMessageToWorker = (message) => {
|
||||
workerRef.current.postMessage(message);
|
||||
};
|
||||
|
||||
// Rest of your component
|
||||
return (
|
||||
// ...
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
In this example, a Web Worker is initialized in the `useEffect` hook and stored in a ref for future use. Messages from the worker are handled with an `onmessage` event listener, and the worker is terminated when the component is unmounted to clean up resources. The `sendMessageToWorker` function demonstrates how to communicate with the worker using `postMessage`
|
||||
|
||||
### UseTransition Hook
|
||||
|
||||
==The== `==useTransition==` ==hook in React plays a pivotal role in improving the performance of applications by allowing the marking of state updates as non-blocking transitions. This capability enables React to defer rendering for these updates, preventing UI blocking and enhancing overall responsiveness.==
|
||||
|
||||
When utilizing `useTransition,` state updates within the `startTransition` function are treated as low-priority transitions, susceptible to interruption by higher-priority state updates. So if a high-priority update occurs during a transition, React may prioritize finishing the high-priority update, interrupting the ongoing transition.
|
||||
|
||||
This non-blocking transition mechanism is valuable in preventing UI blocking during intensive operations such as data fetching or large-scale updates. By deferring the rendering of components associated with transition updates, React ensures that the user interface remains responsive even in scenarios where the UI might otherwise become unresponsive.
|
||||
|
||||
This example demonstrates the use of `useTransition` in a React component:
|
||||
|
||||
```javascript
|
||||
import React, { useState, useTransition } from 'react';
|
||||
|
||||
function MyComponent() {
|
||||
const [state, setState] = useState(initialState);
|
||||
const [isPending, startTransition] = useTransition();
|
||||
|
||||
function handleClick() {
|
||||
startTransition(() => {
|
||||
setState(newState); // This state update is marked as a transition
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Your component JSX */}
|
||||
<button onClick={handleClick}>Update State</button>
|
||||
{isPending && <div>Loading...</div>}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
This example showcases how React avoids blocking the UI during transitions triggered by user actions, allowing for interruption if higher-priority state updates are detected.
|
||||
|
||||
Note that `useTransition` is part of the Concurrent Mode API, introduced in React 18 and later versions. As a powerful tool for altering the default behavior of state updates, make sure you use it with care, considering the specific implications of deferring rendering within the context of your application.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Optimizing the performance of a React application involves a combination of strategies, from the fundamental understanding of React's diffing algorithm to leveraging built-in features and third-party tools.
|
||||
|
||||
By applying these techniques judiciously, you can create applications that are not only visually appealing but also performant, leading to a better overall user experience.
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
Learn to code for free. freeCodeCamp's open source curriculum has helped more than 40,000 people get jobs as developers. [Get started](https://www.freecodecamp.org/learn/)
|
||||
|
|
@ -1,192 +0,0 @@
|
|||
---
|
||||
id: a6c66f79-fd38-4d76-b05a-9c5d7dc9119f
|
||||
title: |
|
||||
Git Tips 1: Oldies but Goodies
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- dotfiles
|
||||
- git
|
||||
date_added: 2024-02-18 11:02:02
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/git-tips-1-oldies-but-goodies-18dbc861eae
|
||||
url_original: |
|
||||
https://blog.gitbutler.com/git-tips-1-theres-a-git-config-for-that/
|
||||
---
|
||||
|
||||
# Git Tips 1: Oldies but Goodies
|
||||
|
||||
## Highlights
|
||||
|
||||
But there is also `--system` (which probably none of you have used) which writes it to a system-wide config file and `--local` (the default) that writes it to `.git/config` in whatever project you're currently in.
|
||||
|
||||
[source](https://omnivore.app/me/git-tips-1-oldies-but-goodies-18dbc861eae#4994949d-07aa-4baf-8b39-7b003dcc4487)
|
||||
|
||||
---
|
||||
|
||||
However, there is a _secret fourth_ place that Git can look. If you add to your global config something that looks like this:
|
||||
|
||||
```cs
|
||||
[includeIf "gitdir:~/projects/oss"]
|
||||
path = ~/.gitconfig-oss
|
||||
```
|
||||
|
||||
Then Git will look in the `~/.gitconfig-oss` files for values _only if_ the project you are currently working in matches `~/projects/oss` . So, you could have a "work" directory and have work-specific values there (company email address, gpg signing key, etc) and an "oss" directory with values for your open source projects, etc.
|
||||
|
||||
[source](https://omnivore.app/me/git-tips-1-oldies-but-goodies-18dbc861eae#400065ab-ea9d-4b03-80c8-aec98b643a27)
|
||||
|
||||
---
|
||||
|
||||
One thing that is really not great about using blame in GUI tools is that the CLI has much more powerful tooling for finding something closer to the real story behind your code.
|
||||
|
||||
[source](https://omnivore.app/me/git-tips-1-oldies-but-goodies-18dbc861eae#60d94f0c-f71c-4e30-83d7-ed9d4ac07265)
|
||||
|
||||
---
|
||||
|
||||
Finally, if you're rebasing or cherry-picking a lot and you've ever run into the same conflict more than once, you can turn on a feature where Git memorizes the conflict and the resolution to it. If it ever sees that same conflict again, it will _automatically_ re-solve it for you.
|
||||
|
||||
You can easily turn it on with the config setting `rerere.enabled` and you can further ask it to automatically stage it for you with `rerere.autoUpdate`
|
||||
|
||||
```routeros
|
||||
$ git config --global rerere.enabled true
|
||||
$ git config --global rerere.autoUpdate true
|
||||
```
|
||||
|
||||
[source](https://omnivore.app/me/git-tips-1-oldies-but-goodies-18dbc861eae#7e50290a-231d-4e52-9518-2e8ad22503cf)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||

|
||||
|
||||
Do you know some of the cool stuff in Git that's been around for a while? All the magical -L and -C options in the Git world? Let's find out!
|
||||
|
||||
For the first in our [short series of Git tips](https://blog.gitbutler.com/git-tips-and-tricks/), I wanted to start with stuff that's been around for a while, but it still seems like a lot of people don't know about or don't know how to use.
|
||||
|
||||
None of this is new, but I find them useful and they're arguably a little obscure. I'm just going to cover:
|
||||
|
||||
* [Conditional Configs](#conditional-configs)
|
||||
* [Git Blame and Log with Line Ranges](#git-blame-and-log-with-line-ranges)
|
||||
* [Git Blame with Following](https://blog.gitbutler.com/git-tips-1-theres-a-git-config-for-that/git-blame-with-following)
|
||||
* [Word Diff](#word-diff)
|
||||
* [Resolution Reuse](#reuse-recorded-resolution)
|
||||
|
||||
Let's dig in!
|
||||
|
||||
## Conditional Configs
|
||||
|
||||
Many of you probably know this, but Git has a cool little key/value store called `git config` which will check in three places for values to use when it's running various commands.
|
||||
|
||||
Every Git user will have [probably been told](https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup?ref=blog.gitbutler.com) to run something like this when they first set up:
|
||||
|
||||
```routeros
|
||||
$ git config --global user.name "John Doe"
|
||||
$ git config --global user.email johndoe@example.com
|
||||
```
|
||||
|
||||
That adds the `user.name` value to your `~.gitconfig` file. ==But there is also== `==--system==` ==(which probably none of you have used) which writes it to a system-wide config file and== `==--local==` ==(the default) that writes it to== `==.git/====config==` ==in whatever project you're currently in.==
|
||||
|
||||
When Git looks for a value, it will look in that order - local, global, system - for a definition.
|
||||
|
||||
==However, there is a== _==secret fourth==_ ==place that Git can look. If you add to your global config something that looks like this:==
|
||||
|
||||
```cs
|
||||
[includeIf "gitdir:~/projects/oss"]
|
||||
path = ~/.gitconfig-oss
|
||||
```
|
||||
|
||||
==Then Git will look in the== `==~/.gitconfig-oss==` ==files for values== _==only if==_ ==the project you are currently working in matches== `==~====/projects/====oss==` ==. So, you could have a "work" directory and have work-specific values there (company email address, gpg signing key, etc) and an "oss" directory with values for your open source projects, etc.==
|
||||
|
||||
But `gitdir` is not the only filter you can use. You can also put _branch name_ specific values as a include filter with `onbranch` or you can only include config files if the project you are currently in has a remote matching a specific URL with `hasconfig:remote.*.url` . So like if you have GitHub org specific keys or something.
|
||||
|
||||
Check out [the docs](https://git-scm.com/docs/git-config?ref=blog.gitbutler.com#%5Fincludes) for more.
|
||||
|
||||
## Git Blame and Log with Line Ranges
|
||||
|
||||
There are a couple of interesting options that you can use with `git blame` that most people don't know about and nearly none of the existing GUIs implement.
|
||||
|
||||
One is the line range option, `-L`. A lot of times, if you're running blame on the command line, you just page the whole file and find the part you're looking for. However, if you want to just display a subsection of your file, you can give it a line range, like `git blame -L 28,43 path/to/file`
|
||||
|
||||

|
||||
|
||||
git blame -L
|
||||
|
||||
You can also use a semi-strange `:` syntax to give Git a pattern to find the beginning of a block and only blame that block. So in this same situation, I can get the same result by running `git blame -L :'class LocalFile' gitbutler-ui/src/lib/vbranches/types.ts`
|
||||
|
||||
Typically you can use a function name or something for that string.
|
||||
|
||||
The _other_ thing you can do to see similar information in a different way, is to run `git log` with similar options. This will give you all the commits filtered to those that last touched this region of the file. So for example, `git log -L28,43:gitbutler-ui/src/lib/vbranches/types.ts` will give you something like this:
|
||||
|
||||

|
||||
|
||||
So instead of being ordered by lines, it sort of gathers all the commits that are shown in the blame and then shows you those commits with code that modified that block in each commit. Basically the same data, but in a different format, more like a story of how that code was put together.
|
||||
|
||||
## Git Blame with Following
|
||||
|
||||
==One thing that is really not great about using blame in GUI tools is that the CLI has much more powerful tooling for finding something closer to the real story behind your code.==
|
||||
|
||||
There are many scenarios where this is really valuable. The first is ignoring whitespace changes. Some of the GUIs do that, but not all of them. So if you go and implement a `prettierrc` file, BLAM, now you're the owner of tons of lines of code. The `git blame -w` option will ignore these types of whitespace changes.
|
||||
|
||||
The other great option is `-C` which will look for code movement between files in a commit. So if you refactor a function from one file to another, the normal `git blame` will simply show you as the author in the new file, but the `-C` option will follow that movement and show the last person to actually change those lines of code. Either of these scenarios could be what you're looking for, but I would argue that more often it's the latter.
|
||||
|
||||
If you want Git to try even harder (look for movement in multiple commits or in _all_ of your commits) you can pass `-C` up to three times.
|
||||
|
||||
Also, your GUI _does not_ do this (most likely, I can't speak for all of them).
|
||||
|
||||
So, let's look at the VS Code GitLens blame output of the previous example:
|
||||
|
||||

|
||||
|
||||
git blame in GitLens VS Code plugin
|
||||
|
||||
Ok, looks good. Kiril wrote most of this code it appears. Let's now look at the same block with `git blame -w -C -C -C`
|
||||
|
||||

|
||||
|
||||
git blame -C -C -C
|
||||
|
||||
Now we can see that Git has followed this hunk of code from file to file over the course of multiple renames.
|
||||
|
||||
Also, Kiril only really owns a few lines of code, Mattias actually wrote big hunks of it. If we want to know about those lines, it's much better to ask Mattias rather than Kiril, as our GUI blame would suggest.
|
||||
|
||||
## Word Diff
|
||||
|
||||
This is incredibly minor, and some GUIs have nice versions of this (I find GitHub's better than what I'm about to show you, since it subtly does both) but if you _ARE_ running `git diff` on the command line and there is a line change where something small changed within it, you can change Git's default format to word-based rather than line based with the `--word-diff` option.
|
||||
|
||||

|
||||
|
||||
normal, line-based git diff
|
||||
|
||||

|
||||
|
||||
super cool git diff --word-diff
|
||||
|
||||
## Reuse Recorded Resolution
|
||||
|
||||
==Finally, if you're rebasing or cherry-picking a lot and you've ever run into the same conflict more than once, you can turn on a feature where Git memorizes the conflict and the resolution to it. If it ever sees that same conflict again, it will== _==automatically==_ ==re-solve it for you.==
|
||||
|
||||
==You can easily turn it on with the config setting== `==rerere====.enabled==` ==and you can further ask it to automatically stage it for you with== `==rerere.====auto====Update==`
|
||||
|
||||
```routeros
|
||||
$ git config --global rerere.enabled true
|
||||
$ git config --global rerere.autoUpdate true
|
||||
```
|
||||
|
||||

|
||||
|
||||
a conflict... always remembers
|
||||
|
||||
Then, the next time you get a merge conflict that it's seen before, magic!
|
||||
|
||||

|
||||
|
||||
automatically fix it the next time
|
||||
|
||||
## Up Next
|
||||
|
||||
Again, all of this has been in Git for a while, but if you don't know... now you know.
|
||||
|
||||
Next up is [New Stuff in Git](https://blog.gitbutler.com/git-tips-2-new-stuff-in-git/).
|
||||
|
||||
### Subscribe to new posts.
|
||||
|
|
@ -1,208 +0,0 @@
|
|||
---
|
||||
id: 3811e8c9-49ed-47bc-8302-d7dc0529d828
|
||||
title: |
|
||||
Git Tips 2: New Stuff in Git
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- dotfiles
|
||||
- git
|
||||
date_added: 2024-02-18 11:02:19
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/git-tips-2-new-stuff-in-git-18dbc865f77
|
||||
url_original: |
|
||||
https://blog.gitbutler.com/git-tips-2-new-stuff-in-git/
|
||||
---
|
||||
|
||||
# Git Tips 2: New Stuff in Git
|
||||
|
||||
## Highlights
|
||||
|
||||
So, Git has created a new force pushing option called `--force-with-lease` that will essentially check that what you last pushed is still what's on the server before it will force the new branch update.
|
||||
|
||||
[source](https://omnivore.app/me/git-tips-2-new-stuff-in-git-18dbc865f77#303433c7-6c8d-45df-b8ae-729aa598255b)
|
||||
|
||||
---
|
||||
|
||||
It's pretty easy to do. Just set `gpg.format` to `ssh` and tell it where your signing key is:
|
||||
|
||||
```routeros
|
||||
$ git config gpg.format ssh
|
||||
$ git config user.signingKey ~/.ssh/id_rsa.pub
|
||||
```
|
||||
|
||||
Now if you run `git commit -S` it will try to sign your commit with this key. If it succeeds and you upload that public key to GitHub here (under "Signing Keys"), then you'll get pretty "verified" badges on your commits:
|
||||
|
||||
[source](https://omnivore.app/me/git-tips-2-new-stuff-in-git-18dbc865f77#6870b9f8-0e0c-4a26-8d4e-b0dd630f7260)
|
||||
|
||||
---
|
||||
|
||||
provides a way to add cronjobs that run daily, hourly and weekly maintenance tasks on your Git repositories.
|
||||
|
||||
You can turn it on for your Git repository by simply running:
|
||||
|
||||
```crmsh
|
||||
$ git maintenance start
|
||||
```
|
||||
|
||||
[source](https://omnivore.app/me/git-tips-2-new-stuff-in-git-18dbc865f77#0a2d2271-21f5-46e5-8f83-8fd08a82e25c)
|
||||
|
||||
---
|
||||
|
||||
This means that every hour it will rebuild your commit graph and do a prefetch (we will cover these concepts in the next post), and once per day it will clean up loose objects and put them in pack-files and also repack the object directory using the `multi-pack-index` feature (read more about that in an incredible blog post from GitHub's Taylor Blau [here](https://github.blog/2021-04-29-scaling-monorepo-maintenance/?ref=blog.gitbutler.com#multi-pack-indexes)).
|
||||
|
||||
Basically it will just make lots of things faster in the background all the time automatically.
|
||||
|
||||
[source](https://omnivore.app/me/git-tips-2-new-stuff-in-git-18dbc865f77#cdd9aacf-451b-4437-9976-61dcbc1322aa)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||

|
||||
|
||||
There are a bunch of new tricks that Git can do that were added in the last few years. How up to date are you?
|
||||
|
||||
Next up in our [3 part series](https://blog.gitbutler.com/git-tips-and-tricks/) on "Stuff you may not know about Git", we have **New Stuff**!
|
||||
|
||||
Here I'm going to cover 5 relatively new things in Git that you may not have heard about, because _why would you_?
|
||||
|
||||
We'll cover:
|
||||
|
||||
* [Git Branch Stuff](#some-git-branch-stuff)
|
||||
* [Safe Force Pushing](#safe-force-pushing)
|
||||
* [SSH Commit Signing](#ssh-commit-signing)
|
||||
* [Push Signing](#push-signing)
|
||||
* [Git Maintenance](#git-maintenance)
|
||||
|
||||
Let's dig in!
|
||||
|
||||
## Some Git Branch Stuff
|
||||
|
||||
This is pretty minor, but one thing that's always bugged me about Git is that I run `git branch` a lot to view what branches I have, but they're in the dumbest possible order (alphabetic) and there are a million of them after a while.
|
||||
|
||||
At some point I started naming my branches in a way to partially cope with this. Every branch would be something like `sc-0831-my-thing` meaning that the branch topic was "my thing", it was created on August 31st and the `sc` are my initials so I can group them by whose branch. It's a lot of stupid metadata to try to cram into a branch name just because of how it's listed.
|
||||
|
||||
However, now we can ask Git to do two things that help with this. We can ask it to sort by `objectsize`, `authordate`, `committerdate`, `creatordate`, or `taggerdate` with the `--sort` option and we can set it as a default with the `branch.sort` config setting.
|
||||
|
||||
So for example, if I want to sort by last commit date descending, I can run:
|
||||
|
||||
```routeros
|
||||
$ git config --global branch.sort -committerdate
|
||||
```
|
||||
|
||||
And now the default will show the branch that I last committed to at the top.
|
||||
|
||||
💡
|
||||
|
||||
Important note: the `-committerdate` has a leading `-` but __not_ a double dash. It's just a negative. I've seen people mess this up and then things break.
|
||||
|
||||
However, now if I have a bunch of branches, that will scroll off the screen. Sad. But now Git also has a way to take a list of branches and try to split it into columns to make better use of the screen real estate. You can do this either with the new `--column` option, or with the `column.ui` setting.
|
||||
|
||||
Check it out:
|
||||
|
||||

|
||||
|
||||
Nice sorted columns for my branch output
|
||||
|
||||
As another sort of funny thing, in order to help with this, Git implemented it's own list to column terminal command that is sort of completely independent of anything else in Git and is it's own command called `git column`.
|
||||
|
||||

|
||||
|
||||
Just in case there is anything else you need to convert into columns that isn't Git related.
|
||||
|
||||
## Safe Force Pushing
|
||||
|
||||
The next interesting thing that Git has added somewhat recently is a way to do much safer forced pushes.
|
||||
|
||||
Generally most of us don't love doing forced pushes, because there is always a chance that you're overwriting someone else's commits. Let's take a scenario:
|
||||
|
||||
* You commit and push something to GitHub
|
||||
* Someone else pulls it down, commits something and pushes it back up.
|
||||
* You amend a commit, rewriting the history, and force push it, not knowing that anyone had based something off your work.
|
||||
* This effectively removes what the other person had done.
|
||||
|
||||
What you really want to do is check to see if anyone else had pushed and only force push if the answer is no. However, there is always a bit of a race condition here because even if you check first, in the second it takes you to then push, something else could have landed from elsewhere in the meantime.
|
||||
|
||||
==So, Git has created a new force pushing option called== `==--====force====-====with====-lease==` ==that will essentially check that what you last pushed is still what's on the server before it will force the new branch update.==
|
||||
|
||||

|
||||
|
||||
A failed --force-with-lease push
|
||||
|
||||
If someone has updated the remote ref (pushed in the meantime), then push now fails with a "stale info" error.
|
||||
|
||||
If you're amending and rebasing stuff a lot, it may be worth setting up a nice little alias for this, because it's almost _always_ better than running `--force`
|
||||
|
||||
```routeros
|
||||
$ git config --global alias.fpush push --force-with-lease
|
||||
```
|
||||
|
||||
May the force be with you.
|
||||
|
||||
## Commit Signing with SSH
|
||||
|
||||
We [wrote about this](https://blog.gitbutler.com/signing-commits-in-git-explained/) a few months ago in mind-numbing detail, because the GitButler client does this automatically for you with the flip of a config setting, but if you want to do this on the command line, read on.
|
||||
|
||||
Git has supported signing your commits with GPG for a while, but GPG is often pretty difficult to get working properly and completely understand if you've never used it before. Recently, OpenSSH provided a new way to sign data using your existing SSH key and Git has integrated this as an option to use instead of GPG to do the same thing. Also, importantly, GitHub and GitLab support verifying these signatures if you upload your public signing key to your user account there.
|
||||
|
||||
==It's pretty easy to do. Just set== `==gpg====.format==` ==to== `==ssh==` ==and tell it where your signing key is:==
|
||||
|
||||
```routeros
|
||||
$ git config gpg.format ssh
|
||||
$ git config user.signingKey ~/.ssh/id_rsa.pub
|
||||
```
|
||||
|
||||
==Now if you run== `==git commit -S==` ==it will try to sign your commit with this key. If it succeeds and you upload that public key to GitHub here (under "Signing Keys"), then you'll get pretty "verified" badges on your commits:==
|
||||
|
||||

|
||||
|
||||
Stay vigilant.
|
||||
|
||||
## Push Signing
|
||||
|
||||
I won't go into a ton of detail here because this isn't really widely used, but it might be interesting to some. Git can also now sign _pushes_, not just commits.
|
||||
|
||||
Since none of the major Git hosting solutions (GitHub, GitLab, Bitbucket) support this, it's only really possible to do this if you run your own server. However, if you do, you can run `git push --signed` in order to sign the ref update on the server and have the server save a transparency log with verifiable signatures somewhere.
|
||||
|
||||
If you're interested in this, there is a very nice [writeup](https://people.kernel.org/monsieuricon/signed-git-pushes?ref=blog.gitbutler.com) by over at kernel.org.
|
||||
|
||||
Push it real good.
|
||||
|
||||
## Git Maintenance
|
||||
|
||||
The final fun new thing I'll cover is `git maintenance`.
|
||||
|
||||
The maintenance command was introduced in Git 2.30 I believe. It essentially ==provides a way to add cronjobs that run daily, hourly and weekly maintenance tasks on your Git repositories.==
|
||||
|
||||
==You can turn it on for your Git repository by simply running:==
|
||||
|
||||
```crmsh
|
||||
$ git maintenance start
|
||||
```
|
||||
|
||||
This will modify your `.git/config` file to add a `maintenance.strategy` value set to `incremental` which is a shorthand for the following values:
|
||||
|
||||
* `gc`: disabled.
|
||||
* `commit-graph`: hourly.
|
||||
* `prefetch`: hourly.
|
||||
* `loose-objects`: daily.
|
||||
* `incremental-repack`: daily.
|
||||
|
||||
==This means that every hour it will rebuild your commit graph and do a prefetch (we will cover these concepts in the next post), and once per day it will clean up loose objects and put them in pack-files and also repack the object directory using the== `==multi-====pack====-====index==` ==feature (read more about that in an incredible blog post from GitHub's Taylor Blau== ==[here](https://github.blog/2021-04-29-scaling-monorepo-maintenance/?ref=blog.gitbutler.com#multi-pack-indexes)====).==
|
||||
|
||||
==Basically it will just make lots of things faster in the background all the time automatically.==
|
||||
|
||||
Git maintenance will schedule these cron jobs differently depending on the operating system. On Mac it will add some LaunchAgents like this:
|
||||
|
||||

|
||||
|
||||
If you're curious what these plist files look like, it's something like this:
|
||||
|
||||

|
||||
|
||||
You can read more about git maintenance and it's various options [here](https://git-scm.com/docs/git-maintenance?ref=blog.gitbutler.com).
|
||||
|
||||
OK, now onto our next post where we cover those commit graph and prefetching topics. Let's get into [Really Big Repositories](https://blog.gitbutler.com/git-tips-3-really-large-repositories/).
|
||||
|
||||
### Subscribe to new posts.
|
||||
|
|
@ -1,300 +0,0 @@
|
|||
---
|
||||
id: 0f04cdaa-c871-4ba1-a882-7aecf65a2505
|
||||
title: |
|
||||
Git Tips 3: Really Large Repositories
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- dotfiles
|
||||
- git
|
||||
date_added: 2024-02-18 11:02:27
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/git-tips-3-really-large-repositories-18dbc867c96
|
||||
url_original: |
|
||||
https://blog.gitbutler.com/git-tips-3-really-large-repositories/
|
||||
---
|
||||
|
||||
# Git Tips 3: Really Large Repositories
|
||||
|
||||
## Highlights
|
||||
|
||||
Git has had shallow clones. You could almost always run something like `git clone --depth=1` to get only the last commit and the objects it needs and then `git fetch --unshallow` to get the rest of the history later if needed. But it did break lots of things. You can't `blame`, you can't `log`, etc.
|
||||
|
||||
[source](https://omnivore.app/me/git-tips-3-really-large-repositories-18dbc867c96#d319f349-d2ea-4aed-9558-d67e4b708d74)
|
||||
|
||||
---
|
||||
|
||||
If you want to do a blobless clone, you just pass `--filter=blob:none`
|
||||
|
||||
[source](https://omnivore.app/me/git-tips-3-really-large-repositories-18dbc867c96#d296df77-d1f6-4a1b-99c6-9716824f2ee2)
|
||||
|
||||
---
|
||||
|
||||
If each of those subdirectories was huge, this could be annoying to manage. Instead, we can use sparse checkouts to filter the checkouts to just specified directories.
|
||||
|
||||
To do this, we run `git sparse-checkout set [dir1] [dir2] ...`
|
||||
|
||||
[source](https://omnivore.app/me/git-tips-3-really-large-repositories-18dbc867c96#d92785cc-9dde-46f8-9764-af2195722289)
|
||||
|
||||
---
|
||||
|
||||
[Scalar](https://git-scm.com/docs/scalar?ref=blog.gitbutler.com) is mostly just used to clone with the correct defaults and config settings (blobless clone, no checkout by default, setting up maintenance properly, etc).
|
||||
|
||||
[source](https://omnivore.app/me/git-tips-3-really-large-repositories-18dbc867c96#96d0ab7b-1bf9-4b10-a08a-3d13c01bf56c)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||

|
||||
|
||||
Did you know that Git can handle enormous monorepos like Windows? Let's take a look at how.
|
||||
|
||||
In our third and final section of our [Git Tips series](https://blog.gitbutler.com/git-tips-and-tricks/), we're going to talk about how well Git now handles **very large** repositories and monorepos.
|
||||
|
||||
Do you want to use vanilla Git today to manage a 300GB repo of 3.5M files receiving a push every 20 seconds from 4000 developers without problems? **Read on!**
|
||||
|
||||
Here is our blog agenda. Our blogenda.
|
||||
|
||||
* [Prefetching](#prefetching)
|
||||
* [Commit Graph](#commit-graph)
|
||||
* [Filesystem Monitor](#filesystem-monitor)
|
||||
* [Partial Cloning](#partial-cloning)
|
||||
* [Sparse Checkouts](#sparse-checkouts)
|
||||
* [Scalar](#scalar)
|
||||
|
||||
## First, Let's Thank Windows
|
||||
|
||||
Before we get started though, the first thing we have to do is thank Microsoft for nearly all of this.
|
||||
|
||||
In 2017, Microsoft successfully moved the Windows codebase to Git. Brian Harry wrote a really great blog post about it called [The Largest Git Repo on the Planet](https://devblogs.microsoft.com/bharry/the-largest-git-repo-on-the-planet/?ref=blog.gitbutler.com) that you should read if you're interested, but the size and scope of this repository is astounding.
|
||||
|
||||
* **3.5M** files
|
||||
* for reference, the Linux kernel is about 80k files, or 2% of that
|
||||
* **300GB** repository (vs \~4.5G Linux kernel)
|
||||
* **4,000** active developers
|
||||
* **8,421** pushes per day (on average)
|
||||
* **4,352** active topic branches
|
||||
|
||||
In order to get that to work in any possible way, Microsoft had a lot of work to do. With vanilla Git at that time, a lot of commands (ie, `git status`) would take hours if they ever finished at all. They needed to make every command close to as fast as Source Depot was.
|
||||
|
||||
The first solution to this problem was a new project called [VFS for Git](https://github.com/microsoft/VFSForGit?ref=blog.gitbutler.com) which was a virtual filesystem layer that did virtual checkouts and then requested files from a central server on demand.
|
||||
|
||||
Eventually they moved more and more of the solutions they developed to the [Scalar](https://github.com/microsoft/scalar?ref=blog.gitbutler.com) project, which got rid of the virtualization layer, and would instead request file contents on checkout rather than on demand.
|
||||
|
||||
Then they moved everything, piece by piece, into the [Microsoft Git](https://github.com/microsoft/git?ref=blog.gitbutler.com) fork and then finally every part of _that_ was moved into [core Git](https://git-scm.com/docs/scalar?ref=blog.gitbutler.com).
|
||||
|
||||
So, as promised, if you want to use Git out of the box today to manage a 300GB repo of 3.5M files receiving a push every 20 seconds from 4000 developers, you can _100%_ do so.
|
||||
|
||||
Let's get into everything they added for us.
|
||||
|
||||
## Prefetching
|
||||
|
||||
So, in the last blog post I talked about how running `git maintenance` on a repository will run prefetching and maintain your commit graph every hour. Let's cover the first of those. What is "prefetching"?
|
||||
|
||||
One of the things that the Windows devs found annoying was that fetches would often be slow because there was _so much_ activity going on all the time. Whenever they would fetch, they have to get _all_ the data since whatever the last time they manually fetched.
|
||||
|
||||
So in the cronjob, they added something called "prefetching", which will essentially run a fetch command every hour automatically for you.
|
||||
|
||||
However, it does not update your remote references like it normally would, instead it populates a special `refs/prefetch` area of your references.
|
||||
|
||||

|
||||
|
||||
These references aren't shown normally, even if you run something like `git log --all`, they are quite hidden from you. However, they are used in the remote server negotiation, which means that if you have this turned on, whenever you go to fetch, your computer is never more than 1 hour of pushes behind, data-wise.
|
||||
|
||||
Basically it makes manual fetches fast.
|
||||
|
||||

|
||||
|
||||
Joke stolen from Martin Woodward :)
|
||||
|
||||
## Commit Graph
|
||||
|
||||
The other thing that `git maintenance` does every hour is update your commit graph data. What does that mean exactly?
|
||||
|
||||
Well, essentially, it makes walking your commit history faster.
|
||||
|
||||
Instead of opening up one commit object at a time to see what it's parent is, then opening up that object to see what it's parent is, etc, the commit graph is basically an index of all that information that can be quickly read in one go. This makes things like `git log --graph` or `git branch --contains` much, much faster. For most repositories this probably isn't a horrible problem, but when you start getting into millions of commits, it makes a huge difference.
|
||||
|
||||
Here's a benchmark of some log related subcommands run on the Linux kernel codebase with and without the commit graph data (from the [GitHub blog](https://github.blog/2022-08-30-gits-database-internals-ii-commit-history-queries/?ref=blog.gitbutler.com#the-commit-graph))
|
||||
|
||||
| **Command** | **Withoutcommit-graph** | **Withcommit-graph** |
|
||||
| ------------------------- | ----------------------- | -------------------- |
|
||||
| git rev-list v5.19 | 6.94s | 0.98s |
|
||||
| git rev-list v5.0..v5.19 | 2.51s | 0.30s |
|
||||
| git merge-base v5.0 v5.19 | 2.59s | 0.24s |
|
||||
|
||||
Here is a quick test that I did on the same Linux repo running `git log --graph --oneline` before and after writing a commit graph file.
|
||||
|
||||

|
||||
|
||||
Again, if you have your `maintenance` cron jobs running, this is just magically done for you constantly, you don't really have to do anything explicit.
|
||||
|
||||
## Filesystem Monitor
|
||||
|
||||
One of the things that VFS for Git needed was a filesystem monitor so that it could detect when virtual file contents were being requested and fetch them from a central server if needed.
|
||||
|
||||
This monitor was eventually utilized to speed up the `git status` command by updating the index based on filesystem modification events rather than running `stat` on every file, every time when you run it.
|
||||
|
||||
While the former became unnecessary when the virtualization layer was abandoned, the latter was integrated into Git core. If you want much, much faster `git status` runs for very large working directories, the new Git filesystem monitor is a lifesaver.
|
||||
|
||||
Basically you just set these config settings:
|
||||
|
||||
```routeros
|
||||
$ git config core.fsmonitor true
|
||||
|
||||
```
|
||||
|
||||
What this will do is add a setting that the `git status` command will see when it runs, indicating that it should be using the [fsmonitor-daemon](https://git-scm.com/docs/git-fsmonitor--daemon?ref=blog.gitbutler.com). If this daemon is not running, it will start it.
|
||||
|
||||

|
||||
|
||||
fsmonitor on Chromium makes status 20x faster
|
||||
|
||||
So, the first time you run `status` after setting the config setting, it won't be much faster. But every time after that it will be massively faster.
|
||||
|
||||
Again, there's nothing really to explicitly do after setting the value, things just get faster.
|
||||
|
||||
## Partial Cloning
|
||||
|
||||
Another big issue with large repositories is clone size. As you probably know, by default Git will fetch everything. You don't even need to have a 300GB repository for this to be a problem. [Linux](https://github.com/torvalds/linux?ref=blog.gitbutler.com) is over 4GB, [Chromium](https://github.com/chromium/chromium?ref=blog.gitbutler.com) is over 20GB. A full Chromium clone can easily take an hour, even over a pretty fast connection.
|
||||
|
||||
Now, for a long time ==Git has had shallow clones. You could almost always run something like== `==git== ==clone== ==--depth=========1==` ==to get only the last commit and the objects it needs and then== `==git== ==fetch== ==--unshallow==` ==to get the rest of the history later if needed. But it did break lots of things. You can't== `==blame==`==, you can't== `==log==`==, etc.==
|
||||
|
||||
However, now Git has both blobless and treeless clones. So you do get the whole history (all of the commits), but you don't locally have the actual content. Let's ignore the treeless clones for now because it's not generally recommended, but the blobless clone is.
|
||||
|
||||

|
||||
|
||||
A full clone of the Linux repository is 4.6G, or (for me) a 20 min process
|
||||
|
||||
==If you want to do a blobless clone, you just pass== `==--filter=====blob:none==`
|
||||
|
||||
This will change the process a little. It will download all the commits and trees, which in the case of cloning the Linux kernel reduces 4.6G to 1.4G, and it will then do a _second_ object fetch for just the blobs that it needs in order to populate the checkout.
|
||||
|
||||

|
||||
|
||||
So you can see that instead of 20 minutes for the clone, it took me 4.5 minutes. You can also see that it did two fetches, one for the 1.4GBs of commit and tree data, and a second for the 243MB of files it needs for my local checkout.
|
||||
|
||||
Now, there are downsides to this too. If you want to run a command that needs data that is not there, Git will have to go back to the server and request those objects. Luckily, it does this on-demand as it needs the objects, but it can make something like `blame` do a bunch of roundtrips.
|
||||
|
||||

|
||||
|
||||
round and round we go
|
||||
|
||||
In the case of Linux, my tests showed that a normal file blame might take 4 seconds now takes 45 seconds. But that's only the first time you need to do it.
|
||||
|
||||
## Sparse Checkouts
|
||||
|
||||
The last big thing to look at is not only useful for large repositories, but specifically for monorepos. That is, repositories that contain multiple projects in subdirectories.
|
||||
|
||||
For example, at GitButler, our web services are in a monorepo, with each service we run on AWS in a subdirectory.
|
||||
|
||||
```reasonml
|
||||
❯ tree -L 1
|
||||
.
|
||||
├── Gemfile
|
||||
├── Gemfile.lock
|
||||
├── README.md
|
||||
├── auth-proxy
|
||||
├── butler
|
||||
├── chain
|
||||
├── check.rb
|
||||
├── copilot
|
||||
└── git
|
||||
|
||||
6 directories, 4 files
|
||||
```
|
||||
|
||||
==If each of those subdirectories was huge, this could be annoying to manage. Instead, we can use sparse checkouts to filter the checkouts to just specified directories.==
|
||||
|
||||
==To do this, we run== `==git== ==sparse-checkout== ==set [dir1] [dir2] ...==`
|
||||
|
||||
```smali
|
||||
❯ git sparse-checkout set butler copilot
|
||||
❯ tree -L 1
|
||||
.
|
||||
├── Gemfile
|
||||
├── Gemfile.lock
|
||||
├── README.md
|
||||
├── butler
|
||||
├── check.rb
|
||||
└── copilot
|
||||
```
|
||||
|
||||
So we still have the top level files, but only the two subdirectories that we specified. This is called "cone mode" and tends to be pretty fast. It also makes `status` and related commands faster because there are fewer files to care about. You can also however, set patterns rather than subdirectories, but it's more complicated.
|
||||
|
||||
Here's a local test I did with the Chromium repository:
|
||||
|
||||
```sql
|
||||
❯ time git status
|
||||
On branch main
|
||||
Your branch is up to date with 'origin/main'.
|
||||
|
||||
nothing to commit, working tree clean
|
||||
|
||||
real 0m5.931s
|
||||
|
||||
❯ git sparse-checkout set build base
|
||||
|
||||
❯ time git status
|
||||
On branch main
|
||||
Your branch is up to date with 'origin/main'.
|
||||
|
||||
You are in a sparse checkout with 2% of tracked files present.
|
||||
|
||||
nothing to commit, working tree clean
|
||||
|
||||
real 0m0.386s
|
||||
```
|
||||
|
||||
This is without the `fsmonitor` stuff. You can see that `status` went from 6 seconds to run down to 0.3 seconds because there just aren't as many files.
|
||||
|
||||
If you're using large monorepos, this means you can do a blobless clone to have a much smaller local database (you can also run `clone --no-checkout` to skip the initial checkout), then do a `sparse-checkout` to filter to the directories you need and everything is massively faster.
|
||||
|
||||
## Scalar
|
||||
|
||||
Finally, Git now (since Oct 2022, Git 2.38) ships with an _alternative_ command line invocation that wraps some of this stuff.
|
||||
|
||||
This command is called `scalar`. Just go ahead and type it:
|
||||
|
||||
```fsharp
|
||||
❯ scalar
|
||||
usage: scalar [-C <directory>] [-c <key>=<value>] <command> [<options>]
|
||||
|
||||
Commands:
|
||||
clone
|
||||
list
|
||||
register
|
||||
unregister
|
||||
run
|
||||
reconfigure
|
||||
delete
|
||||
help
|
||||
version
|
||||
diagnose
|
||||
```
|
||||
|
||||
==[Scalar](https://git-scm.com/docs/scalar?ref=blog.gitbutler.com)== ==is mostly just used to clone with the correct defaults and config settings (blobless clone, no checkout by default, setting up maintenance properly, etc).==
|
||||
|
||||
If you are managing large repositories, cloning with this negates the need to run `git maintenance start` and send the `--no-checkout` command and remember `--filter=tree:0` and whatnot.
|
||||
|
||||
Now you're ready to scale! ...-ar.
|
||||
|
||||
## Some More Reading
|
||||
|
||||
If you want to read about all of this in great detail, GitHub has done an amazing job covering lots of this too:
|
||||
|
||||
* [The Commit Graph](https://github.blog/2022-08-30-gits-database-internals-ii-commit-history-queries/?ref=blog.gitbutler.com#the-commit-graph)
|
||||
* [Sparse checkout](https://github.blog/2020-01-17-bring-your-monorepo-down-to-size-with-sparse-checkout/?ref=blog.gitbutler.com)
|
||||
* [Filesystem Monitor](https://github.blog/2022-06-29-improve-git-monorepo-performance-with-a-file-system-monitor/?ref=blog.gitbutler.com)
|
||||
* [Sparse index](https://github.blog/2021-11-10-make-your-monorepo-feel-small-with-gits-sparse-index/?ref=blog.gitbutler.com)
|
||||
* [Partial and shallow clone](https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/?ref=blog.gitbutler.com)
|
||||
* [The Story of Scalar](https://github.blog/2022-10-13-the-story-of-scalar/?ref=blog.gitbutler.com)
|
||||
|
||||
There is also a ton more fascinating information on this from [Derrick Stolee](https://stolee.dev/?ref=blog.gitbutler.com), who did a lot of work on these projects.
|
||||
|
||||
Ok, that's it for our Git Tips series! Hope you enjoyed it and let us know in Discord if you have any questions or comments, or would like to see us do any other topics in Git land.
|
||||
|
||||
Thanks!
|
||||
|
||||
### Subscribe to new posts.
|
||||
|
|
@ -1,462 +0,0 @@
|
|||
---
|
||||
id: 75f0d58e-d13c-11ee-abe1-23b9fd5ced9a
|
||||
title: |
|
||||
How to Use the JavaScript Map and Set Objects – Explained with Code Examples
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- RSS
|
||||
date_added: 2024-02-21 18:39:50
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/how-to-use-the-java-script-map-and-set-objects-explained-with-co-18dcf1d24bb
|
||||
url_original: |
|
||||
https://www.freecodecamp.org/news/javascript-map-and-set-objects-explained/
|
||||
---
|
||||
|
||||
# How to Use the JavaScript Map and Set Objects – Explained with Code Examples
|
||||
|
||||
## Highlights
|
||||
|
||||
Under the hood, the `Map` object performs better when you need to add and remove keys, so you might consider using it when your data changes frequently.
|
||||
|
||||
Also, the Map object has many useful methods for data manipulation, such as `has()` to see if the Map contains a specific key, `keys()` to get all keys defined in the `Map`, `values` to get all values, and `entries()` to get all key/value pairs.
|
||||
|
||||
[source](https://omnivore.app/me/how-to-use-the-java-script-map-and-set-objects-explained-with-co-18dcf1d24bb#9c807b39-b9c0-49de-895e-1d7f6b095ab4)
|
||||
|
||||
---
|
||||
|
||||
The `Set` object allows you to store a collection of elements, just like an Array. The differences between a `Set` and an array are:
|
||||
|
||||
* A `Set` requires all elements to be unique
|
||||
* A `Set` has fewer methods for data manipulation
|
||||
|
||||
[source](https://omnivore.app/me/how-to-use-the-java-script-map-and-set-objects-explained-with-co-18dcf1d24bb#52f87526-14bc-40fb-b821-493da97dd7e3)
|
||||
|
||||
---
|
||||
|
||||
Aside from the regular methods above, `Set` also has composition methods that you can use to perform various set theory operations such as difference, union, and intersection.
|
||||
|
||||
[source](https://omnivore.app/me/how-to-use-the-java-script-map-and-set-objects-explained-with-co-18dcf1d24bb#cb2eebdd-f9f4-4a83-b298-f65c5556f842)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||

|
||||
|
||||
Map and Set are two JavaScript data structures you can use to store a collection of values, similar to Objects and Arrays. They are specialized data structures that can help you store and manipulate related values.
|
||||
|
||||
In this tutorial, we will see how Map and Set work in detail and when to use them. We will also explore the Set object composition methods that were recently added to the JavaScript standard.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
* [The Map Object Explained](#the-map-object-explained)
|
||||
* [How to Create a Map Object](#how-to-create-a-map-object)
|
||||
* [Map Object Methods and Properties](#map-object-methods-and-properties)
|
||||
* [Other Ways to Create a Map Object](#other-ways-to-create-a-map-object)
|
||||
* [Iterate Over Map Object Data](#iterate-over-map-object-data)
|
||||
* [When to Use the Map Object](#when-to-use-the-map-object)
|
||||
* [Set Object Explained](#set-object-explained)
|
||||
* [How to create a Set Object](#how-to-create-a-set-object)
|
||||
* [Set Object Methods and Properties](#set-object-methods-and-properties)
|
||||
* [Set Composition Methods](#set-composition-methods)
|
||||
* [Iterate Over a Set Object](#iterate-over-a-set-object)
|
||||
* [When to Use the Set Object](#when-to-use-the-set-object)
|
||||
* [Conclusion](#conclusion)
|
||||
|
||||
## The Map Object Explained
|
||||
|
||||
The `Map` object stores data in a key/value pair structure, just like an Object. The main differences between a regular object and a `Map` are:
|
||||
|
||||
* A `Map` can have any type of data as the key value
|
||||
* A `Map` maintains the order of data added to the object
|
||||
|
||||
### How to Create a Map Object
|
||||
|
||||
To create a `Map` object, you can call the `Map()` constructor as follows:
|
||||
|
||||
```dart
|
||||
const myMap = new Map();
|
||||
```
|
||||
|
||||
Create a Map object in JavaScript
|
||||
|
||||
The code above creates a new empty `Map` object.
|
||||
|
||||
### Map Object Methods and Properties
|
||||
|
||||
A `Map` object has the following methods and properties:
|
||||
|
||||
* `set(key, value)` – Adds a key/value pair to a Map
|
||||
* `get(key)` – Retrieves a value from a Map (returns `undefined` if key doesn't exist)
|
||||
* `has(key)` – Checks if a Map has a specific key
|
||||
* `delete(key)` – Removes a specific key from a Map
|
||||
* `clear()` – Removes all items from a Map
|
||||
* `keys()` – Returns all keys in a Map
|
||||
* `values()` – Returns all values in a Map
|
||||
* `entries()` – Returns all keys and values in a Map
|
||||
* `size` – Returns the number of items in Map
|
||||
|
||||
To insert data into the `Map` object, you can use the `set()` method:
|
||||
|
||||
```dart
|
||||
const myMap = new Map();
|
||||
|
||||
myMap.set(1, 'Jack');
|
||||
myMap.set(2, 'Jill');
|
||||
myMap.set('animal', 'Elephant');
|
||||
```
|
||||
|
||||
Inserting values to the Map object
|
||||
|
||||
The code above creates a `Map` object with 3 entries as follows:
|
||||
|
||||
```dart
|
||||
Map(3)
|
||||
0: {1 => "Jack"}
|
||||
1: {2 => "Jill"}
|
||||
2: {"animal" => "Elephant"}
|
||||
```
|
||||
|
||||
The Map object entries
|
||||
|
||||
To retrieve a value from the `Map` object, you need to use the `get()` method and pass the key as its argument:
|
||||
|
||||
```livecodeserver
|
||||
console.log(myMap.get(1)); // Jack
|
||||
|
||||
console.log(myMap.get('animal')); // Elephant
|
||||
|
||||
|
||||
```
|
||||
|
||||
Retrieving Map object values
|
||||
|
||||
To see how many key/value pairs a `Map` has, you can access the `size` property:
|
||||
|
||||
```arduino
|
||||
myMap.size; // 3
|
||||
```
|
||||
|
||||
Accessing the Map.size property
|
||||
|
||||
To see if a certain key exists in a `Map` object, you can use the `has()` method. See the example below:
|
||||
|
||||
```angelscript
|
||||
myMap.has(1); // true
|
||||
|
||||
myMap.has(10); // false
|
||||
```
|
||||
|
||||
Using the Map.has() method
|
||||
|
||||
To remove a key/value pair from a `Map` object, you can use the `delete()` method and pass the key of the pair you want to remove as follows:
|
||||
|
||||
```awk
|
||||
myMap.delete(1);
|
||||
|
||||
console.log(myMap);
|
||||
// 0: {2 => "Jill"}
|
||||
// 1: {"animal" => "Elephant"}
|
||||
```
|
||||
|
||||
Deleting an entry from the Map object
|
||||
|
||||
If you want to remove all key/value pairs, you can use the `clear()` method instead:
|
||||
|
||||
```arduino
|
||||
myMap.clear();
|
||||
|
||||
console.log(myMap); // Map(0) {size: 0}
|
||||
```
|
||||
|
||||
Clearing a Map object
|
||||
|
||||
### Other Ways to Create a Map Object
|
||||
|
||||
You can also create a `Map` object from an Array as follows:
|
||||
|
||||
```prolog
|
||||
const myMap = new Map([
|
||||
[1, 'Jack'],
|
||||
[2, 'Jill'],
|
||||
['animal', 'Elephant'],
|
||||
]);
|
||||
```
|
||||
|
||||
Creating a Map from an Array
|
||||
|
||||
When creating a `Map` from an Array, you need to create a two-dimensional array and specify two elements in each array.
|
||||
|
||||
The first element will be the key, the second element will be the value. Any extra value in the array will be ignored.
|
||||
|
||||
In the example below, the value 'Johnson' from the first array will be ignored by the `Map()` constructor:
|
||||
|
||||
```dart
|
||||
const myMap = new Map([
|
||||
[1, 'Jack', 'Johnson'], // the value 'Johnson' is ignored
|
||||
[2, 'Jill'],
|
||||
['animal', 'Elephant'],
|
||||
]);
|
||||
```
|
||||
|
||||
Creating a Map from an array with more than two values
|
||||
|
||||
Because you can create a `Map` object from an array, you can also create one from an object. You need to transform the object into an array first using the `Object.entries()` method.
|
||||
|
||||
The following example shows how to use an object to create a `Map`:
|
||||
|
||||
```javascript
|
||||
const person = {
|
||||
'name': 'Jack',
|
||||
'age': 20,
|
||||
}
|
||||
|
||||
const myMap = new Map(Object.entries(person));
|
||||
|
||||
console.log(myMap); // Map(2) { 'name' => 'Jack', 'age' => 20 }
|
||||
```
|
||||
|
||||
Creating a Map from an object
|
||||
|
||||
### Iterate Over Map Object Data
|
||||
|
||||
To iterate over a `Map` object data, you can use either the `forEach()` method or the `for .. of` loop:
|
||||
|
||||
```javascript
|
||||
const myMap = new Map([
|
||||
[1, 'Jack'],
|
||||
[2, 'Jill'],
|
||||
['animal', 'Elephant'],
|
||||
]);
|
||||
|
||||
// iterate using the forEach() method
|
||||
myMap.forEach((value, key) => {
|
||||
console.log(`${key}: ${value}`);
|
||||
});
|
||||
|
||||
// or using the for .. of loop
|
||||
|
||||
for (const [key, value] of myMap) {
|
||||
console.log(`${key}: ${value}`);
|
||||
}
|
||||
```
|
||||
|
||||
Both methods give the same output:
|
||||
|
||||
```http
|
||||
1: Jack
|
||||
2: Jill
|
||||
animal: Elephant
|
||||
```
|
||||
|
||||
### When to Use the Map Object
|
||||
|
||||
You can think of the `Map` object as an upgraded version of the regular Object. It can use any type of data as the key value, while an object can only use string values as keys.
|
||||
|
||||
==Under the hood, the== `==Map==` ==object performs better when you need to add and remove keys, so you might consider using it when your data changes frequently.==
|
||||
|
||||
==Also, the Map object has many useful methods for data manipulation, such as== `==has====()==` ==to see if the Map contains a specific key,== `==keys====()==` ==to get all keys defined in the== `==Map==`==,== `==values==` ==to get all values, and== `==entries====()==` ==to get all key/value pairs.==
|
||||
|
||||
But if you only want to create an object without further manipulation, then you don't need to use the `Map` object.
|
||||
|
||||
One example is when you send a network request using the `fetch()` method. You would create an object and convert it into a JSON string, so using a `Map` object won't give any benefit.
|
||||
|
||||
## Set Object Explained
|
||||
|
||||
==The== `==Set==` ==object allows you to store a collection of elements, just like an Array. The differences between a== `==Set==` ==and an array are:==
|
||||
|
||||
* ==A== `==Set==` ==requires all elements to be unique==
|
||||
* ==A== `==Set==` ==has fewer methods for data manipulation==
|
||||
|
||||
### How to Create a Set Object
|
||||
|
||||
To create a new `Set` object, you need to call the `Set()` constructor as follows:
|
||||
|
||||
```dart
|
||||
const mySet = new Set();
|
||||
```
|
||||
|
||||
Creating a new Set object
|
||||
|
||||
The code above will create a new empty set.
|
||||
|
||||
### Set Object Methods and Properties
|
||||
|
||||
A `Set` object has the following methods and properties:
|
||||
|
||||
* `add(value)` – Adds a value to a Set
|
||||
* `has(value)` – Checks if a Set contains a specific value
|
||||
* `delete(value)` – Removes a specific value from a Set
|
||||
* `clear()` – Removes all items from a Set
|
||||
* `keys()` – Returns all values in a Set
|
||||
* `values()` – Returns all values in a Set
|
||||
* `entries()` – Returns all values in a Set as `[value, value]` array
|
||||
* `size` – Returns the number of items in Set
|
||||
|
||||
Note that the `keys()` and `values()` methods in a Set object return the same output.
|
||||
|
||||
There's also the `entries()` method which returns an array as follows:
|
||||
|
||||
```javascript
|
||||
const mySet = new Set(['Jack', 'Jill', 'John']);
|
||||
|
||||
console.log(mySet.entries());
|
||||
```
|
||||
|
||||
Running Set entries() method
|
||||
|
||||
Output:
|
||||
|
||||
```prolog
|
||||
[Set Entries] {
|
||||
[ 'Jack', 'Jack' ],
|
||||
[ 'Jill', 'Jill' ],
|
||||
[ 'John', 'John' ]
|
||||
}
|
||||
```
|
||||
|
||||
Output of Set entries() method
|
||||
|
||||
Notice how the values are repeated once in each array above. The `entries()` method is created to make `Set` similar to the `Map` object, but you probably don't need it.
|
||||
|
||||
There are extra methods that you can use to interact with another `Set` object. We'll discuss them in the next section.
|
||||
|
||||
To add an element to the Set object, you can use the add method:
|
||||
|
||||
```processing
|
||||
const mySet = new Set();
|
||||
|
||||
mySet.add(1);
|
||||
mySet.add(2);
|
||||
mySet.add(3);
|
||||
|
||||
console.log(mySet); // [1, 2, 3]
|
||||
```
|
||||
|
||||
Adding new elements to the Set object
|
||||
|
||||
To get all values stored in a `Set`, call the `values()` method:
|
||||
|
||||
```pgsql
|
||||
mySet.values(); // [Set Iterator] { 'Jack', 'Jill', 'John' }
|
||||
```
|
||||
|
||||
Getting all values from a Set object
|
||||
|
||||
To check if the `Set` has a specific value, use the `has()` method:
|
||||
|
||||
```elixir
|
||||
mySet.has('Jack'); // true
|
||||
|
||||
mySet.has('Michael'); // false
|
||||
```
|
||||
|
||||
Check if a Set has a specific value
|
||||
|
||||
To remove a single value, call the `delete()` method. To remove all values, use the `clear()` method:
|
||||
|
||||
```less
|
||||
mySet.delete('Jill');
|
||||
|
||||
mySet.clear();
|
||||
```
|
||||
|
||||
Delete a single value or clear all from Set
|
||||
|
||||
### Set Composition Methods
|
||||
|
||||
==Aside from the regular methods above,== `==Set==` ==also has composition methods that you can use to perform various set theory operations such as difference, union, and intersection.==
|
||||
|
||||
The following table is from [MDN Set documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global%5FObjects/Set#set%5Fcomposition):
|
||||
|
||||

|
||||
|
||||
A List of Set Composition Methods
|
||||
|
||||
For example, you can get a set containing the differences between two other sets as follows:
|
||||
|
||||
```angelscript
|
||||
const setA = new Set([1, 2, 3, 4, 5]);
|
||||
|
||||
const setB = new Set([4, 5, 6, 7, 8]);
|
||||
|
||||
const diffsA = setA.difference(setB); // Set(3) {1, 2, 3}
|
||||
const diffsB = setB.difference(setA); // Set(3) {6, 7, 8}
|
||||
|
||||
```
|
||||
|
||||
Example of using the Set difference() method
|
||||
|
||||
Here, the `setA.difference(setB)` returns a `Set` containing values unique to the `setA` object.
|
||||
|
||||
The opposite values are returned when you run `setB.difference(setA)` method.
|
||||
|
||||
Note that these methods are new additions to the JavaScript standard, and as of this writing, only Safari 17 and Chrome 122 support these methods.
|
||||
|
||||
Most likely, these methods will be included in Node.js soon.
|
||||
|
||||
### Iterate Over a Set Object
|
||||
|
||||
To iterate over a `Set` object, you can use either the `forEach()` method or the `for .. of` loop:
|
||||
|
||||
```pgsql
|
||||
const mySet = new Set(['Jack', 'Jill', 'John']);
|
||||
|
||||
// iterate using the forEach() method
|
||||
mySet.forEach(value => {
|
||||
console.log(value);
|
||||
});
|
||||
|
||||
// or using the for .. of loop
|
||||
|
||||
for (const value of mySet) {
|
||||
console.log(value);
|
||||
}
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```mipsasm
|
||||
Jack
|
||||
Jill
|
||||
John
|
||||
```
|
||||
|
||||
### When to Use the Set Object
|
||||
|
||||
You can think of the `Set` object as the alternative version of the regular Array.
|
||||
|
||||
Because a `Set` object ignores duplicate values, you can use this object to purge duplicates from an Array, then turn the `Set` object back to an Array:
|
||||
|
||||
```angelscript
|
||||
const myArray = [1, 1, 2, 2, 3, 3];
|
||||
|
||||
const uniqueArray = [...new Set(myArray)];
|
||||
|
||||
console.log(uniqueArray); // [ 1, 2, 3 ]
|
||||
```
|
||||
|
||||
Creating a unique array with the help of Set
|
||||
|
||||
Another reason you may want to use a `Set` is when you need to compose multiple set objects using the composition methods, such as `union()` and `difference()`. These methods are not available in an Array.
|
||||
|
||||
## Conclusion
|
||||
|
||||
In this article, you've learned how the Map and Set objects work and when to use them in your code.
|
||||
|
||||
If you enjoyed this article and want to take your JavaScript skills to the next level, I recommend you check out my new book __Beginning Modern JavaScript_ [here](https://codewithnathan.com/beginning-modern-javascript).
|
||||
|
||||
[](https://codewithnathan.com/beginning-modern-javascript)
|
||||
|
||||
The book is designed to be easy for beginners and accessible to anyone looking to learn JavaScript. It provides a step-by-step gentle guide that will help you understand how to use JavaScript to create a dynamic web application.
|
||||
|
||||
Here's my promise: __You will actually feel like you understand what you're doing with JavaScript._
|
||||
|
||||
See you later!
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
Learn to code for free. freeCodeCamp's open source curriculum has helped more than 40,000 people get jobs as developers. [Get started](https://www.freecodecamp.org/learn/)
|
||||
|
|
@ -1,598 +0,0 @@
|
|||
---
|
||||
id: 085bfd7c-d52a-11ee-bfc7-b34a261d031c
|
||||
title: |
|
||||
How to Learn the Hard Parts of React – and Tips to Conquer Them
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- RSS
|
||||
date_added: 2024-02-26 18:07:53
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/how-to-learn-the-hard-parts-of-react-and-tips-to-conquer-them-18de8db4244
|
||||
url_original: |
|
||||
https://www.freecodecamp.org/news/hard-parts-of-react/
|
||||
---
|
||||
|
||||
# How to Learn the Hard Parts of React – and Tips to Conquer Them
|
||||
|
||||
## Highlights
|
||||
|
||||
The first instinct for many developers when faced with creating dynamic lists is to use the index property as the key. It seems like a convenient solution, as the index provides a unique identifier for each element in the array – but it isn’t the best approach for the following reasons:
|
||||
|
||||
* **Non-Persistent**: If the order or number of items changes, React may get confused. For example, if an item is added or removed from the beginning of the list, all the subsequent indices change, causing potential re-rendering issues.
|
||||
* **Array Mutations**: Operations like sorting or filtering can alter the order of items, breaking the association between the index and the actual item.
|
||||
* **Performance Concerns**: React relies on keys for efficient updates. Using the index as a key might impact performance when dealing with large lists or frequent updates.
|
||||
|
||||
Some of the better alternatives include:
|
||||
|
||||
* **Use a Unique ID**: If each item in your array has a unique identifier, such as an `id` property, use that as the key.
|
||||
|
||||
[source](https://omnivore.app/me/how-to-learn-the-hard-parts-of-react-and-tips-to-conquer-them-18de8db4244#e912d65e-4c82-41f1-94d4-56c151254c3e)
|
||||
|
||||
---
|
||||
|
||||
Generate a Unique Key: In cases where items lack a natural unique identifier, consider using a function like `crypto.randomUUID()` to generate a unique key.
|
||||
|
||||
[source](https://omnivore.app/me/how-to-learn-the-hard-parts-of-react-and-tips-to-conquer-them-18de8db4244#9074fe2d-d95d-4fc6-af45-be052bb24de5)
|
||||
|
||||
---
|
||||
|
||||
To ensure your component behaves as expected and follows React's principles, always use the setter function (`setNames`) to update the state.
|
||||
|
||||
[source](https://omnivore.app/me/how-to-learn-the-hard-parts-of-react-and-tips-to-conquer-them-18de8db4244#a42adf04-e7ec-4612-a7ea-c179bfce9163)
|
||||
|
||||
---
|
||||
|
||||
To safeguard your component from unexpected errors, incorporate optional chaining (`?.`) when accessing nested properties in API data.
|
||||
|
||||
[source](https://omnivore.app/me/how-to-learn-the-hard-parts-of-react-and-tips-to-conquer-them-18de8db4244#7ef6781d-7b8b-496d-bd2d-2974995be502)
|
||||
|
||||
---
|
||||
|
||||
* **Put data outside components**: Move things like lists and groups of information outside the main part of a component when possible. This helps avoid extra updates and makes it simpler to handle data without using special functions like `useCallback`.
|
||||
* **Be careful with `React.memo`**: Using `React.memo` can help your components run better, but it's not always needed. If a component changes a lot with new information, using `React.memo` might not be as helpful. Use it wisely.
|
||||
* **Create your own custom React hooks**: I also like making my own special tools with custom React hooks. It's a bit advanced, but it helps keep my code neat and organized.
|
||||
|
||||
[source](https://omnivore.app/me/how-to-learn-the-hard-parts-of-react-and-tips-to-conquer-them-18de8db4244#eb5d0b4b-a153-4551-a3a4-522a590854b5)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||

|
||||
|
||||
Have you started learning React, only to face bugs that made you contemplate a career in goat herding? Don't worry – we've all been there.
|
||||
|
||||
In this guide, you'll join me on a quest through the quirky wonders of React. I'll help you navigate the perplexing moments, ensuring you never have to ask yourself, "What’s up with React?"
|
||||
|
||||
Whether you're a seasoned React adventurer or unearthing the mysteries of virtual DOMs, fear not. I'm here to share the tales of my early struggles, demystify the enigmatic bugs, and pave the way for a smoother journey.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
* Fundamentals of HTML and CSS
|
||||
* Fundamentals of ES6 JavaScript and React
|
||||
|
||||
## ****What We'll Cover:**
|
||||
|
||||
1. [Quick Recap of React Fundamentals](#what-we-ll-cover-)
|
||||
– [Components: The Web Building Blocks](#components-the-web-building-blocks)
|
||||
– [JSX: Where HTML Meets JavaScript](#jsx-where-html-meets-javascript)
|
||||
– [State and Props: The Dynamic Duo](#state-and-props-the-dynamic-duo)
|
||||
2. [The Good, the Bad, and the Challenging Parts of React](#the-good-the-bad-and-the-challenging-parts-of-react)
|
||||
– [The Good Parts of React](#the-good-parts-of-react)
|
||||
– [The Bad Parts of React](#the-bad-parts-of-react)
|
||||
– [The Challenging Parts of React](#the-challenging-parts-of-react)
|
||||
– [Key Prop Mishaps](#key-prop-mishaps)
|
||||
– [Mutating States Directly](#mutating-states-directly)
|
||||
– [Mysterious Bugs with Conditional Rendering](#mysterious-bugs-with-conditional-rendering)
|
||||
– [Ignoring Dependency Arrays in React Hooks](#ignoring-dependency-arrays-in-react-hooks)
|
||||
– [Neglecting Optional Chaining for API Data](#neglecting-optional-chaining-for-api-data)
|
||||
– [Ignoring React Fragments for Grouping JSX Elements](#ignoring-react-fragments-for-grouping-jsx-elements)
|
||||
3. [Opinionated Approaches to React](#opinionated-approaches-to-react)
|
||||
4. [Wrapping Up the Quirky Journey with React](#wrapping-up-the-quirky-journey-with-react)
|
||||
|
||||
## Quick Recap of React Fundamentals
|
||||
|
||||
The React library revolves around 3 building blocks: Components, JSX, and State & Props.
|
||||
|
||||
### Components: The Web Building Blocks
|
||||
|
||||
Imagine components as the LEGO bricks of your user interface—a single, reusable piece that contributes to the grand structure. They encapsulate functionality, styling, and behavior, making your UI both modular and scalable.
|
||||
|
||||
From a simple button to an elaborate sidebar, components are the heart and soul of React development.
|
||||
|
||||
### JSX: Where HTML Meets JavaScript
|
||||
|
||||
JSX, or JavaScript XML, may seem like an odd fusion of HTML and JavaScript at first, but it’s quite straightforward. It's the secret sauce that makes React's syntax so expressive and dynamic.
|
||||
|
||||
With JSX, you write your UI components using a syntax that resembles HTML, but underneath, it's pure JavaScript.
|
||||
|
||||
### State and Props: The Dynamic Duo
|
||||
|
||||
The dynamic duo of state and props bring React pages to life as they add interactivity to your web applications.
|
||||
|
||||
#### State: Granting Memory to Components
|
||||
|
||||
State provides memory to components, allowing them to remember past events and alter their behavior over time. It's the key to making your UI responsive and dynamic.
|
||||
|
||||
Picture a form that remembers the user's input or a counter that increments with each click. That's the magic of state.
|
||||
|
||||
#### Props: Enabling Communication
|
||||
|
||||
Props (short for properties) facilitate communication between components. They allow parent components to pass data down to their children, creating a seamless flow of information.
|
||||
|
||||
Think of props as messengers, ensuring that each component knows its role and receives the necessary information to perform it.
|
||||
|
||||
## The Good, the Bad, and the Puzzling Parts of React
|
||||
|
||||
Before we delve into the puzzling aspects of React, it's essential to shine a spotlight on the treasures that make React a true hero in your arsenal.
|
||||
|
||||
### The Good Parts of React
|
||||
|
||||
#### Virtual DOM and its Advantages
|
||||
|
||||
The virtual DOM is a revolutionary concept that gives React its speed and efficiency.
|
||||
|
||||
When changes occur in your app, React doesn't immediately update the actual DOM. Instead, it works with a lightweight copy, the Virtual DOM, making minimal, lightning-fast adjustments. This not only optimizes performance but also provides a smoother user experience.
|
||||
|
||||
```reasonml
|
||||
ReactDOM.createRoot(document.getElementById("root")).render(
|
||||
<App />
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
This process leverages [React's diffing algorithm](https://legacy.reactjs.org/docs/reconciliation.html) in the Virtual DOM. It identifies the minimal set of changes needed in the actual DOM to reflect the updated state.
|
||||
|
||||

|
||||
|
||||
Explaining how React updates the UI using the virtual DOM
|
||||
|
||||
#### Reusable Components
|
||||
|
||||
In React, the guiding principle is reusability. Components, the fundamental building blocks we discussed above, can be crafted and employed across your application. This not only fosters a modular and organized code structure but also frees you from the burden of reinventing the wheel.
|
||||
|
||||
```hsp
|
||||
// Reusable Button Component
|
||||
const Button = ({ label, onClick }) => (
|
||||
<button onClick={onClick}>{label}</button>
|
||||
);
|
||||
|
||||
// Usage
|
||||
<Button label="Click me" onClick={() => console.log("Button Clicked")} />
|
||||
|
||||
```
|
||||
|
||||
#### One-way Data Binding for a Predictable Flow
|
||||
|
||||
React enforces a unidirectional data flow, ensuring predictability and maintainability.
|
||||
|
||||
Parent components convey data down to their children through props, and any modifications are overseen by the parent component. This one-way street prevents the chaos with 2-way data binding seen in other frameworks.
|
||||
|
||||
```kotlin
|
||||
const ParentComponent = () => {
|
||||
const [data, setData] = useState("Hello from Parent!");
|
||||
|
||||
return <ChildComponent data={data} />;
|
||||
};
|
||||
|
||||
const ChildComponent = ({ data }) => <div>{data}</div>;
|
||||
|
||||
```
|
||||
|
||||
### The Bad Parts of React
|
||||
|
||||
There are some parts of React that aren't ideal, though. Let's go through them briefly now so you can be aware of them.
|
||||
|
||||
#### Steep Learning Curve for Beginners
|
||||
|
||||
Starting with React can be tough, especially if you're new to web development. Concepts like JSX, components, and state management might seem like a maze. But don't worry! With some practice and patience, it gets easier, and React becomes more familiar.
|
||||
|
||||
#### JSX Might Puzzle You at First
|
||||
|
||||
JSX, the special mix of HTML and JavaScript, can be a bit confusing at the beginning. It's like learning a new language that blends the two. But as you get the hang of it, you'll see how it makes your code shorter and clearer.
|
||||
|
||||
#### State Management Challenges
|
||||
|
||||
Using state in React is powerful, but it can also be tricky. Handling state across lots of different pieces, especially in big projects, can create complex setups and potential problems. Luckily, tools like [Redux](https://redux.js.org/) exist to help manage this complexity.
|
||||
|
||||
## The Challenging Parts of React
|
||||
|
||||
### Key Prop Mishaps
|
||||
|
||||
When building your applications, you may often have repeating elements which show similar information or share the same styles. The logical step would be to loop over them to create a list of elements.
|
||||
|
||||
```xquery
|
||||
function ListComponent() {
|
||||
const people = [{ name: "Mitchelle" }, { name: "July" }, { name: "David" }];
|
||||
return (
|
||||
<ul>
|
||||
{/ Looping over the people array to create list items /}
|
||||
{people.map((person) => (
|
||||
<li>{person.name}</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Everything seems fine until you notice a warning in your console or, worse, strange behaviour in how your list renders.
|
||||
|
||||

|
||||
|
||||
The console an error due to missing key prop
|
||||
|
||||
React uses keys to update and reorder elements in a list. When you forget to provide a key prop or if the keys are not unique, React gets a bit lost. It's like trying to keep track of items in the array without any specific identifiers – things get mixed up, and you might end up with unexpected bugs in your UI.
|
||||
|
||||
#### How to solve it
|
||||
|
||||
==The first instinct for many developers when faced with creating dynamic lists is to use the index property as the key. It seems like a convenient solution, as the index provides a unique identifier for each element in the array== ==– but it isn’t the best approach for the following reasons:==
|
||||
|
||||
* **==Non-Persistent==**==: If the order or number of items changes, React may get confused. For example, if an item is added or removed from the beginning of the list, all the subsequent indices change, causing potential re-rendering issues.==
|
||||
* **==Array Mutations==**==: Operations like sorting or filtering can alter the order of items, breaking the association between the index and the actual item.==
|
||||
* **==Performance Concerns==**==: React relies on keys for efficient updates. Using the index as a key might impact performance when dealing with large lists or frequent updates.==
|
||||
|
||||
==Some of the better alternatives include:==
|
||||
|
||||
* **==Use a Unique ID==**==: If each item in your array has a unique identifier, such as an== `==id==` ==property, use that as the key.==
|
||||
|
||||
```clojure
|
||||
{people.map((person) => (
|
||||
<li key={person.id}>{person.name}</li>
|
||||
))}
|
||||
|
||||
```
|
||||
|
||||
* ==Generate a Unique Key: In cases where items lack a natural unique identifier, consider using a function like== `==crypto====.randomUUID====()==` ==to generate a unique key.==
|
||||
|
||||
```clojure
|
||||
{people.map((person) => (
|
||||
<li key={crypto.randomUUID()}>{person.name}</li>
|
||||
))}
|
||||
|
||||
```
|
||||
|
||||
By choosing one of these alternatives, you provide React with stable and unique keys, helping it manage and update your dynamic lists,
|
||||
|
||||
**Note**: You may be thinking “If `crypto.randomUUID` generates a unique ID, (`Math.random()` \* some big number) would work the same, right”?
|
||||
|
||||

|
||||
|
||||
Nope gif
|
||||
|
||||
`Math.random()` could also suffice as a key, but it's a bad idea because the generated keys won't be stable across re-renders, leading to potential performance issues and rendering inconsistencies.
|
||||
|
||||
### Mutating States Directly
|
||||
|
||||
Imagine you're working on a component that manages an array of names. Rather than using the appropriate setter method to update the state, you decide to directly mutate the state.
|
||||
|
||||
```javascript
|
||||
const MutableStateComponent = () => {
|
||||
const [names, setNames] = useState(["David", "John", "Steph", "Anthony"]);
|
||||
|
||||
const removeLastName = () => {
|
||||
console.log(names);
|
||||
// Direct mutation of state using pop()
|
||||
names.pop();
|
||||
setNames(names); // This won't trigger a re-render
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>Names: {names.join(", ")}</p>
|
||||
<button onClick={removeLastName}>Remove Last Name</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
To your surprise, the UI doesn't update as expected, and you find yourself stuck in a scenario where the list of names seems frozen. Make no mistake, the array is getting updated as seen below:
|
||||
|
||||

|
||||
|
||||
Array getting mutated with UI being updated
|
||||
|
||||
#### What's the Problem?
|
||||
|
||||
React relies on an immutable state for efficient updates, and when you bypass this mechanism, it disrupts the unidirectional data flow.
|
||||
|
||||
In this case, using `pop()` mutates the original array in place, and React loses track of the changes. This leads to an inaccurate rendering of the component.
|
||||
|
||||
#### How to Solve it
|
||||
|
||||
==To ensure your component behaves as expected and follows React's principles, always use the setter function (==`==setNames==`==) to update the state.==
|
||||
|
||||
```javascript
|
||||
const MutableStateComponent = () => {
|
||||
const [names, setNames] = useState(["David", "John", "Steph", "Anthony"]);
|
||||
|
||||
const removeLastName = () => {
|
||||
// Use setNames to update state
|
||||
setNames((prevNames) => prevNames.slice(0, -1));
|
||||
console.log(names);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>Names: {names.join(", ")}</p>
|
||||
<button onClick={removeLastName}>Remove Last Name</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
By using `setNames` and creating a new array with the desired changes (in this case, using `slice` to remove the last element), you ensure that React can accurately track and update the state, resulting in the expected UI behavior.
|
||||
|
||||

|
||||
|
||||
Result of mutating states with the correct method
|
||||
|
||||
### Mysterious Bugs with Conditional Rendering
|
||||
|
||||
Conditional rendering, while powerful, can introduce subtle bugs when not handled with care. Understanding common pitfalls, particularly those related to truthy and falsy evaluations, is crucial for preventing mysterious rendering behaviour.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
```javascript
|
||||
const IncorrectConditionalComponent = ({ showContent }) => (
|
||||
{showContent && <div>Show me if true!</div>}
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
#### The Bug: Unexpected Rendering with Falsy Values
|
||||
|
||||
In this code snippet, if `showContent` happens to be a falsy value, such as `0`, the component will render an unexpected result. Instead of gracefully not rendering the content, it will display `0` on the screen due to the direct inclusion of curly braces.
|
||||
|
||||

|
||||
|
||||
I gotcha gif
|
||||
|
||||
#### What's the Problem?
|
||||
|
||||
The issue lies in the mismanagement of truthy and falsy values. The direct use of curly braces creates an object wrapper (`[object Object]`), causing the component to render whatever value is present, even if it's falsy.
|
||||
|
||||
#### How to Solve it
|
||||
|
||||
To catch rendering bugs related to truthy and falsy values, use a more explicit conditional check.
|
||||
|
||||
```javascript
|
||||
const CorrectConditionalComponent = ({ showContent }) => (
|
||||
showContent ? <div>Show me if true!</div> : null
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
In this corrected version, the ternary operator ensures a clear check for truthiness, preventing unexpected rendering issues. By explicitly handling truthy and falsy values, you build robust components that behave predictably in various scenarios.
|
||||
|
||||
### Ignoring Dependency Arrays in React Hooks
|
||||
|
||||
Imagine working on a component that relies on an effect to perform some logic when a certain state, let's say `count`, changes. But even though you're incrementing the count, the effect doesn't seem to run, and you're left wondering why your logic isn't taking effect.
|
||||
|
||||
```javascript
|
||||
const Counter = () => {
|
||||
const [count, setCount] = useState(0);
|
||||
|
||||
const handleClick = () => {
|
||||
|
||||
setCount((count) => count + 1);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
console.log("The current count value is ", count);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>Count: {count}</p>
|
||||
<button onClick={handleClick}>Increment</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
Testing the count component without fixing the useEffect dependency array
|
||||
|
||||
#### What's the Problem?
|
||||
|
||||
The issue lies in neglecting the dependency array in your `useEffect`. When you omit the dependencies, React might not recognize that the effect is tied to a specific piece of state, leading to stale data and unexpected behavior.
|
||||
|
||||
#### How to Solve it
|
||||
|
||||
To get your effect back on track, include the relevant dependencies in the dependency array. It's like setting up triggers – you're telling React, "Hey, run this effect whenever these specific pieces of data change."
|
||||
|
||||
```coffeescript
|
||||
useEffect(() => {
|
||||
console.log("The current count value is ", count);
|
||||
}, [count]);
|
||||
|
||||
```
|
||||
|
||||
Which now fires the `useEffect` hook:
|
||||
|
||||

|
||||
|
||||
Testing the count component after fixing the useEffect dependency array
|
||||
|
||||
### Neglecting Optional Chaining for API Data
|
||||
|
||||
You're working on a component that displays user data fetched from an API. Everything seems fine until you encounter an unexpected runtime error. The culprit? A missing optional chaining operator.
|
||||
|
||||
#### What's the Problem?
|
||||
|
||||
API responses can be unpredictable, and not all data structures match your expectations. Neglecting optional chaining, especially when accessing deeply nested properties (looking at you Strapi response data 👀) can lead to runtime errors if a property is undefined.
|
||||
|
||||
#### How to Solve it
|
||||
|
||||
==To safeguard your component from unexpected errors, incorporate optional chaining (==`==?.==`==) when accessing nested properties in API data.==
|
||||
|
||||
As an example, say you want to read a deeply nested property (label) from this data:
|
||||
|
||||
```dts
|
||||
const data = {
|
||||
id: 1,
|
||||
title: "First Item",
|
||||
content: "Content for the first item",
|
||||
category: {
|
||||
id: 101,
|
||||
name: "Category A",
|
||||
description: "Description of Category A",
|
||||
tags: [
|
||||
{
|
||||
id: 1001,
|
||||
label: "Tag 1",
|
||||
},
|
||||
{
|
||||
id: 1002,
|
||||
label: "Tag 2",
|
||||
},
|
||||
],
|
||||
},
|
||||
author: {
|
||||
id: 201,
|
||||
name: "John Doe",
|
||||
email: "john.doe@example.com",
|
||||
},
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
The correct way would be to use optional chaining to retrieve that data:
|
||||
|
||||
```ebnf
|
||||
const firstLabel = data?.category?.tags?.[0]?.label;
|
||||
|
||||
```
|
||||
|
||||
Rather than accessing those properties directly:
|
||||
|
||||
```angelscript
|
||||
const firstLabel = data.category.tags[0].label;
|
||||
|
||||
```
|
||||
|
||||
This prevents you from seeing a white screen error and a flooded console if the data structure changes. It's like putting on a safety net – if a property is missing, your app won't come crashing down like so:
|
||||
|
||||

|
||||
|
||||
Error occurring when optional chaining isn't applied
|
||||
|
||||
### Ignoring React Fragments for Grouping JSX Elements
|
||||
|
||||
When working with React components, you may encounter a scenario where you want to return multiple JSX elements from a function, only to be met with a syntax error.
|
||||
|
||||
#### What's the Problem?
|
||||
|
||||
This is due to a limitation in JavaScript, as it doesn't allow the return of adjacent elements without a common parent.
|
||||
|
||||
Consider the following problematic code:
|
||||
|
||||
```javascript
|
||||
function User() {
|
||||
return <div> David Jaja</div>
|
||||
<div>Twitter: https://twitter.com/JajaDavid8</div>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
This code results in an error: “Adjacent JSX elements must be wrapped in an enclosing tag.”
|
||||
|
||||

|
||||
|
||||
Error occurring when JSX returns 2 direct adjacent elements
|
||||
|
||||
#### How to Solve it
|
||||
|
||||
I know what you might be thinking—why not simply wrap the elements in a div and move on?
|
||||
|
||||

|
||||
|
||||
Spongebob bored gif
|
||||
|
||||
While this seems like a quick fix, it introduces a potential downside. By adding a div, you create an unnecessary parent element in the DOM.
|
||||
|
||||
This additional markup, though resolving the immediate error, can lead to unintended consequences, such as affecting styles or layout, and may not align with optimal coding practices.
|
||||
|
||||
And I’m sure you don’t want to end up with a "divpocalipse".
|
||||
|
||||

|
||||
|
||||
A divpocalpse
|
||||
|
||||
To overcome both the syntax error and the unnecessary DOM markup, React introduced an optimized solution: React Fragments.
|
||||
|
||||
React Fragments are used to address the need for returning multiple JSX elements without introducing unnecessary parent elements in the DOM.
|
||||
|
||||
Here's how you can utilize React Fragments:
|
||||
|
||||
```javascript
|
||||
import React from "react";
|
||||
function User() {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div> David Jaja</div>
|
||||
<div>Twitter: https://twitter.com/JajaDavid8</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Or using the shorthand syntax:
|
||||
|
||||
```javascript
|
||||
function User() {
|
||||
return (
|
||||
<>
|
||||
<div> David Jaja</div>
|
||||
<div>Twitter: https://twitter.com/JajaDavid8</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
By using React Fragments, you maintain clean and concise JSX code without introducing unnecessary elements to the DOM, enhancing code readability.
|
||||
|
||||

|
||||
|
||||
Showing the DOM tree after using fragments without any extra elements
|
||||
|
||||
## Opinionated Approaches to React
|
||||
|
||||
I've found some handy ways to make working with React more enjoyable. Instead of strict rules, think of these as my personal choices to make code easier to read, improve how it works, and make sure it stays in good shape.
|
||||
|
||||
1. **==Put data outside components==**==: Move things like lists and groups of information outside the main part of a component when possible. This helps avoid extra updates and makes it simpler to handle data without using special functions like== `==useCallback==`==.==
|
||||
2. **==Be careful with== `==React====.====memo==`**==: Using== `==React====.====memo==` ==can help your components run better, but it's not always needed. If a component changes a lot with new information, using== `==React====.====memo==` ==might not be as helpful. Use it wisely.==
|
||||
3. **==Create your own custom React hooks==**==: I also like making my own special tools with custom React hooks. It's a bit advanced, but it helps keep my code neat and organized.==
|
||||
|
||||

|
||||
|
||||
Just my opinion gif
|
||||
|
||||
## Wrapping Up the Quirky Journey with React
|
||||
|
||||
React's journey is a blend of smooth sailing and bumpy rides. We've seen the strength of reusable components and virtual DOM and tackled puzzling moments like missing key props and conditional rendering bugs and so on.
|
||||
|
||||
As you continue your journey with React, may your code be clean, your components reusable, and your "What's Up with React?" moments turn into "Aha!" revelations. Happy coding! 🚀
|
||||
|
||||
### **Contact Information**
|
||||
|
||||
Want to connect or contact me? Feel free to hit me up on the following:
|
||||
|
||||
* Twitter: [@jajadavid8](https://twitter.com/JajaDavid8)
|
||||
* LinkedIn: [David Jaja](https://www.linkedin.com/in/david-jaja-8084251b4/)
|
||||
* Email: Jajadavidjid@gmail.com
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
Learn to code for free. freeCodeCamp's open source curriculum has helped more than 40,000 people get jobs as developers. [Get started](https://www.freecodecamp.org/learn/)
|
||||
|
|
@ -1,267 +0,0 @@
|
|||
---
|
||||
id: 39278362-dbfc-11ee-8a2b-139ebfa11748
|
||||
title: |
|
||||
How to Build a Basic CMS with Google Sheets and React
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
- RSS
|
||||
date_added: 2024-03-06 14:55:48
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/how-to-build-a-basic-cms-with-google-sheets-and-react-18e158f0d8c
|
||||
url_original: |
|
||||
https://www.freecodecamp.org/news/how-to-build-a-basic-cms-with-google-sheets-and-reactjs/
|
||||
---
|
||||
|
||||
# How to Build a Basic CMS with Google Sheets and React
|
||||
|
||||
## Highlights
|
||||
|
||||
### Step 1: Set Up Your Google Sheets
|
||||
|
||||
1. Go to your Google Sheets
|
||||
2. Open the sheet you want to use or create a new one
|
||||
3. Click on `Extensions` in the menu
|
||||
4. Then click on `Apps Script`
|
||||
|
||||
In the Apps Script editor, you can write a script to serve as your endpoint. Here's a script that returns the contents of a Google Sheet in JSON format:
|
||||
|
||||
```kotlin
|
||||
function convertRangeToJson(data) {
|
||||
var jsonArray = [];
|
||||
|
||||
// Check if data is empty or doesn't contain enough rows for headers and at least one data row
|
||||
if (!data || data.length < 2) {
|
||||
// Return an empty array or a meaningful message as needed
|
||||
return jsonArray; // or return 'No data available';
|
||||
}
|
||||
|
||||
var headers = data[0];
|
||||
for (var i = 1, length = data.length; i < length; i++) {
|
||||
var row = data[i];
|
||||
var record = {};
|
||||
|
||||
for (var j = 0; j < row.length; j++) {
|
||||
record[headers[j]] = row[j];
|
||||
}
|
||||
|
||||
jsonArray.push(record);
|
||||
}
|
||||
|
||||
return jsonArray;
|
||||
}
|
||||
```
|
||||
|
||||
Then:
|
||||
|
||||
1. Click `File` \> `Save`, and give your project a name
|
||||
2. Click on `Deploy` \> `New deployment`.
|
||||
3. Click on `Select type` and choose `Web app`.
|
||||
4. Fill in the details for your deployment. Under `Execute as`, choose whether the script should run as your account or as the user accessing the web app. Under `Who has access`, choose who can access your web app.
|
||||
5. Click `Deploy`.
|
||||
|
||||
[source](https://omnivore.app/me/how-to-build-a-basic-cms-with-google-sheets-and-react-18e158f0d8c#d5dee3e3-c455-4623-952d-2b11f076c3fa)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||

|
||||
|
||||
In today's digital landscape, creating a content management system (CMS) that is both cost-effective and easy to maintain can be difficult, especially if you're operating on a tight budget.
|
||||
|
||||
This tutorial will show you a solution that leverages Google Sheets as a makeshift database and React to build the frontend. This will let you effectively bypass the need for a dedicated server or traditional database system.
|
||||
|
||||
This approach not only reduces the overhead costs associated with web development, but also simplifies content updates and management. It's an ideal solution if you're looking to launch your own simple CMS without substantial investment.
|
||||
|
||||
This solution is suitable for freelancers at the beginning of their career and for clients who cannot invest much in their website.
|
||||
|
||||
## Why Google Sheets?
|
||||
|
||||
Opting for Google Sheets as the backbone of your CMS comes down to its simplicity, flexibility, and cost-effectiveness.
|
||||
|
||||
Traditional web development requires a backend server to process data, a database to store information, and a frontend to display content. But each layer adds complexity and cost.
|
||||
|
||||
Google Sheets, on the other hand, acts as a highly accessible and intuitive interface that eliminates the need for a server and a database. It lets your users update content in real-time, much like any CMS, but without the usual setup and maintenance costs. This makes it an excellent choice for individuals, small businesses, or anyone looking to deploy a web application quickly and with minimal expense.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Before diving into the code, ensure you have Node.js and npm installed on your system. These tools will allow us to create a React application and manage its dependencies.
|
||||
|
||||
Let's start with Google Sheets now.
|
||||
|
||||
### ==Step 1: Set Up Your Google Sheets==
|
||||
|
||||
1. ==Go to your Google Sheets==
|
||||
2. ==Open the sheet you want to use or create a new one==
|
||||
3. ==Click on== `==Extensions==` ==in the menu==
|
||||
4. ==Then click on== `==Apps== ==Script==`
|
||||
|
||||
==In the Apps Script editor, you can write a script to serve as your endpoint. Here's a script that returns the contents of a Google Sheet in JSON format:==
|
||||
|
||||
```kotlin
|
||||
function convertRangeToJson(data) {
|
||||
var jsonArray = [];
|
||||
|
||||
// Check if data is empty or doesn't contain enough rows for headers and at least one data row
|
||||
if (!data || data.length < 2) {
|
||||
// Return an empty array or a meaningful message as needed
|
||||
return jsonArray; // or return 'No data available';
|
||||
}
|
||||
|
||||
var headers = data[0];
|
||||
for (var i = 1, length = data.length; i < length; i++) {
|
||||
var row = data[i];
|
||||
var record = {};
|
||||
|
||||
for (var j = 0; j < row.length; j++) {
|
||||
record[headers[j]] = row[j];
|
||||
}
|
||||
|
||||
jsonArray.push(record);
|
||||
}
|
||||
|
||||
return jsonArray;
|
||||
}
|
||||
```
|
||||
|
||||
==Then:==
|
||||
|
||||
1. ==Click== `==File==` ==>== `==Save==`==, and give your project a name==
|
||||
2. ==Click on== `==Deploy==` ==>== `==New== ==deployment==`==.==
|
||||
3. ==Click on== `==Select== ==type==` ==and choose== `==Web app==`==.==
|
||||
4. ==Fill in the details for your deployment. Under== `==Execute== ==as==`==, choose whether the script should run as your account or as the user accessing the web app. Under== `==Who has== ==access==`==, choose who can access your web app.==
|
||||
5. ==Click== `==Deploy==`==.==
|
||||
|
||||
You may be asked to authorize the script to access your Google Sheets. Follow the prompts to do so.
|
||||
|
||||
After deploying, you'll be given a URL for your web app. This is your API endpoint.
|
||||
|
||||
To give you an idea of what you have done so far, this is your sheet structure:
|
||||
|
||||

|
||||
|
||||
How your sheet should currently look
|
||||
|
||||
And this is the JSON you get when you call the endpoint:
|
||||
|
||||

|
||||
|
||||
JSON
|
||||
|
||||
### Step 2: Create Your React App
|
||||
|
||||
With your Google Sheets API ready, it's time to create the React app that will fetch and display this data.
|
||||
|
||||
First, go ahead and create a React app. Run the following command in your terminal to create a new React application:
|
||||
|
||||
```dsconfig
|
||||
npx create-react-app google-sheets-cards
|
||||
cd google-sheets-cards
|
||||
npm start
|
||||
```
|
||||
|
||||
You can also [use modern build tools like Vite](https://www.freecodecamp.org/news/get-started-with-vite/) for this purpose, as CRA is no longer the recommended way of building a React app.
|
||||
|
||||
Next, create the card component. Inside the `src` directory, create a file named `Card.js`. This component will be responsible for displaying each data record:
|
||||
|
||||
```javascript
|
||||
// src/Card.js
|
||||
function Card({ title, content }) {
|
||||
return (
|
||||
<div className="card">
|
||||
<h1>{title}</h1>
|
||||
<p>{content}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Card;
|
||||
```
|
||||
|
||||
Now it's time to fetch and display your data in App.js. Modify the `App.js` file to include logic for fetching the data from your Google Sheets API and using the Card component to display it:
|
||||
|
||||
```javascript
|
||||
// src/App.js
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import Card from './Card';
|
||||
import './App.css'; // Make sure to create some basic styles for the cards in App.css
|
||||
|
||||
function App() {
|
||||
const [data, setData] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
fetch('YOUR_ENDPOINT_URL') // Replace with your actual endpoint URL
|
||||
.then(response => response.json())
|
||||
.then(data => setData(data))
|
||||
.catch(error => console.error('Error fetching data:', error));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<h1>Data from Google Sheets</h1>
|
||||
<div className="cards-container">
|
||||
{data.map((item, index) => (
|
||||
<Card key={index} title={item.Title} content={item.Content} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
Next, you can style your cards. Go ahead and add the below CSS in `App.css` for basic card styling:
|
||||
|
||||
```css
|
||||
.card {
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
margin: 10px;
|
||||
padding: 10px;
|
||||
display: inline-block;
|
||||
background: #f9f9f9;
|
||||
}
|
||||
|
||||
.cards-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
```
|
||||
|
||||
### Step 3: Run Your React App
|
||||
|
||||
With everything set up, you can now run your React application and see the data from Google Sheets displayed in your browser. To do this, follow these steps:
|
||||
|
||||
First, start the React app. In your terminal, navigate to the root directory of your React app if you're not already there. Run the following command to start the development server:
|
||||
|
||||
```coffeescript
|
||||
npm start
|
||||
```
|
||||
|
||||
This command compiles your React application and opens it in your default web browser. You should see a webpage with a title "Data from Google Sheets", and below that, a series of cards, each displaying a title and content fetched from your Google Sheets data.
|
||||
|
||||
Here's, in fact, what we get:
|
||||
|
||||

|
||||
|
||||
Data from Google Sheets and Card 1, Card 2, and Card 3 displayed on the screen
|
||||
|
||||
Now you can view your data. Each card on the page corresponds to a row in your Google Sheets, with the title and content fields displayed as specified in your Card component. If you make any updates to your Google Sheets data, you can refresh the web page to see the changes reflected immediately.
|
||||
|
||||
You can deploy your React app to one of the many services you can find online such as Github Actions or Netlify. This is a simple and effective way to host your frontend application for free with significant performance.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Congratulations! You've created a dynamic web application that fetches data from a Google Sheet and displays it using React.
|
||||
|
||||
This approach offers a flexible and straightforward way to manage your application's content without needing a backend server or database.
|
||||
|
||||
Google Sheets serves as an accessible and collaborative platform for managing data, while React allows you to build a responsive and interactive user interface. Together, they provide a powerful combination for creating web applications that can be quickly updated and easily maintained.
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
Learn to code for free. freeCodeCamp's open source curriculum has helped more than 40,000 people get jobs as developers. [Get started](https://www.freecodecamp.org/learn/)
|
||||
|
|
@ -1,155 +0,0 @@
|
|||
---
|
||||
id: b342d646-2ec3-4e27-a72d-dac0d46219d3
|
||||
title: |
|
||||
How to Do a Digital Detox | Everyday Health
|
||||
status: ARCHIVED
|
||||
tags:
|
||||
- read-later
|
||||
date_added: 2024-03-11 09:49:55
|
||||
url_omnivore: |
|
||||
https://omnivore.app/me/https-www-everydayhealth-com-emotional-health-how-to-do-a-digita-18e2d8fec8e
|
||||
url_original: |
|
||||
https://www.everydayhealth.com/emotional-health/how-to-do-a-digital-detox-without-unplugging-completely/
|
||||
---
|
||||
|
||||
# How to Do a Digital Detox | Everyday Health
|
||||
|
||||
## Highlights
|
||||
|
||||
“When something is consuming a lot of your thoughts and conditioning your behaviors, and when it is interfering with your life — like your job or schoolwork or your relationships — it may be time to consider cutting back on its use,”
|
||||
|
||||
[source](https://omnivore.app/me/https-www-everydayhealth-com-emotional-health-how-to-do-a-digita-18e2d8fec8e#e757b03d-61d5-413d-b9b9-47019876445c)
|
||||
|
||||
---
|
||||
|
||||
cutting back on anything that makes you feel worse or stressed, or that takes away from your life rather than adding to it.
|
||||
|
||||
[source](https://omnivore.app/me/https-www-everydayhealth-com-emotional-health-how-to-do-a-digita-18e2d8fec8e#07a0c2b4-39f7-43bd-a39c-9f4da9933354)
|
||||
|
||||
---
|
||||
|
||||
“There’s no magic amount of screen time that is good or bad,”
|
||||
|
||||
[source](https://omnivore.app/me/https-www-everydayhealth-com-emotional-health-how-to-do-a-digita-18e2d8fec8e#0614f527-dd2d-4377-aac5-e2fce661ef85)
|
||||
|
||||
---
|
||||
|
||||
Set up time in your calendar or with an alarm on your phone to remind you to go for a walk or to eat lunch away from your desk, Becker says. And remember to leave your phone behind.
|
||||
|
||||
[source](https://omnivore.app/me/https-www-everydayhealth-com-emotional-health-how-to-do-a-digita-18e2d8fec8e#81332fd1-2e6c-4292-97c1-42077bdaddd9)
|
||||
|
||||
---
|
||||
|
||||
“If the Facebook app is something that you click on often and find yourself scrolling through for long periods of time, getting rid of the app and having to go through the search browser takes an extra step and allows for a moment to pause and decide if it is a good time to engage in this activity,”
|
||||
|
||||
[source](https://omnivore.app/me/https-www-everydayhealth-com-emotional-health-how-to-do-a-digita-18e2d8fec8e#3ff32057-315b-4fb7-8a34-8db8528990d8)
|
||||
|
||||
---
|
||||
|
||||
eliminate the distractions by replacing your smartphone with a simple cell phone that cannot support apps.
|
||||
|
||||
[source](https://omnivore.app/me/https-www-everydayhealth-com-emotional-health-how-to-do-a-digita-18e2d8fec8e#d64ced03-c9fb-4217-abc0-090512cb6b07)
|
||||
|
||||
---
|
||||
|
||||
Try powering down before dinner and until the next morning.
|
||||
|
||||
[source](https://omnivore.app/me/https-www-everydayhealth-com-emotional-health-how-to-do-a-digita-18e2d8fec8e#5cc985b9-75ac-4988-8637-c5d11336e657)
|
||||
|
||||
---
|
||||
|
||||
Apple iPhone users can set limits with [Screen Time](https://support.apple.com/en-us/HT208982) (find it in your phone’s settings) and schedule Downtime, when only phone calls or specific apps are allowed and specified apps have a time limit. [Digital Wellbeing](https://play.google.com/store/apps/details?id=com.google.android.apps.wellbeing&hl=en%5FUS&gl=US) works similarly for Google devices.
|
||||
|
||||
[source](https://omnivore.app/me/https-www-everydayhealth-com-emotional-health-how-to-do-a-digita-18e2d8fec8e#8d60c80d-2d5f-410a-a901-435de882e3c6)
|
||||
|
||||
---
|
||||
|
||||
setting limits on certain apps doesn’t always work. Instead, she suggests removing yourself from device use completely.
|
||||
|
||||
[source](https://omnivore.app/me/https-www-everydayhealth-com-emotional-health-how-to-do-a-digita-18e2d8fec8e#7ca00f44-692d-4435-bed2-8d742e634aed)
|
||||
|
||||
---
|
||||
|
||||
## Original
|
||||
|
||||

|
||||
|
||||
Your phone doesn’t have to be on lockdown for you to preserve your peace of mind.Adobe Stock
|
||||
|
||||
Life during the most connected era in human history has many positives — faraway family members are just a FaceTime session away, and the answer to nearly any question that pops into your mind is at your fingertips.
|
||||
|
||||
But too much technology — whether it’s time spent on smartphones, social media, or in front of other digital screens — can have unintended consequences. That may signal the need for a digital [detox](https://www.everydayhealth.com/diet-and-nutrition/diet/detox-cleanses-most-popular-types-what-know/).
|
||||
|
||||
“Excessive technology use can take away time from activities such as sleep, exercise, and socializing, which are all important for well-being,” says [Carol Vidal, MD, PhD, MPH](https://www.hopkinsmedicine.org/profiles/details/carolina-vidal), an assistant professor of psychiatry and behavioral sciences at the Johns Hopkins University School of Medicine in Baltimore.
|
||||
|
||||
A [research review](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7366948/) noted that frequent technology use has been linked to heightened attention-deficit symptoms, impaired emotional and social intelligence, technology addiction, social isolation, impaired brain development, and disrupted sleep in some cases.
|
||||
|
||||
**RELATED:** [**Are the Stresses of Social Media Too Much for Teens and Young Adults?**](https://www.everydayhealth.com/emotional-health/under-pressure/are-the-stresses-of-social-media-too-much-for-teens-and-young-adults/)
|
||||
|
||||
Technology is not inherently bad, says [Madeleine George, PhD](https://www.rti.org/expert/madeleine-george), a public health research analyst at RTI International, a nonprofit research institute, in Durham, North Carolina. “Technology and social media can have positive or negative effects, depending on what someone is doing online and who they are.”
|
||||
|
||||
Other research suggests, for example, that social media use can help you build and maintain connections when you’re more actively interacting with others, but tends to have the opposite effect when people use it more passively, such as when scrolling through an Instagram or Facebook feed without interacting with the content, [according to research](https://journals.sagepub.com/doi/full/10.1177/0963721417730833#%5Fi5%20%5Fi6)_._
|
||||
|
||||
You’ll know you’re overdoing it and may need a digital detox if technology interferes with your work, relationships, mental and physical health, or finances, according to [Brittany Becker](https://thedorm.com/team/brittany-becker/), a licensed mental health counselor based in New York City and the director of the Dorm, a holistic treatment center for mental health.
|
||||
|
||||
**RELATED:** [**Are the Virtual Interactions of Social Media Busting or Boosting Your Stress?**](https://www.everydayhealth.com/wellness/united-states-of-stress/social-media-busting-boosting-your-stress/)
|
||||
|
||||
Dr. Vidal agrees. ==“When something is consuming a lot of your thoughts and conditioning your behaviors, and when it is interfering with your life — like your job or schoolwork or your relationships — it may be time to consider cutting back on its use,”== Vidal says.
|
||||
|
||||
Scaling back through a digital detox may have positive effects.
|
||||
|
||||
A [study from 2021](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7717533/) found that students who completed a social media detox reported positive changes to their mood, sleep, and anxiety. And [another study](https://pubmed.ncbi.nlm.nih.gov/31851833/) found that women who quit Instagram reported higher life satisfaction and more positive effects than women who continued using the social media app. (It should be noted that both studies were small, with 68 and 80 participants, respectively.)
|
||||
|
||||
## **7 Ways to** Do a Digital Detox **(Without Pulling the Plug Entirely)**
|
||||
|
||||
For most people, ditching technology altogether isn’t going to happen. “Cutting down seems like a more realistic approach,” Vidal says.
|
||||
|
||||
To do this, make a plan, Becker says. Pinpoint your unhealthy habits and then decide which ones you want to change. “I think it is really helpful to get a clear picture of your tech use and review the time spent on your phone,” Becker says. “How that time is divided up with different applications is a great place to start, and then you can identify which areas to begin to limit.”
|
||||
|
||||
Dr. George suggests ==cutting back on anything that makes you feel worse or stressed, or that takes away from your life rather than adding to it.== And remember, what constitutes healthy technology use varies from person to person. “There’s no magic amount of screen time that is good or bad,” George says. “You have to find out what works for you and your family.”
|
||||
|
||||
Here are seven strategies to help you manage your technology use and experiment with your own personal digital detox.
|
||||
|
||||
### **1\. Schedule Time Away From Screens Throughout the Day**
|
||||
|
||||
If you work at a computer, it’s hard to avoid screens, which means it’s all the more important to prioritize breaking away. ==Set up time in your calendar or with an alarm on your phone to remind you to go for a walk or to eat lunch away from your desk, Becker says. And remember to leave your phone behind.==
|
||||
|
||||
### **2\. Take Periodic Breaks From Technology**
|
||||
|
||||
Breaks can reduce stress, particularly among heavy users, Vidal says. She says more research is needed on digital abstinence before there can be specific recommendations on what this looks like and how long it should last. But it could mean joining others who are committed to disconnecting through events like those run by [Digital Detox](https://www.digitaldetox.com/) (a company that leads tech-free retreats) or deleting problematic apps from your phone, temporarily or for good.
|
||||
|
||||
==“If the Facebook app is something that you click on often and find yourself scrolling through for long periods of time, getting rid of the app and having to go through the search browser takes an extra step and allows for a moment to pause and decide if it is a good time to engage in this activity,”== Becker says.
|
||||
|
||||
### **3\. Downgrade Your Phone**
|
||||
|
||||
If you’re having trouble staying present, ==eliminate the distractions by replacing your smartphone with a simple cell phone that cannot support apps.== “It can absolutely be helpful to downgrade from a smartphone if that is possible,” says [Jennifer Kelman, LCSW](https://www.jenniferkelman.com/bio.html), a social worker based in Boca Raton, Florida. In fact, this is what she uses with her own children. “They have simple call or text features and that’s it,” she says.
|
||||
|
||||
### **4\. Turn Off Your Phone at a Specific Time**
|
||||
|
||||
==Try powering down before dinner and until the next morning.== Apple and Android users can enable do-not-disturb settings that can silence alerts, notifications, and calls. Becker says it’s a good idea to take advantage of the tools that are built into your devices.
|
||||
|
||||
### **5\. Adjust Your Phone Settings to Limit Certain Apps**
|
||||
|
||||
==Apple iPhone users can set limits with== ==[Screen Time](https://support.apple.com/en-us/HT208982)== ==(find it in your phone’s settings) and schedule Downtime, when only phone calls or specific apps are allowed and specified apps have a time limit.== ==[Digital Wellbeing](https://play.google.com/store/apps/details?id=com.google.android.apps.wellbeing&hl=en%5FUS&gl=US)== ==works similarly for Google devices.== People who didn’t use these features were more likely to experience problematic smartphone use and worse well-being than those who did use them, according to a [research analysis](https://pubmed.ncbi.nlm.nih.gov/32354288/)_._
|
||||
|
||||
**RELATED:** [**How to Recognize When a Self-Care Practice Is No Longer Self-Care**](https://www.everydayhealth.com/self-care/how-to-recognize-when-a-self-care-practice-is-no-longer-self-care/)
|
||||
|
||||
### **6\.** **Create No-Phone Areas**
|
||||
|
||||
Kelman believes that ==setting limits on certain apps doesn’t always work. Instead, she suggests removing yourself from device use completely.== Banning phones and screens from the bedroom, for instance, can keep screens from interfering with your sleep, Becker says. And if you have to go into a different room or part of your home to use a device, it may deter you from mindlessly scrolling.
|
||||
|
||||
### **7\. Consider Reaching Out to a Mental Health Professional**
|
||||
|
||||
“We are all using technology constantly, and therefore it can be hard to always know the difference between having a problem or not,” Becker says. If your behaviors with or feelings regarding technology or certain apps and sites begin to interfere with your daily functioning, it may be time to seek professional help, Becker says. Kelman adds that if your self-esteem plummets or you find yourself dealing with anxiety or depression, it’s time to talk to someone.
|
||||
|
||||
## Editorial Sources and Fact-Checking
|
||||
|
||||
Everyday Health follows strict sourcing guidelines to ensure the accuracy of its content, outlined in our [editorial policy](https://www.everydayhealth.com/editorial-policies/). We use only trustworthy sources, including peer-reviewed studies, board-certified medical experts, patients with lived experience, and information from top institutions.
|
||||
|
||||
#### Resources
|
||||
|
||||
* Small GW, Lee J, Kaufman A, et al. Brain Health Consequences of Digital Technology Use. [_Dialogues in Clinical Neuroscience_](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7366948/). June 2020.
|
||||
* Clark JL, Algoe SB, Green MC. Social Network Sites and Well-Being: The Role of Social Connection. [_Current Directions in Psychological Science_](https://journals.sagepub.com/doi/full/10.1177/0963721417730833#%5Fi5%20%5Fi6). February 2018.
|
||||
* El-Khoury J, Haidar R, Kanj RR, et al. Characteristics of Social Media ‘Detoxification’ in University Students. [_Libyan Journal of Medicine_](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7717533/). December 2021.
|
||||
* Fioravanti G, Prostamo A, Casale S. Taking a Short Break From Instagram: The Effects on Subjective Well-Being. [_Cyberpsychology, Behavior, and Social Networking_](https://pubmed.ncbi.nlm.nih.gov/31851833/). February 2020.
|
||||
* Schmuck D. Does Digital Detox Work? Exploring the Role of Digital Detox Applications for Problematic Smartphone Use and Well-Being of Young Adults Using Multigroup Analysis. [_Cyberpsychology, Behavior, and Social Networking_](https://pubmed.ncbi.nlm.nih.gov/32354288/). August 2020.
|
||||