Nota do moderador
Esta pergunta já teve dezessete respostas postadas nela. Antes de postar uma nova resposta, leia as respostas existentes e verifique se o seu ponto de vista ainda não está coberto adequadamente.
Eu tenho seguido algumas das práticas recomendadas no livro "Código Limpo" de Robert Martin, especialmente as que se aplicam ao tipo de software com o qual trabalho e as que fazem sentido para mim (não o sigo como dogma) .
Um efeito colateral que notei, no entanto, é que o código "limpo" que escrevo é mais código do que se eu não seguisse algumas práticas. As práticas específicas que levam a isso são:
- Encapsulando condicionais
Então, ao invés de
if(contact.email != null && contact.emails.contains('@')
Eu poderia escrever um pequeno método como este
private Boolean isEmailValid(String email){...}
- Substituindo um comentário embutido por outro método privado, para que o nome do método se descreva em vez de ter um comentário embutido sobre ele
- Uma classe deve ter apenas um motivo para mudar
E alguns outros. O ponto é que, o que poderia ser um método de 30 linhas, acaba sendo uma classe, por causa dos métodos minúsculos que substituem comentários e encapsulam condicionais, etc. Quando você percebe que tem tantos métodos, "faz sentido" coloque toda a funcionalidade em uma classe, quando realmente deveria ter sido um método.
Estou ciente de que qualquer prática levada ao extremo pode ser prejudicial.
A pergunta concreta que eu estou procurando uma resposta é:
Esse é um subproduto aceitável da escrita de código limpo? Em caso afirmativo, quais são alguns argumentos que posso usar para justificar o fato de que mais LOC foram escritos?
A organização não está preocupada especificamente com mais LOC, mas mais LOC pode resultar em classes muito grandes (que, novamente, podem ser substituídas por um método longo sem várias funções auxiliares de uso único para facilitar a leitura).
Quando você vê uma classe que é grande o suficiente, dá a impressão de que a classe está ocupada o suficiente e que sua responsabilidade foi concluída. Você pode, portanto, acabar criando mais classes para obter outras partes da funcionalidade. O resultado são muitas classes, todas fazendo "uma coisa" com a ajuda de muitos métodos auxiliares pequenos.
Essa é a preocupação específica ... essas classes podem ser uma classe única que ainda alcança "uma coisa", sem a ajuda de muitos métodos pequenos. Pode ser uma aula única com talvez 3 ou 4 métodos e alguns comentários.
fonte
Respostas:
Esse pessoal identificou algo corretamente: eles querem que o código seja mais fácil de manter. Onde eles deram errado, porém, está assumindo que quanto menos código houver, mais fácil será manter.
Para que o código seja fácil de manter, ele precisa ser fácil de alterar. De longe, a maneira mais fácil de obter código fácil de alterar é ter um conjunto completo de testes automatizados, que falharão se a alteração for uma alteração. Os testes são código, portanto, escrever esses testes aumentará sua base de códigos. E isso é uma coisa boa.
Em segundo lugar, para descobrir o que precisa ser alterado, o código precisa ser fácil de ler e fácil de raciocinar. Código muito conciso, reduzido em tamanho apenas para manter a contagem de linhas baixa é muito improvável que seja fácil de ler. Obviamente, existe um compromisso a ser alcançado, pois um código mais longo levará mais tempo para ser lido. Mas se é mais rápido entender, vale a pena. Se não oferecer esse benefício, essa verbosidade deixará de ser um benefício. Mas se um código mais longo melhorar a legibilidade, novamente isso é uma coisa boa.
fonte
Sim, é um subproduto aceitável, e a justificativa é que agora está estruturado de forma que você não precisa ler a maior parte do código na maioria das vezes. Em vez de ler uma função de 30 linhas toda vez que estiver fazendo uma alteração, você está lendo uma função de 5 linhas para obter o fluxo geral e talvez algumas das funções auxiliares se sua alteração tocar nessa área. Se sua nova classe "extra" for chamada
EmailValidator
e você souber que seu problema não está na validação de email, você pode pular a leitura.Também é mais fácil reutilizar peças menores, o que tende a reduzir a contagem de linhas em todo o programa. Um
EmailValidator
pode ser usado em todo o lugar. Algumas linhas de código que validam e-mails, mas são agrupadas com o código de acesso ao banco de dados, não podem ser reutilizadas.E considere o que precisa ser feito se as regras de validação de email precisarem ser alteradas - o que você prefere: um local conhecido; ou muitos locais, possivelmente faltando alguns?
fonte
iterations < _maxIterations
para um método chamadoShouldContinueToIterate
é estúpido .É famoso o fato de Bill Gates ter dito: "Medir o progresso da programação por linhas de código é como medir o progresso da construção de aeronaves em peso".
Eu humildemente concordo com esse sentimento. Isso não quer dizer que um programa deva se esforçar por mais ou menos linhas de código, mas que isso não é o que conta para criar um programa que funcione e funcione. É bom lembrar que, em última análise, a razão por trás da adição de linhas extras de código é que é teoricamente mais legível dessa maneira.
Pode haver discordâncias sobre se uma alteração específica é mais ou menos legível, mas não acho que você esteja errado em fazer uma alteração em seu programa, porque, ao fazê-lo, está tornando-a mais legível. Por exemplo, fazer um
isEmailValid
pode ser considerado supérfluo e desnecessário, especialmente se for chamado exatamente uma vez pela classe que o define. No entanto, eu preferiria ver umaisEmailValid
condição em vez de uma série de condições ANDed, na qual devo determinar o que cada condição individual verifica e por que está sendo verificada.O problema é quando você cria um
isEmailValid
método que tem efeitos colaterais ou verifica outras coisas além do email, porque isso é pior do que simplesmente escrever tudo. É pior porque é enganoso e eu posso perder um bug por causa disso.Embora claramente você não esteja fazendo isso neste caso, gostaria de encorajá-lo a continuar como está fazendo. Você deve sempre se perguntar se, fazendo a alteração, é mais fácil de ler e, se esse for o seu caso, faça-o!
fonte
É uma questão de perder de vista o objetivo real.
O que importa é diminuir as horas gastas em desenvolvimento . Isso é medido no tempo (ou esforço equivalente), não nas linhas de código.
É como dizer que os fabricantes de automóveis devem fabricar seus carros com menos parafusos, porque leva um tempo diferente de zero para colocar cada parafuso. Enquanto isso é pedanticamente correto, o valor de mercado de um carro não é definido por quantos parafusos ele faz. ou não tem. Acima de tudo, um carro precisa ter desempenho, segurança e facilidade de manutenção.
O restante da resposta são exemplos de como o código limpo pode levar a ganhos de tempo.
Exploração madeireira
Pegue um aplicativo (A) que não possui registro. Agora crie o aplicativo B, que é o mesmo aplicativo A, mas com o log. B sempre terá mais linhas de código e, portanto, você precisará escrever mais código.
Mas muito tempo será dedicado à investigação de problemas e bugs e à descoberta do que deu errado.
Para o aplicativo A, os desenvolvedores ficam presos lendo o código e tendo que reproduzir continuamente o problema e percorrer o código para encontrar a origem do problema. Isso significa que o desenvolvedor deve testar desde o início da execução até o final, em todas as camadas usadas, e precisa observar todas as peças lógicas usadas.
Talvez ele tenha sorte de encontrá-lo imediatamente, mas talvez a resposta esteja no último lugar que ele pensa em procurar.
Para o aplicativo B, assumindo um log perfeito, um desenvolvedor observa os logs, pode identificar imediatamente o componente defeituoso e agora sabe onde procurar.
Isso pode ser uma questão de minutos, horas ou dias economizados; dependendo do tamanho e da complexidade da base de código.
Regressões
Tome o aplicativo A, que não é compatível com SECA.
Tome o aplicativo B, que é SECO, mas acabou precisando de mais linhas por causa das abstrações adicionais.
Uma solicitação de mudança é arquivada, o que requer uma alteração na lógica.
Para o aplicativo B, o desenvolvedor altera a lógica (exclusiva, compartilhada) de acordo com a solicitação de mudança.
Para o aplicativo A, o desenvolvedor precisa alterar todas as instâncias dessa lógica em que se lembra de ter sido usada.
Isso pode levar a um enorme desperdício de tempo. Não apenas no desenvolvimento, mas em caçar e encontrar o bug. O aplicativo pode começar a se comportar de maneira irregular, de uma maneira que os desenvolvedores não possam entender facilmente. E isso levará a longas sessões de depuração.
Intercambiabilidade do desenvolvedor
Desenvolvedor A. Aplicativo criado A. O código não é limpo nem legível, mas funciona como um encanto e está sendo executado em produção. Sem surpresa, também não há documentação.
O desenvolvedor A está ausente por um mês devido a feriados. Uma solicitação de mudança de emergência é arquivada. Não pode esperar mais três semanas para o Dev A retornar.
O desenvolvedor B precisa executar essa alteração. Ele agora precisa ler toda a base de código, entender como tudo funciona, por que funciona e o que tenta realizar. Isso leva séculos, mas digamos que ele possa fazer isso em três semanas.
Ao mesmo tempo, o aplicativo B (que o desenvolvedor B criou) tem uma emergência. O Dev B está ocupado, mas o Dev C está disponível, mesmo que ele não conheça a base de código. O que nós fazemos?
O desenvolvedor A volta de suas férias e vê que B não entendeu o código e, portanto, o implementou mal. Não é culpa de B, porque ele usou todos os recursos disponíveis, o código fonte simplesmente não era suficientemente legível. A agora precisa gastar tempo corrigindo a legibilidade do código?
Todos esses problemas, e muitos mais, acabam perdendo tempo . Sim, a curto prazo, o código limpo exige mais esforço agora , mas acabará pagando dividendos no futuro quando erros / alterações inevitáveis precisarem ser resolvidos.
A gerência precisa entender que uma tarefa curta agora economizará várias tarefas longas no futuro. Falhar no planejamento é planejar para falhar.
Minha explicação a seguir é perguntar à gerência o que eles prefeririam: um aplicativo com uma base de código de 100KLOC que pode ser desenvolvida em três meses ou uma base de código de 50KLOC que pode ser desenvolvida em seis meses.
Obviamente, eles escolherão o menor tempo de desenvolvimento, porque o gerenciamento não se importa com o KLOC . Os gerentes que se concentram no KLOC são microgerenciados e informados sobre o que estão tentando gerenciar.
fonte
Eu acho que você deve ter muito cuidado ao aplicar práticas de "código limpo", caso elas levem a mais complexidade geral. A refatoração prematura é a raiz de muitas coisas ruins.
A extração de uma condicional para uma função leva a um código mais simples no ponto em que a condicional foi extraída , mas leva a uma complexidade mais geral, porque agora você tem uma função que é visível a partir de mais pontos no programa. Você adiciona uma carga de complexidade leve a todas as outras funções em que essa nova função agora está visível.
Não estou dizendo que você não deve extrair o condicional, apenas que você deve considerar cuidadosamente se precisar.
Em todas as opções acima, há uma razão para a extração além de ser apenas "código limpo". Além disso, você provavelmente nem ficaria em dúvida se era a coisa certa a fazer.
Eu diria que, em caso de dúvida, sempre escolha o código mais simples e direto.
fonte
Eu apontaria que não há nada inerentemente errado com isso:
Pelo menos assumindo que é usado desta vez.
Eu poderia ter problemas com isso muito facilmente:
Algumas coisas pelas quais eu observaria:
Se estiver sendo usado uma vez, é simples de analisar e leva menos de uma linha, eu adivinharia a decisão. Provavelmente não é algo que eu chamaria se não fosse um problema específico de uma equipe.
Por outro lado, vi métodos fazerem algo assim:
Esse exemplo obviamente não é SECO.
Ou mesmo apenas essa última declaração pode dar outro exemplo:
O objetivo deve ser tornar o código mais legível:
Outro cenário:
Você pode ter um método como:
Se isso se encaixa na lógica de negócios e não é reutilizado, não há problema aqui.
Mas quando alguém pergunta "Por que o '@' é salvo, porque isso não está certo!" e você decide adicionar alguma validação real e extraí-la!
Você ficará satisfeito quando tiver também que prestar contas da segunda conta de e-mail dos presidentes Pr3 $ sid3nt @ h0m3! @ Mydomain.com e decidir se empenhar e tentar apoiar a RFC 2822.
Sobre legibilidade:
Se seu código estiver claro, você não precisa de comentários aqui. Na verdade, você não precisa de comentários para dizer o que o código está fazendo na maioria das vezes, mas sim por que está fazendo:
Se os comentários acima de uma declaração if ou dentro de um método minúsculo são para mim, pedantes. Eu poderia até argumentar o contrário de útil com bons comentários dentro de outro método, porque agora você teria que navegar para outro método para ver como e por que ele faz o que faz.
Em resumo: não meça essas coisas; Concentre-se nos princípios dos quais o texto foi criado (SECO, SÓLIDO, BEIJO).
fonte
Whether the comments above an if statement or inside a tiny method is to me, pedantic.
Esse é um problema do "canudo que quebrou as costas do camelo". Você está certo que essa coisa não é particularmente difícil de ler completamente. Mas se você tem um método grande (por exemplo, uma grande importação) que tem dezenas de estas pequenas avaliações, tendo estes encapsulado em nomes de métodos legível (IsUserActive
,GetAverageIncome
,MustBeDeleted
, ...) se tornará uma melhora notável na leitura do código. O problema com o exemplo é que ele observa apenas um canudo, não o pacote inteiro que quebra as costas do camelo.if (contact.email != null && contact.email.contains('@'))
é incorreto. Se o if for falso, nenhuma das outras linhas poderá ser verdadeira. Isso não é visível noLooksSortaLikeAnEmail
bloco. Uma função que contém uma única linha de código não é muito melhor do que um comentário explicando como a linha funciona.O Código Limpo é um excelente livro e vale a pena ler, mas não é a autoridade final sobre tais assuntos.
Dividir o código em funções lógicas geralmente é uma boa idéia, mas poucos programadores fazem isso da mesma forma que Martin - em algum momento, você obtém retornos decrescentes ao transformar tudo em funções e pode ser difícil de seguir quando todo o código é minúsculo peças.
Uma opção quando não vale a pena criar uma função totalmente nova é simplesmente usar uma variável intermediária:
Isso ajuda a manter o código fácil de seguir sem ter que pular muito o arquivo.
Outra questão é que o Clean Code está ficando velho como um livro agora. Muita engenharia de software avançou na direção da programação funcional, enquanto Martin se esforça para adicionar estado às coisas e criar objetos. Eu suspeito que ele teria escrito um livro completamente diferente se o tivesse escrito hoje.
fonte
Considerando o fato de que a condição "é válido por email", você atualmente aceita o endereço de email inválido "
@
", acho que você tem todos os motivos para abstrair uma classe EmailValidator. Melhor ainda, use uma biblioteca boa e bem testada para validar endereços de email.Linhas de código como métrica não fazem sentido. As questões importantes na engenharia de software não são:
As questões importantes são:
Nunca pensei em LoC ao escrever código para qualquer finalidade, exceto o Code Golf. Eu me perguntei "Eu poderia escrever isso de forma mais sucinta?", Mas, para fins de legibilidade, manutenção e eficiência, não apenas o comprimento.
Claro, talvez eu possa usar uma longa cadeia de operações booleanas em vez de um método utilitário, mas devo?
Sua pergunta realmente me faz pensar em algumas longas cadeias de booleanos que escrevi e percebi que provavelmente deveria ter escrito um ou mais métodos utilitários.
fonte
Em um nível, eles estão certos - menos código é melhor. Outra resposta citada Gate, eu prefiro:
Em resumo, quanto menos código você tiver, menos poderá dar errado. Se algo não for necessário, corte-o.
Se houver código muito complicado, simplifique-o até que os elementos funcionais reais sejam tudo o que resta.
O que é importante aqui é que todos eles se referem à funcionalidade e possuem apenas o mínimo necessário para fazê-lo. Não diz nada sobre como isso é expresso.
O que você está fazendo tentando ter um código limpo não é contra o acima. Você está adicionando ao seu LOC, mas não adicionando funcionalidades não utilizadas.
O objetivo final é ter um código legível, mas sem extras supérfluos. Os dois princípios não devem agir um contra o outro.
Uma metáfora estaria construindo um carro. A parte funcional do código é o chassi, o motor, as rodas ... o que faz o carro funcionar. Como você divide isso é mais parecido com a suspensão, a direção hidráulica e assim por diante, facilita o manuseio. Você deseja que sua mecânica seja a mais simples possível, enquanto ainda executa seu trabalho, para minimizar a chance de as coisas darem errado, mas isso não impede que você tenha bons assentos.
fonte
Há muita sabedoria nas respostas existentes, mas eu gostaria de acrescentar mais um fator: a linguagem .
Alguns idiomas usam mais código que outros para obter o mesmo efeito. Em particular, enquanto Java (que eu suspeito ser a linguagem em questão) é extremamente conhecido e geralmente muito sólido, claro e direto, algumas linguagens mais modernas são muito mais concisas e expressivas.
Por exemplo, em Java, seria fácil levar 50 linhas para escrever uma nova classe com três propriedades, cada uma com um getter e setter e um ou mais construtores - enquanto você pode realizar exatamente o mesmo em uma única linha do Kotlin * ou Scala. (Ainda maior poupança se você também queria adequados
equals()
,hashCode()
etoString()
métodos.)O resultado é que, em Java, o trabalho extra significa que é mais provável que você reutilize um objeto geral que realmente não se encaixa, espremer propriedades em objetos existentes ou transmitir um monte de propriedades "vazias" individualmente; enquanto estiver em uma linguagem concisa e expressiva, é mais provável que você escreva um código melhor.
(Isso destaca a diferença entre a complexidade "superficial" do código e a complexidade das idéias / modelos / processamento que ele implementa. As linhas de código não são uma medida ruim da primeira, mas têm muito menos a ver com a segunda .)
Portanto, o "custo" de fazer as coisas certas depende do idioma. Talvez um sinal de uma boa linguagem seja aquele que não faça você escolher entre fazer bem as coisas e fazê-las simplesmente!
(* Este não é realmente o lugar para um plugue, mas vale a pena conferir Kotlin IMHO.)
fonte
Vamos supor que você esteja trabalhando com a classe
Contact
atualmente. O fato de você estar escrevendo outro método para validação do endereço de email é uma prova do fato de que a classeContact
não está lidando com uma única responsabilidade.Ele também está lidando com alguma responsabilidade por email, que idealmente deve ser de sua própria classe.
Outra prova de que seu código é uma fusão
Contact
eEmail
classe é que você não poderá testar facilmente o código de validação de email. Isso exigirá muitas manobras para alcançar o código de validação de email em um grande método com os valores corretos. Veja o método viz abaixo.Por outro lado, se você tivesse uma classe de email separada com um método para validação de email, para testar o seu código de validação, basta fazer uma chamada simples
Email.Validation()
com seus dados de teste.Conteúdo bônus: o discurso do MFeather sobre a profunda sinergia entre testabilidade e bom design.
fonte
Verificou-se que a redução no LOC está correlacionada com defeitos reduzidos, nada mais. Supondo que, sempre que você reduz o LOC, você reduziu a chance de defeitos essencialmente caindo na armadilha de acreditar que a correlação é igual a causação. O LOC reduzido é o resultado de boas práticas de desenvolvimento e não o que torna o código bom.
Na minha experiência, as pessoas que podem resolver um problema com menos código (no nível macro) tendem a ser mais hábeis do que aquelas que escrevem mais código para fazer a mesma coisa. O que esses desenvolvedores qualificados fazem para reduzir as linhas de código é usar / criar abstrações e soluções reutilizáveis para resolver problemas comuns. Eles não gastam tempo contando linhas de código e agonizando sobre se podem cortar uma linha aqui ou ali. Muitas vezes, o código que eles escrevem é mais detalhado do que o necessário, eles apenas escrevem menos.
Deixe-me lhe dar um exemplo. Eu tive que lidar com a lógica em torno de períodos de tempo e como eles se sobrepõem, se são adjacentes e que lacunas existem entre eles. Quando comecei a trabalhar nesses problemas, eu teria blocos de código fazendo os cálculos em todos os lugares. Eventualmente, construí classes para representar os períodos e operações que calculavam sobreposições, complementos etc. Isso removeu imediatamente grandes faixas de código e as transformou em algumas chamadas de método. Mas essas aulas em si não foram escritas de maneira concisa.
Declarando claramente: se você está tentando reduzir o LOC, tentando cortar uma linha de código aqui ou ali com mais concisão, está fazendo errado. É como tentar perder peso, reduzindo a quantidade de vegetais que você come. Escreva um código fácil de entender, manter, depurar e reduzir o LOC por meio da reutilização e abstração.
fonte
Você identificou uma compensação válida
Portanto, existe de fato uma troca aqui e é inerente à abstração como um todo. Sempre que alguém tenta colocar N linhas de código em sua própria função para nomeá-lo e isolá-lo, simultaneamente facilita a leitura do site de chamada (referindo-se a um nome e não a todos os detalhes sangrentos subjacentes a esse nome) e mais complexo (agora você tem um significado emaranhado em duas partes diferentes da base de código). "Fácil" é o oposto de "difícil", mas não é sinônimo de "simples", que é o oposto de "complexo". Os dois não são opostos, e a abstração sempre aumenta a complexidade para inserir uma forma ou outra de facilidade.
Podemos ver a complexidade adicional diretamente quando alguma mudança nos requisitos de negócios faz com que a abstração comece a vazar. Talvez alguma nova lógica tenha sido mais natural no meio do código pré-abstraído, digamos, por exemplo, se o código abstraído atravessa alguma árvore e você realmente gostaria de coletar (e talvez agir sobre) algum tipo de informação enquanto está atravessando a árvore. Enquanto isso, se você abstraiu esse código, pode haver outros sites de chamada, e a adição da lógica necessária no meio do método pode interromper esses outros sites de chamada. Veja, sempre que alteramos uma linha de código, precisamos apenas olhar para o contexto imediato dessa linha de código; quando alteramos um método, devemos Cmd-F todo o nosso código-fonte procurando por algo que possa quebrar como resultado da alteração do contrato desse método,
O algoritmo ganancioso pode falhar nesses casos
A complexidade também tornou o código, em certo sentido, menos legível em vez de mais. Em um trabalho anterior, lidei com uma API HTTP estruturada com muito cuidado e precisão em várias camadas, cada ponto de extremidade é especificado por um controlador que valida a forma da mensagem recebida e a entrega a algum gerente da "camada de lógica de negócios" , que solicitou uma "camada de dados" responsável por fazer várias consultas a uma camada de "objeto de acesso a dados", responsável pela criação de vários delegados SQL que realmente responderiam à sua pergunta. A primeira coisa que posso dizer sobre isso foi que algo como 90% do código foi copiado e colado, ou seja, não era uma operação. Portanto, em muitos casos, a leitura de qualquer passagem de código era muito "fácil", porque "oh, esse gerente apenas encaminha a solicitação para esse objeto de acesso a dados".muita troca de contexto e localização de arquivos e tentativa de rastrear informações que você nunca deveria estar rastreando ", isso é chamado X nesta camada, ele se chama X 'nessa outra camada e depois é chamado X' 'nessa outra outra camada ".
Acho que quando parei, essa simples API CRUD estava no estágio em que, se você a imprimisse a 30 linhas por página, seriam necessários 10 a 20 livros de quinhentos páginas em uma prateleira: era uma enciclopédia inteira código. Em termos de complexidade essencial, não tenho certeza de que havia metade de um livro de complexidade essencial; tivemos apenas 5-6 diagramas de banco de dados para lidar com isso. Fazer qualquer alteração leve era uma tarefa gigantesca, aprender que era uma tarefa gigantesca, a adição de novas funcionalidades era tão dolorosa que, na verdade, tínhamos arquivos de modelo padrão que usaríamos para adicionar novas funcionalidades.
Então, eu vi em primeira mão como tornar cada parte muito legível e óbvia pode tornar o todo muito ilegível e não óbvio. Isso significa que o algoritmo ganancioso pode falhar. Você conhece o algoritmo ganancioso, sim? "Eu darei qualquer passo que melhore a situação localmente e depois confiarei em uma situação globalmente melhorada". Geralmente, é uma bela primeira tentativa, mas também pode faltar em contextos complexos. Por exemplo, na fabricação, você pode tentar aumentar a eficiência de cada etapa específica de um complexo processo de fabricação - faça lotes maiores, grite com as pessoas que parecem não estar fazendo nada para ocupar as mãos com outra coisa - e isso geralmente pode destruir a eficiência global do sistema.
Prática recomendada: use DRY e comprimentos para fazer a chamada
(Nota: o título desta seção é uma piada; muitas vezes digo aos meus amigos que quando alguém está dizendo "devemos fazer X porque as práticas recomendadas o fazem", 90% do tempo não está falando sobre algo como injeção SQL ou hash de senha ou o que quer que seja - práticas recomendadas unilaterais - e, portanto, a declaração pode ser traduzida em 90% do tempo para "deveríamos fazer X porque eu o digo ". Como se eles pudessem ter algum artigo de blog de alguma empresa que fez um trabalho melhor com X em vez de X ', mas geralmente não há garantia de que sua empresa se assemelhe a essa, e geralmente há algum outro artigo de outra empresa que fez um trabalho melhor com X' em vez de X. Portanto, não tome o título também a sério.)
O que eu recomendaria é baseado em uma palestra de Jack Diederich chamada Stop Writing Classes (youtube.com) . Ele faz vários pontos importantes nessa conversa: por exemplo, que você pode saber que uma classe é realmente apenas uma função quando ela possui apenas dois métodos públicos, e um deles é o construtor / inicializador. Mas, em um caso, ele está falando sobre como uma biblioteca hipotética que ele substituiu por string como "Muffin" declarou sua própria classe "MuffinHash", que era uma subclasse do
dict
tipo interno que o Python possui. A implementação estava totalmente vazia - alguém tinha acabado de pensar: "podemos precisar adicionar funcionalidades personalizadas aos dicionários Python mais tarde, vamos apresentar uma abstração agora, apenas por precaução".E sua resposta desafiadora foi simplesmente: "sempre podemos fazer isso mais tarde, se precisarmos".
Eu acho que às vezes fingimos que seremos programadores piores no futuro do que somos agora, então podemos querer inserir algum tipo de coisinha que pode nos fazer felizes no futuro. Antecipamos as necessidades do futuro. "Se o tráfego for 100 vezes maior do que pensamos, essa abordagem não será dimensionada, por isso temos de colocar o investimento inicial nessa abordagem mais difícil que será dimensionada". Muito suspeito.
Se levarmos esse conselho a sério, precisamos identificar quando "mais tarde" chegou. Provavelmente, a coisa mais óbvia seria estabelecer um limite superior na duração das coisas por razões de estilo. E acho que o melhor conselho restante seria usar DRY - não se repita - com essas heurísticas sobre os comprimentos das linhas para corrigir um buraco nos princípios do SOLID. Com base na heurística de 30 linhas, sendo uma "página" de texto e uma analogia com a prosa,
Como mencionei lá em cima, testei essas estatísticas com a árvore de fontes Linux atual para encontrar essas porcentagens aproximadas, mas elas também raciocinam na analogia literária.
fonte