Código Duplicado
Repetição é sinal de maturidade�Repetição é sinal de maturidade
Repetição é sinal de maturidade
Repetição é sinal de maturidade
Repetição é sinal de maturidade
06/2023
Código Duplicado
Repetição é sinal de maturidade�Repetição é sinal de maturidade
Repetição pode ser sinal de maturidade
06/2023
Vinítius Salomão
Staff Software Engineer
@vinitius
@vinitius
/vinitius
Zero Hash
Crypto-as-a-Service�Leader
Trading
Blockchain�Intercom
Real time�data
Number one in the stink parade is duplicated code. If you see the same code structure in more than one place, you can be sure that your program will be better if you find a way to unify them.
—Martin Fowler & Kent Beck - Refactoring
D.R.Y
Don't Repeat Yourself
D.R.Y
Don't Repeat Yourself
"Duplicação sai muito mais barato do que lidar com a abstração errada"
"Duplicação sai muito mais barato do que lidar com a abstração errada"
Generalização Prematura
"This is really going to be a clean framework. I'll make an ABSTRACT CLASS out of this part so that folks can SUBCLASS it later, and I'll put in a bunch of well-commented OVERRIDABLE hooks in the concrete SUBCLASSES so that folks can use them as TEMPLATES, and just in case somebody ever needs to build special debug SUBCLASSES, I'll put in extra STUBS over there (somebody will thank me for 'em one of these days). Yeah, this is really going to be neat."
https://wiki.c2.com/?PrematureGeneralization
Uma função sem um nome bem definido
Um parâmetro com sempre o mesmo valor
Métodos com sobrecarga sem nenhuma similaridade entre si
Classe Abstrata com apenas 1 descendente
Uma biblioteca utilizada apenas por 1 programa
W.E.T
W.E.T
Write Every Time
Duplicação Acidental
BaseController extends <SomeFrameworkNativeController> {
.....
(métodos descolados que reduzirão a duplicidade)
.....
}
CheckoutController extends BaseController {
.....
(métodos descolados que reduzirão ainda mais a duplicidade para um fluxo específico)
.....
}
CartController extends CheckoutController {
@Override
public void doIt(it Something<T>) {
this.justDoIt(it);
}
}
Identificar o comportamento exato do Controller contendo a implementação concreta se tornou extremamente mais complexo
Novos membros integrados agora devem suportar a carga cognitiva do Framework utilizado assim como da abstração (desnecessária)
Em muitos desses casos, a duplicação inicial é meramente Acidental, pois a lógica de negócio e sintaxe poderá evoluir de formas completamente diferentes.
function saveFile(moduleName: string, fileName: string, json: any) {
try {
const path = `${toFolderName(moduleName)}/${toFileName(fileName)}`
fs.writeFileSync(`./${path}.json`, JSON.stringify(json));
} catch(err) {
console.error(err);
}
}
https://medium.com/@mariusbongarts/when-you-should-duplicate-code-b0d747bc1c67
function toFileName(fileName:string) {
return fileName.split(/(?=[A-Z])/).join('_').toLowerCase();
}
function toFolderName(moduleName: string) {
return moduleName.split(/(?=[A-Z])/).join('_').toLowerCase();
}
function toFileOrFolderName(fileOrFolderName:string) {
return fileOrFolderName.split(/(?=[A-Z])/).join('_').toLowerCase();
}
function saveFile(moduleName: string, fileName: string, json: any) {
try {
const path = `${toFileOrFolderName(moduleName)}/${toFileOrFolderName(fileName)}`
fs.writeFileSync(`./${path}.json`, JSON.stringify(json));
} catch(err) {
console.error(err);
}
}
Os arquivos devem conter no nome o timestamp do momento em que foram salvos. E Agora?
function toFileOrFolderName(fileOrFolderName:string, isFile: boolean) {
const underScoreName = fileOrFolderName.split(/(?=[A-Z])/).join('_').toLowerCase();
if (isFile) {
return `${new Date().getTime()}_${underScoreName}`
}
return underScoreName;
}
function toFileOrFolderName(fileOrFolderName:string, isFile: boolean) {
const underScoreName = fileOrFolderName.split(/(?=[A-Z])/).join('_').toLowerCase();
if (isFile) {
return `${new Date().getTime()}_${underScoreName}`
}
return underScoreName;
}
function toUnderscore(camelCase: string) {
return camelCase.split(/(?=[A-Z])/).join('_').toLowerCase();
}
function toFileName(fileName:string) {
const timeStamp = new Date().getTime();
return `${timeStamp}_${toUnderscore(fileName)}`;
}
function toFolderName(moduleName: string) {
return toUnderscore(moduleName);
}
“Three strikes and you refactor”
WhiteDwarfException
Perspectiva Arquitetural
Entidades de Domínio
Bibliotecas "Utilitárias"
Frameworks em cima de Frameworks
Analisadores Estáticos
Pensamentos Finais
Código "Molhado"
Atenção às nuances e tradeoffs de cada contexto
Cuidado com bibliotecas utilitárias
Duplicação > Acoplamento (99% dos casos)
Clean Code != Clever Code
Perguntas?
Muito Obrigado!