terça-feira, 30 de setembro de 2008

Regras de nomeação de Namespaces

Namespaces são principalmente utilizadas para organizar suas implementações em uma hierarquia lógica e fácil de ser utilizada. Abaixo algumas diretrizes para dar nome às Namespaces:   

- Como os nomes dos identificadores, o nome da Namespace deve ser facilmente interpretado, ou seja, deve ser possível saber suas funcionalidades através do seu nome.   

- Se precisar de algum padrão, considere o seguinte:               {Empresa}.({Produto}|{Tecnologia}) [.{Características}] [.{Subnamespace}] – Ex. Microsoft.VisualStudio.Design   

- É uma boa prática sempre colocar o nome da empresa como prefixo para evitar confusões caso haja uma Namespace com o mesmo nome de outra empresa, por exemplo.   

- No segundo nível da Namespace, escolha algo imutável, ou seja, que não irá mudar a cada versão lançada. Lembre-se que a Namespace será algo que ficará fixo no código, sendo algo muito trabalhoso para ficar mudando a cada release do seu produto.   

- Não utilize nomes “virtuais” em suas Namespaces, por exemplo, o nome dado para a equipe que você está trabalhando em um determinado projeto. Esses nomes tendem a mudar dependendo da estrutura organizacional da empresa.   

- Sempre utilize o PascalCasing e separe os componente das namespaces utilizando o ponto ”.”.   

- Se for necessário e fizer sentido, pluralize. Essa regra não deve ser utilizada no caso de siglas. Ex. System.Collections e System.IO.   

- Não utilize nomes genéricos demais como Element, Node, Log e Message. A probabilidade de haver nomes iguais é muito grande. Utilize então FormElement, XmlNode, EventLog e SoapMessage.

Regras de nomeação de Assemblies / Dlls

- Na escolha do nome físico de seus arquivos “.dll”, tente escolher algo bem abrangente, que descreva o propósito de suas funcionalidades. Ex. System.Data    

- Se precisar de algum padrão, considere o seguinte:

[Empresa].[Componente].dll – onde [componente]  pode ser conter mais de um nome. Ex. Microsoft.VisualBasic.Vsa.dll    

- Também faz sentido nomear o arquivo seguindo o nome da Namespace nele implementada.

Referencias:

segunda-feira, 29 de setembro de 2008

Princípio da Divisão de Responsabilidades (Single-Responsibility Principle)

O princípio da divisão de responsabilidades, também conhecido como coesão, defende que uma classe deve possuir apenas um, e apenas um, motivo para ser modificada. Se a classe possuir mais de um motivo para ser modificada então ela está mal definida.

A classe somente terá mais de um motivo para ser modificada se a mesma for responsável pelas ações às quais ela foi definida e por outras fora de seu escopo. No contexto do princípio da divisão de responsabilidades, responsabilidade é definida como razão para mudanças. Se for possível imaginar mais de um motivo para modificar a classe, logo esta classe possui mais de uma responsabilidade.

No exemplo a seguir foi definida uma interface “Modem” onde as funções declaradas parecem corretas dentro do contexto das funcionalidades que um modem deve exercer.


Ilustração 1 - Interface Modem

Porém, analisando detalhadamente a iliustração 1 é possível identificar que a classe possui duas responsabilidades: conexão e comunicação. As funções “Dial” e “Hangup” controlam a conexão e as funções “Send” e “Recv” controlam a comunicação.

Se os requisitos da aplicação mudassem de modo a afetar mais frequentemente as funções de conexão, o design demonstraria rigidez, um dos odores de decomposição do software. A aplicação seria rígida porque ao alterar algo na conexão seria necessário compilar e distribuir novamente toda a parte de comunicação sem necessidade alguma.
A ilustração 2 demonstra como ficaria o design ao separar as responsabilidades.


Ilustração 2 - Interface modem separada

Para separar as responsabilidades da interface modem de modo que a aplicação não sofra de rigidez, foi necessário aumentar a complexidade do sistema. Todavia deve-se tomar muito cuidado ao aplicar o princípio, pois se os requisitos da aplicação fossem tais que sempre alterariam ambas as responsabilidades, conexão e comunicação, o novo design seria incorreto devido ao fato de ter gerado complexidade desnecessária à aplicação, outro odor da decomposição do software. Portanto a aplicação do princípio de divisão de responsabilidades, ou outro qualquer, deve ser feito de modo cuidadoso e inteligente. Só se deve utilizá-los se o design estiver exalando algum dos odores de decomposição do software.



Design Ágil

Design ágil é um processo continuo de princípios, modelos, e praticas visando a melhoria da arquitetura do software.

Design de uma aplicação não são apenas diagramas UML. Os diagramas UML podem representar partes do design, mas ainda não é o design propriamente dito. O design de um software é um conceito abstrato que representa de uma forma macro a estrutura do sistema como um todo e ao mesmo tempo de forma detalhada cada módulo, classe e método.

O design pode ser representado por diversas maneiras, mas no fim das contas, o código fonte é a principal fonte de design. Um design mal feito, consequentemente um código mal desenvolvido, pode acelerar o processo de decomposição do software, sendo que a velocidade de decomposição de um software está diretamente ligada à sua qualidade, ou seja, quanto maior a velocidade de decomposição do software, menor é a qualidade. Para evitar tal decomposição, deve-se ficar atento aos sintomas ou odores que o software exala.

Desenvolvedores ágeis se dedicam para manter o design coeso, limpo, e livre de sintomas ou odores sempre que possível. Eles sabem como fazer isso porque sempre seguem alguns passos antes de escrever qualquer linha de código:

1. Eles acham o problema seguindo praticas ágeis;
2. Eles analisam o problema aplicando princípios de design;
3. Eles resolvem o problema aplicando o modelo de design apropriado ao caso.

Dificilmente um software perfeito livre de defeitos é produzido por alguém. O que pode ser feito para minimizar os defeitos no fim do processo e em sua manutenção, é ter conhecimento dos motivos que levam um software a decompor. Um software suscetível à decomposição exala os seguintes odores:

Rigidez: Rigidez ocorre quando é necessário um grande esforço para alterá-lo, mesmo quando a alteração é pequena.

Fragilidade: Fragilidade é a tendência que o programa tem para dar problema em diversos pontos quando uma única alteração é feita.

Imobilidade: Imobilidade ocorre quando o software contém muitas partes que podem ser reaproveitadas em outros softwares, mas para reutilizar essas partes é necessário um grande esforço junto com um alto risco, pois não foram planejadas para ser reutilizadas. Logo, uma grande parte do sistema terá que ser levada junto sem necessidade nenhuma.

Viscosidade: Um projeto viscoso é aquele que quando uma alteração é necessária, devido ao seu design não planejado para trabalhar de forma componentizada, fica difícil fazer a alteração do modo correto, gerando desvios para que a alteração seja mais fácil e mais rápida de programar.

Complexidade desnecessária: Acontece quando o design do sistema é superdimensionado e implementado para prever situações que nem sequer foram especificadas. Isso torna o software complexo demais e difícil de entender.

Redundância desnecessária: Acontece muito quando o programador necessita do mesmo código utilizado em outra função para resolver um problema, porém com algumas alterações. Acontece que isso acaba gerando redundância de código tornando a manutenção difícil e trabalhosa já que o erro deve ser corrigido em todas as repetições de código.

Opacidade: Opacidade é a falta de clareza na hora de escrever o código fonte. Muitas vezes o código é legível apenas para quem o programou. Isso pode ser evitado utilizando padrões na hora de escrever o código e fazendo com que outras pessoas revisem o código.

Todos esses odores são pontos extremamente importantes que devem ser considerados ao desenvolver um software. Em ambientes não ágeis, o design de um sistema degrada pois os requisitos mudam de uma forma que o design inicial não previa causando a mudança do design original, tornando-o desorganizado e ineficaz.

Um time ágil investe um pouco a mais no design inicial para tornar o sistema resistente a mudanças evitando que ele apodreça.
Nos próximos posts vou falar sobre os princípios de design ágil que podem ser utilizados para evitar o apodrecimento do software. Esses princípios são: Divisão de responsabilidades, Aberto / Fechado, Substituição de Liskov, Inversão de dependências e Segregação de interfaces.

Regras gerais de nomeação de identificadores

Segue algumas convenções gerais de como escolher a palavra que será o nome de um identificador.

 - O nome escolhido deve estar sempre ligado ao propósito do identificador. Deve ficar claro o que o identificador faz ou representa logo na primeira leitura do seu nome.
 
 - Esqueça as abreviações e dê preferência para a clareza do nome. Abreviações não irão tornar seu código mais rápido. Ex. NomeDoFuncionário é mais fácil de entender que nmFunc.
 
 - Não utilize hífens ou outros separadores de palavras nos nomes. Utilize PascalCase ou camelCase dependendo da situação.
 
 - Esqueça a Notação Húngara.
 
 - Tente evitar nomes que conflitem com palavras chave ou reservadas de outras linguagens de programação. Isso ajudará a evitar muitas dores de cabeça case seja necessário migrar o código para outras linguagens.
 
 - Se for utilizar uma sigla, não invente, utilize apenas se a mesma for largamente conhecida. Ex. Html, Xml.

 - Dê preferência para a utilização de nomes genéricos da CLR ao invés de nomes específicos da linguagem. Ex. Uma método que converte algo para boleano deve se chamar ConvertToBoolean e não ConvertToBool, pois Boolean é o nome base na CLR que é representado por bool em C#.

 - Use um nome comum como value ou item quando um identificador é algo que não possui um propósito tão específico. Ex. void Gravar(double value) ; void Gravar(int value) ; void Gravar(short value) ; 
 
 - Quando for criar uma nova versão de uma API, crie um nome similar ao original. No novo nome, opte por utilizar sufixos ao invés de prefixos, assim ficará mais fácil de achar a nova função através do Intellisense. Se o nome antigo é o único que faz sentido para aquele propósito, utilize um sufixo numérico. Ex. public class Carro {...}  ->  public class Carro2 ou public class Automóvel.

 - Nos casos dos métodos obsoletos, utilize o atributo [Obsolete(...)].


Referencias:

PascalCasing e camelCasing

Para a nomeação de identificadores, existem duas formas mais apropriadas: PascalCasing camelCasing


- PascalCasing: É utilizado para em Namespaces, tipos, e variáveis que possuem mais de uma palavra. Consiste em capitalizar a primeira letra de cada palavra. 

Ex: NomeDoFuncionário

No caso de siglas composta por 2 letras, ambas as letras devem ser capitalizadas. 

Ex: IOStream onde IO é uma sigla para input/output.

- camelCasing: É utilizado apenas para parâmetros. Consiste em capitalizar a primeira letra de cada palavra com exceção da primeira palavra. 

Ex: nomeDoFuncionário 

No caso de siglas composta por 2 letras, ambas as letras devem ser minúsculas. 

Ex: ioStream onde IO é uma sigla para input/output. 


Maiores informações em:.NET Framework Developer's Guide - Capitalization Conventions

Naming Guidelines

O que são "Naming Guidelines"

Bom, são diretrizes para nomear as coisas... hum, essa não foi muito boa. Vamos mergulhar mais fundo então. 

Quando codificamos, nos deparamos com um universo de coisas que precisam de um nome. Estas 'coisas' são chamadas de Identificadores. Um identificador é tudo que não se enquadra como palavra reservada, símbolos ou números. Por exemplo, nomes de Assemblies, DLLs, Namespaces, Clases, Estruturas, Interfaces, Variáveis, etc.

Um ex-professor sempre me dizia: "O que custa reservar um tempo para inventar um bom nome? Lembre-se que sua mãe demorou 9 meses para te dar um!" 

Para entender a importância dos nomes, imagine um sistema com 26 variáveis cujo padrão de nomenclatura utilizado foi o de "A" a "Z", ou seja, a primeira variável tem o nome de "A" e a última de "Z" 

Agora imagine se der algum problema na variável "K", quanto tempo demoraria para lembrar que a variável "K" armazena o nome do funcionário? 

Agora um pesadelo, imagine que o sistema foi feito por um colega de trabalho que já saiu da empresa e que o escolhido para dar manutenção neste sistema foi você! 

Acho que já deu pra ter uma idéia da importância de se adotar um conjunto consistente de diretrizes de nomenclatura no desenvolvimento de um software. Essas diretrizes possuem um propósito muito importante quando falamos de usabilidade e manutenibilidade do software. 

Tentarei passar nos próximos posts algumas técnicas de nomenclatura de identificadores e como utilizá-las. 

Abraços,

Livro: Agile Principles, Patterns, and Practices in C# (Robert C. Martin Series)



Agile Principles, Patterns, and Practices in C# (Robert C. Martin Series)

Este é um ótimo livro pra que quer aprender mais a respeito de como desenvolver uma boa arquitetura utilizando metodologia ágil. 
Creio que irei postar aqui muitas coisas interessantes que estão neste livro, principalmente na parte de arquitetura.

Hello World!

Olá a todos!

Seja bem vindo ao meu novo blog!

Decidi criar este blog para compartilhar os meus conhecimentos com todos, já que grande parte do que conheço aprendi em blogs como este. 

Meu objetivo aqui neste blog é expor informações sobre Arquitetura de Software, Melhores Práticas, testes, desenvolvimento entre outras informações que utilizam a tecnologia Microsoft.Net.

Espero que gostem!

Denis Yomura