Fullsix Engineering

Duas ferramentas de optimização de sites

Wednesday, October 6th, 2010
Autor: gustavo.castelo


Abram um site que tenham feito e testem-no com o Yslow. Que pontuação obtêm?.. A minha média andava entre os 65-75.
Quantos de nós realmente nos preocupamos em optimizar cada site que fazemos?..

O César já nos apresentou dicas para optimizar a performance de um site mas, falando por mim, na prática não tenho conseguido aplicar grande parte delas, até olhar para o Yslow com atenção e seguir as dicas e programas que nos sugere e vão de encontro a algumas que ele nos mostrou.

Dois dos problemas que o YSlow normalmente aponta nos sites que fazemos são: Make fewer HTTP Requests e Minify JavaScript and Css.

• O 1º normalmente está relacionado com o número de chamadas a scripts e Css (a partir de 3 chamadas, já se queixa). Associado a este costuma vir o Put Javascript at Bottom, que desaparece assim que este estiver resolvido.

• O 2º acontece porque os nossos scripts “saiem em claro” para produção, com comentários e espaços em branco que só aumentam o tamanho e criam tráfego desnecessário. O que ele também se devia queixar é que estamos a expôr o nosso código a outros com tanta clareza que doi e que devemos protegê-lo. Daí a minificação estar associada à obfuscação (troca de nomes de variáveis e nomes de métodos).

As duas ferramentas que nos podem ajudar a resolver estes problemas são: YuiCompressor e um handler HTTPCombiner.

A 1ª encontrei através do Yslow e serve para minificar (e até certo ponto, obfuscar) CSS’s e JS’s. A 2ª serve para juntar num só pedido, ficheiros CSS e JS.

Usando-as, fiz a pontuação dos meus sites subirem 10 pontos para a média dos 80-85 e com desempenho visivelmente melhor.
Podem ver aqui: http://www.tapme.pt/en e http://www.campanha.infarmed.pt/ e http://brisa.dev.fullsix.local/pt-bcr.

Os pontos que normalmente ficam a faltar depois disto, são por não termos uma CDN, subdominios para as imagens ou usar Gzip para certos conteúdos (também podemos configurar facilmente), mas de resto podemos lavar as nossas mãos de SS e queixarmo-nos ao HTML para juntar imagens num só ficheiro (outra coisa que aparece muito no relatório) .

Como tudo, convém analisar se realmente é necessário usar isto no site ou estamos a complicar 

YuiCompressor - http://yuilibrary.com/downloads/#yuicompressor

Este programa pega nos nossos scripts e css’s e elimina comentários, espaços em brancos e altera nomes de varíaveis e métodos de forma a tornar o ficheiro mais pequeno.

Como usar:
1 – Criar uma pasta (eu chamo-lhe toMinify) no projecto, onde colocamos os css e js’s a serem minificados juntamente com o jar.
2 – Como a ferramenta é um jar, convém ter o java.exe definido nas variáveis de ambiente:
Java Path3 Duas ferramentas de optimização de sites

3 – Configurar os Pre-build events (Propriedades do projecto) para correr o programa para cada ficheiro que queremos minificar. Ex:
java -jar “$(ProjectDir)toMinify\yuicompressor-2.4.2.jar” “$(ProjectDir)toMinify\scripts\library.js” -o “$(ProjectDir)scripts\library.js” –charset utf-8
java -jar “$(ProjectDir)toMinify\yuicompressor-2.4.2.jar” “$(ProjectDir)toMinify\css\BCR\brisa_bcr.css” -o “$(ProjectDir)css\BCR\brisa_bcr.css” –charset utf-8

Pre build events1 Duas ferramentas de optimização de sites

3 – Testar um build e verificar que na pasta final está o ficheiro alterado.

HTTPCombiner - http://www.codeproject.com/KB/aspnet/HttpCombine.aspx
Download – http://code.msdn.microsoft.com/HttpCombiner/Release/ProjectReleases.aspx?ReleaseId=1462

Este handler junta no mesmo pedido os ficheiros que definimos numa key do webconfig, fazendo também cache desse pedido. Assim, passa-se para apenas uma chamada para scripts e outra para css.

1 – Download do rar e copiar o .ashx para o projecto.
2 – Abrir o web.config e criar os sets para Js’s e CSS’s. Algo deste género:

<!-- http combiner settings-->
<add key="CommonScriptsInovacao"
value="~/scripts/jquery-1.4.2.min.js,
~/scripts/jquery.infinite-carousel.js,
~/scripts/accordion.js,
~/scripts/thickbox.js,
~/scripts/hoverIntent.js,
~/scripts/genericcode.js,
~/scripts/slider.js,
~/scripts/json2.js,
~/scripts/library.js,
~/scripts/swfobject.js"/>

<add key="CommonCssInovacao"
value="~/css/Inovacao/brisa.css,
~/css/brisaTinyMCE.css,
~/css/thickbox.css,
~/css/accordion.css,
~/css/superfish.css,
~/css/slider.css"/>

3 – Na chamada dos css’s e js’s em vez de termos algo deste género:

<umbraco:Macro Alias="CssFile" runat="server"></umbraco:Macro>
<link rel="stylesheet" type="text/css" href="/css/brisaTinyMCE.css" />
<link rel="stylesheet" type="text/css" href="/css/thickbox.css" />
<link rel="stylesheet" type="text/css" href="/css/slider.css" />
<link rel="Stylesheet" type="text/css" href="/css/accordion.css" />

<script type="text/javascript" src="/scripts/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="/scripts/jquery.infinite-carousel.js"></script>
<script type="text/javascript" src="/scripts/accordion.js"></script>
<script type="text/javascript" src="/scripts/thickbox.js"></script>
<script type="text/javascript" src="/scripts/hoverIntent.js"></script>
<script type="text/javascript" src="/scripts/genericcode.js"></script>
<script type="text/javascript" src="/scripts/slider.js"></script>
<script type="text/javascript" src="/scripts/json2.js"></script>
<script type="text/javascript" src="/scripts/library.js"></script>
<script type="text/javascript" src="/scripts/swfobject.js"></script>

Comentamos e escrevemos:

<link type="text/css" rel="stylesheet" href="/HttpCombiner.ashx?s=CommonCssBCR&t=text/css&v=1" />
<script type="text/javascript" src="/httpcombiner.ashx?s=CommonScriptsBCR&t=text/javascript&v=1" />

Atenção aos parâmetros:
s = Nome do set que definimos no web.config
t = tipo de set
v = versão.

4 – Testar e se os caminhos estiverem bem, tudo ficará como antes só que mais rápido.

Um problema que vi neste handler é que faz cache durante 30 dias dos ficheiros, se não modificarmos os parâmetros que lhe passamos, por isso se alteramos algum dos ficheiros do set, o mais provável é vermos sempre a mesma versão.
A solução mais simples é alterar a versão para outro valor, por ex: v=2 ou v=xtpo.. Senão podem sempre editar o código fonte :p

Alguns dos problemas que tenho tido ao usar estas ferramentas são com a malta de HTML que não está habituada a editar os ficheiros numa pasta que não a de CSS ou scripts e fazer build  ou então, por causa da cache que o handler faz, editam o css e como vêem sempre o mesmo simplesmente apagam a chamada ao handler e põe a chamada directa ao script. Mas explicando como é que funciona, entram no esquema e habituam-se.

Espero que seja útil e se não for pensem que com sites mais rápido há menos processamento, logo há menos ciclos de cpu, menos tempo à espera, logo poupa-se energia e paciência. Façamos da Fullsix uma empresa Eco-Friendly icon smile Duas ferramentas de optimização de sites

Ciclo de formação Scrum em Junho de 2010

Monday, May 24th, 2010
Autor: Tiago Andrade e Silva


Em Junho haverá mais dois cursos Certified Scrum Master em Lisboa e no Porto.

Mais informações no site da comunidade em

http://scrumpt.com/content/Training.aspx

Log4net – SmtpAppender

Tuesday, May 4th, 2010
Autor: nuno.lourenco


Ao se configurar o log4net para usar um SmtpAppender, para envio de e-mails com os logs da aplicação, deixo uma nota de reparo no que concerne o envio para vários destinatários:

A documentação refere que para diversos destinatários dever-se-à configurar o log4net separando os endereços por (;). Se assim for surgirá o seguinte erro:

System.FormatException: The specified string is not in the form required for an e-mail address.
   at System.Net.Mime.MailBnfHelper.ReadMailAddress(String data, Int32& offset, String& displayName)
   at System.Net.Mail.MailAddressCollection.ParseValue(String addresses)
   at log4net.Appender.SmtpAppender.SendEmail(String messageBody)
   at log4net.Appender.SmtpAppender.SendBuffer(LoggingEvent[] events)

Isto porque

O SmtpAppender do log4net recorre ao tipo System.Net.Mail. MailAddressCollection da Framework .NET, que por sua vez usa o método Add(string) para adicionar os endereços. Ora acontece que na documantação está o seguinte:

If multiple e-mail addresses separated with a semicolon character (";") are passed in the addresses parameter. a FormatException exception is raised.

Portanto a documentação do log4net pode induzir em erro. Modificar a separação dos endereços por (,) resolverá o problema.

Happy codding icon smile Log4net   SmtpAppender

ref: Log4net’s SmtpAppender with multiple email addresses

C#, .NET and Diacritics

Monday, May 3rd, 2010
Autor: nuno.lourenco


Talvez se perguntem, hein? Pois a ideia é saber “converter” texto com acentuação e não só, pelo corresponde texto sem acentuação. Ora dito isto o que se quer:

  1. âãäåçèéêë –> aaaaceeee
  2. ìíîïðñòó –> iiiiðnoo
  3. ôõöùúûüý –> ooouuuuy

Ora então o código que possibilita a alteração:

 1:  public string RemoveDiacritics(string input)
 2: {
 3:  string stFormD = input.Normalize(NormalizationForm.FormD);
 4: var sb = new StringBuilder();
 5:  
 6:  for (int i = 0; i < stFormD.Length; i++)
 7: {
 8: UnicodeCategory uc = CharUnicodeInfo.GetUnicodeCategory(stFormD[i]);
 9:  if (uc != UnicodeCategory.NonSpacingMark)
 10: {
 11: sb.Append(stFormD[i]);
 12: }
 13: }
 14:  
 15:  return (sb.ToString().Normalize(NormalizationForm.FormC));
 16: }

Happy Coding icon smile C#, .NET and Diacritics

ref: Michael Kaplan blog

Umbraco: Guardar dataypes complexos e navegar pelos parâmetros destes usando xslt

Tuesday, April 13th, 2010
Autor: gustavo.castelo


Para os que têm pressa, o que quero partilhar é que é possível guardar os dados de um DataType como XML e navegar pelas propriedades usando XPATH. Quem prefere usar UserControls talvez não sinta falta disto.

As vantagens que vejo nesta abordagem é que não precisamos de usar splits sobre os valores dos dataTypes, tanto em .Net como em XSLT, que para mais do que dois campos podem induzir em erros.

 

A história completa é assim:

Era uma vez um dataType do Umbraco chamado RelatedLinks, que permite adicionar links para conteúdos ou URLs:

RelatedLinkdatatype thumb1 Umbraco: Guardar dataypes complexos e navegar pelos parâmetros destes usando xslt

Certo dia este DataType deixou de mostrar a informação guardada na árvore dos nós do site (ainda não resolvi este mistério) então criei o meu controlo. Não tão sofisticado, mas faz o que quero.

clip image0025 thumb1 Umbraco: Guardar dataypes complexos e navegar pelos parâmetros destes usando xslt

Em vez de guardar os dados como string separada por | ou , ou ; queria ter um objecto que representasse o estado deste controlo em XML e guardá-lo na BD usando serialização de Xml.

E até aqui tudo bem. Usei o XMLSerializer e o Robbe D. Morri neste artigo, http://www.eggheadcafe.com/articles/xmlserializer_bulkload.asp, deu um toque ao relembrar que não precisamos de guardar os cabeçalhos de xml gerados por esta classe, visto que vamos encapsulá-los no xml do umbraco.

 

public partial class LinkPicker : System.Web.UI.UserControl, IUsercontrolDataEditor

{

       public class LinkPickerState

        {

            public string Title { get; set; }

            public string Url { get; set; }

            public string ContentId { get; set; }

            public string SelectedOption { get; set; }

        }

   /// <summary>

        /// Gets or sets the value.

        /// </summary>

        /// <value>The value.</value>

        public object value

        {

            get

            {

                LinkPickerState lps = new LinkPickerState() { Title = txtTitle.Text, Url = txtUrl.Text, SelectedOption = rblLinkUsed.SelectedValue, lps.ContentId = cpContentId.Text };  

                StringWriter Output = new StringWriter(new StringBuilder());

                new XmlSerializer(typeof(LinkPickerState)).Serialize(Output,lps);  

                //Cut down extra parameters (Credits to: http://www.eggheadcafe.com/articles/xmlserializer_bulkload.asp )   

                String ret = Output.ToString().Replace("xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"","");

                ret = ret.Replace("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"","");

                ret = ret.Replace("<?xml version=\"1.0\" encoding=\"utf-16\"?>","").Trim();

                ret = ret.Replace(Environment.NewLine,"");                

                return ret;

            }

            set

            {

                string _raw = value as string;

                if (!string.IsNullOrEmpty(_raw))

                {

                    StringReader sr = new StringReader(_raw);  

                    LinkPickerState lps = (LinkPickerState)new XmlSerializer(typeof(LinkPickerState)).Deserialize(sr);  

                    txtTitle.Text = lps.Title;

                    txtUrl.Text = lps.Url;

                    cpContentId.Text = lps.ContentId;

                    rblLinkUsed.SelectedValue = lps.SelectedOption;

                }

            }

        }

}

   

E na árvore de nós do umbraco apareceu assim:

 

<node id="1255" level="4" nodeName="Link 1" urlName="link-1" nodeTypeAlias="relatedLink">

<data alias="url"><![CDATA[asdsa]]></data>

          <data alias="text"><![CDATA[ads]]></data>

<data alias="link"><![CDATA[<LinkPickerState  >

  <Title />

  <Url />

  <ContentId />

  <SelectedOption>url</SelectedOption>

</LinkPickerState>]]></data>

</node>

O próximo problema era como converter esta string de dados em XML navegável.

O Google dizia para usar o node-set, uma extensão do XSLT que converte string em XML, mas comigo não funcionou. Por isso procurei como fazer isto em código, mas não estando familiarizado com XPATH em .net ia demorar algum tempo. Felizmente para mim, já alguém o tinha feito (fiz algumas alterações ao original):

http://forum.umbraco.org/yaf_postst5730_Parsing-a-string-as-XML-using-XSLT.aspx (No fim)

public XPathNodeIterator ParseToXML(string data){

      if (string.IsNullOrEmpty(data)){

                data = @"<Empty />”;

            }  

            StringReader stringReader = new StringReader(data);

            XPathDocument xPathDocument = new XPathDocument(stringReader);

            XPathNavigator xPathNavigator = xPathDocument.CreateNavigator();

            XPathExpression xPathExpression = xPathNavigator.Compile("/"); 

            XPathNodeIterator xPathNodeIterator = xPathNavigator.Select(xPathExpression); 

            return xPathNodeIterator;

        }

Adicionei este método às extensões que estou a usar e assim consigo a partir disto:

...
<![CDATA[<LinkPickerState  >
  <Title />
  <Url />
  <ContentId />
  <SelectedOption>url</SelectedOption>
</LinkPickerState>]]>
 

obter xml válido, fazendo assim:

<xsl:variable name="linkParameters" select="XsltExtensions:ParseToXml(string($relatedLink/data[@alias='link']))/LinkPickerState" />

clip image006 thumb1 Umbraco: Guardar dataypes complexos e navegar pelos parâmetros destes usando xslt

E fiquei feliz icon smile Umbraco: Guardar dataypes complexos e navegar pelos parâmetros destes usando xslt Podem ver que a seguir é possível navegar como se fosse um xml normal.

Para quem usa mais XSLT esta abordagem podem simplificar o processo em XPATH para além de podermos a nível de código estruturar melhor o estado do nosso datatype e introduzir-lhe funcionalidades adicionais.

 

Code long and prosper


Better Tag Cloud