Programming Languages Hacks

Importanti regole per linguaggi di programmazione rilevanti come Java, C, C++, C#…

  • Subscribe

  • Lettori

    I miei lettori abituali

  • Twitter

WCF Client: “Using” best practices

Posted by Ricibald on March 15th, 2013

According to this official Microsoft link you should not use “using” to dispose your wcf client.

Instead use this extension method:

namespace System.ServiceModel
{
    public static class Extensions
    {
        /// <summary>
        /// Release safely your WCF Client
        /// </summary>
        public static void UsingSafe<T>(this T client, Action<T> work)
            where T : ICommunicationObject
        {
            try
            {
                work(client);
            }
            finally
            {
                try
                {
                    client.Close();
                }
                catch (CommunicationException)
                {
                    client.Abort();
                }
                catch (TimeoutException)
                {
                    client.Abort();
                }
                catch (Exception)
                {
                    client.Abort();
                    throw;
                }
            }
        }
    }
}

Usage:

new SomeClient().UsingSafe(channel => {
    channel.Login(username, password);
});

Posted in .net, wcf | 2 Comments »

Ninject: Replace without unbind

Posted by Ricibald on August 10th, 2012

In Ninject the method Rebind<T> does the following:

  • Unbind<T>: removes all binding for that types, also named binding!
  • Bind<T>: add the specified binding

This means that using Rebind<T>().To<U>().Named(“X”) you are not just replacing the binding named “X” but you are clearing all existing binding registered with T!

If you want to just replace it just use this:

Bind<T>().To<U>.Named("X").ReplaceExisting();

 

Here the source code to achieve this (works in Ninject 2+):
 

using System.Linq;
using Ninject.Planning.Bindings;
using Ninject.Syntax;

// ReSharper disable CheckNamespace
namespace System
// ReSharper restore CheckNamespace
{
    public static class ExtensionsNinject
    {
        /// <summary>
        /// Replace existing binding.
        /// To replace a binding you should never use rebind becauses unbind all existing
        /// binds and then bind yours.
        /// You should first configure the entire binding using Bind and only as last
        /// operation you should declare to replace it using this method.
        /// </summary>
        public static void ReplaceExisting<T>(this IBindingInSyntax<T> bindingInSyntax)
        {
            ReplaceExistingImpl<T>(bindingInSyntax);
        }

        /// <summary>
        /// Replace existing binding.
        /// To replace a binding you should never use rebind becauses unbind all existing
        /// binds and then bind yours.
        /// You should first configure the entire binding using Bind and only as last
        /// operation you should declare to replace it using this method.
        /// </summary>
        public static void ReplaceExisting<T>(this IBindingOnSyntax<T> bindingInSyntax)
        {
            ReplaceExistingImpl<T>(bindingInSyntax);
        }

        /// <summary>
        /// Replace existing binding.
        /// To replace a binding you should never use rebind becauses unbind all existing
        /// binds and then bind yours.
        /// You should first configure the entire binding using Bind and only as last
        /// operation you should declare to replace it using this method.
        /// </summary>
        public static void ReplaceExisting<T>(this IBindingWhenSyntax<T> bindingInSyntax)
        {
            ReplaceExistingImpl<T>(bindingInSyntax);
        }

        private static void ReplaceExistingImpl<T>(IBindingSyntax bindingInSyntax)
        {
            var kernel = bindingInSyntax.Kernel;
            var bindingsToRemove = kernel.GetBindings(typeof(T)).Where(b => string.Equals(b.Metadata.Name, bindingInSyntax.BindingConfiguration.Metadata.Name, StringComparison.Ordinal));
            foreach (var bindingToRemove in bindingsToRemove)
            {
                kernel.RemoveBinding(bindingToRemove);
            }

            var binding = new Binding(typeof(T), bindingInSyntax.BindingConfiguration);
            kernel.AddBinding(binding);
        }
    }
}

Posted in ninject | No Comments »

NHibernate – Paging by root entity with eager join fetch of a child collection

Posted by Ricibald on July 15th, 2012

With nhibernate we can fetch entities using the fetch strategies explained in the link.

Now we consider only the use of fetching by join.

Scenario: I want to fetch by join the first 5 students with all the exams eagerly loaded.

If I write the QueryOver I end not with 5 results but with 100 results, almost all of these duplicated!

Why does this happen? The response is: count the rows! If you execute in SQL Server the query you ends with 5 results combinated with the corresponding exams. If every student has 20 exam, you ends with 100 students!

A simple solution: change fetch strategy to select. But if you want join fetch to overcame to N+1 problem you should use the following fixes:

You can merge duplicates by setting a DistinctRootEntityResultTransformer in the QueryOver, but merging them means that you obtain just the merged result of the first 5 rows: a single student!

To obtain all the students you should first create a query with none eagerly loaded, and then use this query as subquery to obtain the remaining references to eagerly loaded.

You can follow this example:

                // this will hold the criterial for the query
                var subQuery = QueryOver.Of<Parent>();

               // we build the criteria here...

               // add paging id projection so we only get one page of ids
                var pageSubQuery = subQuery.Clone()
                    .OrderBy(p => p.Id).Asc
                    .Select(p => p.Id)
                    .Skip(index ?? 0)
                    .Take(itemsPerPage ?? 20)
                    ;

                var items = session.QueryOver<Parent>()
                    .WithSubquery.WhereProperty(p => p.Id).In(pageSubQuery)
                    .OrderBy(p => p.Id).Asc // important to have the same order as above!
                    .Fetch(p => p.Children).Eager
                    .TransformUsing(new DistinctRootEntityResultTransformer())
                    .Future()
                    ;

                // Count
                var count = subQuery.GetExecutableQueryOver(session)
                    .Select(Projections.CountDistinct<Parent>(p => p.Id))
                    .FutureValue<int>();

Other solutions from the official post in nhforge.

Posted in .net | No Comments »

ASP.NET MVC: Dropdown EditorTemplate from ViewModel Instance by Convention

Posted by Ricibald on June 2nd, 2012

Based on separation between ViewModel and View when you want to display a Dropdown you should configure allowedvalues for a certain type inside the ViewModel instead of the Controller or the View.

For this reason, after long searches, I decided to implement my own solution based on convention.

This is the ideally expected result:

    public class UserViewModel
    {
        // the enum type is already handled specializing the string template
        public AreaEnumType AreaId { get; set; }

        [MultivalueAllowed]
        public int? CityId { get; set; }

        public IEnumerable<SelectListItem> CityIdAllowedValues()
        {
            var cities = getCitiesByRegion(this.AreaId);
            foreach(var city in cities) {
                yield return new SelectListItem { Text = city.Text, Value = city.Id, Selected = this.CityId == city.Id };
            }
        }
    }

In other words:

if you have a property that is to view as a dropdown, just add the attribute MultivalueAllowed and implement an instance method using the convention PropNameAllowedValues: you can also access to every instance property inside it!!!

These are the files to modify to achieve this (I’m using extension methods, reflection, UIHintAttribute, EditorTemplates, Razor):

/********** MultivalueAllowedAttribute.cs **********/
    public class MultivalueAllowedAttribute : UIHintAttribute
    {
        public MultivalueAllowedAttribute(bool allValuesVisibleFromStart = false)
            : base(getUiHintFromConfiguration(allValuesVisibleFromStart))
        {
        }
        private static string getUiHintFromConfiguration(bool allValuesVisibleFromStart)
        {
            return allValuesVisibleFromStart ? "Combobox" : "Dropdown";
        }
    }
/********** global.asax.cs **********/
protected override void OnApplicationStarted()
{
     ModelMetadataProviders.Current = new CustomMetadataProvider();
}
/********** CustomMetadataProvider.cs **********/
namespace MvcExtensions
{
    public class CustomMetadataProvider : DataAnnotationsModelMetadataProvider
    {
        protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
        {
            var modelMetadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);

            // add container instance
            if(modelAccessor != null && modelAccessor.Target != null)
            {
                var containerField = modelAccessor.Target.GetType().GetField("container");
                if(containerField != null)
                {
                    var containerValue = containerField.GetValue(modelAccessor.Target);
                    modelMetadata.SetContainerInstance(containerValue);
                }
            }

            return modelMetadata;
        }
    }
}

namespace System
{

    public static class ModelMetadataExtensions
    {
        private static void addSafe(ModelMetadata modelMetadata, string key, object value)
        {
            modelMetadata.AdditionalValues.Add(key, value);
        }

        private static T getSafe<T>(ModelMetadata modelMetadata, string key)
        {
            object value;
            if(modelMetadata.AdditionalValues.TryGetValue(key, out value))
                return (T)value;
            return default(T);
        }

        public static void SetContainerInstance(this ModelMetadata modelMetadata, object value)
        {
            addSafe(modelMetadata, "containerInstance", value);
        }

        public static object GetContainerInstance(this ModelMetadata modelMetadata)
        {
            return getSafe<object>(modelMetadata, "containerInstance");
        }
    }
}
/********** Views/Shared/EditorTemplates/Dropdown.cshtml **********/
@model System.Object

@if (ViewData.ModelMetadata.DisplayName != null)
{
    @Html.LabelForModel()
}
@Html.DropDownListByConvention("")
@Html.Description("", new { @class = "description" })
@Html.ValidationMessage("", null, new { @class = "ym-message" })
        /********** HtmlHelperExtensions.cs **********/
        public static MvcHtmlString DropDownListByConvention<TModel>(this HtmlHelper<TModel> htmlHelper, string expression)
        {
            var metadata = ModelMetadata.FromStringExpression(expression, htmlHelper.ViewData);
            var containerInstance = metadata.GetContainerInstance();
            var containerType = metadata.ContainerType;
            var items = containerInstance.GetAllowedValues(containerType, metadata.PropertyName);
            if (metadata.IsNullableValueType)
            {
                items = SingleEmptyItem.Concat(items);
            }

            return htmlHelper.DropDownList(expression, items);
        }

        public static IEnumerable<SelectListItem> GetAllowedValues(this object instance, Type instanceType, string propertyName)
        {
            var allowedValuesMethodName = propertyName + "AllowedValues";
            var allowedValuesMethod = instanceType.GetMethod(allowedValuesMethodName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);

            if(allowedValuesMethod == null)
            {
                throw new Exception("Unable to find instance method " + instanceType.Name + "." + allowedValuesMethodName);
            }

            var result = allowedValuesMethod.Invoke(instance, null);
            return (IEnumerable<SelectListItem>)result;
        }

Posted in .net | 1 Comment »

Come salvare la buona progettazione da morte certa…

Posted by Ricibald on January 15th, 2012

Ormai è tantissimo che non pubblico più nulla su questo blog, e con un buon motivo… Ero alla ricerca di me stesso

Può sembrare uno scherzo, ma limitatamente all aspetto tecnologico è proprio così.

Dagli ultimi articoli che ho letto in questo periodo ho approfondito tantissime tecniche di progettazione e implementazione:

  • TDD (Nunit), utilizzabile anche con semplici js tramite divisione MVC
  • Mock e Stub (Moq, Moles)
  • IoC e DI (Unity, NInject)
  • AOP e Decorator/Proxy (PostSharp)
  • DDD (l’unico vero modo per non ottenere codice procedurale ma vero OOP)
  • Code-First: il codice regna, il database è solo un’implementazione della persistenza (Persistence Ignorance)
  • Principio “Tell Don’t Ask”
  • ALM (VS Team System, tracking, branching, …)
  • CQRS: separa comandi (cambiano stato) da query (leggono stato) per non avere effetti collaterali. Questo porta all’uso di eventi a livello di sistema e a nuovi scenari di scalabilità (vedi Azure e db NoSql)
  • Generic Specialization: Double-Dispatch, Visitor pattern
  • Design: confine tra utility (semplice da usare) ed entertainment (evocativa e figa)
  • AHP e Reti neurali per supportare la Teoria delle decisioni
  • Progressive Enhancement, unobtrusive javascript, preemptive fetching
  • Reactive programming: solo eventi, nessun multithreading
  • Agile programming: XP, Scrum, Pair programming
  • Design By Contract
  • Convention over Configuration

Ora, questi sono “solo” puntatori a tutto ciò che ho imparato. Sono tutti concetti importantissimi, ma più o meno tutti si basano sul fatto che il team sia estremamente affiatato e competente nella tecnologia e nella progettazione.

E da qui sono arrivato al punto contraddittorio:

non riuscirò, probabilmente mai, a mettere in pratica questi concetti in un sistema omogeneo dove i membri del team abbiano la piena coscienza di cosa si sta facendo.

Ora, immaginiamo anche di aver trovato 2-3 persone molto competenti che sanno applicare queste tematiche: questo non basterebbe comunque! Nuove persone arriveranno nei progetti, le competenze cambieranno, le persone stesse cambieranno e considereranno “meno rilevante” fare bene le cose, “basta che funziona“. Quindi bisogna chiedere a sé stessi:

vale veramente la pena approfondire in questo modo le proprie conoscenze?

La filosofia “basta che funziona” è in realtà molto più nobile di come la si dipinge, basti pensare allo slogan “it just works” dell’Apple: porta all’efficacia di un progetto.

La buona analisi/progettazione può essere vista come un “cruccio” dell’analista/tecnico, quando poi alla fine comanda sempre e solo il risultato finale, il “just works”. Allora perché preoccuparsi tanto, perché dedicare tempo allo studio di pattern di analisi e progettazione? Beh, molto semplice, in tutti questi discorsi del “just works” non abbiamo considerato la dimensione risorse:

con risorse infinite… tutto funziona!

Una buona progettazione porta a tre benefici fondamentali: la predicibilità, il riuso e la separazione delle responsabilità. Il riuso consente di non reinventare funzionalità già scritte e “mature”, evitando di sprecare tempo inutile in cose già fatte e rifatte, analizzate e testate; la predicibilità è un requisito fondamentale del riuso. La separazione delle responsabilità consente di ottenere alta coesione e basso accoppiamento, consente di limitare gli impatti di una modifica e di implementare funzionalità trasversali, come caching o security abilitandone il riuso e l’attivazione o disattivazione su richiesta.

Questi benefici agiscono sulle risorse necessarie: comportano un beneficio concreto in termini di tempo, persone, soldi richiesti. Il caching se implementato correttamente consente di acquistare meno server, il riuso consente di diminuire i tempi di sviluppo e i bug riscontrati. La predicibilità consente di commettere meno errori in quanto il codice è privo di effetti collaterali.

Quindi questo porta a dire una cosa fondamentale:

la progettazione non ha lo scopo di produrre un sistema che funziona, ma serve a realizzarlo con meno impiego di risorse (tempo, persone, soldi).

La buona progettazione consente quindi di ottenere l’efficienza di un progetto.

Quindi, dopo aver prima messo in discussione e in seguito ricostituito il concetto di progettazione conferendogli quindi una rinnovata dignità di esistere, torniamo alla domanda iniziale:

come fare in modo che le tecniche di buona progettazione siano usate nel tempo?

Non possiamo pretendere che tutti siano competenti, ma possiamo sfruttare a nostro vantaggio molte debolezze umane, tra cui l’estrema conservatività con cui lavora la maggior parte delle persone, che non si domanda i perché delle cose, “basta che funzionano”. Immaginiamo un framework perfetto, che consente di suddividere il progetto in blocchi funzionali ideali, come potrebbe essere (a meno di qualche problema) ASP.NET MVC 3. In questo caso anche il programmatore più inesperto non può esimersi dal realizzare codice scritto in quella forma, e qualunque altra forzatura richiedere troppo sforzo per essere implementata, da cui potremmo sfruttare la “debolezza dell’incompetente”.

Quindi, secondo il sottoscritto, la strategia vincente non è fare in modo che tutti abbiano competenze a questo livello, ma costruire un team dove un “senior architect” sia incaricato della stesura della progettazione e della separazione dei componenti. La “novità” dell’approccio sta nel fatto che i componenti orchestrati devono avere caratteristiche tali da impedire utilizzi impropri alterandone l’architettura. Ad esempio c’è una bella differenza tra esporre questo metodo:

void setUserStatus(string status);

e questo metodo:

void setUserStatus(UserStatus status);

Il primo è suscettibile a utilizzi impropri (potrei scrivere uno stato valido “Active” ma anche uno non valido “Ready”), il secondo non ha possibilità di utilizzi impropri (l’enumerato ha solo valori discreti). Se i metodi rispettono queste regole, se le classi che lo contengono hanno i membri incapsulati correttamente, se i metodi non facade sono visibili solo nell’ambito dei moduli che lo contengono, se si segue l’approccio Design-By-Contract e si validano precondizioni e postcondizioni, non sarà possibile dall’esterno ottenere comportamenti che violano i vincoli architetturali.

Se inoltre abbiniamo controlli di Code Analysis e di complessità ciclomatica minima possiamo fare in modo che anche l’implementazione del singolo metodo non faccia uso di funzioni sbagliate definite altrove. Ma il principio deve sempre essere lo stesso:

permettere anche a un tecnico non evoluto di integrarsi in un sistema complesso nel modo corretto, senza che questo possa compromettere l’architettura.

Diventa quindi fondamentale che il ruolo dell’architetto sia ben delineato e confinato e che tecnici meno competenti non si occupino di concetti architetturali.

Oltre a questo è fondamentale che i singoli tecnici meno esperti abbiano al tempo stesso la giusta motivazione (non sono macchine!) e quindi il ruolo dell’architetto è da una parte schermare da usi impropri, dall’altra quello di concedere la giusta autonomia di implementazione poiché ognuno ha il proprio stile. Questo serve a motivare dal punto di vista tecnico, mentre dal punto di vista degli obiettivi è importante che ogni persona si senta responsabile del proprio blocco funzionale in tempi in cui lui stesso si senta impegnato a rispettare. Ad esempio c’è una bella differenza tra il dire: “fai questo task prima possibile” o dire: “se sviluppi tutto questo use case dall’inizio alla fine, mi dici quando credi di finire?“. Questo responsabilizza le persone poiché le fa sentire parte di qualcosa e se qualcosa va male nel loro use case o sono in ritardo nella consegna stai tranquillo che faranno anche mezzanotte poiché si sentiranno responsabili della loro parte. Ovviamente il loro use case deve essere comunque sempre protetto da implementazioni improprie che alterano l’architettura, e qui torniamo al punto precedente!

E per ultimo, le funzioni di utilità: aldilà del framework che implementiamo, ci sono funzioni utility di uso comune che spesso mettiamo a fattor comune, ma la cui memoria si perde nel tempo. Come fare per forzarne l’uso? Inanzitutto l’uso si può “suggerire” mediante gli extension method, sarà l’IDE che ne suggerirà l’autocomplete. Ma per forzare realmente si dovranno implementare dei custom Code Analysis mediante strumenti come FxCop.

Sintetizzando, design, progettazione e tecniche di programmazione sono fondamentali per minimizzare le risorse necessarie a realizzare un progetto e ottenere efficienza oltre a efficacia (“it just works”). Ma tali caratteristiche non devono appartenere a tutti, come suggeriscono tutti i modelli agili, ma possono purtroppo appartenere solo a poche persone “sagge”, che avranno il compito di costruire un’infrastruttura atta a garantirne il corretto uso nel tempo, anche quando loro stessi avranno (finalmente) cambiato o costruito la loro società ideale.

Posted in analysis, design | No Comments »

Perché passare da Svn a Git

Posted by Ricibald on August 30th, 2011

Come al solito… articolo condensato per non perdere tempo…!

Perché scegliere Git rispetto agli altri controlli versione come Svn, Cvs, …? Di seguito un elenco delle cose che Git consente in più rispetto agli altri sistemi:

  1. git è distribuito: ogni client non ottiene l’ultima versione disponibile (come in Svn) ma un clone dell’intero repository con tutto lo storico. Questo abilita un uso completo offline di tutte le funzionalità (commit, diff, log, branch, merge, annotation) in modo istantaneo. Inoltre il sistema non avrà un Single Point of Failure poiché ogni client avrà il full backup del progetto. Infine si può articolare una struttura di workflow in cui si mantengono dei repository separati con diversi permessi di lettura/scrittura che vengono integrati in un workflow “gold” (si veda questo articolo) [in TFS strutturare in questo modo è possibile grazie a un uso corretto dei permessi e delle policy].
  2. branch semplici: creare un branch ed eseguire lo switch a un branch sono operazioni che impiegano qualcosa come 0.1 secondi. Tale velocità cambia l’aspetto psicologico del branch: diventa un’operazione comune per qualunque cosa su cui si lavora: ogni feature, idea, bugfix, senza essere online con la possibilità di annullare un branch e cambiare contesto quasi in modo istantaneo. Il merge inoltre è a 3 vie e riduce al minimo le probabilità di conflitti.
  3. commit organizzate per feature: a differenza di altri sistemi come Svn, in Git i file locali non vengono inviati direttamente nel repository ma passano prima per una staging area (o index) che consente di specificare nel dettaglio quali file (e quali porzioni di file) si andranno a committare, in modo da risolvere il problema della “copia di lavoro intricata” e mantenere ogni commit un evento con il preciso scopo di riportare i file modificati impattati dopo aver implementato una determinata feature. Questa separazione consente di eseguire ad esempio il merge solo di determinate feature, lasciandone indietro altre.
    Infatti Git viene definito un “change control” invece di un “version control”: invece di presentare il progetto linearmente (mentalità dell’”undo”) Git vede solo un manipolo di commit pronti per essere rimescolati o amalgamati insieme
  4. utile a te: spesso si sceglie di non usare Git poiché non si fa parte di un team numeroso. In realtà Git aiuta te, non il tuo team: il branch locale, il context switching, le commit come feature, aiutano l’individuo, non il team. Velocità e backup sono sempre una buona cosa, sia in team che non.
Ottimi articoli:

Posted in .net | No Comments »

Adapt/convert Microsoft Ajax events to JQuery

Posted by Ricibald on July 22nd, 2011

It’s very useful to express everything in JQuery instead of ASP.NET AJAX events system: in this way we can use a lot of useful JQuery controls.

To achieve this just add this snippet of javascript code:

<script type="text/javascript">
	Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(BeginRequest);
	Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequest);
	function BeginRequest(sender, args) {
		jQuery.event.trigger('ajaxSend');
	}
	function EndRequest(sender, args) {
		jQuery.event.trigger('ajaxComplete');
	}
</script>

In this way you can capture standard JQuery event to obtain for example a modal progress feedback both in case of JQuery ajax POST and in case of ASP.NET UpdatePanel events:

<script type="text/javascript">
	$(document).bind("ajaxSend", function () {
		$("#loadingAjax").dialog({ modal: true });
	}).bind("ajaxComplete", function () {
		$("#loadingAjax").dialog("close");
	});
</script>

Posted in asp.net, javascript, jQuery | No Comments »

iOS NIB Localization in Localizable.strings

Posted by Ricibald on June 3rd, 2011

Scenario:

I want to localize my app AllSync but I was taken by a little frustration.

Following this good guide you can see that there are two main way to localize your iOS (iPhone/iPad) app:

  • localize strings using Localizable.strings
  • localize single nib file creating one version for each
The second point is very frustrating for three reasons:
  • you have to mantain updated all version of your nib localized files
  • there are specialized sites like icanlocalize that translates only your Localizable.string, not your nib files
  • you have to take care about the resulting layout of single translation
The problem:
I want to localize my nib files in the same way of using Localizable.strings

A possible solution can be to externalize in code every text setting but is a tedious process and you can’t use the flexibility of xcode 4. The real solution I hope will be used by many of you is this:

The solution:

Create an extended version of iOS user control that automatically translates every single text

Simple to obtain: just see this extended UIButton

@interface UIButtonThemed : UIButton
@end

@implementation UIButtonThemed
- (id)initWithCoder:(NSCoder *)aDecoder {
    if ((self = [super initWithCoder:aDecoder]))
	{
        self.titleLabel.adjustsFontSizeToFitWidth = YES;
        NSString* text = NSLocalizedString(self.titleLabel.text, nil);
        [self setTitle:text forState:UIControlStateNormal];
        [self setTitle:text forState:UIControlStateHighlighted];
        [self setTitle:text forState:UIControlStateDisabled];
        [self setTitle:text forState:UIControlStateSelected];
	}
	return self;
}
@end

You can use it inside xcode 4 configuring the base class for your control:

Then you can see my italian Localizable.strings:
"Sync" = "Sincronizza";
"Settings" = "Impostazioni";
"Help" = "Guida";
"Share" = "Condividi";
"Rate us" = "Votaci";
"Follow us" = "Seguici";
And the corresponding result:

Posted in iphone, projects | 4 Comments »

jQuery: HTTP POST with specific <input type=”submit”>

Posted by Ricibald on April 19th, 2011

jQuery allows only to do a global form submit using

$("form").submit()

This method doesn’t allow to do a specific form submit when multiple <input type=”submit”> exists, like in many ASP.NET sites, where there are a single form with many buttons.

To achieve this and obtain an ASP.NET POSTBACK behavior simply use this snippet of jQuery code that builds a “submit simulation from input”:

// simulate submit from button "myButton"
var input = $("<input>").attr("type", "hidden").attr("name", $('#myButton').attr("name")).val("");
$('form').append($(input));
$('form').submit();

Posted in .net, javascript, jQuery | No Comments »

Pattern Flyweight in Pratica: Predisporre un’Applicazione per il Precache

Posted by Ricibald on January 18th, 2010

Il pattern Flyweight consente di riutilizzare gli oggetti in modo da poter evitare allocazioni. Questo risulta utile se:

  1. gli oggetti da creare richiedono molta memoria
  2. gli oggetti da creare sono molti
  3. gli oggetti da creare sono costosi da creare (e distruggere) dal punto di vista computazionale
  4. i vincoli impongono un sistema che non abbia cali improvvisi di performance, derivanti ad esempio dall’inizializzazione pesante di un oggetto
  5. i vincoli impongono un utilizzo molto attento delle risorse
Facciamo un esempio pratico di ognuno di questi punti:
  1. un’animazione può avere tante caratteristiche ingenti da memorizzare come accelerazione, direzione, …
  2. un word processor utilizza migliaia di caratteri con le stesse info su font, dimensione, colore, …
  3. un’immagine: il caricamento richiede ogni volta l’accesso al filesystem
  4. un videogioco deve avere fps costanti e non avere improvvisi picchi negativi di 10fps solo perché si alloca una risorsa
  5. un dispositivo mobile come il Nokia o l’iPhone
La parte critica a mio parere non è implementare il pattern direttamente: con un po’ di sforzo si riesce! Il problema sta nell’adattare un progetto non pensato per questo pattern, in questo caso l’implementazione non diventa affatto banale!
Facciamo un esempio pratico: ho un’applicazione per iPhone che deve gestire delle biglie che rimbalzano di numero crescente. All’inizio le prestazioni risultano buone ma poi iniziano a degradare evidenziando due problemi:
  • la memoria inizia a non essere sufficiente per le info necessarie
  • l’allocazione/deallocazione causa picchi negativi di fps, ora (più) evidenti a causa dello stesso degrado delle performance generali
Per questo vorremmo gestire tutti gli aspetti comuni a ogni singola biglia attraverso il pattern Flyweight. Vorremmo quindi gestire:
  • lo stato intrinseco della biglia nel flyweight
    • posizione, comportamento specifico della biglia
  • lo stato estrinseco della biglia nella nostra app, che lo passa al flyweight
    • immagine, colore, dimensione, comportamenti comuni di animazioni
Facile a dirsi, ma se non abbiamo pensato la app in questo modo ci troveremo tanti problemi. Infatti al momento di creare una biglia prima:
  • veniva creata e associata l’immagine corrispondente
  • veniva aggiunta l’immagine alla scena corrente assegnando uno z-index
  • veniva assegnato un comportamento della biglia: quanto rimbalzare, se esplode, …
Capire effettivamente cosa estrarre da tutto questo diventa una sfida a volte irrisolvibile, anche a causa dei vincoli tecnologici a cui ci sottopongono i framework stessi, che non prevedono il riuso delle strutture.
Per questo, a parte la teoria del pattern, bisognerebbe:

capire come predisporre una applicazione per fare uso di un precaching in modo da abilitare il pattern con poco sforzo

Rivediamo quindi l’obiettivo: non vogliamo applicare alla lettera il pattern Flyweight (difficile da adattare al nostro contesto) ma vogliamo evitare allocazioni inutili. Una strategia sta nel riutilizzare le stesse istanze ogni volta che queste non sono più utili. Infatti se una biglia esce dal gioco la strategia comune è deallocare la biglia stessa e allocarne una nuova quando necessario. Invece decidiamo di riutilizzare le stesse istanze quando escono dal campo visivo: ci sarà l’illusione di distruggere la biglia, ma non sarà così! In questo modo possiamo ottenere due vantaggi:
  • l’allocazione e deallocazione, che causavano picchi negativi di fps sono presenti un’unica volta
  • creiamo le premesse per un precaching di ad es. 40 biglie, utile per impedire completamente il problema di picchi negativi di fps
Tornando al problema precedente, quando costruiamo una app non sapremo se questo servirà o meno, ma nel dubbio la cosa conveniente è senza dubbio:

dividere inizializzazione estrinseca da inizializzazione intrinseca in modo da poter riutilizzare l’inizializzazione quando richiesto

Il trucco è quindi proprio questo: nella creazione degli oggetti dovremmo inizializzare solo quello che non cambia nella biglia come l’immagine il colore, … Dopo aver creato gli oggetti passiamo quindi per una seconda fase di inizializzazione che imposta lo stato intrinseco della biglia stessa come la posizione e il comportamento. Questo lo facciamo a priori!! Un piccolo sforzo, ma in fondo ben gestibile. Se un giorno servirà questo ci verrà di aiuto!
Immaginiamo che sia venuto quel giorno! Basta creare una FlyweightFactory che consente il seguente flusso:

  • allo startup la FlyweightFactory crea ad es. 40 biglie e le mantiene in un proprio pool di precaching
  • quando alla app serve una biglia richiede un’istanza disponibile alla FlyweightFactory
  • la FlyweightFactory restituirà un’istanza dal pool con lo stato intrinseco correttamente inizializzato
  • quando la biglia non viene più referenziata nella nostra app ma esiste solo nella FlyweightFactory deve esistere una strategia per marcare l’istanza come disponibile nel pool (es. un meccanismo di notifica a eventi)

Fare questo a fronte della divisione tra allocazione/inizializzazione è un gioco da ragazzi!

A questo punto rimane solo il problema dell’allocazione dello stato estrinseco, che viene ridondata per ogni biglia. Per questo risulta quindi necessario aggiungere come parametro nell’allocazione (creazione) delle biglie lo stato estrinseco stesso, che viene creato un’unica volta dalla factory. In questo modo risolviamo il problema finale.

Il flusso di inizializzazione diventa quindi:

  • allo startup viene inizializzato lo stato estrinseco
  • la FlyweightFactory alloca un pool di 40 biglie passando lo stato estrinseco
  • le singole istanze memorizzano il riferimento allo stato estrinseco
  • la app richiede un’istanza alla FlyweightFactory
  • la FlyweightFactory inizializza un’istanza disponibile dal pool e la restituisce. Rimangono quindi 39 biglie nel pool
  • la app usa la biglia. Quando non serve più la rimuove dalla app
  • la app lancia un evento di avvenuta rimozione della biglia
  • la FlyweightFactory riceve l’evento e aggiunge la biglia nel pool delle istanze disponibili. Rimangono quindi 40 biglie nel pool
Concludendo abbiamo leggermente modificato il pattern Flyweight per adattarlo a contesti reali: il pattern infatti prevede che le singole operazioni portino con sé lo stato estrinseco su cui lavorano mentre la nostra soluzione prevede un’allocazione che assegni lo stato estrinseco e le singole operazioni che lo usano come se lo avessero creato loro. Questo si sposa bene con il refactoring necessario per applicare il pattern, che altrimenti richiederebbe un ripensamento globale dell’applicazione.

Posted in .net, performance | 1 Comment »