March 2008 - Artículos

Pues tras una comprobación este fin de semana, y aproximadamente tras unas 20 cargas:

  • Duración (6 apagados y encendidos): Unas 9 horas, 1 hora aprox. encendido sin leer.
  • Páginas pasadas (es decir, cambios de pantalla): Algunos menos de 500.
  • Con el Wifi apagado, sin sacar en ningún momento el stick.

¿Qué dice la publicidad?
Pues resulta bastante imprecisa, pero en http://www.irextechnologies.com/products/features se dice "Fortunately, your iLiad will allow you to read and write for up to 15 hours* without recharging the battery", y el asterisco nos lleva a "With current Software Version 2.11 and depending on usage pattern.", lo que es, evidentemente, mentira, ya que la versión de mi Firmware es la 2.11, aunque el aparato es la versión 1.0.

¿Y en la caja orignal?
"Very low power: You can read three hours a day for more than one week, from the iLiad without recharging the battery". Es decir, 3 horas por 7 días, 21 horas. Todavía una mentira mayor.

Qué lástima que sea una empresa holandesa y cueste más la denuncia que el beneficio...

Ahora que están de moda los antipatrones, voy a explicar un patrón que es muy famoso pero que no me gusta absolutamente nada, no por el diseño del mismo, sino por los efectos laterales no deseados que genera. Por ello también voy a explicar otra forma de construirlo que me gusta más, aunque adolece de otras limitaciones.

Singleton es un patrón que nos obliga a tener una sola instancia de una clase, es decir, globalmente sólo podremos disponer de un objeto de ese tipo. El truco está en conseguir que, hagamos lo que hagamos, no podamos crear más de una instancia.

En lenguajes como C++ este patrón tiene menos utilidad que en C++/CLI, C# o VB.NET, ya que la forma clásica de hacer algo similar es tener una variable global accesible por todos los módulos, cosa de la que suele encargarse el enlazador de hacer.

Pero los lenguajes .NET adolecen de falta de variables globales; es decir, no puedes tener un objeto global y visible en toda la aplicación. Personalmente no entiendo este purismo tan quisquilloso, ya que los lenguajes .NET no son precisamente orientados a objetos puros, y menos aún con la especificación 3.0 de C#. Y si encima este hecho complica bastante ciertos desarrollos, el absurdo sube de nivel.

Pero es lo que hay.

La solución para tener un objeto global es disponer de una clase estática. Si bien a priori resulta una buena idea, en la práctica no lo es tanto. Independientemente del hecho de que los constructores estáticos en .NET no funcionan muy bien o, en otras palabras, tienen bastante bugs (al menos en la versión 2.0, aunque dudo mucho que lo hayan solucionado en los SP1), tenemos ciertas limitaciones, como la imposibilidad de que se llame a otro constructor estático de forma encadenada…

¿Y por qué comento esto? Pues porque el patrón Singleton utiliza una variable y un constructor estático. Veámoslo en C#:

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Text;
   4:  
   5: class Singleton
   6: {
   7:     public static Singleton Instancia=new Singleton();
   8:  
   9:     private Singleton() {}
  10:  
  11:     public int Numero;
  12:     public void DiNumero()
  13:     {
  14:         Console.WriteLine(Numero++.ToString());
  15:     }
  16: }
  17:  
  18: class Program
  19: {
  20:     static void Main(string[] args)
  21:     {
  22:         Singleton.Instancia.Numero = 33;
  23:         for (int i = 0; i < 10;i++)
  24:             Singleton.Instancia.DiNumero();
  25:     }
  26: }

Observamos que el truco está en definir un constructor privado. Al hacerlo, ya no podremos equivocarnos y crear varias instancias de esta clase, y la única forma de acceder al único objeto que pueda haber en toda la aplicación es mediante

   1: Singleton.Instancia

Si intentamos crearnos un objeto del tipo Singleton, el compilador protestará y nos dirá que el constructor no está accesible.

Si alguien quiere una explicación más en detalle, se puede pasar por la MSDN o por aquí.

¿Nadie ve el problema?

Pues hay dos. El primero ya lo hemos dicho: tenemos un objeto global al sistema, que es estático y por tanto sigue unas reglas algo diferentes, como la imposibilidad de hacer una llamada a otra variable estática que implemente su propio constructor estático dentro del constructor de nuestro Singleton… O en otras palabras: no podemos tener Singletones anidados, no al menos bajo .NET.

Pero el mayor problema es otro. Cuando se habla de Singleton, se pone un ejemplo con dos líneas de código y listo. Pero una clase de la Vida Real™ no es sencilla. Tendremos varios métodos miembro, así como variables. ¿Cómo las inicializamos? ¿En el constructor? ¡Pero si no tiene constructor al que podamos pasarle valores! ¿Las ponemos públicas? ¿Propiedades?

Una solución es la mostrada aquí:

   1: Singleton.Instancia.Numero = 33;
   2: for (int i = 0; i < 10;i++)
   3:     Singleton.Instancia.DiNumero();

Pero a mí al menos eso me parece una guarrería mayor, y más cuando haya varios datos miembro, como suele ser habitual en clases no triviales… La única cosa que podemos hacer es especificar valores por defecto en el constructor estático:

   1: private Singleton() { Numero = 50; }

Pero eso sólo alivia el problema, no lo soluciona.

Qué bonito sería que pudiéramos indicar algo como

   1: [Pattern(Singleton)]
   2: class Singleton
   3: {…

Y disponer de la clase como si tal cosa… Pero esa es otra guerra.

Otra aproximación

Veamos ahora una variante, que es la que yo implemento en mis propios programas. Primero el código:

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Text;
   4:  
   5: class MiSingleton
   6: {
   7:     private static int m_cuenta=0;
   8:  
   9:     private int m_numero;
  10:     public MiSingleton(int num)
  11:     {
  12:         m_cuenta++;
  13:         if (m_cuenta > 1)
  14:             throw new Exception("RFOG Singleton Exception");
  15:  
  16:         m_numero = num; 
  17:     }
  18:     public void DiNumero()
  19:     {
  20:         Console.WriteLine(m_numero++.ToString());
  21:     }
  22: }
  23: class Program
  24: {
  25:     static void Main(string[] args)
  26:     {
  27:         MiSingleton m = new MiSingleton(33);
  28:         for (int i = 0; i < 10;i++)
  29:             m.DiNumero();
  30:  
  31:         MiSingleton n=new MiSingleton(88);
  32:     }
  33: }

Aquí encontramos otros problemas y otras limitaciones, pero personalmente me gusta más así. Definimos una variable estática, un entero que nos servirá para contar cuántas instancias de esta clase tenemos.

Definimos un constructor público al que podremos pasarle cualquier número de parámetros que queramos, de hecho se trata de una clase normal y corriente que tiene un bloque de código concreto en el constructor:

   1: m_cuenta++;
   2: if (m_cuenta > 1)
   3:     throw new Exception("RFOG Singleton Exception");

La segunda vez que intentemos instanciar esta clase obtendremos una excepción. Aquí la limitación está en que nos daremos cuenta de nuestro error en tiempo de ejecución, no de compilación, lo que ciertamente es una desventaja seria pero que pierde fuerza cuando nos enfrentamos a las limitaciones y bugs de los constructores estáticos.

La segunda instanciación dentro del bloque de main() lanzará la excepción. La otra limitación a esto viene de la imposibilidad de tener variables globales y de que tengamos que pasar m siempre que queramos usarlo.

Lo ideal sería tener ambas opciones juntas, pero ciertamente dentro de .NET es imposible.

con 21 comment(s)
Archivado en: ,,,

Ya sé que últimamente no abundan los contenidos técnicos por aquí, pero estoy laboralmente muy ocupado y el tiempo libre que tengo lo paso leyendo y relajándome, imagino que de aquí a un mes volveré a estar más libre… Eso o estaré en paro, ya que no me gusta absolutamente nada la dinámica que está tomando mi curro, con salidas a toda España a reparar máquinas de las que no entiendo ni quiero entender y que ya de por sí su comprensión suponen un oficio en sí mismo.

Pero hoy no voy a hablar de mí, sino de Microsoft y sus últimas pifias. Ahora como MVP tengo línea directa, pero a fin de cuentas es como si no la tuviera, ya que por lo menos a mi no me hacen ni p*to caso. Y a veces son cosas muy serias, como las del final de esta entrada.

Visual Studio 2008
Quien tenga una subscripción a la MSDN lo habrá podido descargar más o menos desde noviembre del año pasado, así que debe estar bastante familiarizado con él. En mi caso no le encuentro ninguna pega destacable. Aunque tampoco es que le haya dado mucha caña: una pequeña aplicación en C#, dos tonterías en MFC y sí una espuerta de DLLs en Win32. Y si fallara haciendo DLLs pues ya sería la rehostia…

Estooooo… ¿Digo que no falla? Pues sí que falla, o mejor dicho fallaba. Y no sé cómo lo han actualizado, pero lo han hecho. Si uno crea un proyecto con una DLL nativa, y usa esa DLL nativa en otro proyecto dentro de la misma solución, el linker revienta a la hora de enlazar. Es muy curioso, porque solo revienta justo después de reiniciar Windows, y sólo en Vista. O en otras palabras: la primera compilación parcial tras un reinicio hace que el linker genere un error interno. Curioso, ¿no?

Pues tras informar del error (yo fui el primero, luego comenzó a pasarle a más gente), lo han solucionado. ¿Cómo? Pues no lo sé. El Visual Studio no lo han actualizado, así que ha debido ser una actualización secreta de esas que no te dicen nada o junto a alguna actualización del propio Windows.

Decir que está actualizado es mucho afirmar, más bien el problema queda minimizado y sólo ocurre con muy poca frecuencia, tan poca que apenas es molesto.

Más Visual Studio 2008 y el SDK 6.1
Otra, esta algo más grande. Hay dos nuevos Windows SDK, ambos con la versión 6.1. Uno para Vista SP1 y otro para Windows Server 2008. El que trae el Visual Studio es la versión 6.0A.

¿Los ha instalado alguien? ¿En Vista x64, con o sin SP1? No hace falta que lo hagáis, ya que si bien se instalan perfectamente, cuando utilizamos el nuevo “Windows SDK Configuration Tool” para cambiarle al VS2008 el SDK activo, lo rompe y lo deja incapaz de compilar; en el caso del SDK de Vista, ya no es posible crear aplicaciones en C++/CLI, y en el caso del de Windows Server, nativas. Tras comprobar que la instalación del SDK del Server falló, y un par de cuelgues duros de Vista durante la reinstalación, al final el problema que presenta el SDK del Server es el mismo que el del Vista.

Tampoco vale la pena que utilices dicha herramienta para volver al status anterior: El Visual Studio 2008 ya no te volverá a funcionar a no ser que desinstales los SDK (menos mal).

¿Solución? Ninguna. Silencio administrativo.

Windows Vista SP1
Antes de la salida pública del SP1 los suscriptores a la MSDN también tienen acceso a dicho Service Pack. Ciertamente pagar una suscripción a la MSDN cada vez tiene menos sentido, sobre todo las caras, ya que MS va liberando poco a poco casi todo lo que antes costaba dinero o tenías que ser un Partner para obtenerlo. Como consecuencia de ello, los subscriptores pusieron el grito en el cielo y al poco se permitió la descarga del SP1. Decir que tampoco a los MVP que no fueran betatester del propio SP1 nos dieron acceso a él…

Pues bien, tras estar un par de semanas con él instalado de forma limpia, es decir, instalas el Vista, luego el SP1 y sigues con todo lo demás, ya que los chicos de las altas esferas han decidido que no se pueda crear un CD integrado, mis conclusiones no podrían ser más pésimas. Vamos allá.

Windows Mail. Si antes del SP1 era pésimo, después de él sigue siéndolo. Es decir, los parpadeos continúan, los autismos también, y en general los problemas de que adolece se siguen presentando de igual forma, aunque con un, digamos, 10% menos de frecuencia.

Arranque y apagado. Ninguna mejora. Tarda la misma eternidad en arrancar y parar, y durante el arranque sigues dejando de tener todo funcional hasta pasado un buen rato después del que te muestre el escritorio.

Autismos varios. Es decir, esas congelaciones que se producen en ciertas aplicaciones se vienen produciendo con algo menos de frecuencia, pero siguen pasando.

Otros. Parece ser que sí que han mejorado algo la I/O por prioridades, y ahora copia y mueve archivos mucho más rápido, pero siguen los autismos en cuanto a arrastrar y soltar. El IE se sigue cayendo solo igual que antes, el explorador sigue sin recordar posiciones ni ciertas configuraciones y en general, salvo la copia, la gestión de archivos sigue siendo tan mala que antes, lo que me lleva al siguiente punto.

No se copian ni mueven todos los ficheros
Pues lo dicho. Así que ojito con copiar y luego borrar el original sin comprobar la copia. Me da igual que se deba a los hooks de terceros o a lo que sea. Es completamente inaceptable. Ni siquiera Linux en sus peores días hacía eso.

Antes del SP1 experimenté el problema de dos formas distintas. En la primera, al mover ficheros, en el origen quedaban restos que si bien se habían copiado, no se habían borrado. En la segunda, al borrar ficheros, me pasaba lo mismo, pues supuse que se debía a que alguien bloqueaba el fichero y se olvidaba de liberarlo, ya que la única forma de poderlos borrar era saliendo y volviendo a entrar en la sesión. Como eran ficheros que no se habían visto en ningún momento, el candidato que generaba el problema debía ser el propio Vista.

Después de eso otro MVP comentó que le parecía que le había fallado la copia, pero no estaba seguro de ello.

Y yo me quedé con la mosca detrás de la oreja… Después instalé el SP1, y observé el problema que cuento en la sección siguiente (que ya es el súmmum de todo), por lo que procedí a limpiar la unidad…

¿Imaginan? Pues se quedaron ficheros sin mover. Bien es cierto que eran ficheros ocultos y de sólo lectura, pero otros ocultos y de sólo lectura se movieron, así que ese no era el motivo. Un arrastrar y soltar los copió, pero el problema está ahí.

Y vayamos al apoteósico final.

Particiones sucia
Tengo una partición con la que trabajo todos los días, donde está el código fuente de la empresa, almacenes de correo y demás. El System Restore está deshabilitado globalmente. La unidad es NTFS formateada desde la misma instalación. Pues bien, de 11 GB de datos que hay (datos en disco, teniendo en cuenta el tamaño del cluster), en el disco hay realmente más de 20 GB. Tras borrar todo lo del disco, me seguían quedando esos 10 GB ocupados, o sea, que son basuras que deja el Vista, ya que a nivel de usuario no queda nada. Activando mostrar ficheros ocultos por el sistema operativo, tomo posesión de "System Volume Information" y veo un montón de archivos con nombres de GUIID con tamaños de entre varios cientos de megas y gigas... Y de repente, antes de que me dé tiempo de mirarlos, ¡desaparecen! y la unidad se queda como debería haber estado en un primer momento.

¿Qué se oculta ahí? ¿Por qué desaparecen esos ficheros nada más verlos? ¿Qué son esos restos (el system restore no puede ser ya que está desactivado) que Vista no quiere que tengamos acceso a ellos?

Me hubiera gustado haber recibido una respuesta oficial, creíble y documentada. Pero no fue así. Silencio administrativo.

¿Por qué roba Vista ese espacio en disco?

Podría ser un resto del shadow copy de la copia de seguridad del propio Vista: en ese caso, chapuzas dobles y triples. Nunca los programas de copia de seguridad que han acompañado al sistema operativo han sido buenos, pero llegar hasta ese punto... Es decir, tengo programado el Backup del Vista para que haga copia de esa unidad sobre otra, si son los restos de la preparación del shadow, lo dicho.

Podría ser que aunque se ha desactivado globalmente el System Restore, Vista pasara olímpicamente de nosotros e hiciera copias... en una unidad que nunca lo ha tenido activado. Aquí entraríamos en cuestiones de otro tipo, como las actualizaciones ocultas que se instalan de forma oculta aunque las tengas desactivadas... lo que me parece un punto de soberbia, prepotencia y abuso de poder completamente intolerable...

No se me ocurren otras posibles causas, y las que se me ocurren mejor no mencionarlas (qué casualidad que sólo pase en la única partición en la que hay código fuente...) etc.

El tema es que han pasado unos días y ya tengo otra vez la partición con 5 gigas de basura… Pero esta vez no se me escapan…

Eso será después de que instale XP.