Los peligros de Serializable
Serializable tiene una serie de problemas que hacen que, aunque nos intenten sugerir lo contrario, no deberíamos utilizarlo como método de almacenamiento primario a largo plazo de nuestros programas. El principal problema de Serializable es que no está pensado para almacenar a largo plazo y que cualquier atisbo de corrupción en la estructura de datos provoca que los datos queden irrecuperables.
Veamos: esta clase que os acabo de contar, y esta interfaz... readObject(), writeObject(), Serializable... hay dos problemas bastante importantes a tener en cuenta con Serializable. De hecho, este segundo problema es nuevo. Hace un par de años sólo os hubiese dicho que hay uno, pero en realidad hay dos.
El primer problema es conocido desde hace muchísimo tiempo, pese a que sigue habiendo cursos, guías, tutoriales e incluso asignaturas de universidad y FP, donde se ignora el hecho de que Serializable no vale para guardar a largo plazo. Serializable no es un formato que puedas usar para guardar en un archivo y esperar que el día de mañana puedas leerlo. Por la razón que os he contado: nunca se sabe cuándo se puede modificar el esquema y eso puede provocar que las clases se vuelvan rígidas y que haya problemas a la hora de leer. Como tal, no habrá problemas a la hora de escribir, pero sí a la hora de leer. Y no digas bueno, se puede adaptar un poquito
. El formato de Serializable es bastante complicado y no está pensado para que simplemente vengas a hacer una lectura propia, porque vas a sufrir bastante y te vas a encontrar bastantes problemas. Serializable fue pensado para hacer transmisiones de datos a corto plazo. Por ejemplo, si tienes conectado tu ObjectInputStream y tu ObjectOutputStream a los OutputStreams que hay por debajo de un socket TCP. Por ejemplo, si estás transfiriendo una instancia de una clase a través de la red hacia una instancia de una clase que esté ejecutando otra copia del mismo programa. Y ese es el caso de uso previsto realmente para ObjectInputStream: transmitir datos a través de la red, o en general, información que va a tener una duración breve. Es decir, yo tarnsmito y en muy poco tiempo estoy leyendo. Pero no está pensado para simplemente guardarlo y ya está, porque tiene muchísimos riesgos, y porque cualquier tipo de cambio en cualquier elemento: como cualquier número, cualquier cambio, incluso cualquier byte del archivo, va a provocar que el archivo quede corrupto y ya no se pueda volver a abrir. Nunca se pensó como una forma de serializar a largo plazo y no sé por qué a día de hoy sigue habiendo libros y sigue habiendo cursos y asignaturas donde se sigue explicando esto de una forma que hace pensar que se puede llamar a write() para tenerlo para dentro de un par de años. Eso no es así.
La otra razón por la que Serializable es una clase un poco complicada de utilizar es por los problemas de seguridad que tiene, y esto es algo que solamente hace un par de años que como sociedad nos empezamos a dar cuenta: los peligros que tiene que puedas empujarle cualquier masa de bits a una aplicación y lo interprete y lo convierta en una instancia de una clase, porque vete a saber lo que puede ocurrir si una persona con conocimientos suficientes empuja una serie de bytes inválidos que provocan que tu clase se comporte de una forma peligrosa o de una forma que puede poner en peligro la integridad de los datos, la seguridad de la aplicación o cualquier otro tipo de cosa. Si nosotros hacemos privados esos campos y lo hacemos con el modificador private, eso por lo que podéis saber de Java, hace que ya no se pueda acceder desde fuera a esos campos. Nos da cierto sentido de tranquilidad, en el sentido de que yo ya no puedo simplemente hacer .nombre o .apellido y lo que sea, y acceder desde fuera a esa información. Bueno, el principal problema es que, en el caso de los ObjectStream, le da bastante igual. ¿Que tu campo es privado? Me da igual que sea privado: cuando llame a escribirEmpleado() voy a compartir el funcionamiento interno de tu clase y se va a guardar ahí, sea privado, público, me da igual. Eso puede provocar que gente con malas intenciones decodifique el formato, vea de qué tipo son las cosas y vea cómo comprometer tu aplicación. Y eso es un riesgo en aplicaciones que se utilizan día a día por bastante gente, así que conviene evitarlo.
Por lo tanto, si queremos usar serialización, pese a que nosotros tenemos a nuestra disposición ObjectOutputStream y que, como digo, se puede seguir usando para cosas pequeñas que no sea a largo plazo, idealmente deberíamos evitarlo y deberíamos usar otro tipo de serializadores más robustos como Jackson o cualquier tipo de serializador que permita guardar a formatos más amigables a futuro como JSON, XML u otro que os podáis imaginar, pero conviene no usar Serializable para lo que no debe ser utilizado.
Desplegar transcripción del episodio
[Música]
Veamos: esta clase que os acabo de contar, y esta interfaz... readObject(), writeObject(), Serializable... hay dos problemas bastante importantes a tener en cuenta con Serializable. De hecho, este segundo problema es nuevo. Hace un par de años sólo os hubiese dicho que hay uno, pero en realidad hay dos.
El primer problema es conocido desde hace muchísimo tiempo, pese a que sigue habiendo cursos, guías, tutoriales e incluso asignaturas de universidad y FP, donde se ignora el hecho de que Serializable no vale para guardar a largo plazo. Serializable no es un formato que puedas usar para guardar en un archivo y esperar que el día de mañana puedas leerlo. Por la razón que os he contado: nunca se sabe cuándo se puede modificar el esquema y eso puede provocar que las clases se vuelvan rígidas y que haya problemas a la hora de leer. Como tal, no habrá problemas a la hora de escribir, pero sí a la hora de leer. Y no digas bueno, se puede adaptar un poquito
. El formato de Serializable es bastante complicado y no está pensado para que simplemente vengas a hacer una lectura propia, porque vas a sufrir bastante y te vas a encontrar bastantes problemas. Serializable fue pensado para hacer transmisiones de datos a corto plazo. Por ejemplo, si tienes conectado tu ObjectInputStream y tu ObjectOutputStream a los OutputStreams que hay por debajo de un socket TCP. Por ejemplo, si estás transfiriendo una instancia de una clase a través de la red hacia una instancia de una clase que esté ejecutando otra copia del mismo programa. Y ese es el caso de uso previsto realmente para ObjectInputStream: transmitir datos a través de la red, o en general, información que va a tener una duración breve. Es decir, yo tarnsmito y en muy poco tiempo estoy leyendo. Pero no está pensado para simplemente guardarlo y ya está, porque tiene muchísimos riesgos, y porque cualquier tipo de cambio en cualquier elemento: como cualquier número, cualquier cambio, incluso cualquier byte del archivo, va a provocar que el archivo quede corrupto y ya no se pueda volver a abrir. Nunca se pensó como una forma de serializar a largo plazo y no sé por qué a día de hoy sigue habiendo libros y sigue habiendo cursos y asignaturas donde se sigue explicando esto de una forma que hace pensar que se puede llamar a write() para tenerlo para dentro de un par de años. Eso no es así.
La otra razón por la que Serializable es una clase un poco complicada de utilizar es por los problemas de seguridad que tiene, y esto es algo que solamente hace un par de años que como sociedad nos empezamos a dar cuenta: los peligros que tiene que puedas empujarle cualquier masa de bits a una aplicación y lo interprete y lo convierta en una instancia de una clase, porque vete a saber lo que puede ocurrir si una persona con conocimientos suficientes empuja una serie de bytes inválidos que provocan que tu clase se comporte de una forma peligrosa o de una forma que puede poner en peligro la integridad de los datos, la seguridad de la aplicación o cualquier otro tipo de cosa. Si nosotros hacemos privados esos campos y lo hacemos con el modificador private, eso por lo que podéis saber de Java, hace que ya no se pueda acceder desde fuera a esos campos. Nos da cierto sentido de tranquilidad, en el sentido de que yo ya no puedo simplemente hacer .nombre o .apellido y lo que sea, y acceder desde fuera a esa información. Bueno, el principal problema es que, en el caso de los ObjectStream, le da bastante igual. ¿Que tu campo es privado? Me da igual que sea privado: cuando llame a escribirEmpleado() voy a compartir el funcionamiento interno de tu clase y se va a guardar ahí, sea privado, público, me da igual. Eso puede provocar que gente con malas intenciones decodifique el formato, vea de qué tipo son las cosas y vea cómo comprometer tu aplicación. Y eso es un riesgo en aplicaciones que se utilizan día a día por bastante gente, así que conviene evitarlo.
Por lo tanto, si queremos usar serialización, pese a que nosotros tenemos a nuestra disposición ObjectOutputStream y que, como digo, se puede seguir usando para cosas pequeñas que no sea a largo plazo, idealmente deberíamos evitarlo y deberíamos usar otro tipo de serializadores más robustos como Jackson o cualquier tipo de serializador que permita guardar a formatos más amigables a futuro como JSON, XML u otro que os podáis imaginar, pero conviene no usar Serializable para lo que no debe ser utilizado.