Suponha que eu tenha um segmento de código para conectar-se à Internet e mostrar os resultados da conexão como ele:
HttpRequest* httpRequest=new HttpRequest();
httpRequest->setUrl("(some domain .com)");
httpRequest->setRequestType(HttpRequest::Type::POST);
httpRequest->setRequestData("(something like name=?&age=30&...)");
httpRequest->setResponseCallback([=](HttpClient* client, HttpResponse* response){
string responseString=response->getResponseDataString();
if(response->getErrorCode()!=200){
if(response->getErrorCode()==404){
Alert* alert=new Alert();
alert->setFontSize(30);
alert->setFontColor(255,255,255);
alert->setPosition(Screen.MIDDLE);
alert->show("Connection Error","Not Found");
}else if((some other different cases)){
(some other alert)
}else
Alert* alert=new Alert();
alert->setFontSize(30);
alert->setPosition(Screen.MIDDLE);
alert->setFontColor(255,255,255);
alert->show("Connection Error","unknown error");
}
}else{
(other handle methods depend on different URL)
}
}
o código é longo e é comumente usado, mas o código acima não exige itens extras, como função e classe personalizadas (HttpRequest e Alert são fornecidos por estrutura por padrão) e, embora o segmento de código seja longo, é simples e não complexo (é longo apenas porque existem pacotes de configurações como url, tamanho da fonte ...) e o segmento de código tem pequenas variações entre as classes (por exemplo: url, dados de solicitação, casos de manipulação de código de erro, manipulação normal casos ...)
Minha pergunta é: é aceitável copiar e colar códigos longos, mas diretos, em vez de agrupá-los em uma função para reduzir a dependência do código?
Alert
objetos?) Agora imagine que você precisa encontrar todas as instâncias copiadas desse código para corrigir o erro. Agora imagine que não é você quem deve fazer isso, mas um assassino maluco que sabe que você foi quem criou todas essas cópias em primeiro lugar.Respostas:
Você precisa considerar o custo da mudança. E se você quisesse mudar como as conexões são feitas? Quão fácil seria? Se você tiver muito código duplicado, encontrar todos os locais que precisam ser alterados pode ser bastante demorado e propenso a erros.
Você também precisa considerar a clareza. Provavelmente, ter que analisar 30 linhas de código não será tão fácil de entender como uma única chamada para uma função "connectToInternet". Quanto tempo será perdido tentando entender o código quando novas funcionalidades precisarem ser adicionadas?
Existem certos casos raros em que a duplicação não é um problema. Por exemplo, se você estiver fazendo um experimento e o código será descartado no final do dia. Mas, em geral, o custo da duplicação supera a pequena economia de tempo em não precisar extrair o código para uma função separada .
Consulte também https://softwareengineering.stackexchange.com/a/103235/63172
fonte
HttpRequest
são todos iguais " é uma falácia fácil de se fazer.Não.
De fato, mesmo seu código "simples" deve ser dividido em partes menores. Ao menos dois.
Um para fazer a conexão e lidar com a resposta 200 normal. Por exemplo, e se você mudar de um POST para um PUT em alguns casos? E se você estiver fazendo zilhões dessas conexões e precisar de algum multiencadeamento ou pool de conexões? Ter o código em um único local, com um argumento para o método, tornará isso muito mais fácil
Da mesma forma, outro para lidar com erros. Por exemplo, se você alterar a cor ou o tamanho da fonte do alerta. Ou você está tendo problemas com conexões intermitentes e deseja registrar os erros.
fonte
Não.
Para mim, o argumento decisivo é este:
Se você usa um trecho de código em mais de um local, quando ele muda, é necessário alterá- lo em mais de um local ou você começa a obter inconsistências - "coisas estranhas" começam a acontecer (ou seja, você introduz Bugs).
E, portanto, deve ser ainda mais fácil refatorar em uma função.
E o que os usuários gostam de mudar? Fontes, tamanhos, cores, etc., etc.
Agora; em quantos lugares você precisará alterar o mesmo trecho de código para obter a mesma cor / fonte / tamanho novamente? (Resposta recomendada: apenas uma ).
Variação => parâmetro (s) da função.
fonte
Isso realmente não tem nada a ver com copiar e colar. Se você pegar o código de outro lugar, no segundo, o código é seu e sua responsabilidade; portanto, se ele é copiado ou gravado completamente por você, não faz diferença.
Nos seus alertas, você toma algumas decisões de design. Provavelmente, decisões de design semelhantes devem ser tomadas para todos os alertas. Portanto, é provável que você deva ter um método em algum lugar "ShowAlertInAStyleSuitableForMyApplication" ou talvez um pouco mais curto, e isso deve ser chamado.
Você terá muitas solicitações http com tratamento de erro semelhante. Você provavelmente não deve duplicar o tratamento de erros repetidamente, mas extrair o tratamento de erros comum. Especialmente se o tratamento de erros se tornar um pouco mais elaborado (e quanto aos erros de tempo limite, 401 e assim por diante).
fonte
A duplicação é boa em algumas circunstâncias. Mas não neste. Esse método é muito complexo. Há um limite inferior, quando a duplicação é mais fácil do que "fatorar" um método.
Por exemplo:
é estúpido, basta fazer a + b.
Mas quando você se torna um pouco mais complexo, geralmente fica exagerado.
Deve se tornar
No seu caso, vejo quatro "métodos". Provavelmente em diferentes classes. Um para fazer a solicitação, um para obter a resposta, outro para exibir erros e algum tipo de retorno de chamada para ser chamado após o retorno da resposta para processar a resposta. Pessoalmente, provavelmente adicionaria uma espécie de "invólucro" além disso, para facilitar as chamadas.
No final, para fazer uma solicitação da Web, eu gostaria que uma chamada se parecesse com:
Essa linha é o que eu teria em todo o meu código. Então, quando eu precisava fazer alterações em "como eu recebo coisas", eu podia fazer isso rapidamente, com muito menos esforço.
Isso também mantém o código SECO e ajuda com o SRP .
fonte
Em um projeto de qualquer tamanho / complexidade, desejo encontrar código quando necessário para os seguintes fins:
Não seria adorável ingressar em um projeto em andamento ou continuar trabalhando em um projeto por vários anos e quando uma nova solicitação para "conectar-se à Internet e mostrar os resultados da conexão" estava em um local fácil de encontrar devido a uma bom design em vez de depender de fazer uma pesquisa em todo o código para uma solicitação de ativação? Provavelmente é mais fácil encontrar com o Google.
Não se preocupe, eu sou o novo cara e refatorarei esse bloco de código porque estou muito chateado por me juntar a essa equipe sem noção com a terrível base de código ou agora estou sob muita pressão como o resto você e apenas copiará e colará. Pelo menos, manterá o chefe longe das minhas costas. Então, quando o projeto for realmente identificado como um desastre, serei o primeiro a recomendar que o reescrevamos copiando e colando a versão na melhor e mais recente estrutura que nenhum de nós entende.
fonte
Uma classe e / ou uma função é melhor, pelo menos na minha opinião. Pela primeira vez, ele torna o arquivo menor, o que é um ganho muito alto se você lida com aplicativos da Web ou aplicativos para dispositivos com pouco armazenamento (IoT, telefones mais antigos etc.)
E, obviamente, o melhor ponto é que, se você tem algo para mudar devido a novos protocolos, etc., basta alterar o conteúdo da função e, inúmeras vezes, coloca essa função em algum lugar que pode estar em arquivos diferentes, dificultando ainda mais a sua execução. encontre e mude.
Eu escrevi um intérprete inteiro para poder mudar melhor do MySQL para o MySQLi em PHP, porque só preciso mudar meu intérprete e tudo está funcionando, embora esse seja um exemplo um pouco extremo.
fonte
Para decidir se um código deve ser duplicado ou movido para uma função chamada duas vezes, tente determinar qual é mais provável:
Será necessário alterar os dois usos do código da mesma maneira.
Será necessário alterar pelo menos um uso do código para que eles sejam diferentes.
No primeiro caso, provavelmente será melhor ter uma função para lidar com ambos os usos; neste último caso, provavelmente será melhor ter um código separado para os dois usos.
Ao decidir se um pedaço de código que será usado uma vez deve ser escrito em linha ou extraído para outra função, descubra como alguém descreveria completamente o comportamento necessário da função. Se uma descrição completa e precisa do comportamento necessário da função for maior ou maior que o próprio código, movê-lo para uma função separada pode tornar as coisas mais difíceis de entender do que mais fáceis. Ainda pode valer a pena fazer se houver uma alta probabilidade de que um segundo chamador precise usar a mesma função, e quaisquer alterações futuras na função precisarão afetar os dois chamadores, mas, na ausência de tal consideração, a legibilidade favoreceria a divisão das coisas. até o nível em que o código e uma descrição do comportamento necessário seriam igualmente longos.
fonte