Anotações Capítulo 5: Formatting
Tags: books, codequality
Published: 2021-06-09 14:09:46

- **“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>
}
```