Conforme programamos, todos nós desenvolvemos práticas e padrões que usamos e nos quais confiamos. No entanto, com o tempo, conforme nosso entendimento, maturidade e até mesmo o uso da tecnologia mudam, percebemos que algumas práticas que antes pensávamos serem excelentes não são (ou não se aplicam mais).
Um exemplo de prática que usei com bastante frequência, mas que mudei nos últimos anos, é o uso do padrão de objeto Singleton .
Por meio de minha própria experiência e longos debates com colegas, percebi que singletons nem sempre são desejáveis - eles podem tornar o teste mais difícil (inibindo técnicas como a simulação) e podem criar acoplamentos indesejáveis entre as partes de um sistema. Em vez disso, agora uso fábricas de objetos (normalmente com um contêiner IoC) que ocultam a natureza e a existência de singletons de partes do sistema que não se importam - ou precisam saber. Em vez disso, eles contam com uma fábrica (ou localizador de serviço) para adquirir acesso a tais objetos.
Minhas perguntas para a comunidade, no espírito de autoaperfeiçoamento, são:
- Quais padrões ou práticas de programação você reconsiderou recentemente e agora tenta evitar?
- Com o que você decidiu substituí-los?
fonte
Pontos de retorno único.
Certa vez, preferi um único ponto de retorno para cada método, pois com isso eu poderia garantir que qualquer limpeza necessária pela rotina não fosse esquecida.
Desde então, mudei para rotinas muito menores - portanto, a probabilidade de ignorar a limpeza é reduzida e, de fato, a necessidade de limpeza é reduzida - e descobri que os retornos iniciais reduzem a complexidade aparente (o nível de aninhamento) do código. Artefatos do único ponto de retorno - mantendo variáveis de "resultado" ao redor, mantendo variáveis de sinalização, cláusulas condicionais para situações ainda não concluídas - fazem o código parecer muito mais complexo do que realmente é, tornando-o mais difícil de ler e manter. Saídas antecipadas e métodos menores são o caminho a percorrer.
fonte
Em uma palavra superengenharia .
fonte
Notação húngara (formas e sistemas). Eu costumava prefixar tudo. strSomeString ou txtFoo. Agora eu uso someString e textBoxFoo. É muito mais legível e fácil para alguém novo vir e pegar. Como um bônus adicional, é trivial mantê-lo consistente - camelCase o controle e acrescente um nome útil / descritivo. O Formulários húngaro tem a desvantagem de nem sempre ser consistente e os Sistemas húngaro não trazem muito lucro. Agrupar todas as suas variáveis juntas não é realmente útil - especialmente com IDEs modernos.
fonte
A arquitetura "perfeita"
Eu vim com THE arquitetura alguns anos atrás. Empurrei-me tecnicamente o máximo que pude para que houvesse camadas 100% fracamente acopladas, uso extensivo de delegados e objetos leves. Era o paraíso técnico.
E foi uma porcaria. A pureza técnica da arquitetura apenas desacelerou minha equipe de desenvolvimento visando a perfeição em vez de resultados e quase alcancei o fracasso total.
Agora temos uma arquitetura muito mais simples, menos tecnicamente perfeita, e nossa taxa de entrega disparou.
fonte
O uso de caffine. Certa vez, ele me manteve acordado e em um clima de programação glorioso, onde o código voou de meus dedos com fluidez febril. Agora não faz nada e, se não tiver, fico com dor de cabeça.
fonte
Comentando o código. Eu costumava pensar que o código era precioso e que você não pode simplesmente deletar aquelas lindas joias que você criou. Eu agora excluo qualquer código comentado que encontrar, a menos que haja um TODO ou NOTA anexado, porque é muito perigoso deixá-lo. A saber, eu me deparei com classes antigas com grandes porções comentadas e realmente me confundiu por que eles estavam lá: foram comentados recentemente? esta é uma mudança de ambiente dev? por que ele faz esse bloqueio não relacionado?
Considere seriamente não comentar o código e apenas excluí-lo. Se você precisar, ainda está no controle de origem. YAGNI embora.
fonte
O uso excessivo / abuso das diretivas #region. É apenas uma coisa pequena, mas em C #, eu costumava usar as diretivas #region em todo o lugar, para organizar minhas classes. Por exemplo, eu agruparia todas as propriedades de classe em uma região.
Agora eu olho para o código antigo e principalmente fico irritado com eles. Eu não acho que isso realmente torna as coisas mais claras na maioria das vezes, e às vezes eles simplesmente te atrasam. Portanto, mudei de ideia e sinto que as aulas bem organizadas são em sua maioria mais limpas, sem diretivas regionais.
fonte
Desenvolvimento em cascata em geral e, em específico, a prática de escrever especificações funcionais e de design completas e abrangentes que, de alguma forma, se espera que sejam canônicas e, em seguida, esperar que uma implementação delas seja correta e aceitável. Já o vi ser substituído pelo Scrum, e bom tempo para ele, eu digo. O simples fato é que a natureza mutável das necessidades e desejos do cliente torna qualquer especificação fixa efetivamente inútil; a única maneira de realmente abordar o problema de maneira adequada é com uma abordagem iterativa. Não que Scrum seja uma bala de prata, é claro; Eu já vi isso ser mal usado e abusado muitas e muitas vezes. Mas é melhor do que cachoeira.
fonte
Nunca batendo.
Parece uma ideia tão boa, não é? Os usuários não gostam de programas que travam, então vamos escrever programas que não travem, e os usuários devem gostar do programa, certo? Foi assim que comecei.
Hoje em dia, estou mais inclinado a pensar que, se não funcionar, não deveria fingir que está funcionando. Fracasse o mais rápido possível, com uma boa mensagem de erro. Se você não fizer isso, seu programa irá travar ainda mais fortemente algumas instruções depois, mas com algum erro de ponteiro nulo indefinido que levará uma hora para depurar.
Meu padrão favorito de "não travar" é este:
Agora, em vez de pedir a seus usuários para copiar / colar a mensagem de erro e enviá-la a você, você terá que mergulhar nos registros tentando encontrar a entrada do registro. (E como eles inseriram um ID de usuário inválido, não haverá entrada de registro.)
fonte
null
ou a string vazia).Achei que fazia sentido aplicar padrões de design sempre que os reconhecia.
Mal sabia eu que estava realmente copiando estilos de linguagens de programação estrangeiras, enquanto a linguagem com a qual estava trabalhando permitia soluções muito mais elegantes e fáceis.
Usar várias (muito) línguas diferentes abriu meus olhos e me fez perceber que não tenho que aplicar mal as soluções de outras pessoas para problemas que não são meus. Agora eu estremeço ao ver o padrão de fábrica aplicado em uma linguagem como Ruby.
fonte
Teste obsessivo. Eu costumava ser um defensor fanático do desenvolvimento teste-primeiro. Para alguns projetos, faz muito sentido, mas percebi que não é apenas inviável, mas prejudicial para muitos projetos, aderir de maneira submissa a uma doutrina de escrever testes de unidade para cada peça de funcionalidade.
Realmente, aderir servilmente a qualquer coisa pode ser prejudicial.
fonte
Isso é uma coisa pequena, mas: Preocupar-se sobre onde vão as chaves (na mesma linha ou na próxima linha?), Sugeriu comprimentos máximos de linha de código, convenções de nomenclatura para variáveis e outros elementos de estilo. Descobri que todos parecem se importar mais com isso do que eu, então sigo o fluxo de quem quer que esteja trabalhando hoje em dia.
Edit: A exceção é, é claro, quando sou eu quem mais se importa (ou quem está em posição de definir o estilo de um grupo). Nesse caso, faço o que quero!
(Observe que isso não é o mesmo que não ter estilo consistente. Acho que um estilo consistente em uma base de código é muito importante para facilitar a leitura.)
fonte
Talvez a "prática de programação" mais importante sobre a qual mudei de ideia desde então é a ideia de que meu código é melhor do que o de todo mundo. Isso é comum para programadores (especialmente iniciantes).
fonte
Bibliotecas de utilitários. Eu costumava carregar uma montagem com uma variedade de métodos e classes auxiliares com a teoria de que eu poderia usá-los em outro lugar algum dia.
Na verdade, acabei de criar um namespace enorme com muitas funcionalidades mal organizadas.
Agora, apenas os deixo no projeto em que os criei. Com toda probabilidade, não vou precisar disso e, se precisar, sempre posso refatorá-los em algo reutilizável mais tarde. Às vezes, vou sinalizá-los com um // TODO para possível extração em um assembly comum.
fonte
Projetando mais do que eu codifiquei. Depois de um tempo, torna-se uma paralisia da análise.
fonte
O uso de um DataSet para realizar a lógica de negócios. Isso vincula o código com muita força ao banco de dados, também o DataSet geralmente é criado a partir de SQL, o que torna as coisas ainda mais frágeis. Se o SQL ou o Banco de dados mudar, ele tende a escorrer para tudo o que o DataSet toca.
Executar qualquer lógica de negócios dentro de um construtor de objeto. Com herança e a capacidade de criar construtores sobrecarregados tendem a dificultar a manutenção.
fonte
Abreviando variável / método / tabela / ... Nomes
Eu costumava fazer isso o tempo todo, mesmo quando trabalhava em idiomas sem limite obrigatório de comprimento de nomes (bem, provavelmente eram 255 ou algo assim). Um dos efeitos colaterais foram muitos comentários espalhados por todo o código explicando as abreviações (não padronizadas). E, claro, se os nomes fossem alterados por qualquer motivo ...
Agora, prefiro muito mais chamar as coisas do que realmente são, com bons nomes descritivos. incluindo apenas abreviações padrão . Não há necessidade de incluir comentários inúteis, e o código é muito mais legível e compreensível.
fonte
Foo(int arg0, String arg1, float arg2)
etcEnvolvendo os componentes de acesso a dados existentes, como a biblioteca corporativa, com uma camada personalizada de métodos auxiliares.
fonte
Eu ouvi pela primeira vez sobre programação orientada a objetos enquanto lia sobre Smalltalk em 1984, mas não tive acesso a uma linguagem oo até usar o compilador cfront C ++ em 1992. Eu finalmente consegui usar Smalltalk em 1995. Eu esperava ansiosamente oo tecnologia e comprou a ideia de que isso economizaria o desenvolvimento de software.
Agora, eu apenas vejo oo como uma técnica que tem algumas vantagens, mas é apenas uma ferramenta na caixa de ferramentas. Eu faço a maior parte do meu trabalho em Python e freqüentemente escrevo funções autônomas que não são membros da classe, e freqüentemente coleto grupos de dados em tuplas ou listas onde no passado eu teria criado uma classe. Ainda crio classes quando a estrutura de dados é complicada ou preciso de um comportamento associado aos dados, mas tendo a resistir.
Na verdade, estou interessado em fazer algum trabalho em Clojure quando tiver tempo, o que não fornece recursos oo, embora possa usar objetos Java se eu entendi corretamente. Não estou pronto para dizer nada como oo está morto, mas pessoalmente não sou o fã que costumava ser.
fonte
Em C #, usando
_notation
para membros privados. Agora acho que é feio.Em seguida, mudei para
this.notation
para membros privados, mas descobri que era inconsistente ao usá-lo, então abandonei também.fonte
this
ouMe
(C # e VB.NET respectivamente) ao chamar métodos e propriedades. IMO, torna meu código mais fácil de ler e entender mais tarde, especialmente quando há quatro ou mais objetos dentro desse escopo específico.Eu parei de usar o método de design recomendado pela universidade antes da implementação. Trabalhar em um sistema caótico e complexo me forçou a mudar de atitude.
É claro que ainda faço pesquisas de código, especialmente quando estou prestes a mexer em um código que nunca toquei antes, mas normalmente tento me concentrar em implementações tão pequenas quanto possível para fazer algo funcionar primeiro. Este é o objetivo principal. Em seguida, refine gradualmente a lógica e deixe o design aparecer por si só. A programação é um processo iterativo e funciona muito bem com uma abordagem ágil e com muita refatoração.
O código não terá a aparência que você inicialmente pensou que seria. Acontece sempre :)
fonte
Eu costumava ser grande em design por contrato. Isso significou colocar muitas verificações de erros no início de todas as minhas funções. Os contratos ainda são importantes, do ponto de vista da separação de interesses, mas em vez de tentar impor o que meu código não deve fazer, tento usar testes de unidade para verificar o que ele faz.
fonte
Eu usaria estática em muitos métodos / classes, pois era mais conciso. Quando comecei a escrever testes, essa prática mudou muito rapidamente.
fonte
Exceções verificadas
Uma ideia incrível no papel - define o contrato de forma clara, sem margem para erros ou esquecimento de verificar alguma condição de exceção. Fui vendido quando soube disso.
Claro, acabou sendo uma bagunça na prática. A ponto de ter bibliotecas hoje como Spring JDBC, que tem como um de seus principais recursos ocultar exceções verificadas de legado.
fonte
Que tudo o que vale a pena só foi codificado em um idioma específico. No meu caso, eu acreditava que C era a melhor linguagem de todos os tempos e nunca tive motivo para codificar nada em qualquer outro idioma ... nunca.
Desde então, comecei a apreciar muitos idiomas diferentes e os benefícios / funcionalidades que eles oferecem. Se eu quiser codificar algo pequeno - rapidamente - eu usaria Python. Se eu quiser trabalhar em um grande projeto, codificaria em C ++ ou C #. Se eu quiser desenvolver um tumor no cérebro, codificaria em Perl .
fonte
Quando precisei fazer alguma refatoração, achei que era mais rápido e mais limpo começar imediatamente e implementar o novo design, consertando as conexões até que funcionassem. Então percebi que é melhor fazer uma série de pequenas refatorações para progredir de forma lenta, mas confiável, em direção ao novo design.
fonte
Talvez a maior mudança em minhas práticas de codificação, assim como em outras, seja a aceitação de classes e bibliotecas externas baixadas da internet como base para comportamentos e funcionalidades em aplicativos. Na escola, na época em que frequentei a faculdade, éramos incentivados a descobrir como melhorar as coisas por meio de nosso próprio código e confiar na linguagem para resolver nossos problemas. Com os avanços em todos os aspectos da interface do usuário e consumo de serviço / dados, essa não é mais uma noção realista.
Existem certas coisas que nunca irão mudar em uma linguagem, e ter uma biblioteca que envolve esse código em uma transação mais simples e em menos linhas de código que eu tenho que escrever é uma bênção. Conectar-se a um banco de dados sempre será o mesmo. A seleção de um elemento no DOM não mudará. O envio de um e-mail por meio de um script do lado do servidor nunca mudará. Ter que escrever isso uma e outra vez é uma perda de tempo que eu poderia usar para melhorar minha lógica central no aplicativo.
fonte
Inicializando todos os membros da classe.
Eu costumava inicializar explicitamente cada membro da classe com algo, geralmente NULL. Eu percebi que isto:
fonte
Como você, também adotei os padrões de IoC para reduzir o acoplamento entre vários componentes dos meus aplicativos. Isso torna a manutenção e a troca de peças muito mais simples, desde que eu consiga manter cada componente o mais independente possível. Também estou utilizando mais estruturas de objetos relacionais, como o NHibernate, para simplificar as tarefas de gerenciamento de banco de dados.
Em suma, estou usando "mini" frameworks para ajudar na construção de software de forma mais rápida e eficiente. Esses mini-frameworks economizam muito tempo e, se feitos da maneira certa, podem tornar a manutenção de um aplicativo extremamente simples. Plug 'n Play para a vitória!
fonte