quarta-feira, 7 de dezembro de 2016

Como dar Permissão para o ApplicationPoolIdentity no sistema de arquivos

As vezes você está fazendo um website ou sistema web em Asp.Net que precisa ler e gravar um arquivo em uma determinada pasta. Geralmente é uma subpasta do proprio aplicativo.

Quando você tenta rodar a aplicação recebe uma mensagem de erro dizendo que a aplicação não tem privilégios para gravar o dito cujo arquivo.

Geralmente, quando isso acontecia, eu ia lá nas configurações avançadas do AppPool e trocava o ApplicationPoolIdentity por NetworkService ou coisa assim, e dava permissão na pasta para o NetworkService. Afinal o AppPool cria um usuário instantâneo para o ApplicationPoolIdentity e esse cara não existe no windows, não tem como dar permissão pra ele, certo? Errado.

Propriedades do App Pool
Geralmente o usuário é ApplicationPoolIdentity

Escolha de conta de sistema
Muita gente troca para NetworkService




Você pode dar permissão para o ApplicationPoolIdentity fazendo o seguinte: na hora de escolher o nome do usuário que terá acesso a pasta da sua aplicação (lá no inetpub/wwwroot/SeuApp/ você coloca o nome do seu AppPoll prefixado de IIS AppPool\.

Por exemplo: se o nome do seu AppPool é DefaultAppPool, então o nome do usuário (em local machine) é IIS AppPool\DefaultAppPool. Se é HelDesk, então IIS AppPool\HelpDesk e assim por diante.

Na figura o nome do meu AppPool é DNN2, porque é o segundo appPool que criei para meu DotNetNuke.

permissões de acesso ao sistema de arquivos
Digite iis apppool\NomeDoPool
Quando você digita IIS AppPool\NomeDoPool o usuário não existe, mas quando você verifica o nome (check names) o nome é substituído automaticamente pelo nome do AppPool, mas se você digitar o nome do appPool direto não funciona.

Depois do check
Depois de dar um Check o nome vira o próprio appPool

Fontes
http://stackoverflow.com/questions/7334216/iis7-permissions-overview-applicationpoolidentity
https://www.iis.net/learn/manage/configuring-security/application-pool-identities
http://stackoverflow.com/questions/5437723/iis-apppoolidentity-and-file-system-write-access-permissions

sexta-feira, 2 de dezembro de 2016

Muitas vezes nós criamos Enums para expressar possíveis opções/valores de um campo de múltipla escolha onde os itens são fixos do sistema e não cadastrados em uma tabela.
Há casos em que os itens definem regras de negócio e rumos a tomar na aplicação. Nesses casos usar enum não é a melhor opção.
Em todos os outros casos usar enum pode ser legal, mas existe um problema: como popular um combo box / dropdown list com os itens do combo com nomes amigáveis? Sim, você não pode colocar espaços e caracteres especiais em um enum. Mas ao popular as opções, seja em uma aplicação windows forms ou web forms, você pode querer mostrar descrições longas e cheias de acentos e caracteres especiais para as opções no dropdown.
Você pode usar os atributos Description ou EnumMember para definir programaticamente essas descrições longas, mas obter esses valores de volta vai algumas linhas de código.
Nesse código que eu compartilho abaixo escrevi um extension method (não abuse deles) para o tipo enum chamado ToText() que tenta obter o Description, se não existir tenta obter o EnumMember, e se não existir eu criei um outro, chamado text, para exemplificar como podemos adicionar a qualquer membro do código propriedades e valores declarativamente através de atributos.
Você pode adaptar outros atributos, ou separar Description, EnumMember e Text em métodos separados se desejar.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.ComponentModel;
using System.Runtime.Serialization;

namespace VtrFramework.Extensions
{
    /// 
    /// classe que permite usar um atributo texto em um item de enum, para ele ter uma descrição amigável
    /// 
    public class TextAttribute : Attribute
    {
        public string Text;
        public TextAttribute(string text)
        {
            Text = text;
        }
    }

    /// 
    /// Adiciona um método a mais em um  elemento do tipo enum para pegarmos seu texto amigável
    /// 
    public static class EnumExtensions
    {

        /// 
        /// Dado um enum, retorna seu correspondente string que pode ser: "" se ele for null, Seu decorator/atributo Text se houver, ToString caso contrário
        /// funciona também com o atributo Description e com o atributo EnumMember
        /// 
        /// O Enum a ser convertido
        /// string - O texto do enum
        public static string ToText(this Enum enumeration)
        {

            if (enumeration == null)
            {
                return "";
            }

            MemberInfo[] memberInfo = enumeration.GetType().GetMember(enumeration.ToString());

            if (memberInfo != null && memberInfo.Length > 0)
            {
                try
                {
                    object[] descrs = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);

                    if (descrs != null && descrs.Length > 0)
                    {
                        return ((DescriptionAttribute)descrs[0]).Description;
                    }


                    object[] enumbs = memberInfo[0].GetCustomAttributes(typeof(EnumMemberAttribute), false);

                    if (enumbs != null && enumbs.Length > 0)
                    {
                        return ((EnumMemberAttribute)enumbs[0]).Value;
                    }

                    object[] txts = memberInfo[0].GetCustomAttributes(typeof(TextAttribute), false);

                    if (txts != null && txts.Length > 0)
                    {
                        return ((TextAttribute)txts[0]).Text;
                    }
                }
                catch
                {
                    //catch mudinho porque o fallback é direto para o ToString
                }

            }

            return enumeration.ToString();

        }



    }
}


Use-o assim:

   
 namespace VtrFramework.Test.Extensions
{
    [TestFixture, Description("Teste de métodos de extensão para enuns"), Category("ExtensionMethods")]
    public class EnumExtensionsTest
    {
        public enum TargetEnum
        {
            [System.ComponentModel.Description("Opção 1")]
            Opcao1,

            [EnumMember(Value ="Opção 2")]
            Opcao2,

            [Text("Opção 3")]
            Opcao3,

            Opcao4
        }

        [Test]
        [Description("Teste de método que traz descrição amigável do enum")]
        [Category("ExtensionMethods")]
        public void ToTextTest()
        {
            Assert.AreEqual("Opção 1", TargetEnum.Opcao1.ToText());
            Assert.AreEqual("Opção 2", TargetEnum.Opcao2.ToText());
            Assert.AreEqual("Opção 3", TargetEnum.Opcao3.ToText());
            Assert.AreEqual("Opcao4", TargetEnum.Opcao4.ToText());
        }
    }
}

Você pode popular listbox e dropdowns assim:
    
  /// <summary>
    /// Ferramentas para trabalhar com Enuns
    /// </summary>
    public class EnumTools
    {
        /// <summary>
        /// publica os itens de um enum em um ListItemCollection
        /// </summary>
        /// <typeparam name="TEnum">O tipo do enum a ser publicado</typeparam>
        /// <param name="lst">System.Web.UI.WebControls.ListItemCollection da ListBox ou DropDownList que vai ser preenchida</param>
        /// <param name="primeiroVazio">true se o primeiro item for o vazio/default, false caso contrário</param>
        /// <param name="textoPrimeiroVazio">texto do primeiro item, que não deve fazer parte do enum</param>
        /// <param name="valorPrimeiroVazio">valor do primeiro item, que pode ser String.Empty, 0 ou null dependendo da regra</param>
        public static void PublicaEnum<TEnum>(System.Web.UI.WebControls.ListItemCollection lst, bool primeiroVazio = true, string textoPrimeiroVazio = "Escolha uma opção", string valorPrimeiroVazio = "") where TEnum : struct, IConvertible
        {
            if (!typeof(TEnum).IsEnum)
            {
                throw new ArgumentException("TEnum precisa ser do tipo ENUM");
            }

            lst.Clear();
            if (primeiroVazio)
            {
                lst.Insert(0, new System.Web.UI.WebControls.ListItem(textoPrimeiroVazio, valorPrimeiroVazio));
            }

            var valores = Enum.GetValues(typeof(TEnum));

            foreach(var v in valores)
            {
                string text = ((Enum)v).ToText();
                string value = ((int)v).ToString();
                lst.Add(new System.Web.UI.WebControls.ListItem(text, value));
            }
        }

        /// <summary>
        /// publica os itens de um enum em um DropDownList
        /// </summary>
        /// <typeparam name="TEnum"></typeparam>
        /// <param name="drop">o DropDown/ComboList a ser preenchido</param>
        /// <param name="primeiroVazio">true se o primeiro item for o vazio/default, false caso contrário</param>
        /// <param name="textoPrimeiroVazio">texto do primeiro item, que não deve fazer parte do enum</param>
        /// <param name="valorPrimeiroVazio">valor do primeiro item, que pode ser String.Empty, 0 ou null dependendo da regra</param>
        public static void PublicaEnum<TEnum>(System.Web.UI.WebControls.DropDownList drop, bool primeiroVazio = true, string textoPrimeiroVazio = "Escolha uma opção", string valorPrimeiroVazio = "") where TEnum : struct, IConvertible
        {
            PublicaEnum<TEnum>(drop.Items, primeiroVazio, textoPrimeiroVazio, valorPrimeiroVazio);
        }

        /// <summary>
        /// publica os itens de um enum em um RadioButtonList
        /// </summary>
        /// <typeparam name="TEnum">O tipo do enum a ser publicado</typeparam>
        /// <param name="rbl">o RadioButtonList a ser publicado</param>
        public static void PublicaEnum<TEnum>(System.Web.UI.WebControls.RadioButtonList rbl) where TEnum : struct, IConvertible
        {
            PublicaEnum<TEnum>(rbl.Items, false);
        }

        /// <summary>
        /// publica os itens de um enum em um ListBox
        /// </summary>
        /// <typeparam name="TEnum">O tipo do enum a ser publicado</typeparam>
        /// <param name="lbx">o ListBox a ser publicado</param>
        public static void PublicaEnum<TEnum>(System.Web.UI.WebControls.ListBox lbx) where TEnum : struct, IConvertible
        {
            PublicaEnum<TEnum>(lbx.Items, false);
        }

    }
Isso ajuda bastante na hora de criarmos listas com as UF's do Brasil, por exemplo. Veremos isso num próximo post.

quinta-feira, 6 de agosto de 2015

O absurdo da notação húngara nos dias atuais

Define-se por notação húngara a prática de prefixar variáveis com letras que indiquem o seu tipo. Por exemplo i para inteiros, d para datas, f para floats. 

     As variáveis data de nascimento e nome em notação húngara seriam ddatanascimento e snome, no pior dos casos, ou dDataDeNascimento e sNome se o "programador" resolveu usar camelCase. 

     Como mencionei nos meus artigos anteriores, e como mencionado nos livros "Código Limpo" e qualquer livro sobre XP, essa prática caiu em desuso. 

     Ela foi útil um dia para identificar o tipo das variáveis, e de fato identificava. Hoje damos nomes significativos para as variáveis e deixamos que sua declaração e as facilidades da IDE identifiquem o seu tipo. Além disso hoje podemos mudar o tipo de uma variável mantendo o seu nome e o seu uso, coisa que no passado geraria alguma inconsistência semântica na hora de ler e dar manutenção no código. 

     Soma-se a isso o fato de no passado não existirem, nas linguagens comumente usadas, tipos de dados dinâmicos (variants se aproximavam disso) ou definidos em tempo de execução, tampouco tipos anônimos. 

     Num contexto orientado a objetos o uso de notação húngara, além de ser um overhead, é ridículo e chega a ser prejudicial. 

     Já vi, em várias empresas, classes em C# ou Java prefixadas com "cls". Qual o propósito disso? A notação húngara foi criada para se prefixar variáveis, e nunca tipos ou records. Uma classe é um tipo definido pelo programador, um tipo estruturado, uma classe é um tipo, portanto nunca deveria ser prefixado com a abreviação de um tipo. 

     Qual o propósito de prefixar as classes com cls se TODAS as classes sem exceção forem prefixadas com cls? No que cls as distingue das outras? 

     Pense na diferença entre dizer que todos os animais são do tipo animal, e todos os tipos são do tipo tipo. Redundância. Sempre é prejudicial. 

     Prefixar classes com cls não as distinguem umas das outras, mas o pior é prefixar objetos dessas classes, que podem ser inúmeras e com inúmeros significados, com a letra "o", só porque são objetos.   É afirmar erroneamente e categoricamente que os objetos oUsuario e oProduto são do mesmo tipo, quando suas classes sequer tem algum grau de parentesco. 

     Usar notação húngara em programas modernos e linguagens orientadas a objetos é sinal de acomodação profissional, falta de atualização, porquice ou até mesmo estupidez. 

     Linguagens como Object Pascal e as IDE's Delphi e Lazarus te obrigam a usar notação húngara na criação de classes por um motivo "legado": o código nestas linguagens tem dois níveis de encapsulamento, a unit e a classe/type. Isso faz com que a própria unit seja um "tipo" e seu nome faz parte do namespace total das classes que estão dentro dela. Como o pascal permite variáveis (públicas ou privadas) estáticas fora das classes (globais), não é permitido que a unit tenha o mesmo nome de sua classe, pois isso geraria dois "tipos" com o mesmo nome. 

     Veja que é uma limitação do Delphi / Lazarus: mesmo que você obedeça a orientação e boa prática de ter uma única classe por unit/arquivo, uma classe não pode ter o mesmo nome do arquivo físico onde está contida. E o arquivo físico deve ter o mesmo nome que seu nome "lógico" de unidade. 

     Em contraste com isso linguagens como C# e Java permitem ter classes com o mesmo nome que o arquivo onde elas estão contidas, e isso não te impede de criar outras classes com outros nomes dentro do mesmo arquivo embora isso não seja uma boa prática. 

     Embora o uso de notação húngara seja  justificado no caso do Delphi e do Lazarus, eu acredito que prefixar ou sufixar os arquivos com a letra u (de unit) é melhor do que prefixar os tipos. Assim você tem os tipos de dados, as suas classes, os seus objetos de negócio ( o seu domínio ) com nomes significativos, sem problemas de semântica e com um dicionário padrão do domínio. Isso traria um padrão de nomenclatura mais moderno para quem programa nessas linguagens. Mas nem tudo são flores...

     Por padrão das units de sistema e dos frameworks que acompanham as ferramentas todas as classes (e tipos, records etc) são prefixadas com a letra T (de type) . Então todas as classes de sistema já existem e são prefixadas com T. Não faz sentido você criar uma classe Produto, mas na hora de colocar vários produtos numa lista precisar de uma TList<Produto>. O uso de prefixo de um lado e não do outro pode gerar um gap semântico. 

     Além disso tem o problema das interfaces. As modernas técnicas de POO e DDD e os princípios  SOLID nos ensinam a programar orientado a interfaces, e grandes nomes do projeto e desenvolvimento de software, como Kent beck, Robert Martin, Martin Fowler afirmam categoricamente que: 
  1. Você deve usar as modernas técnicas de POO, padrões de projeto e DDD e 
  2. Você deve usar padrões de nomenclatura, codificação e formatação para nivelar a sua equipe com um mesmo estilo de codificação e todos progredirem rápido. 
     O problema disso é que os melhores padrões de nomenclatura encontrados na literatura hoje afirmam que as interfaces devem ser prefixadas com I .... olha a notação húngara aí geeeeeente!. 

     Acredito que não dá para ser dogmático a ponto de não prefixar as interfaces com I. Se você ver uma interface chamada "Pessoa" é meio difícil saber que é uma interface sem olhar na sua declaração, seus métodos "pelados" e falta de implementação. Ainda assim ela pode ser confundida com uma classe abstrata. Até na UML existem estereótipos e símbolos diferentes para definir as interfaces. 

     Mas, se você não estiver escrevendo uma interface e nem usando Object Pascal, Pelo amor de Deus, não usem mais notação húngara.

sexta-feira, 20 de março de 2015

Modernos padrões de nomenclatura de codificação

     Os padrões apresentados aqui são fruto de uma pesquisa em 2 livros e 4 sites, experiências profissionais do autor, consenso do mercado e recomendações de práticas da Microsoft. Como qualquer convenção ou tecnologia, este não é 100% correto, não é uma verdade absoluta e não é uma bala de prata. São apenas guidelines para que todos nós escrevamos bom código, código limpo e livre de bad smells e que possamos entender e melhorar os códigos uns dos outros, evoluindo como equipe. Nesse texto eu quis expressar não somente regras de nomenclatura e codificação, mas também apresentar algumas boas práticas para um código mais coeso e flexível.
     Esses são os padrões que adotamos na empresa onde trabalho e não há nenhum motivo especial para você e sua equipe adotarem este. Os padrões de codificação devem ser um consenso da equipe.
     Estes foram elaborados com ajuda de outros padrões prontos de outras empresas, unindo o que eu achei de melhor nos padrões da Microsoft e nas práticas já consolidadas da comunidade.

   

"É impossível para um homem aprender aquilo que ele acha que já sabe."                                                                                                                     - Epíteto



     Em se definindo e aplicando “Padrões de Codificação e Documentação”, há um enorme ganho com facilidade de implementação e melhorias no código em:

  • Visibilidade;
  • Portabilidade;
  • Reaproveitamento;
  • Redução de tempo em:
  • Adaptação de novos desenvolvedores.
  • Manutenção;
  • Migração;
  • Identificação, rastreamento e correção de erros.
  • Diminuição de reescrita de código por falta de documentação.


Fonte: http://blog.walkeralencar.com/archives/233


     Coding standards tem sido alvo de várias disciplinas, e tratado em vários livros de programação e boas práticas. Alguns livros que abordam o tema são livros de XP e o Código Limpo, ambos abordando outros aspectos do bom código e da disciplina dos programadores além do aspecto dos padrões de codificação.

     A própria microsoft já fornece, em seu principal veículo de comunicação, msdn, os padrões de codificação. Isso garante, por exemplo, que qualquer programador recém-contratado do mercado já esteja hasbituado com os padrões de codificação.
https://msdn.microsoft.com/en-us/library/ff926074.aspx
Recomendo a adoção deste padrão com algumas alterações muito comuns na comunidade.

   

Nossas Regras

     A regra geral é seguir as convenções e práticas do próprio .net framework (que foram adotadas como padrão pelo mercado) e manter a consistência.


     Definições de casing conventions:

          PascalCase/UpperCamelCase  - Consiste em começar com maiúscula e usar maiúscula na inicial de cada palavra composta. Exemplo: FuncionarioMensalista
Geralmente é utilizada para nomear propriedades e campos públicas e métodos (públicos ou privados). Também deve ser usado para nomear constantes.

          camelCase - Consiste em se iniciar com minúscula e usar maiúscula para a primeira letra de cada palavra composta. Exemplo: funcionarioMensalista
          Geralmente são usados em nomes de variáveis locais e propriedades privadas.


     Notação Húngara

          Os padrões de nomenclatura da comunidade C# em geral dizem para não confiar o tipo de uma variável a seu nome:
"Do not rely on the variable name to specify the type of the variable. It might not be correct."
           Isso põe por terra todo o conceito antiquado de notação húngara.  ( http://pt.wikipedia.org/wiki/Nota%C3%A7%C3%A3o_h%C3%BAngara )
          Outras coisas que põe por terra a notação húngara são as boas práticas de se criar nomes significativos para variáveis e métodos (XP, Código Limpo), que expressem ação e intenção e que dispensam comentários.
          Outra crescente desvantagem da notação húngara é que com os frameworks e ides cada vez mais completos um número cada vez maior de classes prontas, componentes e widgets vêm empacotados com os produtos que usamos (visual studio e .net framework) fora os adquiridos de terceiros e os open-source.
          Criar uma abreviação de duas ou três letras para cada tipo destes torna-se um verdadeiro inferno.
          Notação húngara já é um conceito bem antigo e com certeza seu uso traz muitas desvantagens. Tipos dinâmicos e definição de tipo em runtime perdem todo o sentido com notação húngara, e não é necessário visto que a IDE pode vasculhar e te mostrar todos os atributos de uma variável.
          Quando você cria suas classes você cria seus tipos de dados com lógica própria. E frequentemente renomeamos nossas classes, mudamos, extraímos uma da outra, juntamos, derivamos. Fica impossível arrumar uma abreviação consistente para todas elas.


     Noções gerais ausentes no padrão da Microsoft

           Embora os padrões da microsoft abordem o tema das chaves, arrays, linhas e espaços em branco (assuntos ausentes nos nossos padrões), ela não aborda os padrões de nomenclatura (definidos como notação húngara nos nossos padrões mais antigos).
           É uma prática comum nas linguagens derivadas de c, ao se nomear campos privados dos quais dependem propriedades (públicas ou privadas), nomear em lowerCamelCase precedido de _.
           Outra prática comum é nomear constantes todas em MAIUSCULAS. Isso torna claro que o identificador é somente leitura, além de tornar claro seu tipo e que está relacionado à uma regra de negócio e não à arquitetura do software ou da informação, porém existem recomendações no mercado para não usá-las, portanto seguiremos as recomendações e não usaremos. Nomes de constantes em maiúsculas atraem muito a atenção do programador, distraindo-o, além de não ser consistente com o .net framework.
           Não se deve usar _ entre as palavras de um método, priopriedade ou variáveis, no entanto isso pode ser tolerado em uma constante.
          Um nome deve identificar um elemento (quem ele é) e não generalizá-lo. Além disso deve indicar o que o elemento faz e para que serve, não o que ele é.


     Metáfora

          Todo sistema deve ter uma metáfora que o defina em poucas palavras. Isso ajuda a equipe a formar um vocabulário comum do domínio da aplicação (ou das aplicações) e falarem a mesma língua. Também ajuda na escolha de bons nomes para os projetos e seus componentes. Bons nomes são essenciais para um software coeso e auto-documentável. Bons nomes dispensam comentários ou documentações complexas. Se for gastar um tempo desenvolvendo um software, comece  gastando um bom tempo para o seu nome. O mesmo vale para uma classe ou método: tome tempo para escolher um bom nome. Isso te ajudará a manter o princípio da responsabilidade única  e o princípio da segregação de interface.
          Use nomes significativos e pronunciáveis. Use nomes que expressem propósito.
          Sistemas amplamente usados são baseados em metáforas, por exemplo o sistema de arquivos do Windows é baseado na metáfora do Arquivo (armários para se guardar fichas / pastas).
          Essas ideias estão em acordo com os princípios do XP e do DDD.


     Solution          

          A solution pode agrupar uma série de projetos / programas que são parte de um mesmo sistema, por isso dê um nome para a solution condizente com a metáfora do sistema. A ideia expressa pela solution deveria ser compartilhada pelos seus projetos.
          Exemplo: ServiceDesk
   

     Projetos

          Use a solution como base ou prefixo para o nome dos projetos, e coloque seu objetivo e/ou ambiente como sufixo. Se o seu projeto for dividido em camadas físicas, como Core, DAL/Data, Domain, GUI use esses nomes para identificar a camada a que pertence o projeto.
          Exemplo: ServiceDesk.Web


     Arquivos

          Salvo raras exceções, cada arquivo.cs deve ter apenas uma classe, e o nome do arquivo deve ser o nome desta classe. Uma exceção são os arquivos de partial classes, esses devem ter um sufixo que identifiquem o propósito do arquivo ou o porque dele estar separado. Por exemplo designer ou generated
          Exmeplos: Default.cs Default.design.cs
          Porque: isso é consistente com as práticas da Microsoft no source do próprio .net. Arquivos são ordenados alfabeticamente pelo SO, e isso ajuda arquivos de classes parciais a permanecerem adjacentes.


     Namespaces

          Use PascalCase para nomear os namespaces. Use uma estrutura clara e bem definida.
          Exemplo: NomeDaEmpresa.NomeDoProjeto.NomeDaCamada.NomeDoModulo.NomeDoComponente
                         BBI.ServiceDesk.Web.Data.Services.Repository
          Porque: é consistente com as práticas da Microsoft e mantém uma boa organização da sua base de código.


     Classes

          Use PascalCase para nomear classes. Use substantivos ou predicados nominais em caso de palavras compostas. Não use verbos.
          Exemplo: Funcionario, GrupoDeFuncionario, ProdutoComposto
          Porque: classes são tipos de objetos, mini programas, devem expressar um conceito e não uma ação. Um conceito é melhor expresso por substantivos e adjetivos do que por verbos. Isso é consistente com as práticas da Microsoft e mais fácil de ler.


     Interfaces

          Use PascalCase para nomear interfaces, mas prefixe as mesmas com I. Isso ajuda a diferenciar interfaces de classes abstratas ou outros tipos de dados, ajuda a identificar o que as classes que as implementam fazem, e é uma prática comum do mercado desde a época do COM/COM+.
          Use substantivos, predicados nominais ou adjetivos/advérbios para nomear interfaces.
          Exemplos: IEnumerable, IList, IHierarchyData, IEntity
          Porque: Isso é consistente com os padrões da Microsoft e do COM/COM+, além disso interfaces podem ser usadas para decorar classes, como flags, ou usadas como atributos. Por issp interfaces podem ser nomeadas com adjetivos ou advérbios, pois elas modificam ou segregam comportamento de outras classes.
          Interfaces são a base da abstração e da segregação de responsabilidade. São contratos entre duas partes, ou pontos de encaixe entre componentes. Programe orientado a interfaces e não à implementação.


   

     Ordem dos elementos

          Declare todas as variáveis membro no topo da classe, com as estáticas acima de todas. Utilize a ordem:
          Membros/Fileds


  1.   privadas estáticas
  2.   públicas estáticas (evite-os a todo custo)
  3.   privadas de instância
  4.   públicas de instância (evite-os, transforme-os em propriedades sempre que possível)
  5.   propriedades protegidas
  6.   propriedades públicas de instância



         Métodos (na ordem do mais genérico/abstrato para o mais específico, dos métodos que chamam outros para os chamados)


  1.  Construtores e Destrutores 
  2.  Factory methods públicos de classes (são construtores especializados)
  3.  Métodos públicos de classe
  4.  Métodos privados de classe
  5.  Métodos públicos de instância
  6.  Métodos protegidos de instância
  7.  Métodos privados de instância


          Porque: é uma prática geralmente aceita, evite que se fique procurando por variáveis, garante que a leitura de um source seja como a leitura de um artigo de jornal: dados genéricos em cima, dados detalhados abaixo, com nível crescente de granularidade e decrescente de abstração de cima para baixo. Para isso os métodos que são chamados por outras classes ficam acima, e os chamados pela própria classe abaixo. Com isso você precisa ler apenas o topo da classe para saber o que ela faz e como ela funciona apenas visualizando sua interface implícita sem se aprofundar em sua implementação.


     Propriedades (privadas/protegidas/públicas)

          Use PascalCase para o nome de propriedades. Use preferencialmente substantivos e predicados nominais.
          Exemplo: Nome, DataNascimento
          Porque: além de facilitar a leitura, trata-se de objetos pertencentes a outro, como peças de algo maior, portanto todos substantivos. Está de acordo com as práticas da Microsoft para o .net
   

     Fields ou Variáveis de instância ou Member Variables


  •            Públicos : não devem existir
  •            Privados: aplicar camelCase precedido de _

          Exemplo: _dataNascimento 
          Porque: Está em acordo com as práticas comuns do mercado para linguagens derivadas de _, ajuda a separar os campos privados dos argumentos de métodos / constructors sem a necessidade do uso do this, isola essas variáveis da digitação acidental (porque obriga a digitação do _ no início, excluindo-as do intellisense / autocomplete).


     Variaveis Locais

          Use camelCase para os nomes de variáveis locais, use nomes significativos, evite prefixos e abreviações a não ser que sejam bem conhecidas, não use notação polonesa.
          Exemplo: enderecoServidor, connectionString
          Porque: além de ser fácil de ler é consistente com a metodologia da Microsoft


     Métodos

          Use PascalCase para nomear os métodos. Use o formato Verbo ou Verbo+Complemento para nomear os métodos. Se o verbo for intransitivo o método não deveria ter parâmetros.
          Exemplo:  Salvar(grupoDeFuncionario)
                         Excluir(tipoDeTarefa)
                         ListarEntreDatas(dataInicial, dataFinal)
          Porque: Consistente com o .net framework e fácil de ler. Verbos expressam ações, por isso são melhores que substantivos para expressar métodos. É natural se ler e escrever dessa forma



     Argumentos de Métodos

          Use camelCase para argumentos de métodos, use substantivos. Se o nome de um método contém um verbo, os argumentos devem ser complementos desse verbo.
          Exemplo: CalcularReajuste(porcentagemAumento)
                         Salvar(grupoDeFuncionario)
                         Excluir(tipoDeTarefa)
                         ListarEntreDatas(dataInicial, dataFinal)
          Porque: mais fácil de ler e entender. Tudo que pode ser verbalizado pode ser melhor armazenado pelo nosso cérebro. É condizente com as práticas da Microsoft no .net.


    Ainda Sobre Argumentos de Métodos

          Se você precisar de de mais de 3 argumentos no seu método e/ou precisar usar parâmetros nomeados há uma grande chance de você estar simplesmente enrolado e seu método precisar ser refatorado. Verifique se seu método não está com responsabilidades demais.
          Se você passa argumentos booleanos ou enums para um método onde ele tomará uma ação diferente dependendo do parâmetro é uma evidência clara de que você precisa decompor este em dois ou mais métodos. Dê uma olhada nos padrões de projeto GOF "Template Method" e "Strategy" que eles podem de dar uma ideia de como refazer estes métodos.
          Porque: Métodos grandes são difíceis de ler e de manter. Eles tendem a crescer mais a cada manutenção com a adição de desvios condicionais para fazerem coisas diferentes dependendo de configuração ou parâmetros. Esses métodos degradam o sistema rapidamente, ficando com código inatingível (nunca executado), código comentado e código com side effects (statefull) que não podem ser testados.


     Parâmetros-Tipo (type parameters)

          Type Parameters são os parâmetros que representam um tipo em uma expressão que usa generics. Por exemplo na definição de List<T>   T é o type parameter. Na definição de classes genéricas sempre use PascalCase precedido de T para nomear os type parameters.
          Exemplo: Repository<TEntity> : IRepository<TEntity> where TEntity : Entity

    Strings

          Concatene strings pequenas com sinal de " + " porém use StringBuilder para strings grandes. Use string.Format para strings pré formatadas e substituição de placeholders.
          Porque: Embora tenha sobrecarga de operadores nativa para parecer um value type pimitivo as strings são objetos (reference types). Isso significa que a cada atribuição ou concatenação de duas strings, dois objetos são destruídos  e um novo é criado. Isso cria um grande overhead, principalmente dentro de loops. StringBuilder é uma classe que concatena várias strings de uma só vez sem precisar destruir e recriar a cada adição fazendo um uso mais inteligente da memória. Foi feito para ser usado em loops onde muitas strings são concatenadas, como uma saída html por exemplo.



    Enums

          Use PascalCase. Use substantivos no singular se for um Enum comum. Se for um Enum do tipo bit field / flags (a serem combinados múltiplos valores com o operador "|") pode-se usar substantivos no plural, pois sugere que mais de um valor pode ser usado.
          Exemplo:
enum Importance
{
None,
Trivial,
Regular,
Important,
Critical
}; 

          Porque: Consistente com o .net framework e mais natural para ler


     if ... else if ... else

               Sempre coloque um bloco de código com { } em estruturas de decisão if pulando uma linha antes de { e outra ante de }. Mesmo com if's que só terão uma linha de código.
               Se você precisar de mais de 3 níveis de aninhamento para uma estrutura if ou case significa que você está enrolado. Provavelmente seu método faz coisas demais ou sua classe tem muitas responsabilidades e muitos motivos pra mudar.  
            Porque: if (b1) if (b2) Foo(); else Bar(); // consegue dizer ao primeiro golpe de vista a qual if pertence o else?      


     Case ... default

               Sempre tenha um label default em uma estrutura case. Mesmo se ele nunca devesse ser atingido. Coloque nele código para disparar uma exceção caso um parâmetro inválido tenha sido erroneamente enviado para o case analizar.



     Loops

               Se você precisar de dois níveis de loops aninhados considere transformar o mais interno em um método privado. Se você estiver trabalhando com mais 3 níveis verifique se o método e/ou a classe não estão com responsabilidades demais e se não estão intestáveis.
               Jamais altere a variável de controle do loop for ou foreach dentro do loop. Isso pode levar a loops infinitos.



     Alinhamento vertical de chaves

          Alinhe as  chaves verticalmente. Não mantenha a chave no final da linha, quebre a linha antes da chave e mantenha elas alinhadas. Sempre abra e feche as chaves em novas linhas.
          Certo:
         public virtual void setMensagemExplicacao( string mensagem)
        {
            MensagemExplicacao = mensagem;
            lgdExplicacao.Visible = true;
            lgdExplicacao.InnerText = mensagem;
        }

          Errado:
         public virtual void setMensagemExplicacao( string mensagem){
            MensagemExplicacao = mensagem;
            lgdExplicacao.Visible = true;
            lgdExplicacao.InnerText = mensagem;
        }

         public virtual void setMensagemExplicacao( string mensagem){
            MensagemExplicacao = mensagem;
            lgdExplicacao.Visible = true ;
            lgdExplicacao.InnerText = mensagem;}

          Porque:   Chaves abertas ou fechadas no final de uma linha de código passam despercebidas e não são legíveis. O código pode ser confundido como parte do código acima.


     Espaços em branco

          Deixe espaços em branco entre os operadores e seus operandos. Isso facilita a leitura.    
          Deixe espaços em branco entre um if, for ou foreach e sua expressão. Exemplo: if (UmFuncionario.Equals(EsteFuncionario))
       

     Quebra de linhas

          Quebre linhas antes de abertura e fechamento de chaves, quebre linhas para separar ideias, agrupar conceitos relacionados, separar conceitos não relacionados, separar a declaração de variáveis de seu uso, quebrar cadeias longas de caracteres ou encadeamentos longos de chamadas de métodos ou propriedades.
          Também é bom quebrar as linhas em chamadas de funções com listas de parâmetros muito longas, e edentar esses parâmetros.
          Quebre linhas antes e depois de regions, antes e depois de um using, e separando os fornecedores na lista de usings.

     Regions

          Use regions para agrupar conceitos e separar interface de implementação, eventos de métodos e de variáveris.
          Não use regions aninhadas pois isso impõe complexidade desnecessária.
          Não use regions para esconder código comentado, sujeira e gambiarras.

     Indentação/Recuo

          Use a indentação padrão do C# no visual studio (um tab = 4 espaços). Indente conceitos subordinados. Se precisar separar cadeias longas de chamadas em linhas, ou cadeias longas de parâmetros quebradas em linhas. Quebre as linhas de uma sentença SQL e Intente o SQL.
          Exemplo:
            ChamadaDeFuncao(
                 par1,
                 par2,
                 par3,
                 par4,
                 par5,
                 par6);
            {
                 //código
            }
                               Modulo obj = session
                            .CreateCriteria< Modulo>()
                            .SetTimeout(120)
                            .SetLockMode( LockMode.None)
                            .SetCacheable( true)
                            .Add( Restrictions.Eq("Nome" , nome))
                            .UniqueResult< Modulo>();
     

     Comentarios

           Algumas definições dos nossos padrões foram feitas para VB antigo e se chocam diretamente com os padrões da microsoft, por exemplo o padrão de comentários:
"Do not create formatted blocks of asterisks around comments."
          Há comentários que prejudicam a legibilidade do código, não são atualizados no mesmo ritmo do código, sujam o mesmo e poderiam facilmente ser substituídos por nomes significativos
          Há comentários que simplesmente perdem o sentido pouco tempo depois de terem sido colocados, simplesmente porque o código logo abaixo deles ou o objetivo do sistema em si foi mudado.
          Não comente o código simplesmente para desativá-lo esperando que um dia vá precisar dele. Antes de dar check-in, delete o código comentado. Código comentado apenas emporcalha o sistema, deteriorando-o mais rápido. Outros programadores acharão que é importante e evitarão removê-lo. Se um dia, quando ele não for mais útil, ele acidentalmente for descomentado ele pode comprometer todo o funcionamento do sistema. Confie no seu sistema de versionamento.
          Não coloque cabeçalhos com informações de autor, versionamento, changelog e bugtracking em comentários. Confie no seu sistema de versionamento, faça os comentários de changelog ao dar check-in no sistema, controle o bugtracking com um sistema apropriado. Uma exceção à regra é quando há motivos legais para assegurar o  autor do código, então pode existir um cabeçalho com o autor.
          Não comente o óbvio, coisas muito simples ou muito bem  estabelecidas. Se um comentário óbvio se faz necessário, então na verdade é necessário renomear seu método para um nome que expresse seu propósito.
          Quando necessário, comente em uma linha separada (geralmente acima) e não na linha do código
          Comece o comentário com letra maiúscula e termine com um ponto
          Insira um espaço entre o // e o início do comentário


     Comentários de documentação

          Comentários de documentação são precedidos por /// e servem para definir a estrutura e uso de classes, métodos e propriedades para geração de documentação automática com ferramentas como Doxygene, NDoc e SandCastle.
          Como seu objetivo é documentar uma interface implícita ou API para uso de outros programadores, comente apenas métodos e propriedades públicos e nunca comente membros privados.
          Porque: Isso está de acordo com o Princípio SOLID de programar voltado a interfaces e não implementação. Você não quer que outros programadores usem os métodos privados, então não há necessidade deles aparecerem na documentação. Assim você encapsula e protege o source em um nível adicional e está livre para mudar a implementação contanto que mantenha a mesma interface e funcionalidade.



     Try ... Finally

          Use o using sempre que seu bloco try ... finally servir apenas para chamar dispose em um recurso não gerenciado.
          Exemplo:
// This try-finally statement only calls Dispose in the finally block.
Font font1 = new Font("Arial", 10.0f);
try
{
    byte charset = font1.GdiCharSet;
}
finally
{
    if (font1 != null)
    {
        ((IDisposable)font1).Dispose();
    }
}
// You can do the same thing with a using statement. 
using (Font font2 = new Font("Arial", 10.0f))
{
    byte charset = font2.GdiCharSet;
}




     Refactoring

          Refactorings são saudáveis e devem ser feitos. Sempre que achar que um código pode ser melhorado quanto à legibilidade melhore-o. Sempre que algo pode ser feito de maneira mais rápida, mais fácil, mais elegante ou mais correta, refaça. Sempre que algo soar estranho, parecer "cheirar", troque. Use a regra do escoteiro e deixe o código mais limpo do que quando você encontrou.


     Gambiarras

          Toda gambiarra no código se volta contra você uma hora ou outra. Gambiarras causam infernos de manutenção, horas extras e expedientes de fim de semana.
          Toda gambiarra clama em alta voz por um refactoring. Um código ruim pode ter bad smells que são fruto de desconhecimento, limitações tecnológicas, cansaço ou erro humano, MAS gambiarras são sinais de relaxo, falta de ética e desorganização pessoal. O prazo não é desculpa para se fazer uma gambiarra. Se há uma forma mais elegante de se escrever um código procure melhorá-lo, mas se há uma forma definitivamente correta de se escrever um código, então use essa forma.


     Excessões à regra     

          Widgets demasiadamente usados como Button e Textbox tem padrões de nomenclatura derivados da notação húngara fortemente entrincheiradas em nosso dia - a - dia, por isso são aceitáveis coisas como botões precedidos de btn (btnSalvar) e inputs precedidos de txt (txtNome). Isso está em conformidade com as práticas da Microsoft, pois os widgets de tela do office são todos prefixados.    
          Variáveis de contadores de laço/iteradores podem ter um nome de uma letra só, como i,j,k,l,c. É mais inteligível desta forma, uma vez que os caracteriza como iteradores, além disso eles têm um escopo muito local, muito limitado.  
          Em linguagens onde o nome da classe não pode ser igual ao nome do arquivo que a contém é comum, em PascalCase, prefixar as classes com T, mas apenas nesses casos.  
          Em linguagens que não são case sensitive, como Delphi/Pascal/SQL, não é possível declarar um campo privado com camelCase e a propriedade que o acessa com o mesmo nome em PascalCase como abaixo:
 
//Nào faça isso
private string nome;
public string Nome
{
     get
     {
          return nome;
     }
    
     set
     {
          nome = value;
     }
} 
     Porém esse seria o nosso caso apenas usando SQL/Pascal/VB6. Usando C# isso não se aplica. Esse exemplo é trivial, mas o uso de _ ou de camelCase para os fields privados são os mais usados em C#.
     Nesses casos preceder o campo privado com F (PascalCase) em linguagens derivadas de pascal.

//isso só é permitido em linguagens como Pascal ou Delphi. Não faça isso.
private string Fnome;
public string Nome
{
     get
     {
          return Fnome;
     }
 
     set
     {
          Fnome = value;
     }
}

     Como usaremos apenas C#, vamos prefixar campos de instancia locais com _, como geralmente é feito em linguagens derivadas de C.

//Faça ISSO:
private string _nome;
public string Nome
{
     get
     {
          return _nome;
     }
 
     set
     {
          _nome = value;
     }
}


     Faça:



  • Use PascalCasing para nomear classes, propriedades, métodos e Enuns
  • Use camelCasing para nomear variáveis locais, argumentos de métodos e de constructors
  • Use _camelCasing (camelCase precedido de _) para nomear campos privados
  • Se uma apreviação for fazer parte do nome de uma classe, propriedade ou constante, use PascalCase se ela tiver 3 letras ou mais. Ponha a abreviação em maiúsculas se ela tiver até 2 letras.
  • Use os nomes de tipos predefinidos da linguagem em vez dos System Types, exemplo: strung no lugar de String, int no lugar de Int32, bool no lugar de Boolean
  • Use variáveis implícitas para quando o tipo é óbvio ou não é importante, ou em laços for/foreach. Exemplo: var numero = Convert.ToInt32(Console.ReadLine());
  • Escreva um comando por linha
  • Escreva uma declaração por linha
  • Indente todas as linhas de continuação
  • Quebre uma linha para separar a definição de métodos da definição de propriedades
  • Prefira passar estruturas ou objetos DTO como parâmetros para um método do que listas grandes de parâmetros.
  • Prefira retornar objetos DTO ou estruturas com um propósito específico do que usar parâmetros ref ou out nos seus métodos.
  • Sempre que usar o operador "as " para typecasting seguro verifique se o retorno não é null. Se for null é porque o objeto não pode ser convertido para o tipo especificado.
  • Se você precisa comentar um bloco de código, considere usar refactoring para transformar esse bloco em um método, e de-lhe um nome conciso e apropriado.        
  • Mantenha o tamanho de cada linha em até 130 caracteres (o suficiente para evitar rolagem horizontal)
  • Sempre envolva expressões booleanas de estrutura de repetição ou de decisão do tipo if, else, do, while, for e foreach com parênteses, mesmo que o compilador não exija.


       

     Não faça:



  • Não use notação húngara ou qualquer tipo de definição de tipo nos nomes de variáveis, isso é consistente com o .net framework, além disso o Visual Studio já te ajuda a determinar o tipo das variáveis.
  • Não use maiúsculas para nomear constantes, não é assim que é feito no .net. Maiúsculas atraem muito atenção.
  • Evite abreviações nos nomes de variáveis a não ser que sejam abreviações bem conhecidas como Id, XML, HTML
  • Não insira underscore _ no meio de identificadores, classes, constantes, propriedades e variáveis.
  • Não especifique o tipo de um enum a não ser que seja Flags ou bit fields
  • Não prefixe ou sufixe os nomes de Enum com a palavra "Enum"
  • Não comente código, ninguém saberá o que fazer com código comentado
  • Não use parâmetros de função como variáveis temporárias. O nome do parâmetro não reflete a intenção da variável.
  • Não use números em identificadores de campos ou métodos, como "Listar2". Isso geralmente é sinal de preguiça em encontrar um nome que revele propósito.
  • Não compare expressões booleanas com true ou false em if's. Perguntar if (variavel == true) ou if (variavel == false) prejudica a leitura e revela falta de conhecimento da estrutura if. Use if (variavel) ou if (!variavel).



     Lembre-se:

          A qualidade de um código é medida pelo número de "que diabos ..." por segundo.    
          A honestidade nas pequenas coisas não é uma coisa pequena.
   

Veja mais
Lance Hunt C# Coding Standards
AvSol coding guidelines for C# 3.0-5.0
Java code conventions


Livros
http://www.livrariacultura.com.br/p/domain-driven-design-3252884
http://www.livrariacultura.com.br/p/extreme-programming-15065191
http://www.livrariacultura.com.br/p/codigo-limpo-2874223


Sites
http://www.milfont.org/tech/2008/01/21/nao-use-notacao-estranha/
http://www.macoratti.net/13/09/net_pcod1.htm


Outras fontes
     Há vários padrões de codificação e outras boas práticas de programação. Abaixo exemplifico mais algumas fontes como referência / aprofundamento.
     Há também padrões de codificação para linguagens específicas, elaborados pelas empresas que desenvolvem esses produtos ou pela comunidade de programadores destas linguagens, como os padrões de PHP ou Java exemplificados em anexo.
http://www.dofactory.com/reference/csharp-coding-standards
https://csharpguidelines.codeplex.com/
http://se.inf.ethz.ch/old/teaching/ss2007/251-0290-00/project/CSharpCodingStandards.pdf
https://msdn.microsoft.com/en-us/library/vstudio/ms229043(v=vs.100).aspx




 

segunda-feira, 16 de fevereiro de 2015

Versionamento no .net Framework

Aparentemente a Microsoft tem dois esquemas de versionamento do .net framework. Um é lado a lado, quando há uma mudança da major version. O outro esquema é quando há uma substituição total de um framework, devido a correções de assemblies e lançamentos de novas features.

Por exemplo:

A versão 1 e 1.1 rodam ambas no runtime da 1.
As versões 2, 3 e 3.5 rodam todas no runtime da 2 (aqui a Microsoft fez uma cagada, porque deveria versionar a 3 como 2.5, já que é uma atualização da 2, e a 3.5 deveria continuar a manter a major version como 2, por exemplo 2.5.5, mas eles apressaram as coisas para distribuir junto com o finado windows vista)
E temos a versão 4 e 4.5 que rodam no runtime da 4. A substituição de alguns assemblies da versão 4 pelo instalador da 4.5 pode causar alguns conflitos, principalmente para aplicações que usam novas features exclusivas da 4.5 ou programadores de componentes.

Esses conflitos são citados e podem ser contornados conforme as dicas do Rick Strahl e do SCOTT HANSELMAN

Could not load type 'System.ServiceModel.Activation.HttpModule' from assembly 'System.ServiceModel - Trobleshooting

If you get

Could not load type System.ServiceModel.Activation.HttpModule from assembly System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.


error trying to access a webservice in .net framework 4.0 or 4.5 it is caused by a conflict between 3.0 and 4.0 version.

Fortunately you can fix it in a per application basis. You have only to go to IIS Manager, select your application, double click in modules and delete ServiceModel version 3.0 module. 



If you need version 3.0 again or delete 4.0 accidentally you can fix it adding the module again, using the strings below to register the asemblies.

ServiceModel - System.ServiceModel.Activation.HttpModule, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

ServiceModel-4.0 - System.ServiceModel.Activation.ServiceHttpModule, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35

Enjoy :)

Postagens populares

Marcadores

delphi (60) C# (27) poo (21) Lazarus (19) Site aos Pedaços (15) sql (13) Reflexões (10) Humor (9) javascript (9) .Net (8) ASp.Net (8) api (8) Básico (6) Programação (6) ms sql server (5) banco de dados (4) HTML (3) PHP (3) Python (3) Web (3) design patterns (3) jQuery (3) livros (3) metaprogramação (3) Debug (2) Dicas Básicas Windows (2) Pascal (2) games (2) linguagem (2) música (2) singleton (2) tecnologia (2) Ajax (1) Anime (1) Api do Windows (1) Assembly (1) Eventos (1) Experts (1) GNU (1) Inglês (1) JSON (1) SO (1) datas (1) developers (1) dicas (1) easter egg (1) firebird (1) interfaces (1) introspecção (1) memo (1) oracle (1) reflexão (1)