Saltar al contenido

¿Por qué la inmutabilidad es tan importante (o necesaria) en JavaScript?

Al fin luego de tanto luchar hemos dado con la solución de este contratiempo que agunos lectores de este sitio web han presentado. Si deseas aportar algo puedes aportar tu comentario.

Solución:

Recientemente he estado investigando el mismo tema. Haré todo lo posible para responder a su (s) pregunta (s) y trataré de compartir lo que he aprendido hasta ahora.

La pregunta es, ¿por qué es tan importante la inmutabilidad? ¿Qué hay de malo en la mutación de objetos? ¿No simplifica las cosas?

Básicamente, se reduce al hecho de que la inmutabilidad aumenta la previsibilidad, el rendimiento (indirectamente) y permite el seguimiento de mutaciones.

Previsibilidad

La mutación oculta el cambio, que crea efectos secundarios (inesperados) que pueden causar errores desagradables. Cuando aplica la inmutabilidad, puede mantener la arquitectura de la aplicación y el modelo mental simples, lo que hace que sea más fácil razonar sobre su aplicación.

Rendimiento

Aunque agregar valores a un Objeto inmutable significa que se debe crear una nueva instancia donde los valores existentes deben copiarse y los nuevos valores deben agregarse al nuevo Objeto que cuesta memoria, los Objetos inmutables pueden hacer uso del uso compartido estructural para reducir la memoria. gastos generales.

Todas las actualizaciones devuelven nuevos valores, pero las estructuras internas se comparten para reducir drásticamente el uso de memoria (y la destrucción de GC). Esto significa que si agrega a un vector con 1000 elementos, en realidad no crea un nuevo vector de 1001 elementos de longitud. Lo más probable es que internamente solo se asignen unos pocos objetos pequeños.

Puedes leer más sobre esto aquí.

Seguimiento de mutaciones

Además del uso reducido de memoria, la inmutabilidad le permite optimizar su aplicación haciendo uso de la igualdad de valores y referencias. Esto hace que sea realmente fácil ver si algo ha cambiado. Por ejemplo, un cambio de estado en un componente de reacción. Puedes usar shouldComponentUpdate para comprobar si el estado es idéntico comparando Objetos de estado y evitar una representación innecesaria. Puedes leer más sobre esto aquí.

Recursos adicionales:

  • El Dao de la inmutabilidad
  • Estructuras de datos inmutables y JavaScript
  • Inmutabilidad en JavaScript

Si configuro, digo una matriz de objetos con un valor inicialmente. No puedo manipularlo. Eso es lo que dice el principio de inmutabilidad, ¿verdad? (Corrígeme si me equivoco). Pero, ¿qué pasa si tengo un nuevo objeto de Noticias que debo actualizar? En el caso habitual, podría haber agregado el objeto a la matriz. ¿Cómo logro en este caso? ¿Eliminar la tienda y volver a crearla? ¿No es una operación menos costosa agregar un objeto a la matriz?

Si eso es correcto. Si está confundido sobre cómo implementar esto en su aplicación, le recomendaría que vea cómo redux hace esto para familiarizarse con los conceptos centrales, me ayudó mucho.

Me gusta usar Redux como ejemplo porque abarca la inmutabilidad. Tiene un único árbol de estado inmutable (denominado store) donde todos los cambios de estado son explícitos mediante el envío de acciones que son procesadas por un reductor que acepta el estado anterior junto con dichas acciones (una a la vez) y devuelve el siguiente estado de su aplicación. Puede leer más sobre sus principios básicos aquí.

Hay un excelente curso de redux en egghead.io donde Dan Abramov, el autor de redux, explica estos principios de la siguiente manera (modifiqué un poco el código para ajustarlo mejor al escenario):

import React from 'react';
import ReactDOM from 'react-dom';

// Reducer.
const news = (state=[], action) => 
  switch(action.type) 
    case 'ADD_NEWS_ITEM': 
      return [ ...state, action.newsItem ];
    
    default: 
        return state;
    
  
;

// Store.
const createStore = (reducer) => 
  let state;
  let listeners = [];

  const subscribe = (listener) => 
    listeners.push(listener);

    return () => 
      listeners = listeners.filter(cb => cb !== listener);
    ;
  ;

  const getState = () => state;

  const dispatch = (action) => 
    state = reducer(state, action);
    listeners.forEach( cb => cb() );
  ;

  dispatch();

  return  subscribe, getState, dispatch ;
;

// Initialize store with reducer.
const store = createStore(news);

// Component.
const News = React.createClass(
  onAddNewsItem() 
    const  newsTitle  = this.refs;

    store.dispatch(
      type: 'ADD_NEWS_ITEM',
      newsItem:  title: newsTitle.value 
    );
  ,

  render() 
    const  news  = this.props;

    return (
      
    news.map( ( title ) =>
  • title
  • )
); ); // Handler that will execute when the store dispatches. const render = () => ReactDOM.render( , document.getElementById('news') ); ; // Entry point. store.subscribe(render); render();

Además, estos videos demuestran con más detalle cómo lograr la inmutabilidad para:

  • Matrices
  • Objetos

Una visión contraria de la inmutabilidad

TL / DR: La inmutabilidad es más una tendencia de moda que una necesidad en JavaScript. Si está utilizando React, proporciona una solución alternativa para algunas opciones de diseño confusas en la administración del estado. Sin embargo, en la mayoría de las otras situaciones, no agregará suficiente valor a la complejidad que introduce, sirviendo más para rellenar un currículum que para satisfacer una necesidad real del cliente.

Respuesta larga: lea a continuación.

¿Por qué la inmutabilidad es tan importante (o necesaria) en javascript?

Bueno, ¡me alegro de que lo hayas preguntado!

Hace algún tiempo, un tipo muy talentoso llamado Dan Abramov escribió una biblioteca de administración de estado de javascript llamada Redux que usa funciones puras e inmutabilidad. También hizo algunos videos realmente geniales que hicieron que la idea fuera realmente fácil de entender (y vender).

El momento fue perfecto. La novedad de Angular se estaba desvaneciendo, y el mundo de JavaScript estaba listo para fijarse en lo último que tenía el grado correcto de genialidad, y esta biblioteca no solo era innovadora sino que encajaba perfectamente con React, que estaba siendo comercializada por otra potencia de Silicon Valley.

Por triste que sea, las modas gobiernan en el mundo de JavaScript. Ahora Abramov está siendo aclamado como un semidiós y todos nosotros, simples mortales, tenemos que someternos al Dao de la Inmutabilidad … Tanto si tiene sentido como si no.

¿Qué hay de malo en la mutación de objetos?

¡Nada!

De hecho, los programadores han estado mutando objetos por er … siempre que ha habido objetos para mutar. Más de 50 años de desarrollo de aplicaciones en otras palabras.

¿Y por qué complicar las cosas? Cuando tienes objeto cat y muere, ¿de verdad necesitas un segundo? cat para rastrear el cambio? La mayoría de la gente solo diría cat.isDead = true y acabemos con eso.

(Objetos mutantes) ¿no simplifican las cosas?

¡SÍ! .. ¡Claro que lo hace!

Especialmente en JavaScript, que en la práctica es más útil para representar una vista de algún estado que se mantiene en otro lugar (como en una base de datos).

¿Qué sucede si tengo un nuevo objeto de noticias que debo actualizar? … ¿Cómo lo logro en este caso? ¿Eliminar la tienda y volver a crearla? ¿No es una operación menos costosa agregar un objeto a la matriz?

Bueno, puede optar por el enfoque tradicional y actualizar el News objeto, por lo que su representación en memoria de ese objeto cambia (y la vista que se muestra al usuario, o eso es lo que uno esperaría) …

O alternativamente…

Puede probar el enfoque sexy FP / inmutabilidad y agregar sus cambios al News objeto a una matriz que rastrea cada cambio histórico para que luego pueda iterar a través de la matriz y averiguar cuál debería ser la representación de estado correcta (¡uf!).

Estoy tratando de aprender qué es lo que hay aquí. Por favor ilumíname 🙂

Las modas van y vienen, amigo. Hay muchas formas de despellejar a un gato.

Lamento que tenga que soportar la confusión de un conjunto de paradigmas de programación en constante cambio. Pero bueno, ¡¡BIENVENIDO AL CLUB !!

Ahora, un par de puntos importantes para recordar con respecto a la inmutabilidad, y los recibirás con la intensidad febril que solo la ingenuidad puede reunir.

1) La inmutabilidad es increíble para evitar condiciones de carrera en entornos de subprocesos múltiples.

Los entornos de subprocesos múltiples (como C ++, Java y C #) son culpables de la práctica de bloquear objetos cuando más de un subproceso quiere cambiarlos. Esto es malo para el rendimiento, pero es mejor que la alternativa de la corrupción de datos. Y, sin embargo, no es tan bueno como hacer que todo sea inmutable (¡Dios mío, alabado sea Haskell!).

¡PERO AY! En JavaScript, siempre operas en un solo hilo. Incluso los trabajadores web (cada uno se ejecuta dentro de un contexto separado). Entonces, dado que no puedes tener un relacionado con el hilo condición de carrera dentro de su contexto de ejecución (todas esas encantadoras variables globales y cierres), el punto principal a favor de la inmutabilidad desaparece.

(Habiendo dicho eso, hay es una ventaja de usar funciones puras en los trabajadores web, que es que no tendrá expectativas sobre manipular objetos en el hilo principal).

2) La inmutabilidad puede (de alguna manera) evitar las condiciones de carrera en el estado de su aplicación.

Y aquí está el verdadero quid del asunto, la mayoría de los desarrolladores de (React) le dirán que Immutability y FP de alguna manera pueden hacer funcionar esta magia que permite que el estado de su aplicación se vuelva predecible.

Por supuesto, esto no significa que pueda evitar las condiciones de carrera en la base de datos, para lograrlo tendría que coordinar todos los usuarios en todos los navegadores, y para eso necesitaría una tecnología push de back-end como WebSockets (más sobre esto a continuación) que transmitirá los cambios a todos los que ejecutan la aplicación.

Tampoco significa que haya algún problema inherente en JavaScript donde el estado de su aplicación necesita inmutabilidad para volverse predecible, cualquier desarrollador que haya estado codificando aplicaciones front-end antes de React le diría esto.

Esta afirmación bastante confusa simplemente significa que con React, el estado de su aplicación será más propenso a las condiciones de carrera, pero esa inmutabilidad te permite quitar ese dolor. ¿Por qué? Debido a que React es especial … se ha diseñado como una biblioteca de renderizado altamente optimizada con la administración del estado como una ocurrencia tardía y, por lo tanto, el estado del componente se administra a través de una cadena de eventos asincrónica (también conocida como “enlace de datos unidireccional”) que usted no tiene control y confíe en que recuerde no mutar el estado directamente …

Dado este contexto, es fácil ver cómo la necesidad de inmutabilidad tiene poco que ver con JavaScript y mucho que ver con las condiciones de carrera en React: si tiene un montón de cambios interdependientes en su aplicación y no hay una manera fácil de averiguar qué su estado se encuentra actualmente, se va a confundir y, por lo tanto, Tiene mucho sentido usar la inmutabilidad para rastrear cada cambio histórico..

3) Las condiciones de carrera son categóricamente malas.

Bueno, podrían serlo si está usando React. Pero son raros si elige un marco diferente.

Además, normalmente tienes problemas mucho mayores lidiar con … Problemas como el infierno de la dependencia. Como una base de código hinchada. Como si tu CSS no se cargara. Como un proceso de compilación lento o estar atrapado en un back-end monolítico que hace que la iteración sea casi imposible. Como desarrolladores sin experiencia que no entienden lo que está pasando y hacen un lío de las cosas.

Sabes. Realidad. Pero bueno, ¿a quién le importa eso?

4) La inmutabilidad hace uso de tipos de referencia. para reducir el impacto en el rendimiento del seguimiento de cada cambio de estado.

Porque en serio, si vas a copiar cosas cada vez que cambia tu estado, es mejor que te asegures de ser inteligente al respecto.

5) La inmutabilidad te permite DESHACER cosas.

Porque er … esta es la característica número uno que va a pedir su gerente de proyecto, ¿verdad?

6) El estado inmutable tiene mucho potencial genial en combinación con WebSockets

Por último, pero no menos importante, la acumulación de deltas de estado constituye un caso bastante convincente en combinación con WebSockets, que permite una fácil consumo del estado como flujo de sucesos inmutables …

Una vez que el centavo cae en este concepto (indique que un flujo de eventos – en lugar de un crudo conjunto de registros que representan la última vista), el mundo inmutable se convierte en un lugar mágico para habitar. Una tierra de maravillas y posibilidades de eventos que trasciende el tiempo mismo. Y cuando se hace bien, esto definitivamente puede facilitar las aplicaciones en tiempo real.er Para lograrlo, simplemente transmita el flujo de eventos a todos los interesados ​​para que puedan construir su propia representación del presente y escribir sus propios cambios en el flujo común.

Pero en algún momento te despiertas y te das cuenta de que toda esa maravilla y esa magia no son gratis. A diferencia de sus ávidos colegas, sus partes interesadas (sí, las personas que le pagan) se preocupan poco por la filosofía o la moda y mucho por el dinero que pagan para construir un producto que pueden vender. Y la conclusión es que es más difícil escribir código inmutable y más fácil romperlo, además de que tiene poco sentido tener un front-end inmutable si no tienes un back-end que lo soporte. Cuando (¡y si!) Finalmente convence a sus partes interesadas de que debe publicar y consumir eventos a través de una tecnología push como WebSockets, descubrirá lo complicado que es escalar en producción.


Ahora, un consejo, si decide aceptarlo.

La opción de escribir JavaScript usando FP / Immutability también es una opción para hacer que la base de código de su aplicación sea más grande, más compleja y más difícil de administrar. Yo abogaría fuertemente por limitar este enfoque a sus reductores Redux, a menos que sepa lo que está haciendo … Y SI va a seguir adelante y usar la inmutabilidad independientemente, entonces aplique el estado inmutable a toda su pila de aplicaciones, y no solo a la del lado del cliente, ya que de lo contrario se está perdiendo el valor real.

Ahora, si tiene la suerte de poder tomar decisiones en su trabajo, intente usar su sabiduría (o no) y haga lo correcto por la persona que le paga. Puede basar esto en su experiencia, en su instinto o en lo que sucede a su alrededor (es cierto que si todos están usando React / Redux, entonces hay un argumento válido de que será más fácil encontrar un recurso para continuar con su trabajo). puede probar los enfoques de desarrollo impulsado por currículum vitae o desarrollo impulsado por bombo publicitario. Puede que sean más tu tipo de cosas.

En resumen, lo que hay que decir sobre la inmutabilidad es que voluntad ponerte a la moda con tus compañeros, al menos hasta que llegue la próxima moda, momento en el que estarás feliz de seguir adelante.


Ahora, después de esta sesión de autoterapia, me gustaría señalar que agregué esto como un artículo en mi blog => Immutability in JavaScript: A Contrarian View. Siéntase libre de responder allí si tiene sentimientos fuertes que le gustaría desahogar también;).

La pregunta es, ¿por qué es tan importante la inmutabilidad? ¿Qué hay de malo en la mutación de objetos? ¿No simplifica las cosas?

En realidad, es todo lo contrario: la mutabilidad complica las cosas, al menos a largo plazo. Sí, facilita la codificación inicial porque puede cambiar las cosas donde quiera, pero cuando su programa crece, se convierte en un problema: si un valor cambió, ¿qué lo cambió?

Cuando haces que todo sea inmutable, significa que los datos ya no se pueden cambiar por sorpresa. Sabe con certeza que si pasa un valor a una función, no se puede cambiar en esa función.

En pocas palabras: si usa valores inmutables, es muy fácil razonar sobre su código: todos obtienen una copia única * de sus datos, por lo que no pueden jugar con ellos y romper otras partes de su código. ¡Imagínese cuánto más fácil esto hace que trabajar en un entorno de subprocesos múltiples!

Nota 1: Existe un costo potencial de rendimiento para la inmutabilidad dependiendo de lo que esté haciendo, pero cosas como Immutable.js optimizan lo mejor que pueden.

Nota 2: En el improbable caso de que no esté seguro, Immutable.js y ES6 const significan cosas muy diferentes.

En el caso habitual, podría haber agregado el objeto a la matriz. ¿Cómo logro en este caso? ¿Eliminar la tienda y volver a crearla? ¿No es una operación menos costosa agregar un objeto a la matriz? PD: Si el ejemplo no es la forma correcta de explicar la inmutabilidad, hágamelo saber cuál es el ejemplo práctico correcto.

Sí, su ejemplo de noticias es perfectamente bueno y su razonamiento es exactamente correcto: no puede simplemente modificar su lista existente, por lo que debe crear una nueva:

var originalItems = Immutable.List.of(1, 2, 3);
var newItems = originalItems.push(4, 5, 6);

Si sostienes alguna suspicacia y forma de aumentar nuestro tutorial eres capaz de añadir una anotación y con deseo lo ojearemos.

¡Haz clic para puntuar esta entrada!
(Votos: 2 Promedio: 4.5)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *