- “Você deve tomar conta para que seu código fique bem formatado”;
- Escolha regras simples e aplique de forma consistente.
- Em equipe, todos devem concordar com uma única série de regras de formatação.
Objetivo da formatação
- A formatação de código é importante.
- Serve como comunicação.
- Legibilidade do código terá um grande efeito em todas as mudanças futuras.
Formatação vertical
- Há uma grande diversidade de tamanhos e diferenças de estilo.
- As linhas verticais mostram os comprimentos mínimo e máximo.
- Arquivos pequenos costumam ser mais fáceis de se entender do que os grandes.
A metáfora do jornal
- “No topo você espera ver uma manchete que lhe diz do que se trata a história e lhe permite decidir se deseja ou não ler”.
- Primeiro parágrafo é a sinopse da história.
- O demais detalhes vem no decorrer da leitura.
- Queremos que o código fonte seja como artigo de jornal.
Espaçamento vertical entre conceitos
- Há linhas em branco que separam a declaração e a importação do pacote e cada uma das funções.
- “Cada linha em branco indica visualmente a separação entre conceitos”.
- Retirar as linhas em branco, gera um efeito muito ruim na legibilidade do código.
Continuidade vertical
- A continuidade vertical indica uma associação íntima.
- Linhas de código que estão intimamente relacionadas devem aparecer verticalmente unidas.
- Comentários inúteis quebram essa intimidade de duas variáveis:
public class ReporterConfig {
/**
* The class name of the reporter listener
*/
private String m_className;
/**
* The properties of the reporter listener
*/
private List<Property> m_properties = new ArrayList<Property>();
public void addProperty(Property property) {
m_properties.add(property);
}
- Removendo os comentários fica mais fácil de ler:
public class ReporterConfig {
private String m_className;
private List<Property> m_properties = new ArrayList<Property>();
public void addProperty(Property property) {
m_properties.add(property);
}
}
Esse último exemplo, o código cabe numa única visão, podemos compreender todo o método sem ter que mover a cabeça ou os olhos.
Distância vertical
- Os conceitos intimamente relacionados para conceitos em arquivos separados.
- Não devemos separar em arquivos distintos conceitos intimamente relacionados, a menos que tenha uma razão muito boa.
- A separação vertical deles deve ser uma medida do quão importante eles são para a inteligibilidade um do outro.
- Devemos declarar variáveis o mais próximo possível de onde serão usadas”.
- Exemplo: Devemos declarar variáveis de controle para loops dentro da estrutura de iteração:
public int countTestCases() {
int count= 0;
for (Test each : tests)
count += each.countTestCases();
return count;
}
- Em alguns casos pode-se declarar uma variável no início de um bloco ou logo depois de um loop em uma função longa:
for (XmlTest test : m_suite.getTests()) {
TestRunner tr = m_runnerFactory.newTestRunner(this, test);
tr.addListener(m_textReporter);
m_testRunners.add(tr);
invoker = tr.getInvoker();
for (ITestNGMethod m : tr.getBeforeSuiteMethods()) {
beforeSuiteMethods.put(m.getMethod(), m);
}
for (ITestNGMethod m : tr.getAfterSuiteMethods()) {
afterSuiteMethods.put(m.getMethod(), m);
}
}
- Variáveis de Instância: Devemos declarar as variáveis de instância no início da classe. Isso não deve aumentar a distância vertical entre tais variáveis, elas serão usadas por muitos, senão todos, os métodos da classe.
- O importante é que as variáveis de instância sejam declaradas em um local bem conhecido. Todos devem saber onde buscar as declarações.
- Funções dependentes: Se uma função chama outra, elas devem ficar verticalmente próximas. Assim, a que chama deve ficar acima da que for chamada. Isso dá um fluxo natural ao programa.
- Assim, os leitores poderão confiar que as declarações daquelas funções virão logo em seguida.
- Afinidade conceitual: Quanto maior a afinidade, menor deve ser a distância entre eles.
- A afinidade se baseia numa dependência direta. Uma função chamando outra. Uma função usando uma variável.
- Um grupo de funções que efetuam uma operação parecida cria uma afinidade. Exemplo:
public class Assert {
static public void assertTrue(String message, boolean condition) {
if (!condition)
fail(message);
}
static public void assertTrue(boolean condition) {
assertTrue(null, condition);
}
static public void assertFalse(String message, boolean condition) {
assertTrue(message, !condition);
}
static public void assertFalse(boolean condition) {
assertFalse(null, condition);
}
...
Essas funções possuem uma afinidade conceitual forte, pois compartilham de uma mesma convenção de nomes e efetuam variações de uma mesma tarefa. Bem como o fato de uma chamar a outra.
Ordenação vertical
- Desejamos que as chamadas das dependências da função apontem para baixo;
- No caso, “a função chamada deve ficar embaixo da que a chama”;
- Cria um fluxo natural para baixo no módulo do código-fonte, de um nível maior para um menor.
- Assim os detalhes de baixo nível venham por último.
Formatação horizontal
- “Devemos nos esforçar para manter nossas linhas curtas”;
- O antigo limite de 80 de Hollerith é arbitrário;
- Com 100 linhas ou 120 ainda é aceitável, porém ultrapassar 120 caracteres é uma falta de cuidado;
Espaçamento e continuidade horizontal
- Operadores de atribuição entre espaços em branco:
int lineSize = line.length();
Essas instruções tem dois lados distintos, o lado esquerdo e o lado direito. Assim, os espaços tornam essa separação óbvia.
- Porém não coloque espaços entre os nomes das funções e os parênteses de abertura. Isso porque a função e seus parâmetros estão intimamente relacionados;
- Bem como separar os parâmetros entre parênteses na chamada da função realçar a vírgula e mostram que estão separados;
- Espaço em branco entre operadores é para destacar a prioridade dos mesmo;
Alinhamento horizontal
- Esse tipo de alinhamento não é prático;
- Parece enfatizar as coisas erradas e afasta o propósito real;
- As ferramentas de reformatação automática geralmente eliminam esse tipo de alinhamento;
- É melhor não usar esse tipo de alinhamento;
- Se tiver listas longas que precisam ser alinhadas, “o problema está no tamanho das listas”e não na falta de alinhamento;
Indentação
- Um código-fonte é mais como uma hierarquia do que algo esquematizado;
- Informações pertinentes ao arquivo, classes individuais dentro do arquivo, aos métodos das classes, aos blocos dentro dos métodos.
- Cada nível dessa hierarquia é um escopo.
- E para tornar visível essa hierarquia indentamos o código.
- Os programadores dependem bastante dessa indentação.
- Elas alinham visualmente na esquerda as linhas para ver em qual escopo eles estão.
- Assim a navegação e a compreensão do código para o programador é facilitada, ele sempre vai procurar a declaração variáveis mais a esquerda, etc.
- A mesma versão de um código sem indentação é quase incompreensível.
- Ignorando a indentação: Podemos querer não fazer a indentação mas no fim voltamos e fazemos, é uma necessidade.
Escopos minúsculos
- Estruturas while ou for minúsculas, é complicado para uma boa indentação.
Regra de equipes
- Todo programador tem suas regras de formatação prediletas;
- Mais em uma equipe, as regras são dela;
- A equipe deve escolher um único estilo de formatação e todos devem usá-lo;
- Assim o código tem estilo consistente;
- O leitor precisa poder confiar que as formatações que ele vir em uma arquivo-fonte terão o mesmo significado nos outros.
Regras de formatação do Uncle Bob
- Considere este um exemplo de como o código torna o melhor documento padrão de codificação:
public class CodeAnalyzer implements JavaFileAnalysis {
private int lineCount;
private int maxLineWidth;
private int widestLineNumber;
private LineWidthHistogram lineWidthHistogram;
private int totalChars;
public CodeAnalyzer() {
lineWidthHistogram = new LineWidthHistogram();
}
public static List<File> findJavaFiles(File parentDirectory) {
List<File> files = new ArrayList<File>();
findJavaFiles(parentDirectory, files);
return files;
}
private static void findJavaFiles(File parentDirectory, List<File> files) {
for (File file : parentDirectory.listFiles()) {
if (file.getName().endsWith(".java"))
files.add(file);
else if (file.isDirectory())
findJavaFiles(file, files);
}
}
public void analyzeFile(File javaFile) throws Exception {
BufferedReader br = new BufferedReader(new FileReader(javaFile));
String line;
while ((line = br.readLine()) != null)
measureLine(line);
}
private void measureLine(String line) {
lineCount++;
int lineSize = line.length();
totalChars += lineSize;
lineWidthHistogram.addLine(lineSize, lineCount);
recordWidestLine(lineSize);
}
private void recordWidestLine(int lineSize) {
if (lineSize > maxLineWidth) {
maxLineWidth = lineSize;
widestLineNumber = lineCount;
}
}
public int getLineCount() {
return lineCount;
}
public int getMaxLineWidth() {
return maxLineWidth;
}
public int getWidestLineNumber() {
return widestLineNumber;
}
<restante do código>
}
Top comments (0)