Facebook: Applicazione Pet Society e RAM a GoGo

Sono un patito di Pet Society, applicazione in flash di PlayFish usufruibile tramite Facebook e MySpace.

Altro non è che un giochino dove devi far crescere il tuo pet, costruirgli una casa con i soldi che accumuli partecipando a delle gare, farlo interaggire con gli altri pet, etc; la formula di gioco non è niente di nuovo sotto al sole, ma anche gli errori di sviluppo sembrano sempre gli stessi.

Questa è la prima schermata di gioco:

1Capture

234 Mb di ram.

Dopo neanche 1 min:

2Capture

 

 

341 Mb, e poi:

3Capture

419 Mb, e adesso:

4Capture

527 Mb.

A questo punto ho concluso di prelevare informazioni. Comunque l’utilizzo della memoria continuava a crescere sino a far crashare Internet Explorer.

Non so se è un bug di Adobe Flash Player, ma ne dubbito.

E’ strano come nel 2009 ancora non si vuol capire che le risorse vanno liberate ed anche il prima possibile.
Manderei i tizi di PlayFish a programmare su un vecchio GameBoy, lì si che sudavi 7 camicie per 4kByte!!!

Ma ci sono sviluppatori .NET e Java che neanche scherzano con l'utilizzo delle risorse, per fortuna a noi ci salva il GC; quando può.

Tags:

Indecent Exposure: Encapsulate Classes with Factory

Continuiamo con lo smell: Indecent Exposure

 

Problema:

Il client istanzia direttamente un oggetto che risiede in una libreria.

 

Motivazione:

Durante la realizzazione di una libreria, si potrebbe cadere nella tentazione di creare delle classi che istanziano oggetti di cui il client necessita.

Un esempio di logica errata:

smell_Indecent_Exposure

Ciò significa dare al client la responsabilità di conoscere tutti gli oggetti presenti nella nostra libreria.

 class Program
{
static void Main(string[] args)
{
List<AttributeDescriptor> lstAttDesc = new List<AttributeDescriptor>();
lstAttDesc.Add(new BooleanDescriptor("boolean"));
lstAttDesc.Add(new DefaultDescriptor("primo", typeof(string), 10));
lstAttDesc.Add(new ReferenceDescriptor("secondo", typeof(MiaClasse), sizeof(MiaClasse)));
// ...
}
}

public abstract class AttributeDescriptor
{
protected AttributeDescriptor()
{
// ...
}
}

public class BooleanDescriptor : AttributeDescriptor
{
public BooleanDescriptor(string name)
: base()
{
// ...
}
}

public class DefaultDescriptor : AttributeDescriptor
{
public DefaultDescriptor(string name, Type t, long length)
: base()
{
// ...
}
}

public class ReferenceDescriptor : AttributeDescriptor
{
public ReferenceDescriptor(string name, Type t, long length)
: base()
{
// ...
}
}
 

 

E ciò è un male == smells.


Soluzione:

Tenendo presente la regola: far lavorare il client tramite interfacce e non tramite oggetti.

Ne consegue che, quanto sopra, si potrebbe risolvere con un Factory pattern:

 class Program
{
static void Main(string[] args)
{
List<AttributeDescriptor> lstAttDesc = new List<AttributeDescriptor>();
lstAttDesc.Add(AttributeDescriptor.CreateBoolean("boolean"));
lstAttDesc.Add(AttributeDescriptor.CreateDefault("primo", 10));
lstAttDesc.Add(AttributeDescriptor.CreateReference("secondo", typeof(MiaClasse), sizeof(MiaClasse)));
// ...
}
}

public abstract class AttributeDescriptor
{
protected AttributeDescriptor()
{
// ...
}

public static AttributeDescriptor CreateBoolean(string name)
{
return new BooleanDescriptor(name);
}

public static AttributeDescriptor CreateDefault(string name, long length)
{
return new DefaultDescriptor(name, typeof(string), length);
}

public static AttributeDescriptor CreateReference(string name, Type t, long length)
{
return new ReferenceDescriptor(name, t, length);
}
}

public class BooleanDescriptor : AttributeDescriptor
{
public BooleanDescriptor(string name)
{
// ...
}
}

public class DefaultDescriptor : AttributeDescriptor
{
public DefaultDescriptor(string name, Type t, long length)
{
// ...
}
}

public class ReferenceDescriptor : AttributeDescriptor
{
public ReferenceDescriptor(string name, Type t, long length)
{
// ...
}
}

 

Questa è una possibile soluzione

Da notare che classi BooleanDescriptor, DefaultDescriptor e ReferenceDescriptor, dopo il Refactoring, il client non ha nessun bisogno di sapere come queste sono implementate e possono risiedere in qualsiasi dll, il client avrà solamente bisogno di referenziare la classe AttributeDescriptor

refactored

Benefici e non
+ Semplifica la creazione delle istanze degli oggetti.
+ Allegerisce la conoscenza da parte del client delle classi e della loro implementazione.
+ Mantiene viva la regola sull’utilizzo delle interfacce.
- Bisogna creare un metodo Create per ogni oggetto.
- Limita le customizzazioni da parte del client perchè può accedere solo all’interfaccia.

 

E non prendete come scusa: “il mio sistema ormai è troppo evoluto per poterne apportare queste migliorie. E’ troppo tardi.”

Se fosse realmente così non esisterebbe il Refactoring :)

Per questi post sto prendendo, molto, spunto da libro Refactoring To Patterns di Joshua Kerievsky.