Como escrever g̶o̶o̶d não, ótimo código
quem esse cara pensa que é? O que ele sabe sobre escrever códigos “ótimos”?!
Você estaria 100% certo em pensar isso - e para ser completamente honesto ... Eu tenho muito mais experiência em escrever códigos não ótimos.
código ruim é escrito por vários motivos (alguns listados abaixo)
- é difícil
- “ótimo” é subjetivo
- software nunca é feito (não pode “ser” ótimo, tem que “permanecer” ótimo)
- a qualidade pode mudar com base nos requisitos atuais
- muito software funcional não é bom (modelos ruins)
- pessoas que querem software muitas vezes não são engenheiros de software
- …
Apesar de minha profunda experiência com código abaixo do ideal - tenho quase uma década de experiência em pedir ao computador (o mais gentilmente possível) para fazer as coisas que eu e outros humanos queremos.
Ao longo desse tempo, passei a apreciar vários conceitos e padrões, e também aprendi a desconfiar profundamente dos outros.
Neste artigo, descreverei alguns dos pontos positivos e negativos do software — e fornecerei evidências de apoio de pessoas realmente inteligentes.
Bem-vindo ao passeio
O que é “ótimo”
Vamos começar definindo o que é “ótimo”. No entanto, pode ser mais fácil definir afirmando rapidamente o que não é.
Ótimo código é
- não é difícil de ler
- não é difícil raciocinar sobre
- não faz com que você se odeie hoje ou 7 dias depois de escrevê-lo
- 90% de estrutura e 10% de sintaxe
- uma função de abstração de informações emparelhada com o gerenciamento de recursos previstos
- um amigo da matemática (especificamente teoria de conjuntos/categorias)
- escrito para humanos, não para hardware
1. 90% de estrutura e 10% de sintaxe
Todas essas ideias são inspiradas em temas muito mais abrangentes e profundos. Em relação à estrutura, podemos olhar para o paradigma de programação SOLID.
SOLID significa um conjunto de 5 “regras” que devem ser seguidas para construir um software sustentável. Conceitos listados abaixo
S - Single-responsiblity Principle
O - Open-closed Principle
L - Liskov Substitution Principle
I - Interface Segregation Principle
D - Dependency Inversion Principle
Esses princípios giram em torno do poder da Programação Orientada a Objetos (ame-a ou odeie-a) e descrevem uma maneira elegante de dividir suas abstrações em pedaços amigáveis ao software.
Ao seguir esses princípios, você pode evitar muitas complexidades desagradáveis que surgem no software funcional.
Por exemplo, com os princípios SOLID, você reduzirá a pegada de seu código e centralizará os arquivos em torno de funcionalidades comuns; tornando mais fácil navegar e adicionar/remover recursos sem afetar outras partes de sua base de código.
Esses problemas são totalmente evitados no nível da estrutura do seu aplicativo — e não no nível do código
A limpeza no nível da estrutura é uma maneira poderosa de impor uma organização duradoura.
Artigo fácil de digerir sobre o SOLID da Digital Ocean: aqui
Se isso não bastasse - o tio Bob continua lançando bangers .
Eu recomendaria muito seu livro mais recente lançado em 2017 (e honestamente tudo mais recente também).
“Arquitetura Limpa: Um Guia do Artesão para Estrutura e Design de Software” —https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/
Este livro explora como você pode estender esses conceitos para o nível do sistema .
À medida que movemos mais aplicativos para “a nuvem” e aproveitamos os serviços distribuídos. Esses princípios de design têm cada vez mais impacto na grandeza do seu código.
um ótimo código é apenas uma ferramenta que preenche a estrutura do design de seus aplicativos; seu sistema deve ser expresso por meio de sua estrutura, não da sintaxe.
2. uma função de abstração de informações emparelhada com gerenciamento de recursos previstos
hum... o que. Você realmente me perdeu com isso. uma função do quê?
vamos quebrar isso.
“uma função de abstração de informação” é uma forma concisa de expressar que nosso código é a saída de nossas abstrações .
Em outras palavras — nosso código é um reflexo de como decidimos dividir os conceitos de nosso aplicativo.
Mais concretamente; se nos deparamos com um problema e decidimos que devemos criar “Usuários” e “Sessões”, efetivamente dividimos nosso problema nessas ideias abstratas de usuários e sessões.
…ok Acho que abordamos a “função de abstração de informações”.
Em seguida, combinamos isso com “gerenciamento de recursos previstos”, que é uma maneira sofisticada de dizer que os engenheiros de software têm a tarefa de prever o futuro - e construir sistemas que possam suportar mudanças futuras
Se você não sabia - é sua culpa como programador não ter usado a estrutura mais recente um ano antes de ela ser criada. Como você não sabia!? (por favor, leia como sarcasmo - eu prometo que isso não é pessoal).
Então, para resumir; a qualidade do nosso código nem sempre é complexidade computacional, número de linhas ou nomes elegantes de variáveis.
É a capacidade de efetivamente dividir seu problema em pedaços abstratos que resistirão às mudanças imprevisíveis de amanhã.
Sim sim sim, eu sei; isso não parece possível. Bem, não é - e é nosso trabalho como desenvolvedor gerenciar as coisas que sabemos e as coisas que sabemos que não sabemos.
É um exercício de avaliação de risco e planejamento de custos - hein, não sabia que você se inscreveu, sabia?
No entanto, há esperança!
Seguindo conceitos confiáveis (mais em breve) podemos nos fortalecer e aplicar para um mundo em mudança.
Antes de entrarmos nas coisas realmente boas - podemos reconhecer algumas idéias dignas de "confiança" aqui.
- Organismos de padronização (há pessoas que já pensaram profundamente sobre isso - e eles realmente apreciariam se você fizesse uso de seu excelente trabalho. Isso se aplica especialmente a algoritmos, segurança, plataforma cruzada e outras coisas realmente importantes, como códigos QR).
- Linguagens estáticas e fortemente tipadas (honestamente, isso não é realmente sobre os problemas de segurança de baixo nível que você evitará. É sobre a natureza centrada no ser humano dos tipos. Primeiro, se você violar o tipo em seu código, o compilador gritará com você e dois, outros desenvolvedores realmente saberão o que seu código está fazendo).
- Poesia (menos sobre as palavras e mais sobre a capacidade de comunicar um significado complexo com poucos símbolos. Seu código é poesia, embora seja um público muito sem imaginação, mas ainda assim deve ser curto e agradável).
Embora você possa não ser - seu código deve ser amigo da matemática.
Sim, eu sei — a matemática é chata e você nunca usou uma derivada na vida real.
Mas…. Eu prometo - pode ser super útil. Na verdade, é a ferramenta mais confiável que temos.
É confiável porque tem um longo histórico de contribuições de código aberto e eles resolveram a maioria dos bugs no software principal. Agora os desenvolvedores (matemáticos) estão ocupados descobrindo coisas malucas como a física quântica.
Podemos confiar em coisas úteis como criptografia para proteger nossas contas bancárias e comunicações. Podemos confiar na teoria dos conjuntos para impor o sistema de tipos de [ADD FAVORITE PROGRAMMING LANGUAGE HERE]. Podemos até confiar na álgebra linear para otimizar nossa rota nos mapas do Google e no ChatGPT para manter as coisas bobas.
É importante lembrar que, por trás de toda a interface do usuário sofisticada e da tela brilhante, nossos computadores são apenas isso; computer-ers.
Se você eliminar todas as complexidades, ficará com o esqueleto da adição e da subtração.
Talvez, apenas talvez... exista uma maneira de colocarmos todo esse poder em nosso próprio código.
Vamos mergulhar um pouco mais fundo
Vou dar um palpite e assumir que você (o leitor) está familiarizado com a Programação Orientada a Objetos,
E... também irei mais longe para adivinhar que você já ouviu falar em Programação Funcional — mas decidiu que isso é algo para aprender outro dia.
Se você está nesse campo, talvez não esteja ciente da beleza e elegância das linguagens de programação que seguem mais de perto a semântica da matemática tradicional.
Nós (pessoas normais) somos mimados com as abstrações que as linguagens convencionais fornecem. Esperamos poder criar variáveis sempre que quisermos e construir fluxos de controle complexos com torres de ifeelse
Nós (pessoas normais) devemos, no entanto, tomar nota de nossa contraparte de programação funcional mais inteligente.
Existem superpoderes ocultos em linguagens simples e restritivas. Eles fornecem métodos prováveis ( ⚡️ alimentados por matemática ) para mostrar que seu código abrange todos os casos ou que pode ser dividido em partes discretas de trabalho que podem ser espalhadas por máquinas infinitas.
Infinito e Provas são ideias difíceis para o programador médio, mas qualquer matemático as come no café da manhã.
Por exemplo, um desses super-heróis no vídeo abaixo mostra como a modelagem de um sistema pode fornecer maneiras de encontrar instruções passo a passo para explorar bugs incrivelmente complexos sem olhar para uma linha de código real
O segredo está no poder da matemática formal aplicada ao projeto do sistema.
Se aplicado corretamente (e não, isso não requer reescrever tudo em uma linguagem funcional), então você obtém todos os benefícios da matemática gratuitamente.
Esses benefícios incluem, mas não se limitam a
- gerando automaticamente testes para todas as maneiras possíveis de seu programa ser usado
- explore as implicações de adicionar componentes ou sistemas de remoção ao seu aplicativo
- tenha 100% de certeza de que o código funcionará. Você quer ter certeza de que o software do trem de pouso do seu avião funciona, não é?
- outras coisas mais complexas que os palestrantes neste vídeo podem ensinar. Ah, e se você realmente quer aprender isso, confira o TLA+
Talvez possamos usar alguns desses conceitos incrivelmente chatos para tornar nosso código incrivelmente incrível.
um grande código deve aspirar a ter ideias tão concretas que essas mesmas ideias sejam verdadeiras daqui a mais de 1000 anos
Pathagotem criou um ótimo software para triângulos em ~ 570 AC…. isso é como 1500 anos atrás!
Talvez devêssemos aprender ou usar matemática quando possível - é a melhor maneira que nós, humanos, sabemos expressar abstrações duradouras.
4. escrito para humanos, não para hardware
Ok o suficiente sobre o material de matemática. Quando falamos de software — por mais que tentemos evitar humanos. Eles sempre entram na mistura.
Vamos falar sobre humanos. Como os humanos se encaixam?
Bem… são eles que querem o software em primeiro lugar e, na verdade, são eles que criaram essas linguagens.
Além disso, são eles que se preocupam com tudo isso — os computadores não têm opinião sobre o código que executam.
Pessoas fazem. As pessoas definem o que está “funcionando” e o que não está.
Então — acho que devemos orientar tudo para o humano, certo?
Sim! e isso não significa apenas que precisamos de interfaces de usuário bonitas e aplicativos móveis ergonômicos.
Precisamos estender a humanidade para o desenvolvimento de software. Devemos sentir isso em muitos níveis.
A humanidade deve estar na experiência do desenvolvedor em todos os níveis. A seguir estão algumas questões centradas no ser humano.
- As pessoas estão integradas às bases de código. Sua documentação facilita isso?
- Quantas ferramentas/comandos ou etapas especiais de configuração preciso executar?
- Como é adicionar um novo teste? um novo recurso?
- Quantos frameworks/linguagens seu projeto impõe? Pode ser menos?
- Quanto esforço é necessário para passar de completamente novo para totalmente em produção?
- Como é a quebra? e vou precisar acordar para consertar?
Mas uma pequena equipe de bons desenvolvedores é maior que a soma se forem partes (quando feito corretamente).
Então, como podemos obter um ótimo código de uma equipe?
Algumas soluções são mais fáceis do que outras. Por exemplo, um método fácil, mas eficaz, é padronizar tudo — remover toda a personalidade das contribuições individuais.
Embora isso pareça duro - sistemas sólidos terão formas/tipos/padrões específicos para fazer as coisas. Deve haver muito pouca customização e criatividade dentro da sintaxe do código.
Por que isso é uma coisa boa? Facilita muito a carga mental do desenvolvedor. Se existe uma “maneira” de fazer algo – então deve ser feito dessa “maneira”.
Isso efetivamente move a solução do nível de código para o nível de estrutura (mencionado anteriormente). Uma vez que precisamos confiar em decisões e padrões no nível do sistema, em vez de personalizados.
Simplificando, todos os desenvolvedores devem compartilhar tipos comuns. Isso remove a personalização e torna muito mais fácil integrar o trabalho de vários desenvolvedores.
Essa ideia deve se estender muito além dos tipos e de tantos conceitos que possam ser efetivamente padronizados no nível do sistema quanto maior for o seu código.
ótimo código é tão bem escrito que as contribuições de diferentes membros da equipe geralmente são indistinguíveis de outras partes da base de código. Além disso, você não deve ser capaz de ver onde uma pessoa começou e outra terminou.
No vídeo a seguir, são exploradas em detalhes as estratégias para formar equipes e aumentar a produtividade à medida que um sistema se torna mais complexo.
Este é um tópico fascinante, uma vez que as ideias de design de sistemas complexos estão bem fora do escopo dos computadores e abordam fenômenos naturais como biologia animal/planta, interações sociais e planetas.
Nós, meros mortais/desenvolvedores, temos muito poder em nossas mãos. Podemos construir enormes pilhas de merda complexa e inútil - e com essas mesmas mãos podemos construir nossos próprios sistemas dinâmicos complexos não muito diferentes do planeta em que estou escrevendo isso.
Até a próxima, continue codificando, espalhe amor e paz ✌️





































![O que é uma lista vinculada, afinal? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)