Computer Science › Algoritmos e Software
Um repositório git é uma sequência de snapshots imutáveis chamados commits, cada um apontando para seu pai; um branch é um ponteiro móvel barato, não uma cópia; merge reconcilia dois branches divergentes, produzindo um fast-forward ou um commit de merge genuíno com dois pais.
Feature branches isolam cada unidade de trabalho até estar genuinamente completa, e uma main sempre funcional dá a todos uma base confiável; branches de vida curta produzem merges menores, mais fáceis, que os de vida longa, uma decisão de processo de equipe, não algo que git impõe.
Um commit é uma unidade de comunicação para leitores futuros, não um ponto de salvamento; commits atômicos (uma mudança lógica) são revisáveis e reversíveis isoladamente, e uma mensagem que explica por que, não o que, é a única coisa que o diff nunca pode mostrar.
Uma segunda pessoa lendo uma mudança antes de mesclar captura o que um autor perdeu por distância cognitiva, casos de borda que nenhum teste cobriu, e código correto mas confuso demais para confiar à primeira vista.
MIT 6.031 organiza construção de software em torno de três objetivos nomeados, Seguro Contra Bugs, Fácil de Entender, e Pronto para Mudança, três eixos genuinamente distintos que frequentemente competem, não sinônimos para uma única noção de "qualidade".
Uma especificação é um contrato dividido em pré-condição (obrigação do chamador) e pós-condição (obrigação da função); ambiguidades não enunciadas em qualquer uma das duas são a origem da maioria dos bugs "confusos", e uma especificação precisa serve os três objetivos de Seguro/Fácil/Pronto ao mesmo tempo.
Testes de unidade verificam um módulo isolado com dependências falsificadas; testes de integração verificam se módulos reais concordam em sua interface compartilhada; testes de sistema verificam o programa inteiro contra requisitos; a pirâmide de testes reflete custo e precisão diagnóstica.
Reprodução confiável mais bissecção, o mesmo dividir para conquistar da busca binária aplicado a localizar uma falha, escalam depuração de uma única chamada de função para uma entrada gigante ou centenas de commits; git bisect automatiza exatamente essa ideia.
Teste caixa-preta deriva casos de teste só da especificação, sem olhar código; teste caixa-branca deriva casos lendo os ramos e laços reais do código; são fontes complementares de caso de teste, cegas cada uma para o que só a outra vê.
Cobertura de linha e ramo são porcentagens mecânicas de execução de código, não verificação; uma função com um bug genuíno pode ter 100% de cobertura se os testes que a exercitam não afirmam nada sobre o resultado, como o exemplo maximum() mostra diretamente.
TDD estrutura o trabalho em um ciclo curto e repetido, vermelho (um teste falhando escrito antes do comportamento existir), verde (a implementação mínima que o passa), refatorar (limpar estrutura com os testes como rede de segurança); a ordem, não só a presença de testes, é o que importa.
Ocultação de informação, de Parnas, decompõe um sistema em torno de decisões prováveis de mudar e as esconde atrás de uma interface que não precisa mudar quando a decisão muda; vazar representação (por exemplo, uma referência mutável a estado interno) rompe essa fronteira silenciosamente.
Acoplamento mede quanto um módulo depende dos internos de outro (quer-se baixo); coesão mede quão bem as próprias responsabilidades de um módulo pertencem juntas (quer-se alto); ambos são ocultação de informação vista de fora e de dentro respectivamente.
Refatoração muda a estrutura interna de um programa deixando seu comportamento observável exatamente inalterado; só é seguro fazer com confiança quando uma suíte de teste já existente prova esse comportamento antes e depois, como o exemplo de desconto duplicado extraído mostra diretamente.
SOLID, montado por Robert C. Martin a partir da prática de indústria, não pesquisa acadêmica, é um conjunto de cinco técnicas concretas que se reduzem a acoplamento baixo e coesão alta especializados para classes, interfaces, e hierarquias de herança orientadas a objetos.
Um padrão de design é uma solução nomeada, reutilizável, para um problema recorrente, não código para copiar-colar; Strategy encapsula um algoritmo intercambiável, Observer notifica um conjunto aberto de dependentes, ambos aplicações concretas de acoplamento baixo.
Estilos de arquitetura afastam o zoom do design de um único módulo para a forma de um sistema inteiro; cliente-servidor centraliza um recurso compartilhado, camadas (n-tier) empilham responsabilidades em uma sequência ordenada, e os dois frequentemente se combinam.
Reutilizar uma biblioteca madura, amplamente usada, para um problema genuinamente difícil é geralmente uma vitória clara; uma dependência mal mantida para algo trivial é um risco real disfarçado de conveniência; julgar bem exige pesar manutenção, adoção, e dificuldade real do problema.
Uma inconvenção inconsistente não custa nada a um desenvolvedor solo porque só uma pessoa jamais a interpreta; no momento em que uma segunda pessoa se junta, o custo de coordenação cresce combinatoriamente, não linearmente, o que é exatamente por que convenções compartilhadas explícitas importam desproporcionalmente mais em escala de equipe.
Aplicando Seguro/Fácil/Pronto a decisões reais desta disciplina, TDD e feature branches com revisão obrigatória convergem nos três; construir flexibilidade não solicitada "por precaução" expõe uma tensão real, não fabricada, entre Pronto para Mudança e Fácil de Entender.
Part of the Computer Science curriculum.
Um repositório git é uma sequência de snapshots imutáveis chamados commits, cada um apontando para seu pai; um branch é um ponteiro móvel barato, não uma cópia; merge reconcilia dois branches divergentes, produzindo um fast-forward ou um commit de merge genuíno com dois pais.
Feature branches isolam cada unidade de trabalho até estar genuinamente completa, e uma main sempre funcional dá a todos uma base confiável; branches de vida curta produzem merges menores, mais fáceis, que os de vida longa, uma decisão de processo de equipe, não algo que git impõe.
Um commit é uma unidade de comunicação para leitores futuros, não um ponto de salvamento; commits atômicos (uma mudança lógica) são revisáveis e reversíveis isoladamente, e uma mensagem que explica por que, não o que, é a única coisa que o diff nunca pode mostrar.
Uma segunda pessoa lendo uma mudança antes de mesclar captura o que um autor perdeu por distância cognitiva, casos de borda que nenhum teste cobriu, e código correto mas confuso demais para confiar à primeira vista.
MIT 6.031 organiza construção de software em torno de três objetivos nomeados, Seguro Contra Bugs, Fácil de Entender, e Pronto para Mudança, três eixos genuinamente distintos que frequentemente competem, não sinônimos para uma única noção de "qualidade".
Uma especificação é um contrato dividido em pré-condição (obrigação do chamador) e pós-condição (obrigação da função); ambiguidades não enunciadas em qualquer uma das duas são a origem da maioria dos bugs "confusos", e uma especificação precisa serve os três objetivos de Seguro/Fácil/Pronto ao mesmo tempo.
Testes de unidade verificam um módulo isolado com dependências falsificadas; testes de integração verificam se módulos reais concordam em sua interface compartilhada; testes de sistema verificam o programa inteiro contra requisitos; a pirâmide de testes reflete custo e precisão diagnóstica.
Reprodução confiável mais bissecção, o mesmo dividir para conquistar da busca binária aplicado a localizar uma falha, escalam depuração de uma única chamada de função para uma entrada gigante ou centenas de commits; git bisect automatiza exatamente essa ideia.
Teste caixa-preta deriva casos de teste só da especificação, sem olhar código; teste caixa-branca deriva casos lendo os ramos e laços reais do código; são fontes complementares de caso de teste, cegas cada uma para o que só a outra vê.
Cobertura de linha e ramo são porcentagens mecânicas de execução de código, não verificação; uma função com um bug genuíno pode ter 100% de cobertura se os testes que a exercitam não afirmam nada sobre o resultado, como o exemplo maximum() mostra diretamente.
TDD estrutura o trabalho em um ciclo curto e repetido, vermelho (um teste falhando escrito antes do comportamento existir), verde (a implementação mínima que o passa), refatorar (limpar estrutura com os testes como rede de segurança); a ordem, não só a presença de testes, é o que importa.
Ocultação de informação, de Parnas, decompõe um sistema em torno de decisões prováveis de mudar e as esconde atrás de uma interface que não precisa mudar quando a decisão muda; vazar representação (por exemplo, uma referência mutável a estado interno) rompe essa fronteira silenciosamente.
Acoplamento mede quanto um módulo depende dos internos de outro (quer-se baixo); coesão mede quão bem as próprias responsabilidades de um módulo pertencem juntas (quer-se alto); ambos são ocultação de informação vista de fora e de dentro respectivamente.
Refatoração muda a estrutura interna de um programa deixando seu comportamento observável exatamente inalterado; só é seguro fazer com confiança quando uma suíte de teste já existente prova esse comportamento antes e depois, como o exemplo de desconto duplicado extraído mostra diretamente.
SOLID, montado por Robert C. Martin a partir da prática de indústria, não pesquisa acadêmica, é um conjunto de cinco técnicas concretas que se reduzem a acoplamento baixo e coesão alta especializados para classes, interfaces, e hierarquias de herança orientadas a objetos.
Um padrão de design é uma solução nomeada, reutilizável, para um problema recorrente, não código para copiar-colar; Strategy encapsula um algoritmo intercambiável, Observer notifica um conjunto aberto de dependentes, ambos aplicações concretas de acoplamento baixo.
Estilos de arquitetura afastam o zoom do design de um único módulo para a forma de um sistema inteiro; cliente-servidor centraliza um recurso compartilhado, camadas (n-tier) empilham responsabilidades em uma sequência ordenada, e os dois frequentemente se combinam.
Reutilizar uma biblioteca madura, amplamente usada, para um problema genuinamente difícil é geralmente uma vitória clara; uma dependência mal mantida para algo trivial é um risco real disfarçado de conveniência; julgar bem exige pesar manutenção, adoção, e dificuldade real do problema.
Uma inconvenção inconsistente não custa nada a um desenvolvedor solo porque só uma pessoa jamais a interpreta; no momento em que uma segunda pessoa se junta, o custo de coordenação cresce combinatoriamente, não linearmente, o que é exatamente por que convenções compartilhadas explícitas importam desproporcionalmente mais em escala de equipe.
Aplicando Seguro/Fácil/Pronto a decisões reais desta disciplina, TDD e feature branches com revisão obrigatória convergem nos três; construir flexibilidade não solicitada "por precaução" expõe uma tensão real, não fabricada, entre Pronto para Mudança e Fácil de Entender.