Programación AHA

Rate this content
Bookmark

¿Eres el tipo de programador que prefiere nunca ver el mismo código en dos lugares, o haces uso liberal de copiar/pegar? Muchos desarrolladores juran por la filosofía de No Repetirte (DRY) mientras que otros prefieren Escribir Todo Dos Veces (WET). Pero, ¿cuál de estos produce bases de código más mantenibles? He visto que ambos enfoques arruinan bases de código y tengo una nueva ideología que me gustaría proponerte: Evitar Abstracciones Apresuradas (AHA). En esta charla, hablaremos sobre abstracción y cómo puedes mejorar una base de código aplicando y creando abstracciones de manera más reflexiva, así como cómo salir de un lío de sobre o sub-abstracción.

32 min
02 Aug, 2021

Video Summary and Transcription

La charla discute el concepto de programación AHA, que enfatiza abstracciones reflexivas. Presenta un ejemplo codificado en vivo del ciclo de vida de una abstracción y demuestra cómo solucionar errores y mejorar abstracciones. Se destaca la importancia de evitar abstracciones complejas y el valor de la duplicación sobre la abstracción incorrecta. La charla también ofrece ideas sobre cómo construir las abstracciones correctas y ofrece recursos para seguir aprendiendo.

Available in English

1. Introducción a la programación AHA

Short description:

Hola a todos. Mi nombre es Kent C. Dodds y estoy muy emocionado de hablar con ustedes de forma virtual. Estoy emocionado de hablarles sobre la programación AHA. Aquí hay algunos enlaces que podrían ser interesantes para ustedes. Tengo un sitio web en la World Wide Web. Y, en particular, testingjavascript.com. Si aún no lo han probado o lo han visto, definitivamente échenle un vistazo. Y epicreact.dev será aún más grande. Una gran cantidad de contenido estará disponible para ustedes en epicreact.dev en un futuro muy cercano.

Mi nombre es Kent C. Dodds y estoy muy emocionado de hablar con ustedes de forma virtual. Espero que todos estén sanos, felices y bien. Y estoy emocionado de hablarles sobre la programación AHA. Así que adelante y pongan a un lado sus principios de programación seca y húmeda por un momento y hablemos sobre evitar abstracciones apresuradas, programación AHA.

Tengo algunos enlaces aquí que podrían ser interesantes para ustedes. A diferencia de mis diapositivas. Y estoy hablando desde Utah. Tengo una esposa y cuatro hijos y un perro y son increíbles. Tengo un sitio web en la World Wide Web. Y, en particular, testingjavascript.com. Si aún no lo han probado o lo han visto, definitivamente échenle un vistazo. Les enseñará todo lo que sé sobre testing, que no es una cantidad pequeña. Y epicreact.dev será aún más grande. Una gran cantidad de contenido estará disponible para ustedes en epicreact.dev en un futuro muy cercano. Así que estén atentos a eso. Echen un vistazo al resto de estas cosas más tarde.

2. Introducción al ciclo de vida de la abstracción

Short description:

Este es un ejemplo codificado en vivo y ficticio del ciclo de vida de una abstracción. Vamos a considerar qué es importante y por qué es importante ser reflexivo acerca de una abstracción. Es como un ejemplo real de una historia contada por Sandy Metz en esta publicación de blog, La Abstracción Equivocada.

Vamos a seguir adelante y adentrarnos en esto. Esto es lo que vamos a cubrir hoy. Este es un ejemplo codificado en vivo y ficticio del ciclo de vida de una abstracción. Espero que puedas relacionarte con esto, aunque sea un poco ficticio. Pero creo que de todos modos lo disfrutarás.

Y vamos a considerar qué es importante y por qué es importante ser reflexivo acerca de una abstracción. Básicamente vamos a tomar esta historia... Es como un ejemplo real de una historia contada por Sandy Metz en esta publicación de blog, La Abstracción Equivocada, que te recomiendo encarecidamente que leas.

No vamos a pasar diapositivas. La mayor parte de esto está en mi editor de texto aquí, y no es consumible de forma pasiva. Así que debes decidir ahora mismo si te vas a enfocar en Twitter o en mi charla. Porque no podrás hacer ambas cosas de manera efectiva. Así que simplemente elige. No me ofendo.

3. Fixing the Display Name Bug

Short description:

Aquí estamos en 02.js. Tenemos una aplicación con un objeto de usuario llamado Phil. Hay un error que dice Philip indefinido en lugar de Rodrigues. Se nos ha dado la tarea de solucionar este problema. En lugar de arreglar el error en varios lugares, creemos una abstracción llamada GetDisplayName para solucionarlo automáticamente.

Aquí estamos en 02.js. Y voy a usar una herramienta llamada CuocaJS. Es una extensión para VS Code. Entre otras cosas, me permite hacer console log aquí y mostrará en azul el valor de esa declaración de log. Y lo vamos a usar bastante.

Tenemos una aplicación y aquí tenemos un objeto de usuario. Este es Phil. Y Phil tiene un nombre y un nombre de usuario. Y en tres lugares diferentes de nuestra aplicación tenemos código para obtener el nombre de usuario de ese usuario para el primer y último nombre. Este es su nombre que vamos a mostrar en toda la interfaz de usuario de nuestra aplicación. Ahora puedes notar que en realidad tenemos un error aquí y esta es nuestra primera parte de la abstracción. Aquí estamos diciendo Philip indefinido. Pero el apellido de Philip es Rodrigues. Ese es su apellido. Y está un poco frustrado de que diga Philip indefinido cuando inicia sesión en nuestra aplicación.

Se nos ha dado la tarea de solucionar este problema. Y cuando trabajaba en una empresa antes, recuerdo que decían: Oye, tenemos Así que iba a arreglarlo. Y luego el probador manual de QA allí decía: Oye, Kent, pensé que dijiste que lo arreglaste. Y yo decía, sí, lo hice. Y tú decías, bueno, está roto aquí. Oh, vaya. Sí, supongo que fue copiado y pegado. Así que vamos a arreglarlo también allí. Y fue un verdadero dolor. Así que construimos abstracciones para no tener que arreglar el mismo error en muchos lugares. Y tenemos tres lugares donde estamos haciendo exactamente lo mismo. Así que en lugar de arreglar el error aquí mismo, ¿qué tal si simplemente creamos una abstracción y la colocamos y luego todos los demás lugares obtendrán eso arreglado automáticamente. Así que vamos a hacer eso. Voy a hacer una función aquí llamada GetDisplayName. Tomaremos un usuario y luego devolveremos esto y lo generalizaremos. Así que tomaremos ese usuario, obtendremos el nombre y en lugar del primer y último, haremos primero y último.

4. Enhancing the Abstraction for Honorific

Short description:

Reemplazamos todas las apariciones de getDisplayName con la nueva función para Phil, solucionando el error en un solo lugar. Sin embargo, ahora necesitamos agregar soporte para el honorífico en la página de perfil. Dado que ya tenemos una abstracción en su lugar, es natural mejorarla para admitir el nuevo caso de uso. Agregaremos una opción 'includeHonorific' a la función, estableciéndola en false de manera predeterminada para evitar afectar a los usuarios existentes. Esto es solo una refactorización regular sin cambios por ahora.

Entonces, sigamos adelante y reemplazaremos todas estas apariciones por getDisplayName para Phil y luego lo solucionaremos en este único lugar, al final. ¡Ta-da, y todos los lugares se han solucionado! Estamos realmente contentos con esto porque significa que no tenemos que solucionarlo en todos los demás lugares. Solo lo solucionamos en este único lugar y si alguna vez queremos hacer cambios, solo tenemos que hacer cambios en esta función, lo cual es genial.

Bueno, resulta que realmente necesitamos hacer algunos cambios y eso es si en la página de perfil decidimos incluir el honorífico. Digamos que el Dr. Philip Rodríguez dice: `Oye, sería genial si mi página de perfil dice que soy un doctor`. Como fui a mucha escuela, quiero que la gente sepa que soy un doctor. El gerente de producto viene y te dice: `Oye, queremos agregar el honorífico a la página de perfil, el nombre que se muestra allí`, y tú dices: `De acuerdo, genial`. Entonces vienes al código y piensas: `Oh, sí, escribí esta abstracción para esto`. Dado que la abstracción existe, nuestra inclinación natural es ir a la abstracción para mejorarla y admitir el nuevo caso de uso, y también para ver si ya admite el nuevo caso de uso. Así que estamos naturalmente inclinados a ir primero a la abstracción. Y vemos esto y vemos que no hay soporte para el honorífico, así que podríamos eliminar la abstracción aquí o agregar ese caso de uso a esta abstracción existente. Es muy natural para nosotros preferir usar la abstracción existente por varias razones. Tal vez pensemos que otras personas podrían beneficiarse de este caso de uso adicional, o tal vez simplemente sintamos que, dado que ya estamos usando la abstracción, no quiero renunciar a todos los beneficios que me brinda la abstracción. Y en un escenario del mundo real, eso podría ser bastante. Y sí, no necesariamente querrías eliminar la abstracción solo para agregar una característica. Así que parece mucho más fácil mejorar la abstracción para admitir el caso de uso. Entonces eso es lo que vamos a hacer. Y lo que haremos es tomar opciones. Pero no todos pasarán opciones, ¿verdad? Así que lo estableceremos por defecto como un objeto. Y no quiero llamarlo simplemente opciones. Lo desestructuraremos. Y solo tomaremos e incluiremos honorífico. Y lo estableceremos por defecto en false. No queremos afectar a los usuarios existentes de esta abstracción. Así que diremos incluir honorífico aquí. Tomaremos un nombre para mostrar y devolveremos el nombre para mostrar. Así que eso es solo una refactorización regular. Aún no hemos cambiado nada.

5. Mejorando la Abstracción con el Nombre de Usuario

Short description:

Ahora tomaremos ese nombre para mostrar y, si hay un honorífico incluido, lo incluiremos. Hemos reutilizado la abstracción. Sigamos adelante y escribamos pruebas unitarias para asegurarnos de no romper esta funcionalidad. En el futuro, necesitaremos admitir un nombre de usuario para la tarjeta de usuario. Agregaremos esta funcionalidad a la abstracción incluyendo el nombre de usuario.

Ahora tomaremos ese nombre para mostrar. Y si hay un honorífico incluido, diremos que el nombre para mostrar es lo que es. Lo pondremos en una plantilla literal allí. Pero incluiremos el honorífico. Así que diremos user.name.honorific. Genial.

Y luego aquí en la página de perfil, podemos decir incluir honorífico. Sí. Y listo. Lo hemos logrado. Estamos muy contentos con esto. Lo confirmamos. Lo revisamos. Y la gente dice, wow, genial. Hemos reutilizado la abstracción. Así que aprovechemos todo el poder que tenemos con esta abstracción.

Sigamos adelante y escribamos un par de pruebas unitarias para asegurarnos de no romper esta funcionalidad que hemos agregado. Y seguimos avanzando. Y en el futuro, alguien viene y dice, hey, necesitamos admitir un nombre de usuario para la tarjeta de usuario. Queremos que diga su nombre y luego entre paréntesis, su nombre de usuario. Y dices, okay, eso debería ser bastante sencillo. Volvemos a la abstracción. Vemos que no está admitido. Y en lugar de eliminar la abstracción de nuestro código, vamos a agregar esta funcionalidad a la abstracción. Pero no queremos romper lo existente, así que vamos a tocar lo menos posible. Y simplemente agregaremos otra opción aquí para incluir el nombre de usuario. Y lo estableceremos por defecto en falso porque no queremos romper a los usuarios existentes de esta abstracción. Y diremos si incluir nombre de usuario, excepto que tienes que escribirlo correctamente, de lo contrario no funcionará. Y diremos que el nombre para mostrar es el nombre para mostrar actualmente, y luego entre paréntesis, y luego el nombre de usuario, así que user.nombreDeUsuario. Genial, y luego aquí abajo podemos decir incluir nombre de usuario verdadero.

6. Evolución de la Abstracción y Complejidad de las Pruebas

Short description:

Agregamos pruebas para respaldar diferentes combinaciones de opciones. Más tarde, recibimos una solicitud de función para mostrar la inicial en lugar del primer nombre. Modificamos la abstracción para admitir este nuevo caso de uso sin romper el código existente. Sin embargo, los casos de uso admitidos por la abstracción han divergido significativamente. Escribir pruebas para casos de uso inexistentes puede complicar futuras refactorizaciones.

Perfecto, esto es exactamente lo que querían. Pudimos codificar eso en la abstracción y agregamos un par de pruebas para asegurarnos de que esto sea compatible. Y de hecho, en el proceso de agregar pruebas, nos damos cuenta de que hay algunas combinaciones de estas opciones que en realidad no admitimos o que en realidad no necesitamos en nuestro código base pero nuestra abstracción admite y tal vez nos demos cuenta de eso, tal vez no, pero sabemos que esos casos de uso están admitidos donde podrías proporcionar ambos como verdaderos.

Y así agregamos pruebas para eso solo para asegurarnos de que nadie rompa esa función existente. Por si acaso alguien quisiera usar esa función en el futuro. Y así no es demasiado complicado. Es una función pura, es muy fácil de probar, así que seguimos adelante y agregamos una prueba para eso. Y luego más adelante, recibimos otra solicitud de función para este código y dicen, hey, nuestra navegación, queremos que el primer nombre no sea un primer nombre, sino una inicial. Y así vuelves a la abstracción, dices, okay, eso no está admitido hoy. No quiero perder los beneficios de tener la abstracción, está bien probada. Y así voy a agregar mi código aquí, pero no quiero romper nada de lo que ya está ahí. No quiero romper el código existente. Así que voy a tomar una inicial, lo estableceré por defecto en falso, para que los usuarios existentes de esta abstracción no se vean afectados, y tomaremos esa inicial como una opción. Y diremos, si la inicial es verdadera, entonces queremos que el primer nombre sea solo la primera inicial. Así que lo que voy a hacer es sacar esto, lo llamaremos primero. Y en realidad lo asignaremos a un let aquí para que primero sea igual a user.name.first. Y luego, si la inicial es verdadera, entonces diremos que primero es igual a la primera, y cortaremos el primer carácter y agregaremos un punto. Genial, y luego podemos venir aquí abajo y decir, incluir o en realidad es una inicial verdadera. Y boom, tenemos todos estos casos de uso admitidos por nuestra abstracción, tenemos un par de pruebas más aquí, y estamos muy contentos con esto.

Ahora hay dos cosas que quiero destacar sobre esto. En primer lugar, ahora tenemos tres usos de esta abstracción, y tal vez haya más en todo el código base, pero estos tres no se parecen en nada. No tienen nada en común entre sí. Aparte de que algunos de ellos muestran el primer y el último nombre, pero cada uno de ellos tiene diferencias muy distintas entre sí. Y así, esto es algo bastante común que sucede con las abstracciones, es que eventualmente la abstracción evoluciona más allá del caso de uso inicial, y eso no necesariamente es algo malo, pero todos los casos de uso se han divergido bastante entre sí. Y así, aunque nuestra abstracción admite muchas cosas, en realidad está admitiendo casos de uso que no están completamente relacionados entre sí. El otro problema con esto es que al escribir pruebas para esto, estaremos escribiendo pruebas para admitir casos de uso que en realidad no tenemos. Y aunque eso tal vez no sea algo terrible, aquí está el problema con eso. A medida que escribimos todas estas pruebas para probar casos de uso, cuando lleguemos a refactorizar esto si queremos hacer mejoras, entonces tenemos que asegurarnos de que nuestras refactorizaciones admitan todo lo que nuestras pruebas dicen que nuestra abstracción admite.

7. Evitando y Solucionando la Complejidad de las Abstracciones

Short description:

La prueba tiene como objetivo asegurarse de que los casos de uso que necesitas admitir se admitan de manera continua. Al agregar características sin pensar, terminamos en una situación complicada. A menudo mantenemos código y características innecesarias debido al bajo costo y alto riesgo de eliminarlas. Dejar código no utilizado requiere mantenimiento. Terminamos con una abstracción complicada y difícil de trabajar. Sandy Metz sugiere reintroducir la duplicación y eliminar selectivamente el código innecesario como una forma de evitar o solucionar este problema.

Pero lo único que se preocupa por ese caso de uso es la prueba, por lo que existe por sí misma. Y eso es completamente inútil. La prueba tiene como objetivo asegurarse de que los casos de uso que necesitas admitir se admitan de manera continua y si el único que se preocupa por eso no son los usuarios sino las pruebas, entonces simplemente elimina la prueba y ahora a nadie le importa.

Y así, al agregar características sin pensar a esta abstracción, terminamos en una situación realmente complicada y no se detiene aquí. No, tenemos más por hacer. ¿Qué pasa si la página de perfil ya no quiere el tratamiento de cortesía? Entonces pensamos, está bien, sí, eso está bien. Podemos simplemente eliminar el tratamiento de cortesía, boom, se ha ido, estamos contentos, guardamos esto, lo confirmamos, lo enviamos, se fusiona, estamos contentos con esto porque todo lo que tomó fue eliminar esa opción. Y esto es lo que normalmente sucede y en realidad no pensamos en sacar la opción de tratamiento de cortesía y deshacernos del código específico para el tratamiento de cortesía o tal vez sí pensamos en eso y hay un par de razones más por las que es posible que no queramos eliminarlo. Por un lado, el costo de mantenerlo en su lugar es bastante bajo, ¿verdad?, o se siente bajo y el riesgo de eliminarlo y romper algo accidentalmente, eso realmente se siente alto y así con ese análisis de costo versus riesgo, simplemente decidimos mantenerlo allí, no quiero romper nada.

Hacemos esto mucho con CSS en particular, como CSS global. Preferiría agregar algo nuevo en lugar de modificar algo existente o, peor aún, eliminar algo existente porque es muy difícil identificar si realmente se está utilizando. Y siempre hay algo que queda en tu mente, tal vez algún día queramos incluir el tratamiento de cortesía en el futuro, así que dejaremos esa característica y entonces nadie tendrá que hacer cambios para admitir ese caso de uso en el futuro. Y eso también es problemático porque tenemos Git y podemos volver y ver cómo era el código en ese momento. Así que no es algo sin costo dejar este código en su lugar porque tenemos que mantenerlo mientras hacemos refactorizaciones, si lo dejamos allí. Y el único que se preocupa de que este código exista es el código y la prueba en sí, así que si los eliminamos, entonces a nadie le importa y está bien.

Pero aún no hemos terminado. ¿Qué pasa si en nuestra tarjeta de usuario, en lugar del nombre y apellido, deciden, hey, en realidad solo queremos mostrar el apellido. Hacer eso con lo que tenemos aquí es realmente fácil. Simplemente eliminamos la abstracción y luego decimos fill.username() pero debido a que la abstracción existe, nos atrae y pensamos, ¿sabes qué? En lugar de incluir el nombre de usuario, tendré un solo nombre de usuario y luego aquí aceptaré ese solo nombre de usuario. Lo estableceremos por defecto en falso para no romper a otras personas y no quiero tocar nada de esto. Simplemente lo agregaremos aquí abajo y diremos solo nombre de usuario display name igual a user.username() y ahí lo tenemos, tenemos soporte para esta nueva característica y ahora tenemos dos opciones que a nadie le importan excepto el código en sí y las pruebas que se escribieron para asegurarse de que no rompamos esos casos de uso. Así que hemos terminado con una abstracción que en realidad es mucho más complicada de lo necesario y podemos refactorizarla, pero ahora tenemos todas estas pruebas que se aseguran de que no rompamos estos casos de uso que en realidad no nos importan y así se convierte en un lío enredado y esta es una función bastante simple, simplemente concatena cadenas juntas. Piensa en tus complicados componentes React o tus componentes Angular o lo que sea que estés escribiendo y todas estas diferentes abstracciones que has construido en torno a esto y es bastante fácil construir una abstracción que sea aterradora de trabajar. Entonces, ¿cómo evitamos este problema o cómo retrocedemos cuando estamos en él? Y esto es algo de lo que Sandy Metz habla en su publicación de blog, La Abstracción Equivocada. Realmente te aconsejo que le eches un vistazo porque es realmente genial y ella tiene una charla aquí a la que puedes ir y ver, pero aquí ella dice que la forma más rápida de avanzar es retroceder. Entonces, la idea es primero reintroducir la duplicación mediante la inclusión en línea y luego con cada color que uses los parámetros que se pasan para determinar el subconjunto del código en línea que es específico para los colores, lo que el color ejecuta y luego eliminar las partes que no se necesitan para ese color en particular. Y así, en este caso, eso básicamente significa que haremos tres copias de getDisplayName y lo incluiremos en cada una de ellas y luego eliminaremos las partes de cada una de ellas que ya no se necesitan. Así que repasemos eso rápidamente. Lo que voy a hacer es console.log justo aquí y solo necesito tener un console.log justo aquí que sea igual que este. Y el nuestro es bastante simple, así que realmente no necesito hacer una función separada.

8. Inlining the Abstraction

Short description:

Voy a revisar la función y tomar las partes que necesito. Así que aquí solo necesitamos la inicial y luego el apellido. Eso es prácticamente todo el código que necesito para esto. Así que voy a tomar esto aquí. Vamos a obtener el primer nombre de fill.name.first. Y el resto está aquí. Así que vamos a tomar eso. Y en lugar de user, será fill. Ahora esta situación o este archivo de navegación ya no está utilizando la abstracción. Vamos a inlinar la abstracción en todos los lugares donde se utiliza y luego la podemos eliminar. Para el siguiente, agregaremos un console.log y obtendremos el primer y último nombre de fill.name.first y fill.name.last. Para el último, solo necesitamos el nombre de usuario de fill.username. Ahora que has identificado las similitudes entre diferentes abstracciones y las diferencias, eres más reflexivo sobre la abstracción que estás haciendo. Recuerda, la duplicación es mucho más barata que la abstracción equivocada.

Voy a revisar la función y tomar las partes que necesito. Así que aquí solo necesitamos la inicial y luego el apellido. Eso es prácticamente todo el código que necesito para esto. Así que voy a tomar esto aquí. Lo pondremos justo aquí. Y vamos a obtener el primer nombre de fill.name.first. Bien, eso obtiene nuestro p dot. Y el resto está aquí. Así que vamos a tomar eso. Y en lugar de user, será fill. Bien, esas dos cosas son iguales, así que podemos tomar esto ahora y ponerlo en lugar de la abstracción. Ahora esta situación o este archivo de navegación ya no está utilizando la abstracción y podríamos venir aquí y eliminar las cosas que ya no se están utilizando, pero sigamos adelante y inlinemos la abstracción en todos los lugares donde se utiliza y luego la podemos eliminar.

El siguiente es solo el primer y último nombre, y eso está aquí o no es esta parte aquí. Así que vamos a tomar eso, agregaremos un console.log justo aquí y el primero vendrá de fill.name.first y esto será fill.name.last y vamos a necesitar poner eso en una plantilla de etiqueta o en un literal de plantilla allí. Ahí vamos. Genial, eso es exactamente lo que necesitamos, así que vamos a reemplazar eso y ahora hemos eliminado la abstracción de ese y luego para nuestro último, es solo el nombre de usuario y todo lo que estamos usando de la abstracción para esto es solo user.username. Así que vamos a bajar aquí y es tan fácil que solo voy a decir fill.username. ¡Tada! Ahí está. Tenemos exactamente lo mismo que teníamos antes y resulta que podemos eliminar todo esto Ha desaparecido de nuestro código, esa cosa grande, peluda y aterradora de la que te preocupabas se ha ido y tal vez lo tengas todo en línea como esto o tal vez era un gran componente y tienes como cuatro copias diferentes del mismo componente que son solo ligeramente diferentes para cada caso de uso. Ahora que tienes esas cuatro copias diferentes, puedes ver las similitudes entre algunas de ellas y tal vez sean dos categorías diferentes de esa misma abstracción. Está la que muestra el desplegable y luego está la categoría que no lo hace y así que las mantendremos como cosas separadas. Sea cual sea el caso, pero debido a que has hecho esto, eres capaz de identificar las similitudes entre las diferentes abstracciones y las diferencias y en tu estado actual al construir esto hoy, eres mucho más capaz de crear una abstracción que funcione para lo que tenemos hoy. Has experimentado, tienes algunas cicatrices de batalla en malas abstracciones, eres más reflexivo sobre la abstracción que estás haciendo.

Con todo esto, solo quiero concluir con un par de puntos clave. En primer lugar, DRY, no te repitas o DRY, eso no es necesariamente algo malo, no te repitas en teoría es una buena idea porque nos permite deshacernos de algunos errores lógicos del negocio en un solo lugar o incluso algunos errores tipográficos si no estás usando TypeScript, pero realmente puede ayudarte a evitar cierta duplicación. La duplicación no es inherentemente mala, pero puede ser un problema y puede propagar un montón de errores por todas partes. Así que no repetirse en sí mismo no es necesariamente malo. Pero la clave aquí es que no puedes predecir el futuro. Así que lo único en lo que realmente deberías optimizar es el cambio. Algo de lo que Sandy Mintz habla es que la duplicación es mucho más barata que la abstracción equivocada. Así que prefiere la duplicación en lugar de la abstracción equivocada.

9. Building the Right Abstractions

Short description:

A medida que duplicas código y esperas a que aparezcan las similitudes, las abstracciones correctas se vuelven más obvias. Sigue duplicando código y luego identifica las similitudes. Si hay ramas de código compartido, refactoriza en lugar de agregar más condicionales. Aprende sobre los usuarios y divide la abstracción en piezas manejables.

Estoy completamente de acuerdo con eso y creo que a medida que duplicas cosas y simplemente esperas a que las similitudes en ese código duplicado te griten que necesitas una abstracción, entonces esas abstracciones se vuelven mucho más obvias para ti y puedes construir la abstracción correcta para los casos de uso que tienes presentes en ese momento. Entonces, mientras construyes cosas y tienes todas estas ideas como, oh, una buena abstracción aquí, una buena abstracción allá, simplemente sigue duplicando cosas. Copia y pega, muévelo y una vez que hayas terminado, puedes ver lo que tienes y ver las similitudes y pensar, oh, en realidad estas dos cosas no son tan comunes como pensaba cuando quería abstraerlas por primera vez. Así que me alegro de no haberlo hecho. Las dejaremos como cosas separadas o, estas dos cosas son realmente comunes, hay solo como tres cosas que podría parametrizar y luego puedes hacer una abstracción para eso. Si tienes código compartido con muchas ramas, te recomiendo que resistas la tentación de agregar más condicionales y en su lugar lo refactores primero. Aprende todo lo que puedas sobre los usuarios de esa abstracción y tal vez haya algo que puedas aprender sobre la abstracción en su conjunto para que puedas dividirla en varias piezas que sean más fáciles de manejar por sí mismas.

QnA

Resources and Q&A on Aha Programming

Short description:

Así que tengo un par de recursos para ti. Sandy Metz dio una charla llamada Todas las pequeñas cosas. Tengo una publicación en el blog sobre la Programación Aha y una variante de pruebas. Sígueme en Twitter. Gracias. La charla de Kent sobre la Programación Aha siempre es maravillosa. Hagamos algunas preguntas y respuestas. Kent comparte el origen de Aha y las frustraciones con la programación repetitiva y la creación de abstracciones.

Así que tengo un par de recursos para ti. Sandy Metz dio una charla que es realmente buena en torno a esta misma idea llamada Todas las pequeñas cosas. Definitivamente échale un vistazo. Y luego, por supuesto, la publicación en el blog también es genial. Y luego tengo una publicación en el blog sobre este concepto de Programación Aha que puedes consultar en mi blog. Y también tengo una variante de testing de eso. Y sí, sígueme en Twitter porque tuiteo cosas. Muchas gracias. Espero que tengas un tiempo maravilloso en la conferencia. Mantente feliz, mantente saludable y sí, suscríbete. Gracias.

Muy bien. Eso estuvo excelente. Kent, como siempre, esa fue una charla maravillosa. Si eres nuevo en el concepto de Programación Aha, creo que es algo muy interesante. Siempre me encanta ver lo que hace Kent. Y ahora vamos a traer a Kent de vuelta al escenario y haremos algunas preguntas y respuestas. Tenemos algunas preguntas geniales en Slack. Kent, bienvenido de vuelta. Gracias. Gracias. Estoy muy emocionado de estar aquí. Siempre disfruto pasar tiempo contigo, Jason, y nuestros 4,000 amigos o cuantas personas estén viendo en este momento. Sí, creo que ahora estamos por encima de las 4,000 personas en la transmisión en vivo. Así que vaya. Tenía una pregunta porque en realidad te he estado siguiendo durante mucho tiempo y recuerdo el origen de Aha, así que te voy a poner un poco en aprietos. Pero Aha no siempre se llamó Aha. ¿Puedes hablar un poco sobre los orígenes de cómo llegaste hasta ahora? Sí, Aha fue como mis frustraciones con la programación repetitiva como un practicante al principio. Aprendí sobre no repetirte a ti mismo y lo importante que es que crees abstracciones para las cosas. Y luego descubrí lo que creo que la mayoría de las personas descubren con eso, que eventualmente las abstracciones que creas son realmente malas.

Introduction to AHA Programming Continued

Short description:

Y luego escuché sobre la programación húmeda, que consiste en escribir todo dos veces. Y también me frustré con eso porque luego tienes que corregir errores en varios lugares. Y pensé que ambos eran demasiado dogmáticos. Así que decidí ser más consciente de las abstracciones que creamos y espero que todo sea mejor. Eso es genial. Mencionaste brevemente esto, pero quiero hablar, bueno, en realidad, sabes lo que respondiste. No te lo voy a decir, hablaste sobre la diferencia entre dry y AHA. Así que vamos a ir a Slack y alguien pregunta, hay una gran pregunta aquí. ¿Cómo implementas esto en un proyecto? Si lo fueras a implementar en un proyecto específico, ¿cómo lo integrarías en tu proceso? Esa es una gran pregunta. Creo que es muy tentador cuando estamos, si estás comenzando un proyecto completamente nuevo o te unes a un proyecto y ves el desastre de abstracciones que tenemos aquí o lo que sea. Es muy tentador querer arquitecturar todo desde el principio. Y eso es un error enorme. Automáticamente, tienes una base de código de 3000 líneas de código hasta ahora, y la estás arquitecturando para una base de código de tres millones de líneas.

Y luego escuché sobre la programación húmeda, que consiste en escribir todo dos veces. Y también me frustré con eso porque luego tienes que corregir errores en varios lugares. Y pensé que ambos eran demasiado dogmáticos. Así que decidí ser más consciente de las abstracciones que creamos y espero que todo sea mejor, con suerte.

Y así, en el proceso de escribir una publicación en el blog sobre esto, porque tengo que escribir un blog que pienso, decidí, está bien, no es dry, no es wet. ¿Qué no son esas cosas? Supongo que es húmedo. Y así es como lo llamé al principio, húmedo. Y realmente no me gusta el sonido de esa palabra. Y sé que a mucha gente le parece realmente incómodo. Pero pensé, está bien. Y realmente no podía pensar en qué podría significar eso. Así que ni siquiera hice un acrónimo para eso. Y tuiteé al respecto y recibí muchas respuestas de personas que decían que eso era asqueroso. Se reían histéricamente al respecto. Así que pensé, está bien, está bien, necesito encontrar un nombre diferente. Y Cher Scarlet me dio un nombre perfecto. Y AHA, Evitar Abstracciones Apresuradas, era perfecto. Es como un momento de iluminación. Me encanta para todo, ya sabes, es el acrónimo perfecto. Así es de donde viene eso.

Eso es genial. Mencionaste brevemente esto, pero quiero hablar, bueno, en realidad, sabes lo que respondiste. No te lo voy a decir, hablaste sobre la diferencia entre dry y AHA. Así que vamos a ir a Slack y alguien pregunta, hay una gran pregunta aquí. ¿Cómo implementas esto en un proyecto? Si lo fueras a implementar en un proyecto específico, ¿cómo lo integrarías en tu proceso? Esa es una gran pregunta. Creo que es muy tentador cuando estamos, si estás comenzando un proyecto completamente nuevo o te unes a un proyecto y ves el desastre de abstracciones que tenemos aquí o lo que sea. Es muy tentador querer arquitecturar todo desde el principio. Y eso es un error enorme. Automáticamente, tienes una base de código de 3000 líneas de código hasta ahora, y la estás arquitecturando para una base de código de tres millones de líneas.

Enfoque Iterativo y Evitar Malas Abstracciones

Short description:

Toma un enfoque iterativo y no te preocupes por la duplicación. Si encuentras malas abstracciones en una base de código, incorpóralas en línea y finge que siempre han sido así. Sé reflexivo y evita tratar de arquitecturar toda la aplicación para lo que no es hoy.

Terminarás en malas abstracciones y nunca llegarás a esa base de código de tres millones de líneas. Al menos no una en la que quieras trabajar. Así que recomiendo tomar un enfoque realmente iterativo. No te preocupes por la duplicación y, si te encuentras con una base de código con malas abstracciones, entonces lo que menciono en la charla y haciendo referencia a Sandy Metz allí, incorpora esas abstracciones en línea y luego, puedes fingir que siempre ha sido así y pensar, wow, hay una abstracción justo aquí esperándome. Pero será totalmente diferente de la mala abstracción que incorporaste antes. Al menos, con suerte, lo será. Pero eso es lo que recomendaría, sé muy reflexivo en todo el proceso. No intentes arquitecturar toda tu aplicación, eso para algo que no es hoy.

Considerando Abstracción y Duplicación de Código

Short description:

En el contexto de la abstracción, es importante considerar si extenderla o crear múltiples funciones. Copiar el código inicialmente ayuda a determinar si la abstracción es necesaria o si el código no es tan similar como se pensaba. Un ejemplo es tener botones de inicio de sesión y registro similares con atributos diferentes. Crear un componente con muchas props puede no ser más simple que la duplicación. La implementación puede diferir incluso si el código parece visualmente igual. Agregar más props para diferencias pequeñas crea más trabajo. El costo de una mala abstracción puede ser peor que duplicar código y errores. Sin embargo, es un tema sutil y no debe interpretarse como una aversión a la abstracción.

Entonces, una pregunta aquí que creo que, en el contexto de una abstracción, es si sientes que la abstracción no debería extenderse o si sería mejor simplemente extenderla y ver qué sucede hasta que termines con tres o cuatro funciones y luego cambiar. Tal vez no entiendo completamente la pregunta pero mi proceso de pensamiento normalmente, esto es algo por lo que realmente tuve que luchar, pero mientras estoy trabajando en algún código antes de comprometerme con algo solo estoy jugando con cosas, constantemente estoy pensando, oh, esto se parece mucho a esto así que pongámoslo en una función. Y realmente tuve que luchar contra mí mismo y decir, no, no, no, no, no lo hagas todavía. Solo cópialo, incluso si son como cinco líneas de código, aunque parezca tan duplicado, solo copia y pega eso porque eventualmente descubrirás una de dos cosas. O descubrirás que no lo necesitabas en absoluto en primer lugar y así tomar el tiempo para hacer la abstracción y crear los nombres de las variables y generalizar esa función fue una pérdida de tiempo de todos modos o descubrirás que no eran tan similares como pensabas que eran. Así que sí, no sé si eso responde a la pregunta porque tal vez la entendí mal, pero eso es, sí.

Me gustaría profundizar en eso en realidad. Entonces, cuando dices que te das cuenta de que no son tan similares como pensabas, ¿tienes algún ejemplo? Porque siento que eso es una de esas cosas que es fácil de decir en abstracto y difícil de poner en términos concretos. Entonces, si alguien está pensando en esto, ¿cuándo es el caso en que el mismo código, código que has copiado y pegado no es tan similar como pensamos que es.

Sí, esa es una gran pregunta. Un ejemplo de esto que experimenté recientemente y especialmente en una conferencia de React, así que un ejemplo de React, tenía un botón de inicio de sesión y un botón de registro, muy similares, solo palabras diferentes y etiquetas ARIA diferentes para el modal, aparecen en diferentes colores y cosas así. Y pensé, ¿sabes qué? Estos son realmente similares. Podría hacer un componente de React, solo tomar un par de props, pero me contuve. Y descubrí que si hiciera un componente para esto, habría tantas props pequeñas como, esto es lo que debería ser la etiqueta ARIA, esto es lo que debería ser el título del modal, esto es lo que debería ser el tipo de botón. Y simplemente no veo que ese tipo de abstracción sea más simple que la duplicación que tengo en su lugar. Es como si cada uno tuviera seis o siete líneas de código. Ahora hay una pequeña parte ahí que el modal que aparece tiene un pequeño botón de cierre que tiene un estilo específico para los modales de inicio de sesión y registro. Y todo lo que hice fue extraer el CSS para eso porque no hay variables ni nada, no el CSS, sino el JSX para eso. Así que simplemente creé un elemento JSX y luego lo inyecté en línea como una variable. Y así puedo tomar esa pequeña parte de similitud sin convertirla en un componente de función completo que tenga como 12 props. Y sabes, esa es una distinción realmente interesante también porque en ambos casos, estás hablando de código que visualmente se vería igual. Lo que aparece en el navegador, visualmente se ve igual. Es un botón de cierre o es un formulario de registro, pero la implementación es donde comienza a haber diferencias. Si tienes que cambiar cada parte de esos atributos, realmente no estás escribiendo una abstracción, solo te estás dando tareas.

Sí, exactamente. Y luego cada vez que quieras hacer algo que los haga ligeramente diferentes, tienes que agregar otro argumento, otra prop, y solo tienes más trabajo. Y al final del día, ¿qué obtienes? No mucho, solo tareas. Totalmente, totalmente. Ok, así que otra pregunta siguiendo eso. ¿El costo de una mala abstracción suele ser mucho peor que el de duplicar el código en pruebas y posiblemente duplicar errores? ¿Cuál es tu experiencia al respecto? Esa es una gran pregunta y es bastante sutil porque no quiero que nadie salga de mi charla diciendo, oh, a Kent le gusta la duplicación, odia la abstracción.

El Valor de la Abstracción y la Duplicación

Short description:

Como autor de bibliotecas, veo el valor de la abstracción, pero llega un punto en el que la duplicación se convierte en un problema. Si te encuentras duplicando en muchos archivos, puede haber un buen caso para una abstracción. No hay una regla estricta para esto, ya que es sutil.

Eso no es absolutamente cierto. Como autor de bibliotecas, claramente, hago muchas bibliotecas y veo el valor de la abstracción. Solo veo que, llega un punto en el que la duplicación se convierte en un problema real. Para este ejemplo de inicio de sesión y registro que acabamos de compartir, como esa duplicación, está ahí mismo, y si hay un error en uno, es muy fácil solucionar el error en el otro, no es demasiado problema, pero si te encuentras duplicando en muchos, muchos archivos, entonces tal vez haya un buen caso para una abstracción allí. Así que no puedo darte una regla, porque realmente no hay una regla sobre esto, todo es sutil, y sí. Lo siento, eso no es muy útil, pero espero que la charla lo haya sido. No, creo que eso es genial. Y con eso, vamos a seguir adelante, eso es todo el tiempo que tenemos. Kent, muchas gracias, siempre es un placer, y nos vemos en el Slack. Muy bien, nos vemos. Muy bien, adiós. Gracias. Muy bien, adiós. Adiós. Adiós.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

React Advanced Conference 2021React Advanced Conference 2021
39 min
Don't Solve Problems, Eliminate Them
Top Content
Humans are natural problem solvers and we're good enough at it that we've survived over the centuries and become the dominant species of the planet. Because we're so good at it, we sometimes become problem seekers too–looking for problems we can solve. Those who most successfully accomplish their goals are the problem eliminators. Let's talk about the distinction between solving and eliminating problems with examples from inside and outside the coding world.
React Advanced Conference 2022React Advanced Conference 2022
30 min
Using useEffect Effectively
Top Content
Can useEffect affect your codebase negatively? From fetching data to fighting with imperative APIs, side effects are one of the biggest sources of frustration in web app development. And let’s be honest, putting everything in useEffect hooks doesn’t help much. In this talk, we'll demystify the useEffect hook and get a better understanding of when (and when not) to use it, as well as discover how declarative effects can make effect management more maintainable in even the most complex React apps.
React Advanced Conference 2021React Advanced Conference 2021
47 min
Design Systems: Walking the Line Between Flexibility and Consistency
Top Content
Design systems aim to bring consistency to a brand's design and make the UI development productive. Component libraries with well-thought API can make this a breeze. But, sometimes an API choice can accidentally overstep and slow the team down! There's a balance there... somewhere. Let's explore some of the problems and possible creative solutions.
React Summit 2023React Summit 2023
23 min
React Concurrency, Explained
React 18! Concurrent features! You might’ve already tried the new APIs like useTransition, or you might’ve just heard of them. But do you know how React 18 achieves the performance wins it brings with itself? In this talk, let’s peek under the hood of React 18’s performance features: - How React 18 lowers the time your page stays frozen (aka TBT) - What exactly happens in the main thread when you run useTransition() - What’s the catch with the improvements (there’s no free cake!), and why Vue.js and Preact straight refused to ship anything similar
React Day Berlin 2022React Day Berlin 2022
22 min
Jotai Atoms Are Just Functions
Top Content
Jotai is a state management library. We have been developing it primarily for React, but it's conceptually not tied to React. It this talk, we will see how Jotai atoms work and learn about the mental model we should have. Atoms are framework-agnostic abstraction to represent states, and they are basically just functions. Understanding the atom abstraction will help designing and implementing states in your applications with Jotai

Workshops on related topic

React Summit 2023React Summit 2023
170 min
React Performance Debugging Masterclass
Featured WorkshopFree
Ivan’s first attempts at performance debugging were chaotic. He would see a slow interaction, try a random optimization, see that it didn't help, and keep trying other optimizations until he found the right one (or gave up).
Back then, Ivan didn’t know how to use performance devtools well. He would do a recording in Chrome DevTools or React Profiler, poke around it, try clicking random things, and then close it in frustration a few minutes later. Now, Ivan knows exactly where and what to look for. And in this workshop, Ivan will teach you that too.
Here’s how this is going to work. We’ll take a slow app → debug it (using tools like Chrome DevTools, React Profiler, and why-did-you-render) → pinpoint the bottleneck → and then repeat, several times more. We won’t talk about the solutions (in 90% of the cases, it’s just the ol’ regular useMemo() or memo()). But we’ll talk about everything that comes before – and learn how to analyze any React performance problem, step by step.
(Note: This workshop is best suited for engineers who are already familiar with how useMemo() and memo() work – but want to get better at using the performance tools around React. Also, we’ll be covering interaction performance, not load speed, so you won’t hear a word about Lighthouse 🤐)
React Summit Remote Edition 2021React Summit Remote Edition 2021
177 min
React Hooks Tips Only the Pros Know
Top Content
Featured Workshop
The addition of the hooks API to React was quite a major change. Before hooks most components had to be class based. Now, with hooks, these are often much simpler functional components. Hooks can be really simple to use. Almost deceptively simple. Because there are still plenty of ways you can mess up with hooks. And it often turns out there are many ways where you can improve your components a better understanding of how each React hook can be used.You will learn all about the pros and cons of the various hooks. You will learn when to use useState() versus useReducer(). We will look at using useContext() efficiently. You will see when to use useLayoutEffect() and when useEffect() is better.
React Advanced Conference 2021React Advanced Conference 2021
174 min
React, TypeScript, and TDD
Top Content
Featured WorkshopFree
ReactJS is wildly popular and thus wildly supported. TypeScript is increasingly popular, and thus increasingly supported.

The two together? Not as much. Given that they both change quickly, it's hard to find accurate learning materials.

React+TypeScript, with JetBrains IDEs? That three-part combination is the topic of this series. We'll show a little about a lot. Meaning, the key steps to getting productive, in the IDE, for React projects using TypeScript. Along the way we'll show test-driven development and emphasize tips-and-tricks in the IDE.
React Advanced Conference 2021React Advanced Conference 2021
145 min
Web3 Workshop - Building Your First Dapp
Top Content
Featured WorkshopFree
In this workshop, you'll learn how to build your first full stack dapp on the Ethereum blockchain, reading and writing data to the network, and connecting a front end application to the contract you've deployed. By the end of the workshop, you'll understand how to set up a full stack development environment, run a local node, and interact with any smart contract using React, HardHat, and Ethers.js.
React Summit 2023React Summit 2023
151 min
Designing Effective Tests With React Testing Library
Featured Workshop
React Testing Library is a great framework for React component tests because there are a lot of questions it answers for you, so you don’t need to worry about those questions. But that doesn’t mean testing is easy. There are still a lot of questions you have to figure out for yourself: How many component tests should you write vs end-to-end tests or lower-level unit tests? How can you test a certain line of code that is tricky to test? And what in the world are you supposed to do about that persistent act() warning?
In this three-hour workshop we’ll introduce React Testing Library along with a mental model for how to think about designing your component tests. This mental model will help you see how to test each bit of logic, whether or not to mock dependencies, and will help improve the design of your components. You’ll walk away with the tools, techniques, and principles you need to implement low-cost, high-value component tests.
Table of contents- The different kinds of React application tests, and where component tests fit in- A mental model for thinking about the inputs and outputs of the components you test- Options for selecting DOM elements to verify and interact with them- The value of mocks and why they shouldn’t be avoided- The challenges with asynchrony in RTL tests and how to handle them
Prerequisites- Familiarity with building applications with React- Basic experience writing automated tests with Jest or another unit testing framework- You do not need any experience with React Testing Library- Machine setup: Node LTS, Yarn
React Summit 2022React Summit 2022
136 min
Remix Fundamentals
Top Content
Featured WorkshopFree
Building modern web applications is riddled with complexity And that's only if you bother to deal with the problems
Tired of wiring up onSubmit to backend APIs and making sure your client-side cache stays up-to-date? Wouldn't it be cool to be able to use the global nature of CSS to your benefit, rather than find tools or conventions to avoid or work around it? And how would you like nested layouts with intelligent and performance optimized data management that just works™?
Remix solves some of these problems, and completely eliminates the rest. You don't even have to think about server cache management or global CSS namespace clashes. It's not that Remix has APIs to avoid these problems, they simply don't exist when you're using Remix. Oh, and you don't need that huge complex graphql client when you're using Remix. They've got you covered. Ready to build faster apps faster?
At the end of this workshop, you'll know how to:- Create Remix Routes- Style Remix applications- Load data in Remix loaders- Mutate data with forms and actions