As "melhores práticas" estão por toda parte em nosso setor. Uma pesquisa no Google sobre "práticas recomendadas de codificação" mostra quase 1,5 milhão de resultados. A idéia parece trazer conforto para muitos; basta seguir as instruções e tudo ficará bem.
Quando leio sobre uma prática recomendada - por exemplo, acabei de ler várias no Clean Code recentemente - fico nervoso. Isso significa que eu sempre deveria usar essa prática? Existem condições anexadas? Existem situações em que pode não ser uma boa prática? Como posso ter certeza até aprender mais sobre o problema?
Várias das práticas mencionadas no Código Limpo não se encaixam bem comigo, mas sinceramente não tenho certeza se isso é potencialmente ruim ou se é apenas o meu viés pessoal falando. Sei que muitas pessoas proeminentes na indústria de tecnologia parecem pensar que não existem práticas recomendadas ; portanto, pelo menos minhas dúvidas incômodas me colocam em boa companhia.
O número de práticas recomendadas sobre as quais eu li é simplesmente muito numeroso para listar aqui ou fazer perguntas individuais, portanto, gostaria de colocar isso como uma pergunta geral:
Quais práticas de codificação popularmente rotuladas como "melhores práticas" podem ser subótimas ou até prejudiciais sob certas circunstâncias? Quais são essas circunstâncias e por que elas tornam a prática ruim?
Eu preferiria ouvir sobre exemplos e experiências específicas.
fonte
Respostas:
Eu acho que você acertou a cabeça com esta declaração
Ignoro quase todas as práticas recomendadas quando não são fornecidas explicações sobre por que existem
Raymond Chen coloca melhor neste artigo quando ele diz
fonte
É melhor jogar isso no ringue:
Não, não é.
A citação completa:
Isso significa que você aproveita aprimoramentos específicos e estratégicos de desempenho em todo o processo de design. Isso significa que você usa estruturas de dados e algoritmos que são consistentes com os objetivos de desempenho. Isso significa que você está ciente das considerações de design que afetam o desempenho. Mas isso também significa que você não otimiza frivolamente ao fazê-lo, proporcionando ganhos menores à custa da manutenção.
Os aplicativos precisam ser bem arquitetados, para que não caiam no final quando você aplica um pouco de carga neles, e então você os reescreve. O perigo da citação abreviada é que, com muita frequência, os desenvolvedores a usam como desculpa para não pensar em desempenho até o final, quando pode ser tarde demais para fazer algo a respeito. É melhor obter um bom desempenho desde o início, desde que você não se concentre nas minúcias.
Digamos que você esteja criando um aplicativo em tempo real em um sistema incorporado. Você escolhe Python como a linguagem de programação, porque "A otimização prematura é a raiz de todos os males". Agora não tenho nada contra o Python, mas é uma linguagem interpretada. Se o poder de processamento for limitado, e uma certa quantidade de trabalho precisar ser realizada em tempo real ou quase em tempo real, e você escolher um idioma que exija mais poder de processamento para o trabalho do que o seu, você estará realmente ferrado, porque agora tem que começar de novo com uma linguagem capaz.
fonte
Um retorno por função / método.
fonte
return
declaração precoce . Estruturas de controle profundamente aninhadas ou verificações contínuas. Isso pode realmente inchar um método quando umif return
poderia realmente simplificar esse problema.Não reinventar a roda é um dogma amplamente mal utilizado. Sua idéia é que, se existir uma solução adequada, use-a em vez de criar a sua própria; além do esforço de economia, a solução existente provavelmente é melhor implementada (sem erros, eficiente, testada) do que a que você apresentaria inicialmente. Por enquanto, tudo bem.
O problema é que raramente existe uma solução 100% adequada. Uma solução adequada a 80% pode existir e usá-la provavelmente é boa. Mas que tal 60% adequado? 40%? Onde você desenha a linha? Se você não desenhar a linha, poderá acabar incorporando uma biblioteca inchada ao seu projeto porque está usando 10% de seus recursos - apenas porque deseja evitar "reinventar a roda".
Se você reinventar a roda, obterá exatamente o que deseja. Você também aprenderá a fazer rodas. Aprender fazendo não deve ser subestimado. E, no final, uma roda personalizada pode muito bem ser melhor que a roda genérica pronta para uso.
fonte
"Teste de unidade tudo".
Ouvi dizer muitas vezes que todo código deveria ter testes de unidade, um ponto em que não concordo. Quando você tem um teste para um método, qualquer alteração na saída ou estrutura desse método deve ser feita duas vezes (uma vez no código, uma vez no teste).
Como tal, os testes de unidade devem ser, na minha opinião, proporcionais à estabilidade estrutural do código. Se eu estiver escrevendo um sistema em camadas de baixo para cima, minha camada de acesso a dados terá testes do wazoo; minha camada de lógica de negócios será muito bem testada, minha camada de apresentação terá alguns testes e minhas visualizações terão pouco ou nenhum teste.
fonte
Sempre programe para interfaces.
Às vezes, haverá apenas uma implementação. Se atrasarmos o processo de extração de uma interface até o momento em que percebermos a necessidade, frequentemente descobriremos que ela não é necessária.
fonte
Não use nada de código aberto (ou que não seja da Microsoft para desenvolvedores .NET)
Se a Microsoft não a desenvolveu - não a usamos aqui. Deseja usar o ORM-EF, deseja usar o IOC-Unity, deseja registrar o bloco do aplicativo de log corporativo. Existem tantas bibliotecas melhores - mas eu sempre fico presa em pedidos no menu do mundo do desenvolvimento. Juro que sempre que ouço as Melhores Práticas da Microsoft, penso em "Diretrizes Nutricionais do McDonald's". Claro, você provavelmente viverá se os seguir, mas também estará desnutrido e com sobrepeso.
fonte
Orientação a objetos
Existe a suposição, apenas porque o código é "orientado a objetos", é magicamente bom. Então, as pessoas continuam pressionando a funcionalidade em classes e métodos, apenas para serem orientadas a objetos.
fonte
Todo o código deve ser comentado.
Não, não deveria ser. Algum tempo você tem um código óbvio, por exemplo, setters não devem ser comentados, até que façam algo especial. Além disso, por que devo comentar isso:
fonte
/** sets rank. */ void setRank(int rank) { this.rank = rank; }
, assumo o comentário como estúpido. Por que está escrito?/** */
serve o formato, em vez do/* */
comentário do formato. Ou, para o .NET seria///
}//end if
,}//end for
,}//end while
são o melhor exemplo de desperdício comentando que eu já encontrei. Eu já vi isso muitas vezes em que a chave de abertura não está mais do que 2 linhas acima. IMHO, se você precisar desses comentários, seu código precisará ser refatorado ... ou você precisará pagar US $ 20 e comprar um editor de IDE / Texto que destaque chaves correspondentes.Metodologias, particularmente scrum. Não consigo manter a cara séria quando ouço os adultos usarem a frase "Scrum Master". Fico tão cansado de ouvir desenvolvedores protestar que algum aspecto da Metodologia X não está funcionando para a empresa deles, apenas para ser informado pelo Guru So-and-So que a razão pela qual não está funcionando é que eles não são, de fato, verdadeiros praticantes da metodologia X. "Scrum mais difícil, você deve, meu aluno de Padawan!"
Existem pepitas de sabedoria nas metodologias ágeis - muitas delas -, mas elas são muitas vezes engolidas com tanto adubo que não posso combater meu reflexo de vômito. Veja esta parte da página scrum da Wikipedia :
Realmente? Porcos e galinhas, você diz? Fascinante! Mal posso esperar para lançar este aqui para o meu chefe ...
fonte
Mapeamento relacional de objetos ... http://en.wikipedia.org/wiki/Object-relational_mapping
Eu nunca quero ser abstraído dos meus dados, nem quero perder esse controle e otimização precisos. Minha experiência com esses sistemas tem sido extremamente ruim ... As consultas geradas por essas camadas de abstração são ainda piores do que as que vi fora do escoramento.
fonte
Escrever nomes de funções como se fossem frases em inglês:
etc. Isso pode parecer ótimo, mas é uma dor quando você está aprendendo uma API. Quão mais fácil é procurar em um índice por "Tudo o que começa com Foo"?
etc.
fonte
Foo.Draw()
,Foo.Write()
eFoo.Create()
, para que você pudesse fazerFoo.methods.sort
ouFoo.methods.grep([what I seek]).sort
MVC - costumo achar que colocar muitos problemas de design da web na abordagem MVC é mais sobre tornar um framework (trilhos etc.) feliz do que sobre simplicidade ou estrutura. O MVC é o favorito dos "astronautas da arquitetura" que parecem valorizar andaimes excessivos em detrimento da simplicidade. ymmv.
OO baseado em classe - na minha opinião incentiva estruturas complexas de estado mutável. os únicos casos convincentes que encontrei para OO baseado em classe ao longo dos anos são os brega "forma-> retângulo-> quadrado" exemplos que formam o capítulo 1 de qualquer livro de OO
fonte
Square(10).Draw()
isso é suficienteRectangle(10, 10).Draw()
. então acho que isso significa que quadrado é uma subclasse de retângulo. MasmySquare.setWidthHeight(5,10)
isso não faz sentido (ou seja, falha no princípio da substituição de Liskov), um quadrado não pode ter altura e largura diferentes, embora um retângulo possa, de modo que implica que esse retângulo é uma subclasse de quadrado. Isso é conhecido em outros contextos como o "Círculo, problema da elipse"YAGNI
( Você não vai precisar disso )
Essa abordagem me custou horas e horas em que eu tive que implementar recursos em uma base de código existente, onde um planejamento cuidadoso incluiria esses recursos antecipadamente.
As minhas idéias muitas vezes foram rejeitadas por causa do YAGNI, e na maioria das vezes alguém teve que pagar por essa decisão mais tarde.
(É claro que alguém poderia argumentar que uma base de código bem projetada também permitiria que recursos fossem adicionados posteriormente, mas a realidade é diferente)
fonte
Para SQL
Em ordem:
Eles são um recurso que tem seu lugar. Você possui vários caminhos de atualização para uma tabela ou requer auditoria 100%?
Só por que? Eu faria se estivesse refatorando para manter um contrato, mas não quando li que as pessoas mudam a visualização para corresponder a qualquer alteração na tabela
Editar:
Número 3: Evitando * com EXISTS. Tente 1/0. Funciona. A lista de colunas não é avaliada conforme o padrão SQL. Page 191
fonte
Padrões de design principalmente. Eles são muito utilizados e pouco utilizados.
fonte
O princípio da responsabilidade única
("toda classe deve ter apenas uma única responsabilidade; em outras palavras, toda classe deve ter um e apenas um motivo para mudar")
Discordo. Eu acho que um método deve ter apenas um motivo para mudar, e todos os métodos em uma classe devem ter um relacionamento lógico entre si , mas a própria classe pode realmente fazer várias coisas (relacionadas).
Na minha experiência, esse princípio muitas vezes é aplicado com zelo demais, e você acaba com muitas pequenas classes de método único. As duas lojas ágeis em que trabalhei fizeram isso.
Imagine se os criadores da API .Net tivessem esse tipo de mentalidade: em vez de List.Sort (), List.Reverse (), List.Find () etc., teríamos as classes ListSorter, ListReverser e ListSearcher!
Em vez de argumentar mais contra o SRP (o que em si não é terrível em teoria) , vou compartilhar algumas de minhas experiências anedóticas há muito tempo:
Em um local em que trabalhei, escrevi um solucionador de fluxo máximo muito simples que consistia em cinco classes: um nó, um gráfico, um criador de gráficos, um solucionador de gráficos e uma classe para usar o criador / solucionador de gráficos para resolver um problema. problema do mundo real. Nenhuma era particularmente complexa ou longa (o solucionador era de longe o mais longo, com ~ 150 linhas). No entanto, foi decidido que as classes tinham muitas "responsabilidades", então meus colegas de trabalho começaram a refatorar o código. Quando terminaram, minhas 5 classes foram expandidas para 25, cujas linhas de código totais eram mais do que o triplo do que eram originalmente. O fluxo do código não era mais óbvio, nem era o objetivo dos novos testes de unidade; Agora eu tinha dificuldade em descobrir o que meu próprio código fazia.
No mesmo local, quase todas as classes tinham apenas um único método (sua única "responsabilidade"). Seguir o fluxo dentro do programa era quase impossível, e a maioria dos testes de unidade consistia em testar se essa classe chamava código de outra classe , cujo objetivo era igualmente um mistério para mim. Havia literalmente centenas de classes onde deveria haver (IMO) apenas dezenas. Cada classe fez apenas uma "coisa" , mas mesmo com convenções de nomenclatura como "AdminUserCreationAttemptorFactory" , era difícil distinguir o relacionamento entre as classes.
Em outro lugar (que também tinha a mentalidade de que as classes deveriam ter apenas um método ), estávamos tentando otimizar um método que ocupava 95% do tempo durante uma determinada operação. Depois de (um tanto estupidamente) otimizá-lo um pouco, voltei minha atenção para o motivo de ser chamado de bajilhão de vezes. Ele estava sendo chamado em um loop em uma classe ... cujo método estava sendo chamado em um loop em outra classe .. que também estava sendo chamado em um loop ..
Ao todo, havia cinco níveis de loops espalhados por 13 classes (sério). O que qualquer classe realmente estava fazendo era impossível de determinar apenas olhando para ela - você tinha que esboçar um gráfico mental de quais métodos ela chamava e de quais métodos esses métodos chamavam, e assim por diante. Se tudo tivesse sido agrupado em um método, teria apenas cerca de 70 linhas com o nosso método-problema aninhado dentro de cinco níveis de loops imediatamente óbvios.
Meu pedido para refatorar essas 13 classes em uma classe foi negado.
fonte
Agora que você mencionou o Código Limpo, embora ele contenha algumas boas idéias, acho que sua obsessão em refatorar todos os métodos em submétodos e aqueles em subsubmetodos etc. foi levada longe demais. Em vez de alguns métodos de dez linhas, você deve preferir vinte one-liners (supostamente bem nomeadas). Obviamente alguém pensa que é limpo, mas para mim parece muito pior do que a versão original.
Além disso, substituindo coisas simples e elementares, como
dentro de uma classe com uma chamada para o próprio método da classe, como
é um questionável "melhoria" IMHO. Adição: A diferença é que a primeira verificação faz exatamente o que diz: verifica se o comprimento da matriz é 0. Ok, também
isEmpty()
pode verificar a duração da matriz. Mas também pode ser implementado assim:Ou seja, inclui uma verificação nula implícita! Esse pode ser um bom comportamento para um método público - se a matriz for nula, então algo certamente está vazio - mas quando estamos falando de informações internas da classe, isso não é tão bom. Embora o encapsulamento para o exterior seja obrigatório, os internos da classe devem saber exatamente o que está acontecendo dentro da classe. Você não pode encapsular a classe por si mesma . Explícito é melhor que implícito.
Isso não quer dizer que quebrar métodos longos ou envolver comparações lógicas não seja bom; é claro que sim, mas até que ponto fazê-lo - onde está o ponto ideal - é obviamente uma questão de gosto. Quebrar um método longo resulta em mais métodos, e isso não é de graça. Você precisa pular o código-fonte para ver o que realmente está acontecendo, quando você pode ver rapidamente se todas essas coisas estavam em um único método.
Eu diria até que, em alguns casos, um método de 1 linha é muito curto para merecer ser um método.
fonte
"Seja liberal com comentários"
Os comentários são definitivamente uma coisa boa, mas muitos são tão ruins se não piores do que suficientes. Por quê? Bem, as pessoas tendem a ignorar os comentários se veem muitos desnecessários. Não estou dizendo que você pode ter um código perfeitamente auto-documentado, mas é preferível codificar que precisa de comentários para explicação.
fonte
GoTo considerado prejudicial
Se você estiver implementando uma máquina de estado, uma instrução GOTO pode fazer mais sentido (legibilidade e código eficiente) do que uma abordagem de "programação estruturada". Isso realmente preocupou alguns colegas de trabalho quando o primeiro código que escrevi em um novo trabalho incluía não apenas uma, mas várias declarações goto. Felizmente, eles eram inteligentes o suficiente para perceber que era realmente a melhor solução nesse caso específico.
Qualquer "prática recomendada" que não permita exceções sensatas e documentadas a suas regras é simplesmente assustadora.
fonte
import re
Os sacrifícios que fazemos para tornar o código testável
Eu pulo muitos obstáculos para tornar meu código testável, mas não finjo que não faria se tivesse a opção. No entanto, muitas vezes ouço pessoas insistindo na ideia de que essas são "melhores práticas". Essas práticas incluem (escritas no idioma .Net, mas também se aplicam a outros idiomas) :
new MyClass()
é muito mais simples do que escrever uma fábrica, mas agora o método que a cria não pode ser testado isoladamente. Se não fosse por esse fato, eu faria apenas 1/20 do número de classes de fábrica que faço agora.Então, o que podemos fazer para corrigir isso? Precisamos de uma mudança drástica na arquitetura da linguagem:
Em resumo, precisamos de uma linguagem projetada desde o início com a testabilidade em mente .
fonte
Separando aplicativos em camadas; Camada de dados, camada de negócios, camada de interface do usuário
A principal razão pela qual não gosto disso é que a maioria dos lugares que seguem esse método usa estruturas muito frágeis para fazê-lo. O IE UI Layer é codificado manualmente para lidar com objetos da camada de negócios, os objetos da camada de negócios são codificados manualmente para lidar com regras e banco de dados de negócios, o banco de dados é SQL e já é bastante quebradiço e gerenciado pelo grupo "DBA" que não gosta de mudanças.
Por que isso é ruim? A solicitação de aprimoramento mais comum é provável "Preciso de um campo na tela X que tenha Y". Bang! Você tem apenas um novo recurso que afeta todas as camadas e, se você separar camadas com diferentes programadores, tornou-se um grande problema envolvendo várias pessoas e grupos, para uma mudança muito simples.
Além disso, não sei quantas vezes estive em argumentos que são mais ou menos assim. "O campo de nome é limitado a um comprimento máximo de 30, é um problema da camada da interface do usuário, da camada de negócios ou da camada de dados?" E há cem argumentos, e não há resposta certa. A resposta é a mesma, ela afeta todas as camadas, você não quer mudar a interface do usuário, precisa passar por todas as camadas e falhar no banco de dados, apenas para que o usuário descubra que sua entrada é muito longa. Se você mudar, isso afeta todas as camadas, etc.
As "camadas" tendem a vazar também; Se qualquer camada for fisicamente separada pelos limites do processo / máquina (UI da web do IE e lógica de back-end comercial), as regras serão duplicadas para que tudo funcione razoavelmente bem. Ou seja, alguma lógica de negócios acaba na interface do usuário, mesmo que seja uma "regra de negócios", porque o usuário precisa que a interface do usuário seja responsiva.
Se a estrutura usada ou a arquitetura usada for resiliente a pequenas alterações e vazamentos, ou seja, com base em metadados e ajustada dinamicamente em todas as camadas, pode ser menos dolorosa. Mas na maioria das estruturas, isso é uma dor real, exigindo alterações na interface do usuário, alterações na camada de negócios e alterações no banco de dados, a cada pequena alteração, causando mais trabalho e menos ajuda do que a técnica deveria produzir.
Provavelmente vou ser criticado por isso, mas aí está :)
fonte
JavaBeans
O uso do JavaBeans em Java. Veja minha pergunta Por que não devo usar POJOs imutáveis em vez de JavaBeans? no StackOverflow.
fonte
Histórias de usuários / casos de uso / personas
Entendo a necessidade disso quando você está programando para um setor com o qual não está familiarizado, mas acho que, quando implementados com força total, tornam-se muito corporativos e perdem tempo.
fonte
Limites de 80 caracteres / linha são burros
Entendo que alguns compromissos precisam ser feitos para corresponder ao ritmo do corredor mais lento do lado da GUI (limitações de resolução de tela etc.), mas, por que essa regra se aplica à formatação de código?
Veja ... Havia uma pequena invenção chamada barra de rolagem horizontal que foi criada para gerenciar o espaço da tela virtual fora do limite de pixels mais à direita. Por que os desenvolvedores, que conseguiram criar excelentes ferramentas de aprimoramento da produtividade, como destaque de sintaxe e preenchimento automático, não o usam?
Certamente, existem editores de CLI usados religiosamente pelos dinossauros * nix que seguem as antigas limitações cansadas de seus terminais VT220, mas por que o restante de nós é mantido no mesmo padrão?
Eu digo, estrague o limite de 80 caracteres. Se os dinossauros são épicos o suficiente para invadir o emacs / vim o dia todo, por que não é possível criar uma extensão que quebra linhas automaticamente ou fornece recursos de rolagem horizontal para seus IDEs de CLI?
Os monitores de pixel de 1920x1080 acabarão se tornando a norma e os desenvolvedores em todo o mundo ainda vivem sob as mesmas limitações, sem importar o porquê, exceto isso, é o que eles disseram aos seus anciãos quando estavam começando a programar.
Os limites de 80 caracteres não são uma prática recomendada, mas uma prática de nicho para uma minoria de programadores e devem ser tratados como tal.
Editar:
É compreensível que muitos desenvolvedores não gostem da barra de rolagem horizontal porque requer um gesto do mouse, então ... Por que não aumentar o limite da largura da coluna para um número maior (que 80) para aqueles que usam telas modernas.
Quando os monitores de computador 800x600 se tornaram a norma para a maioria dos usuários, os desenvolvedores da Web aumentaram as larguras de seus sites para acomodar a maioria ... Por que os desenvolvedores não podem fazer o mesmo.
fonte
Medida, Medida, Medida
Tão bem, meça a distância, mas para isolar os erros de desempenho, a medição funciona tanto quanto a eliminação sucessiva. Aqui está o método que eu uso.
Eu tenho tentado rastrear a fonte da "medida" medida "sabedoria". Alguém com uma caixa de sabão alta o suficiente disse isso e agora ela viaja.
fonte
Meu professor exige que eu inicie todos os meus identificadores (sem incluir constantes) com letras minúsculas, por exemplo
myVariable
.Eu sei que parece uma coisa pequena, mas muitas linguagens de programação exigem variáveis para começar com letras maiúsculas. Eu valorizo a consistência, por isso é um hábito meu começar tudo com letras maiúsculas.
fonte
Use Singletons
Quando você deve ter apenas uma instância de alguma coisa. Não posso discordar mais. Nunca use um singleton e apenas aloque-o uma vez e passe o ponteiro / objeto / referência conforme necessário. Não há absolutamente nenhuma razão para não fazer isso.
fonte
Usando int não assinado como iterador
Quando eles aprenderão que usar o int assinado é muito mais seguro e menos propenso a erros. Por que é tão importante que o índice de matriz possa ser apenas um número positivo, que todos tenham prazer em ignorar o fato de que 4 - 5 é 4294967295?
fonte
0
é diminuído por1
, você realmente acaba com o valor positivo máximo que um int não assinado pode armazenar?Os métodos não devem ter mais que uma única tela
Concordo totalmente com o princípio da responsabilidade única, mas por que as pessoas o percebem como "uma função / método não pode ter mais do que uma única responsabilidade no mais alto nível de granularidade lógica"?
A ideia é simples. Uma função / método deve realizar uma tarefa. Se parte dessa função / método puder ser usada em outro lugar, corte-a em sua própria função / método. Se puder ser usado em outro lugar do projeto, mova-o para sua própria classe ou classe de utilidade e torne-o acessível internamente.
Ter uma classe que contém 27 métodos auxiliares que são chamados apenas uma vez no código é idiota, um desperdício de espaço, um aumento desnecessário na complexidade e um grande tempo gasto. Parece mais uma boa regra para pessoas que querem parecer ocupadas refatorando código, mas não produzem muito.
Aqui está a minha regra ...
Escreva funções / métodos para realizar algo
Se você estiver prestes a copiar / colar algum código, pergunte-se se seria melhor criar uma função / método para esse código. Se uma função / método é chamada apenas uma vez em outra função / método, existe realmente um ponto em tê-la em primeiro lugar (será chamada com mais frequência no futuro). É valioso adicionar mais saltos dentro / fora das funções / métodos durante a depuração (ou seja, o salto adicionado torna a depuração mais fácil ou mais difícil)?
Concordo plenamente que funções / métodos maiores que 200 linhas precisam ser examinadas, mas algumas funções realizam apenas uma tarefa em tantas linhas e não contêm partes úteis que possam ser abstraídas / usadas no restante do projeto.
Eu olho para ele da perspectiva de um desenvolvedor de API ... Se um novo usuário examinasse o diagrama de classes do seu código, quantas partes desse diagrama fariam sentido no conjunto maior do projeto e quantas existiriam apenas como auxiliares de outras partes internas do projeto.
Se eu escolher entre dois programadores: o primeiro tem tendência a escrever funções / métodos que tentam fazer demais; o segundo divide cada parte de cada função / método no mais alto nível de granularidade; Eu escolheria as primeiras mãos para baixo. O primeiro realizaria mais (ou seja, escreveria mais detalhes do aplicativo), seu código seria mais fácil de depurar (devido a menos saltos dentro / fora de funções / métodos durante a depuração), e ele perderia menos tempo fazendo um trabalho ocupado, aperfeiçoando como o código parece vs aperfeiçoar como o código funciona.
Limite abstrações desnecessárias e não polua o preenchimento automático.
fonte