
[ad_1]
A cada década, no máximo, a indústria de desenvolvimento de software passa por mudanças tecnológicas significativas, e essas mudanças dificultam a entrega de software sustentável. Novas tecnologias resolvem muitos problemas para usuários e desenvolvedores, sejam novas plataformas (web, dispositivos móveis, wearables, VR), novos paradigmas de linguagem de programação (novos sistemas de tipo estático, modelos de simultaneidade e tempos de execução) ou novas opções de implantação ( virtualização, conteinerização, funções sem servidor). Mas há um grande problema que, longe de resolver, as novas tecnologias realmente pioram: o problema de descobrir como escrever software sustentável.
Especificamente, como você pode evitar a queda aparentemente inevitável de uma base de código em problemas como fragilidade (onde as mudanças causam a quebra de coisas inesperadas), rigidez (onde pequenos ajustes forçam mudanças muito maiores) ou incompreensibilidade (onde você não consegue entender o código ser capaz para mudá-lo)? Como você pode integrar novos desenvolvedores à sua equipe devido ao crescimento ou rotatividade, garantindo que eles entendam o código bem o suficiente para serem produtivos, especialmente quando a tecnologia é nova para eles ou nova para eles? todos?
Opções de manutenção
Agora, não é que escrever software sustentável seja impossível em tecnologias mais recentes, mas existem forças que dificultam. Quaisquer que sejam os benefícios que uma tecnologia possa trazer, sempre é possível fazer uma bagunça; ainda não existe uma tecnologia que possa impedir isso completamente. E a documentação das novas tecnologias geralmente não explica como aplicar as técnicas de design de software de forma abrangente. Em vez disso, a documentação se concentra em explicar (1) por que os desenvolvedores devem usar essa tecnologia e (2) como eles podem fazê-la funcionar.
A prioridade dos criadores de tecnologia não é e não pode explicar as práticas de manutenção de software. Em vez disso, são outras pessoas que criam recursos para explicar os princípios de design e arquitetura de software — e esses recursos são criados dentro de um contexto histórico específico que não necessariamente se traduz em novas tecnologias. Por exemplo, para que servem os princípios clássicos de design orientado a objetos quando você está trabalhando em uma tecnologia que não possui objetos? Lá são alguns princípios em materiais clássicos de design de software que se aplicam a tecnologias mais recentes, mas pode ser um desafio identificar quais princípios são transferidos e quais não. Não é realista esperar que os autores tenham previsto tecnologias futuras e as tenham levado em consideração enquanto escreviam. Mesmo que o fizessem, não havia necessidade urgente de esses autores enfatizarem qual de seus pontos era mais provável de se aplicar a essa tecnologia futura imaginada. E se você é um desenvolvedor mais novo tentando ler um livro de design de software escrito em uma tecnologia mais antiga que você não usou, você enfrenta um grande obstáculo. Você precisaria se esforçar um pouco para aprender a tecnologia desse livro na esperança de que algum princípios de design de software desse livro são transferidos para o seu contexto. Poucos de nós têm energia para gastar tanto esforço com essa pouca incerteza sobre a recompensa.
Design Evolucionário
Então, à medida que novas tecnologias surgem constantemente, como você pode continuar escrevendo software sustentável? Esta tem sido a principal pergunta que me fiz nos últimos seis anos, pois estudei, experimentei e trabalhei em vários idiomas e plataformas diferentes. Ao fazer isso, um princípio específico de design de software sustentável chegou ao topo. Vi esse princípio funcionar em tantas tecnologias que estou confiante em adotá-lo como minha abordagem padrão para qualquer tecnologia em que trabalho. software de manutenção.
Esse princípio de design de software universal tem diferentes nomes: design incremental, design evolucionário, design emergente, design simples. O que o princípio afirma é que você obterá o melhor design se:
- Construa o sistema com um design de software que seja excelente para só necessidades de hoje, e
- Quando novos requisitos chegarem, ajuste o design do sistema para que seja um excelente ajuste para esses novos requisitos (essa é a parte “incremental”/”evolutiva”)
Como você pode construir um sistema que seja flexível o suficiente para lidar com mudanças contínuas, flexível o suficiente para que o próprio design do software esteja mudando? Cobrindo-o completamente com testes automatizados para que você possa fazer alterações com segurança e fazendo alterações em pequenas etapas de refatoração que mantêm o sistema funcionando o tempo todo.
O design evolutivo ajuda você a evitar sair da estrada em uma das duas valas. Por um lado, seu software pode cair em sub-design ou sem design: uma vez que você tenha o código funcionando, você imediatamente segue em frente sem pensar mais. Se um novo recurso não se encaixa muito bem no código existente, você o insere com lógica condicional complexa até que funcione. O problema com o design insuficiente é que seus custos aumentam com o tempo. Toda vez que você faz um hack, aumenta a probabilidade de que o próximo recurso também não se encaixe bem, exigindo um hack ainda maior. A base de código se transforma em uma “grande bola de lama”. E se você tinha alguma esperança de adicionar testes para entender o comportamento e evitar regressões, cada hack torna a escrita de testes mais difícil também.
Se você quiser tentar evitar o design insuficiente, a outra vala em que seu software pode cair é design excessivo ou projeto prematuro. Você tenta pensar em tudo no código que pode mudar algum dia e cria uma opção de configuração ou ponto de extensão para cada um. Mas você não pode prever o futuro perfeitamente, então algumas de suas suposições estarão erradas: alguns de seus pontos de configuração não serão necessários e adicionarão indireção sem benefício, e outras alterações serão necessárias que não tenham um ponto de configuração para que você ainda precise de hacks.
O design evolucionário evita o dilema de ter que escolher entre design insuficiente e design excessivo. Você cria um design excelente para hoje e o ajusta aos novos requisitos de amanhã.
Algo faltando?
Agora, se você é um designer de software experiente, pode estar pensando que estou deixando de fora algo essencial. Você pode estar se perguntando “o design orientado a objetos não é necessário para fazer isso?” Ou “um bom sistema de tipos não torna isso mais fácil?” Ou “você não está esquecendo o desenvolvimento orientado a testes?” Embora todas essas técnicas e outras possam ser úteis para alcançar o design evolutivo, nenhuma é essencial. Por exemplo:
- Paradigmas funcionais e orientados a objetos otimizam para dois tipos diferentes de mudança, e um determinado projeto pode se beneficiar de um, do outro ou de ambos.
- O desenvolvimento orientado a testes é uma ótima maneira de obter a cobertura de teste completa necessária para o design evolutivo. Mas é menos natural para alguns tipos de código e para a fiação de algumas pessoas (como argumentado por Kent Beck e Martin Fowler). Nesses casos, você pode optar por adotar abordagens alternativas para obter uma cobertura de teste completa.
- Bons sistemas de tipo estático modernos podem fornecer suporte de ferramentas para ajudá-lo a fazer alterações com segurança. Uma desvantagem é que sua rigidez também pode causar atrito, levando você a adiar a evolução de seu sistema até que você tenha cavado um buraco tão profundo que seja difícil cavar de volta.
- A dissociação de sistemas em serviços separados ou funções sem servidor simplifica cada peça, o que facilita a evolução de cada peça. Mas também torna mais difícil verificar se as peças continuam interagindo corretamente umas com as outras à medida que evoluem.
Se você tem uma coleção específica das técnicas acima que considera essenciais, não estou pedindo para desistir delas: estou encorajando você a mudar a forma como pensa sobre elas. Se seu objetivo é praticar o design evolucionário, pense em cada técnica como um meio para um fim. Essa mentalidade abre a possibilidade de que o conjunto ideal de técnicas possa ser diferente para diferentes indivíduos, equipes diferentes, plataformas diferentes, domínios de negócios diferentes ou em momentos diferentes. Separar o fim (design evolutivo) dos meios nos permite encontrar mais pontos em comum e aprender uns com os outros para impulsionar a prática do design evolutivo.
Distinguir os meios dos fins tem sido a maior parte da minha jornada profissional nos últimos seis anos. Eu aprendi sobre design evolucionário no mundo Ruby, onde tipagem dinâmica, design orientado a objetos e desenvolvimento orientado a testes eram primordiais. A mensagem que recebi, explícita ou implicitamente, foi que essas técnicas são uma parte essencial do design evolucionário. Mas desde aquela época eu vi de perspectivas adicionais: vi como a tipagem estática ajuda a comunicar APIs para grandes equipes, como a API baseada em função do React.js fornece seu próprio tipo de flexibilidade e como o desenvolvimento orientado a testes é mais caro para alguns tipos de programas e alguns tipos de programadores. Nessas situações, descobri que as técnicas específicas não eram a coisa essencial que eu buscava; em vez disso, o essencial era “como posso evoluir meu código ao longo do tempo com confiança?”
Próximos passos
Sempre que uma nova tecnologia de software é introduzida, haverá utópicos que afirmam que ela garante um código que pode ser mantido sem nenhum esforço de design necessário. Haverá também fatalistas que argumentam que isso impede completamente o bom design de software. (Se isso parecer exagero, reserve meia hora para ler os comentários no site de mídia social de notícias de tecnologia de sua escolha!) Sem surpresa, nenhum desses extremos está correto. Em vez disso, novas tecnologias desafiam nossas concepções do que é “essencial” no design de software, de modo que algo que antes pensávamos ser “a coisa toda” se torna apenas uma ferramenta possível. Na melhor das hipóteses, as novas tecnologias fornecem ferramentas de design de software inovadoras que dobram a curva do que é possível em nosso código, proporcionando mais benefícios por um custo menor. Mas, em última análise, nós desenvolvedores somos os únicos ao volante de nossos projetos e responsáveis por dirigir. Será que sairemos da estrada para um projeto insuficiente e ficaremos presos em uma grande bola de lama? Ou em excesso de design e ficar preso em uma estrutura pesada? Ou escreveremos um código flexível para que possamos ajustá-lo para lidar com o que o futuro trouxer?
Se você está interessado na prática do design evolucionário, para onde você vai a partir daqui? Apenas ouvir sobre o conceito de design evolucionário não é suficiente para equipá-lo para fazê-lo – há muito mais para aprender e desaprender. Infelizmente, como mencionei anteriormente, a maioria dos escritos sobre design evolucionário também inclui muito mais detalhes além do essencial. No Big Nerd Ranch, estamos explorando esse tópico e pensando em desenvolver mais recursos. Se você estiver interessado em obter mais recursos de nós, avise-nos!
Enquanto isso, livros clássicos sobre design evolucionário ainda são sua melhor aposta – apenas não sinta a pressão de aceitar todas as especificidades que eles defendem. Eu recomendo começar com Refatoração, segunda edição por Martin Fowler – os dois primeiros capítulos em particular são uma excelente pesquisa e argumento para o design evolutivo. Se você já está familiarizado com a literatura sobre design evolucionário e sente que é o único em sua pilha de tecnologia atual que está, não desanime. Em vez disso, procure maneiras de aplicar esses princípios você mesmo e depois mostre aos outros – uma vez que você se empenhou, os outros podem ver os benefícios e se interessar. Você pode considerar reler esses livros clássicos, não tanto para aprender coisas novas, mas para separar específico técnicas que você usou em um ecossistema a partir dos princípios gerais que podem ser aplicados em qualquer lugar.
[ad_2]
Source link